LogCommand::execute()   F
last analyzed

Complexity

Conditions 21
Paths 4592

Size

Total Lines 138
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 462

Importance

Changes 12
Bugs 0 Features 0
Metric Value
eloc 79
dl 0
loc 138
ccs 0
cts 83
cp 0
rs 0
c 12
b 0
f 0
cc 21
nc 4592
nop 2
crap 462

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Command;
12
13
14
use ConsoleHelpers\ConsoleKit\Exception\CommandException;
15
use ConsoleHelpers\SVNBuddy\Config\AbstractConfigSetting;
16
use ConsoleHelpers\SVNBuddy\Config\IntegerConfigSetting;
17
use ConsoleHelpers\SVNBuddy\Config\RegExpsConfigSetting;
18
use ConsoleHelpers\SVNBuddy\Repository\Parser\RevisionListParser;
19
use ConsoleHelpers\SVNBuddy\Repository\RevisionLog\RevisionLog;
20
use ConsoleHelpers\SVNBuddy\Repository\RevisionLog\RevisionPrinter;
21
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
22
use Symfony\Component\Console\Input\InputArgument;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Input\InputOption;
25
use Symfony\Component\Console\Output\OutputInterface;
26
27
class LogCommand extends AbstractCommand implements IAggregatorAwareCommand, IConfigAwareCommand
28
{
29
30
	const SETTING_LOG_LIMIT = 'log.limit';
31
32
	const SETTING_LOG_MESSAGE_LIMIT = 'log.message-limit';
33
34
	const SETTING_LOG_MERGE_CONFLICT_REGEXPS = 'log.merge-conflict-regexps';
35
36
	const ALL_REFS = 'all';
37
38
	/**
39
	 * Revision list parser.
40
	 *
41
	 * @var RevisionListParser
42
	 */
43
	private $_revisionListParser;
44
45
	/**
46
	 * Revision log
47
	 *
48
	 * @var RevisionLog
49
	 */
50
	private $_revisionLog;
51
52
	/**
53
	 * Revision printer.
54
	 *
55
	 * @var RevisionPrinter
56
	 */
57
	private $_revisionPrinter;
58
59
	/**
60
	 * Prepare dependencies.
61
	 *
62
	 * @return void
63
	 */
64
	protected function prepareDependencies()
65
	{
66
		parent::prepareDependencies();
67
68
		$container = $this->getContainer();
69
70
		$this->_revisionListParser = $container['revision_list_parser'];
71
		$this->_revisionPrinter = $container['revision_printer'];
72
	}
73
74
	/**
75
	 * {@inheritdoc}
76
	 */
77
	protected function configure()
78
	{
79
		$this->pathAcceptsUrl = true;
80
81
		$this
82
			->setName('log')
83
			->setDescription(
84
				'Show the log messages for a set of revisions, bugs, paths, refs, etc.'
85
			)
86
			->addArgument(
87
				'path',
88
				InputArgument::OPTIONAL,
89
				'Working copy path or URL',
90
				'.'
91
			)
92
			->addOption(
93
				'revisions',
94
				'r',
95
				InputOption::VALUE_REQUIRED,
96
				'List of revision(-s) and/or revision range(-s), e.g. <comment>53324</comment>, <comment>1224-4433</comment>'
97
			)
98
			->addOption(
99
				'bugs',
100
				'b',
101
				InputOption::VALUE_REQUIRED,
102
				'List of bug(-s), e.g. <comment>JRA-1234</comment>, <comment>43644</comment>'
103
			)
104
			->addOption(
105
				'refs',
106
				null,
107
				InputOption::VALUE_REQUIRED,
108
				'List of refs, e.g. <comment>trunk</comment>, <comment>branches/branch-name</comment>, <comment>tags/tag-name</comment> or <comment>all</comment> for all refs'
109
			)
110
			->addOption(
111
				'merges',
112
				null,
113
				InputOption::VALUE_NONE,
114
				'Show merge revisions only'
115
			)
116
			->addOption(
117
				'no-merges',
118
				null,
119
				InputOption::VALUE_NONE,
120
				'Hide merge revisions'
121
			)
122
			->addOption(
123
				'merged',
124
				null,
125
				InputOption::VALUE_NONE,
126
				'Shows only revisions, that were merged at least once'
127
			)
128
			->addOption(
129
				'not-merged',
130
				null,
131
				InputOption::VALUE_NONE,
132
				'Shows only revisions, that were not merged'
133
			)
134
			->addOption(
135
				'merged-by',
136
				null,
137
				InputOption::VALUE_REQUIRED,
138
				'Show revisions merged by list of revision(-s) and/or revision range(-s)'
139
			)
140
			->addOption(
141
				'action',
142
				null,
143
				InputOption::VALUE_REQUIRED,
144
				'Show revisions, whose paths were affected by specified action, e.g. <comment>A</comment>, <comment>M</comment>, <comment>R</comment>, <comment>D</comment>'
145
			)
146
			->addOption(
147
				'kind',
148
				null,
149
				InputOption::VALUE_REQUIRED,
150
				'Show revisions, whose paths match specified kind, e.g. <comment>dir</comment> or <comment>file</comment>'
151
			)
152
			->addOption(
153
				'author',
154
				null,
155
				InputOption::VALUE_REQUIRED,
156
				'Show revisions, made by a given author'
157
			)
158
			->addOption(
159
				'with-full-message',
160
				'f',
161
				InputOption::VALUE_NONE,
162
				'Shows non-truncated commit messages'
163
			)
164
			->addOption(
165
				'with-details',
166
				'd',
167
				InputOption::VALUE_NONE,
168
				'Shows detailed revision information, e.g. paths affected'
169
			)
170
			->addOption(
171
				'with-summary',
172
				's',
173
				InputOption::VALUE_NONE,
174
				'Shows number of added/changed/removed paths in the revision'
175
			)
176
			->addOption(
177
				'with-refs',
178
				null,
179
				InputOption::VALUE_NONE,
180
				'Shows revision refs'
181
			)
182
			->addOption(
183
				'with-merge-oracle',
184
				null,
185
				InputOption::VALUE_NONE,
186
				'Shows number of paths in the revision, that can cause conflict upon merging'
187
			)
188
			->addOption(
189
				'with-merge-status',
190
				null,
191
				InputOption::VALUE_NONE,
192
				'Shows merge revisions affecting this revision'
193
			)
194
			->addOption(
195
				'max-count',
196
				null,
197
				InputOption::VALUE_REQUIRED,
198
				'Limit the number of revisions to output'
199
			)
200
			->addOption(
201
				'aggregate',
202
				'a',
203
				InputOption::VALUE_NONE,
204
				'Aggregate displayed revisions by bugs'
205
			);
206
207
		parent::configure();
208
	}
209
210
	/**
211
	 * Return possible values for the named option
212
	 *
213
	 * @param string            $optionName Option name.
214
	 * @param CompletionContext $context    Completion context.
215
	 *
216
	 * @return array
217
	 */
218
	public function completeOptionValues($optionName, CompletionContext $context)
219
	{
220
		$ret = parent::completeOptionValues($optionName, $context);
221
222
		if ( $optionName === 'refs' ) {
223
			return $this->getAllRefs();
224
		}
225
		elseif ( $optionName === 'action' ) {
226
			return $this->getAllActions();
227
		}
228
		elseif ( $optionName === 'kind' ) {
229
			return $this->getAllKinds();
230
		}
231
232
		return $ret;
233
	}
234
235
	/**
236
	 * {@inheritdoc}
237
	 */
238
	public function initialize(InputInterface $input, OutputInterface $output)
239
	{
240
		parent::initialize($input, $output);
241
242
		$this->_revisionLog = $this->getRevisionLog($this->getWorkingCopyUrl());
243
	}
244
245
	/**
246
	 * {@inheritdoc}
247
	 *
248
	 * @throws CommandException When specified revisions are not present in current project.
249
	 * @throws CommandException When project contains no associated revisions.
250
	 * @throws CommandException When bugs from "--bugs" option are not found.
251
	 */
252
	protected function execute(InputInterface $input, OutputInterface $output)
253
	{
254
		$searching_start = microtime(true);
255
		$bugs = $this->getList($this->io->getOption('bugs'));
0 ignored issues
show
Bug introduced by
It seems like $this->io->getOption('bugs') can also be of type string[]; however, parameter $string of ConsoleHelpers\SVNBuddy\...tractCommand::getList() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

255
		$bugs = $this->getList(/** @scrutinizer ignore-type */ $this->io->getOption('bugs'));
Loading history...
256
		$revisions = $this->getList($this->io->getOption('revisions'));
257
258
		$missing_revisions = array();
259
		$revisions_by_path = $this->getRevisionsByPath();
260
261
		if ( $revisions || $bugs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Bug Best Practice introduced by
The expression $bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
262
			if ( $revisions ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
263
				$revisions = $this->_revisionListParser->expandRanges($revisions);
264
265
				// Don't check missing revisions from bugs, because they can affect different repository paths.
266
				$missing_revisions = array_diff($revisions, $revisions_by_path);
267
			}
268
269
			if ( $bugs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
270
				$revisions_from_bugs = $this->_revisionLog->find('bugs', $bugs);
271
272
				if ( !$revisions_from_bugs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $revisions_from_bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
273
					throw new CommandException('Specified bugs aren\'t mentioned in any of revisions');
274
				}
275
276
				$revisions = array_merge($revisions, $revisions_from_bugs);
277
			}
278
279
			// Only show revisions on given path.
280
			$revisions_by_path = array_intersect($revisions_by_path, $revisions);
281
		}
282
283
		$merged_by = $this->getList($this->io->getOption('merged-by'));
284
285
		if ( $merged_by ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $merged_by of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
286
			$merged_by = $this->_revisionListParser->expandRanges($merged_by);
287
			$revisions_by_path = $this->_revisionLog->find('merges', $merged_by);
288
		}
289
290
		if ( $this->io->getOption('merges') ) {
291
			$revisions_by_path = array_intersect($revisions_by_path, $this->_revisionLog->find('merges', 'all_merges'));
292
		}
293
		elseif ( $this->io->getOption('no-merges') ) {
294
			$revisions_by_path = array_diff($revisions_by_path, $this->_revisionLog->find('merges', 'all_merges'));
295
		}
296
297
		if ( $this->io->getOption('merged') ) {
298
			$revisions_by_path = array_intersect($revisions_by_path, $this->_revisionLog->find('merges', 'all_merged'));
299
		}
300
		elseif ( $this->io->getOption('not-merged') ) {
301
			$revisions_by_path = array_diff($revisions_by_path, $this->_revisionLog->find('merges', 'all_merged'));
302
		}
303
304
		$action = $this->io->getOption('action');
305
306
		if ( $action ) {
307
			if ( !in_array($action, $this->getAllActions()) ) {
308
				throw new CommandException('The "' . $action . '" action is unknown.');
0 ignored issues
show
Bug introduced by
Are you sure $action of type string|string[]|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

308
				throw new CommandException('The "' . /** @scrutinizer ignore-type */ $action . '" action is unknown.');
Loading history...
309
			}
310
311
			$revisions_by_path = array_intersect(
312
				$revisions_by_path,
313
				$this->_revisionLog->find('paths', 'action:' . $action)
314
			);
315
		}
316
317
		$kind = $this->io->getOption('kind');
318
319
		if ( $kind ) {
320
			if ( !in_array($kind, $this->getAllKinds()) ) {
321
				throw new CommandException('The "' . $kind . '" kind is unknown.');
0 ignored issues
show
Bug introduced by
Are you sure $kind of type string|string[]|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

321
				throw new CommandException('The "' . /** @scrutinizer ignore-type */ $kind . '" kind is unknown.');
Loading history...
322
			}
323
324
			$revisions_by_path = array_intersect(
325
				$revisions_by_path,
326
				$this->_revisionLog->find('paths', 'kind:' . $kind)
327
			);
328
		}
329
330
		$author = $this->io->getOption('author');
331
332
		if ( $author ) {
333
			$revisions_by_path = array_intersect(
334
				$revisions_by_path,
335
				$this->_revisionLog->find('summary', 'author:' . $author)
336
			);
337
		}
338
339
		if ( $missing_revisions ) {
340
			throw new CommandException($this->getMissingRevisionsErrorMessage($missing_revisions));
341
		}
342
		elseif ( !$revisions_by_path ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $revisions_by_path of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
343
			throw new CommandException('No matching revisions found.');
344
		}
345
346
		rsort($revisions_by_path, SORT_NUMERIC);
347
348
		if ( $bugs || $revisions ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $revisions of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Bug Best Practice introduced by
The expression $bugs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
349
			// Don't limit revisions, when provided explicitly by user.
350
			$revisions_by_path_with_limit = $revisions_by_path;
351
		}
352
		else {
353
			// Apply limit only, when no explicit bugs/revisions are set.
354
			$revisions_by_path_with_limit = array_slice($revisions_by_path, 0, $this->getMaxCount());
355
		}
356
357
		$revisions_by_path_count = count($revisions_by_path);
358
		$revisions_by_path_with_limit_count = count($revisions_by_path_with_limit);
359
360
		if ( $revisions_by_path_with_limit_count === $revisions_by_path_count ) {
361
			$this->io->writeln(sprintf(
362
				' * Showing <info>%d</info> revision(-s) in %s:',
363
				$revisions_by_path_with_limit_count,
364
				$this->getRevisionLogIdentifier()
365
			));
366
		}
367
		else {
368
			$this->io->writeln(sprintf(
369
				' * Showing <info>%d</info> of <info>%d</info> revision(-s) in %s:',
370
				$revisions_by_path_with_limit_count,
371
				$revisions_by_path_count,
372
				$this->getRevisionLogIdentifier()
373
			));
374
		}
375
376
		$searching_duration = microtime(true) - $searching_start;
377
378
		$printing_start = microtime(true);
379
		$this->printRevisions($revisions_by_path_with_limit);
380
		$printing_duration = microtime(true) - $printing_start;
381
382
		$debug_info = 'Generation Time: <info>' . round($searching_duration + $printing_duration, 2) . 's</info>';
383
		$debug_info .= ' (';
384
		$debug_info .= 'searching: <info>' . round($searching_duration, 2) . 's</info>;';
385
		$debug_info .= ' printing: <info>' . round($printing_duration, 2) . 's</info>';
386
		$debug_info .= ').';
387
388
		$this->io->writeln(
389
			$debug_info
390
		);
391
	}
392
393
	/**
394
	 * Returns all refs.
395
	 *
396
	 * @return array
397
	 */
398
	protected function getAllRefs()
399
	{
400
		$ret = parent::getAllRefs();
401
		$ret[] = self::ALL_REFS;
402
403
		return $ret;
404
	}
405
406
	/**
407
	 * Returns all actions.
408
	 *
409
	 * @return array
410
	 */
411
	protected function getAllActions()
412
	{
413
		return array('A', 'M', 'R', 'D');
414
	}
415
416
	/**
417
	 * Returns all actions.
418
	 *
419
	 * @return array
420
	 */
421
	protected function getAllKinds()
422
	{
423
		return array('dir', 'file');
424
	}
425
426
	/**
427
	 * Returns revision log identifier.
428
	 *
429
	 * @return string
430
	 */
431
	protected function getRevisionLogIdentifier()
432
	{
433
		$ret = '<info>' . $this->_revisionLog->getProjectPath() . '</info> project';
434
435
		$ref_name = $this->_revisionLog->getRefName();
436
437
		if ( $ref_name ) {
438
			$ret .= ' (ref: <info>' . $ref_name . '</info>)';
439
		}
440
		else {
441
			$ret .= ' (all refs)';
442
		}
443
444
		return $ret;
445
	}
446
447
	/**
448
	 * Shows error about missing revisions.
449
	 *
450
	 * @param array $missing_revisions Missing revisions.
451
	 *
452
	 * @return string
453
	 */
454
	protected function getMissingRevisionsErrorMessage(array $missing_revisions)
455
	{
456
		$refs = $this->io->getOption('refs');
457
		$missing_revisions = implode(', ', $missing_revisions);
458
459
		if ( $refs ) {
460
			$revision_source = 'in "' . $refs . '" ref(-s)';
0 ignored issues
show
Bug introduced by
Are you sure $refs of type string|string[]|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

460
			$revision_source = 'in "' . /** @scrutinizer ignore-type */ $refs . '" ref(-s)';
Loading history...
461
		}
462
		else {
463
			$revision_source = 'at "' . $this->getWorkingCopyUrl() . '" url';
464
		}
465
466
		return 'The ' . $missing_revisions . ' revision(-s) not found ' . $revision_source . '.';
467
	}
468
469
	/**
470
	 * Returns list of revisions by path.
471
	 *
472
	 * @return array
473
	 * @throws CommandException When given path doesn't exist.
474
	 * @throws CommandException When given refs doesn't exist.
475
	 */
476
	protected function getRevisionsByPath()
477
	{
478
		// When "$path" points to deleted path the "$wc_path" will be parent folder of it (hopefully existing folder).
479
		$path = $this->io->getArgument('path');
480
		$wc_path = $this->getWorkingCopyPath();
481
482
		$refs = $this->getList($this->io->getOption('refs'));
0 ignored issues
show
Bug introduced by
It seems like $this->io->getOption('refs') can also be of type string[]; however, parameter $string of ConsoleHelpers\SVNBuddy\...tractCommand::getList() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

482
		$refs = $this->getList(/** @scrutinizer ignore-type */ $this->io->getOption('refs'));
Loading history...
483
		$relative_path = $this->repositoryConnector->getRelativePath($wc_path);
484
485
		if ( !$this->repositoryConnector->isUrl($wc_path) ) {
486
			$relative_path .= $this->_getPathDifference($wc_path, $path);
0 ignored issues
show
Bug introduced by
It seems like $path can also be of type string[]; however, parameter $sub_path of ConsoleHelpers\SVNBuddy\...d::_getPathDifference() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

486
			$relative_path .= $this->_getPathDifference($wc_path, /** @scrutinizer ignore-type */ $path);
Loading history...
487
		}
488
489
		$relative_path = $this->_crossReferencePathFromRepository($relative_path);
490
491
		if ( $relative_path === null ) {
492
			throw new CommandException(
493
				'The "' . $path . '" path not found in "' . $this->_revisionLog->getProjectPath() . '" project.'
0 ignored issues
show
Bug introduced by
Are you sure $path of type null|string|string[] can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

493
				'The "' . /** @scrutinizer ignore-type */ $path . '" path not found in "' . $this->_revisionLog->getProjectPath() . '" project.'
Loading history...
494
			);
495
		}
496
497
		if ( $refs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $refs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
498
			$incorrect_refs = array_diff($refs, $this->getAllRefs());
499
500
			if ( $incorrect_refs ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $incorrect_refs of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
501
				throw new CommandException(
502
					'The following refs are unknown: "' . implode('", "', $incorrect_refs) . '".'
503
				);
504
			}
505
506
			return $this->_revisionLog->find('refs', $refs);
507
		}
508
509
		return $this->_revisionLog->find('paths', $relative_path);
510
	}
511
512
	/**
513
	 * Returns difference between 2 paths.
514
	 *
515
	 * @param string $main_path Main path.
516
	 * @param string $sub_path  Sub path.
517
	 *
518
	 * @return string
519
	 */
520
	private function _getPathDifference($main_path, $sub_path)
521
	{
522
		if ( $sub_path === '.' || strpos($sub_path, '../') !== false ) {
523
			$sub_path = realpath($sub_path);
524
		}
525
526
		$adapted_sub_path = $sub_path;
527
528
		do {
529
			$sub_path_pos = strpos($main_path, $adapted_sub_path);
530
531
			if ( $sub_path_pos !== false ) {
532
				break;
533
			}
534
535
			$adapted_sub_path = dirname($adapted_sub_path);
536
		} while ( $adapted_sub_path !== '.' );
537
538
		// No sub-matches.
539
		if ( !strlen($adapted_sub_path) ) {
540
			return '';
541
		}
542
543
		return str_replace($adapted_sub_path, '', $sub_path);
544
	}
545
546
	/**
547
	 * Determines path kind from repository.
548
	 *
549
	 * @param string $path Path.
550
	 *
551
	 * @return string|null
552
	 */
553
	private function _crossReferencePathFromRepository($path)
554
	{
555
		$path = rtrim($path, '/');
556
		$try_paths = array($path, $path . '/');
557
558
		foreach ( $try_paths as $try_path ) {
559
			if ( $this->_revisionLog->find('paths', 'exact:' . $try_path) ) {
560
				return $try_path;
561
			}
562
		}
563
564
		return null;
565
	}
566
567
	/**
568
	 * Returns displayed revision limit.
569
	 *
570
	 * @return integer
571
	 */
572
	protected function getMaxCount()
573
	{
574
		$max_count = $this->io->getOption('max-count');
575
576
		if ( $max_count !== null ) {
577
			return $max_count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $max_count returns the type boolean|string|string[] which is incompatible with the documented return type integer.
Loading history...
578
		}
579
580
		return $this->getSetting(self::SETTING_LOG_LIMIT);
581
	}
582
583
	/**
584
	 * Prints revisions.
585
	 *
586
	 * @param array $revisions Revisions.
587
	 *
588
	 * @return void
589
	 */
590
	protected function printRevisions(array $revisions)
591
	{
592
		$column_mapping = array(
593
			'with-full-message' => RevisionPrinter::COLUMN_FULL_MESSAGE,
594
			'with-details' => RevisionPrinter::COLUMN_DETAILS,
595
			'with-summary' => RevisionPrinter::COLUMN_SUMMARY,
596
			'with-refs' => RevisionPrinter::COLUMN_REFS,
597
			'with-merge-oracle' => RevisionPrinter::COLUMN_MERGE_ORACLE,
598
			'with-merge-status' => RevisionPrinter::COLUMN_MERGE_STATUS,
599
		);
600
601
		foreach ( $column_mapping as $option_name => $column ) {
602
			if ( $this->io->getOption($option_name) ) {
603
				$this->_revisionPrinter->withColumn($column);
604
			}
605
		}
606
607
		$this->_revisionPrinter->setMergeConflictRegExps($this->getSetting(self::SETTING_LOG_MERGE_CONFLICT_REGEXPS));
608
		$this->_revisionPrinter->setLogMessageLimit($this->getSetting(self::SETTING_LOG_MESSAGE_LIMIT));
609
610
		$wc_path = $this->getWorkingCopyPath();
611
612
		if ( !$this->repositoryConnector->isUrl($wc_path) ) {
613
			$this->_revisionPrinter->setCurrentRevision(
614
				$this->repositoryConnector->getLastRevision($wc_path)
615
			);
616
		}
617
618
		if ( $this->io->getOption('aggregate') ) {
619
			$this->_revisionPrinter->setAggregateByBug(true);
620
		}
621
622
		$this->_revisionPrinter->printRevisions($this->_revisionLog, $revisions, $this->io->getOutput());
623
	}
624
625
	/**
626
	 * Returns list of config settings.
627
	 *
628
	 * @return AbstractConfigSetting[]
629
	 */
630
	public function getConfigSettings()
631
	{
632
		return array(
633
			new IntegerConfigSetting(self::SETTING_LOG_LIMIT, 10),
634
			new IntegerConfigSetting(self::SETTING_LOG_MESSAGE_LIMIT, 68),
635
			new RegExpsConfigSetting(self::SETTING_LOG_MERGE_CONFLICT_REGEXPS, '#/composer\.lock$#'),
636
		);
637
	}
638
639
	/**
640
	 * Returns option names, that makes sense to use in aggregation mode.
641
	 *
642
	 * @return array
643
	 */
644
	public function getAggregatedOptions()
645
	{
646
		return array(
647
			'merges', 'no-merges', 'merged', 'not-merged', 'action',
648
			'kind', 'author', 'with-full-message', 'with-details', 'with-summary',
649
			'with-refs', 'with-merge-oracle', 'with-merge-status', 'max-count',
650
		);
651
	}
652
653
}
654