PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/VersionControl/Hg/Command/Log.php

https://bitbucket.org/mgatto/versioncontrol_hg
PHP | 387 lines | 121 code | 30 blank | 236 comment | 5 complexity | 9d7e68d7af77e522461045273466f915 MD5 | raw file
  1. <?php
  2. /**
  3. * Contains the definition of the Log command
  4. *
  5. * PHP version 5
  6. *
  7. * @category VersionControl
  8. * @package Hg
  9. * @subpackage Command
  10. * @author Michael Gatto <mgatto@lisantra.com>
  11. * @copyright 2011 Lisantra Technologies, LLC
  12. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  13. * @link http://pear.php.net/package/VersionControl_Hg
  14. * @filesource
  15. */
  16. /**
  17. * Implements the log command.
  18. *
  19. * The hg command-line client also uses 'history' as an alias.
  20. * * <code>
  21. * include_once 'VersionControl/Hg.php';
  22. * $hg = new VersionControl_Hg('/path/to/repository');
  23. * $hg->log()->run('verbose');
  24. * </code>
  25. *
  26. * Show only log entries for the following dates:
  27. * <code>
  28. * $hg->log()->on('Dec 27, 2010')->run();
  29. * $hg->log()->before('Dec 27, 2010')->run();
  30. * $hg->log()->after('Dec 27, 2010')->run();
  31. * $hg->log()->between('Dec 27, 2010', '2010-12-31')->run();
  32. * </code>
  33. *
  34. * Show only log entries for revision 2:
  35. * <code>
  36. * $hg->log()->revision('2')->format('raw')->run('verbose');
  37. * $hg->log()->revision('2')->run('verbose');
  38. * </code>
  39. *
  40. * Show only log entries for specific files:
  41. * <code>
  42. * $hg->log()->files(array('index.php'))->run();
  43. * </code>
  44. *
  45. * Exclude log entries for certain files:
  46. * <code>
  47. * $hg->log()->excluding('**.php')->run();
  48. * </code>
  49. *
  50. * This displays nothing; excluding takes precedence. Remove excluding() to
  51. * get only index.php:
  52. * <code>
  53. * $hg->log()->files(array('index.php'))->excluding('**.php')->run();
  54. * </code>
  55. *
  56. * Include specific files, which might not show up otherwise. Using this with
  57. * files can lead to unexpected results:
  58. * <code>
  59. * $hg->log()->including('**.php')->run();
  60. * </code>
  61. *
  62. * Patching and diffing options are not available in this class as they might
  63. * be when using the command line Mercurial client.
  64. *
  65. * PHP version 5
  66. *
  67. * @category VersionControl
  68. * @package Hg
  69. * @subpackage Command
  70. * @author Michael Gatto <mgatto@lisantra.com>
  71. * @copyright 2011 Lisantra Technologies, LLC
  72. * @license http://www.opensource.org/licenses/mit-license.html MIT License
  73. * @link http://pear.php.net/package/VersionControl_Hg
  74. * @example test_Log.php Some examples to use
  75. */
  76. class VersionControl_Hg_Command_Log
  77. extends VersionControl_Hg_Command_Abstract
  78. implements VersionControl_Hg_Command_Interface
  79. {
  80. /**
  81. * The name of the mercurial command implemented here
  82. *
  83. * @var string
  84. */
  85. protected $command = 'log';
  86. /**
  87. * Template which Mercurial uses to ouput data
  88. *
  89. * @var string
  90. */
  91. protected $template = '{rev}##{branch}##{files}##{date}##{author}##{desc}\r\n';
  92. /**
  93. * Required options for this specific command
  94. *
  95. * These may not be required by Mercurial itself, but are required for the
  96. * proper functioning of VersionControl_Hg.
  97. *
  98. * @var mixed
  99. */
  100. protected $required_options = array(
  101. 'noninteractive' => null,
  102. 'repository' => null,
  103. 'template' => null,
  104. );
  105. /**
  106. * Allowed options for this specific command
  107. *
  108. * The actual option must be the key, while 'null' is a value here to
  109. * accommodate the current implementation of setting options.
  110. *
  111. * @var mixed
  112. */
  113. protected $allowed_options = array(
  114. 'follow' => null,
  115. 'at' => null,
  116. 'on' => null,
  117. 'between' => null,
  118. 'files' => null, // implement with search_for() / searchFor / search
  119. 'keyword' => null,
  120. 'limit' => null,
  121. 'branch' => null, //or should we force a branch selection first?
  122. 'copies' => null, //show copied files
  123. 'removed' => null, //show removed files
  124. 'date' => null,
  125. 'rev' => null,
  126. );
  127. /**
  128. * Constructor
  129. *
  130. * @param mixed $params One or more parameters for the command
  131. * @param VersionControl_Hg $hg Instance of the base object
  132. *
  133. * @return void
  134. */
  135. public function __construct($params = null, VersionControl_Hg $hg)
  136. {
  137. /* Make $hg available to option methods */
  138. $this->hg = $hg;
  139. /* should always be called so we have a full array of valid options */
  140. $this->setOptions($params);
  141. $this->addOption('template', "$this->template");
  142. }
  143. /**
  144. * Execute the command and return the results.
  145. *
  146. * @param mixed $params Options passed to the Log command
  147. * @param VersionControl_Hg $hg Instance of the base object
  148. *
  149. * @return string
  150. */
  151. public function execute(array $params = null, VersionControl_Hg $hg = null)
  152. {
  153. /* take care of options passed in as such:
  154. * $hg->status(array('revision' => 3, 'all' => null));
  155. * We need 'all' to be the key, and not have it interpreted as
  156. * revision => 3, 0 => all */
  157. if ( ! empty($params) ) {
  158. $this->setOptions($params);
  159. }
  160. /* --noninteractive is required since issuing the command is
  161. * unattended by nature of using this package.
  162. * --repository PATH is required since the PWD on which hg is invoked
  163. * will not be within the working copy of the repo. */
  164. $this->addOptions(
  165. array(
  166. 'noninteractive' => null,
  167. 'repository' => $this->hg->getRepository()->getPath(),
  168. 'cwd' => $this->hg->getRepository()->getPath(),
  169. )
  170. );
  171. /* Despite its being so not variable, we need to set the command string
  172. * only after manually setting options and other command-specific data */
  173. $this->setCommandString();
  174. /* no var assignment, since 2nd param holds output */
  175. exec($this->command_string, $this->output, $this->status);
  176. if ( $this->status !== 0 ) {
  177. throw new VersionControl_Hg_Command_Exception(
  178. VersionControl_Hg_Command_Exception::COMMANDLINE_ERROR
  179. );
  180. }
  181. return $this->parseOutput(
  182. $this->output,
  183. array('rev', 'branch', 'files', 'datetime', 'author', 'description'),
  184. '##'
  185. );
  186. }
  187. /**
  188. * Specified the revision to restrict the log operation to
  189. *
  190. * Usage:
  191. * <code>$hg->log('all')->revision(7)->run();</code>
  192. * or
  193. * <code>$hg->log(array('revision' => 7 ))->all()->run();</code>
  194. *
  195. * @param string $revision The revision for which to show the log for
  196. *
  197. * @return void
  198. */
  199. public function revision($revision = 'tip')
  200. {
  201. //@TODO Technically, the following shouldn't occur since 'tip' is default
  202. if ( empty($revision)) {
  203. throw new VersionControl_Hg_Command_Exception(
  204. VersionControl_Hg_Command_Exception::BAD_ARGUMENT
  205. );
  206. }
  207. //@TODO Not sure of the value of this here, instead of a raw string
  208. /*require_once realpath('../Container/Repository/Revision.php');
  209. $revision_instance = new VersionControl_Hg_Repository_Revision(
  210. $revision
  211. );*/
  212. $this->addOption('rev', $revision); //$revision_instance
  213. /* For the fluent API */
  214. return $this;
  215. }
  216. /**
  217. * Returns only files which have been removed from the working copy
  218. * and are no longer tracked by Mercurial.
  219. *
  220. * Usage:
  221. * <code>$hg->log()->removed()->run();</code>
  222. * or
  223. * <code>$hg->log('removed')->run();</code>
  224. *
  225. * @return null
  226. */
  227. public function removed()
  228. {
  229. $this->addOption('removed');
  230. return $this; //for the fluent API
  231. }
  232. /**
  233. * Returns only files copied within the working copy
  234. *
  235. * Usage:
  236. * <code>$hg->log()->copied()->run();</code>
  237. * or
  238. * <code>$hg->log('copied')->run();</code>
  239. *
  240. * @return null
  241. */
  242. public function copied()
  243. {
  244. $this->addOption('copied');
  245. return $this; //for the fluent API
  246. }
  247. /**
  248. * List status information for only the files specified.
  249. *
  250. * VersionControl_Hg_Command_Abstract::formatOptions will automatically
  251. * make this the last option since a files list must be the last item on
  252. * the command line.
  253. *
  254. * Usage:
  255. * <code>$hg->log()->files(array('index.php'))->run();</code>
  256. * or
  257. * <code>$hg->log(array('files' => array('index.php')))->run();</code>
  258. *
  259. * @param mixed $files the list of files as a simple array
  260. *
  261. * @return null
  262. */
  263. public function files(array $files)
  264. {
  265. /* is it a pattern or a simple array of files?
  266. * the scheme must be the very first key.
  267. * Must cast to string since numerical zero seems to always be in an
  268. * array?! (string '0' is not!) */
  269. if ( in_array((string) key($files), array('glob','re','set','path','listfile')) ) {
  270. /* Yup, its a scheme:pattern */
  271. $filter = $this->parseFilter($files);
  272. } else {
  273. $filter = join(' ', $files);
  274. }
  275. $this->addOption('files', $filter);
  276. /* for the fluent API */
  277. return $this;
  278. }
  279. /**
  280. * Restricts the log to changesets only commited on $date
  281. *
  282. * Usage:
  283. * <code>$hg->log()->on('Dec 27, 2010')->run();</code>
  284. *
  285. * @param string $date Show log entries only for this exact date
  286. *
  287. * @return VersionControl_Hg_Command_Log
  288. */
  289. public function on($date)
  290. {
  291. $this->addOption(
  292. 'date',
  293. "\"" . date('Y-m-d G:i:s', strtotime($date)) . "\""
  294. );
  295. return $this;
  296. }
  297. /**
  298. * Restricts the log to changesets only commited before $date
  299. *
  300. * Usage:
  301. * <code>
  302. * * $hg->log()->before('Dec 27, 2010')->run();</code>
  303. *
  304. * @param string $date Show log entries only before this date
  305. *
  306. * @return VersionControl_Hg_Command_Log
  307. */
  308. public function before($date)
  309. {
  310. $this->addOption(
  311. 'date',
  312. "\"<" . date('Y-m-d G:i:s', strtotime($date)) . "\""
  313. );
  314. return $this;
  315. }
  316. /**
  317. * Restricts the log to changesets only commited after $date
  318. *
  319. * Usage:
  320. * <code>
  321. * $hg->log()->after('Dec 27, 2010')->run();</code>
  322. *
  323. * @param string $date Show log entries only after this date
  324. *
  325. * @return VersionControl_Hg_Command_Log
  326. */
  327. public function after($date)
  328. {
  329. $this->addOption(
  330. 'date',
  331. "\">" . date('Y-m-d G:i:s', strtotime($date)) . "\""
  332. );
  333. return $this;
  334. }
  335. /**
  336. * Restricts log output to changesets between dates $from and $to
  337. *
  338. * Usage:
  339. * <code>$hg->log()->between('Dec 27, 2010', '2010-12-31')->run();</code>
  340. *
  341. * @param string $from Show log entries from this date forward
  342. * @param string $to Show log entries only before this date
  343. *
  344. * @return VersionControl_Hg_Command_Log
  345. */
  346. public function between($from, $to)
  347. {
  348. /* validate inputs */
  349. //if ( empty() ) {
  350. $this->addOption(
  351. 'date',
  352. "\"" . date('Y-m-d G:i:s', strtotime($from)) . " to " .
  353. date('Y-m-d G:i:s', strtotime($to)) . "\""
  354. );
  355. return $this;
  356. }
  357. }