Skip to content

Commit

Permalink
Make paths absolute before scanning (#301)
Browse files Browse the repository at this point in the history
  • Loading branch information
villfa authored Feb 9, 2021
1 parent 541fe28 commit 1f80757
Show file tree
Hide file tree
Showing 15 changed files with 194 additions and 74 deletions.
3 changes: 2 additions & 1 deletion phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowEmpty.DisallowedEmpty"/>
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowYodaComparison.DisallowedYodaComparison"/>
<exclude name="SlevomatCodingStandard.ControlStructures.NewWithoutParentheses.UselessParentheses"/>
<exclude name="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceEqualOperator.RequiredNullCoalesceEqualOperator"/>
<exclude name="SlevomatCodingStandard.Files.TypeNameMatchesFileName"/>
<exclude name="SlevomatCodingStandard.Functions.RequireArrowFunction.RequiredArrowFunction"/>
<exclude name="SlevomatCodingStandard.Functions.TrailingCommaInCall.MissingTrailingComma"/>
Expand All @@ -46,4 +47,4 @@
<exclude name="Squiz.Commenting.FunctionComment.SpacingAfterParamName"/>
<exclude name="Squiz.Commenting.FunctionComment.SpacingAfterParamType"/>
</rule>
</ruleset>
</ruleset>
32 changes: 26 additions & 6 deletions src/Command/RunCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Churn\Configuration\Config;
use Churn\Configuration\Loader;
use Churn\File\FileFinder;
use Churn\File\FileHelper;
use Churn\Process\Observer\OnSuccess;
use Churn\Process\Observer\OnSuccessAccumulate;
use Churn\Process\Observer\OnSuccessCollection;
Expand Down Expand Up @@ -109,10 +110,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
*/
private function getConfiguration(InputInterface $input): Config
{
$config = Loader::fromPath((string) $input->getOption('configuration'));

$isDefaultValue = !$input->hasParameterOption('--configuration') && !$input->hasParameterOption('-c');
$config = Loader::fromPath((string) $input->getOption('configuration'), $isDefaultValue);
if ([] !== $input->getArgument('paths')) {
$config->setDirectoriesToScan($input->getArgument('paths'));
$config->setDirectoriesToScan((array) $input->getArgument('paths'));
}

if ([] === $config->getDirectoriesToScan()) {
Expand Down Expand Up @@ -140,7 +141,7 @@ private function getConfiguration(InputInterface $input): Config
private function analyze(InputInterface $input, OutputInterface $output, Config $config): ResultAccumulator
{
$filesFinder = (new FileFinder($config->getFileExtensions(), $config->getFilesToIgnore()))
->getPhpFiles($config->getDirectoriesToScan());
->getPhpFiles($this->getDirectoriesToScan($input, $config));
$accumulator = new ResultAccumulator($config->getFilesToShow(), $config->getMinScoreToShow());
$this->processHandlerFactory->getProcessHandler($config)->process(
$filesFinder,
Expand All @@ -151,6 +152,25 @@ private function analyze(InputInterface $input, OutputInterface $output, Config
return $accumulator;
}

/**
* @param InputInterface $input Input.
* @param Config $config The configuration object.
* @return array<string> Array of absolute paths.
*/
private function getDirectoriesToScan(InputInterface $input, Config $config): array
{
$basePath = null !== $config->getPath() && [] === $input->getArgument('paths')
? \dirname($config->getPath())
: \getcwd();
$paths = [];

foreach ($config->getDirectoriesToScan() as $path) {
$paths[] = FileHelper::toAbsolutePath($path, $basePath);
}

return $paths;
}

/**
* @param InputInterface $input Input.
* @param OutputInterface $output Output.
Expand All @@ -163,7 +183,7 @@ private function getOnSuccessObserver(
): OnSuccess {
$observer = new OnSuccessAccumulate($accumulator);

if ((bool) $input->getOption('progress')) {
if (true === $input->getOption('progress')) {
$progressBar = new ProgressBar($output);
$progressBar->start();
$observer = new OnSuccessCollection($observer, new OnSuccessProgress($progressBar));
Expand Down Expand Up @@ -192,7 +212,7 @@ private function displayLogo(InputInterface $input, OutputInterface $output): vo
*/
private function writeResult(InputInterface $input, OutputInterface $output, ResultAccumulator $accumulator): void
{
if ((bool) $input->getOption('progress')) {
if (true === $input->getOption('progress')) {
$output->writeln("\n");
}

Expand Down
22 changes: 19 additions & 3 deletions src/Configuration/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,34 @@ class Config
*/
private $configuration;

/**
* @var string|null
*/
private $path;

/**
* @param array<mixed> $configuration Raw config data.
* @param string|null $path The path of the configuration file if any.
*/
private function __construct(array $configuration = [])
private function __construct(array $configuration = [], ?string $path = null)
{
if ([] !== $configuration) {
(new Validator())->validateConfigurationValues($configuration);
}

$this->configuration = $configuration;
$this->path = $path;
}

/**
* Create a config with given configuration.
*
* @param array<mixed> $configuration The array containing the configuration values.
* @param string|null $path The path of the configuration file if any.
*/
public static function create(array $configuration): Config
public static function create(array $configuration, ?string $path = null): Config
{
return new self($configuration);
return new self($configuration, $path);
}

/**
Expand All @@ -51,6 +59,14 @@ public static function createFromDefaultValues(): Config
return new self();
}

/**
* Return the path of the configuration file.
*/
public function getPath(): ?string
{
return $this->path;
}

/**
* Get the paths of directories to scan.
*
Expand Down
15 changes: 10 additions & 5 deletions src/Configuration/Loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,27 @@ class Loader

/**
* @param string $confPath Path of the configuration file to load.
* @param boolean $isDefaultValue Indicates whether $confPath contains the default value.
* @throws InvalidArgumentException If the configuration file cannot be read.
*/
public static function fromPath(string $confPath): Config
public static function fromPath(string $confPath, bool $isDefaultValue): Config
{
$originalConfPath = $confPath;

if (\is_dir($confPath)) {
$confPath = \rtrim($confPath, '/\\') . '/churn.yml';
}

if (!\is_readable($confPath)) {
throw new InvalidArgumentException('The configuration file can not be read at ' . $originalConfPath);
if (\is_readable($confPath)) {
$content = (string) \file_get_contents($confPath);

return Config::create(Yaml::parse($content) ?? [], \realpath($confPath));
}

$content = (string) \file_get_contents($confPath);
if ($isDefaultValue) {
return Config::createFromDefaultValues();
}

return Config::create(Yaml::parse($content) ?? []);
throw new InvalidArgumentException('The configuration file can not be read at ' . $originalConfPath);
}
}
33 changes: 33 additions & 0 deletions src/File/FileHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Churn\File;

class FileHelper
{

/**
* @param string $path The path of an item.
* @param string $basePath The absolute base path.
* @return string The absolute path of the given item.
*/
public static function toAbsolutePath(string $path, string $basePath): string
{
$path = \trim($path);

if (0 === \strpos($path, '/')) {
return $path;
}

if ('\\' === $path[0] || (\strlen($path) >= 3 && \preg_match('#^[A-Z]\:[/\\\]#i', \substr($path, 0, 3)))) {
return $path;
}

if (false !== \strpos($path, '://')) {
return $path;
}

return $basePath . '/' . $path;
}
}
9 changes: 0 additions & 9 deletions src/Process/ChangesCount/NoVcsChangesCountProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,6 @@ public function isSuccessful(): bool
return true;
}

/**
* Gets the file name of the file the process
* is being executed on.
*/
public function getFilename(): string
{
return $this->file->getDisplayPath();
}

/**
* Gets the file the process is being executed on.
*/
Expand Down
9 changes: 0 additions & 9 deletions src/Process/ChurnProcess.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,6 @@ public function isSuccessful(): bool
return 0 === $exitCode;
}

/**
* Gets the file name of the file the process
* is being executed on.
*/
public function getFilename(): string
{
return $this->file->getDisplayPath();
}

/**
* Gets the file the process is being executed on.
*/
Expand Down
22 changes: 11 additions & 11 deletions src/Process/Handler/ParallelProcessHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,15 @@ private function checkRunningProcesses(array &$pool, OnSuccess $onSuccess): void
*/
private function addToPool(array &$pool, File $file, ProcessFactory $processFactory): void
{
$process = $processFactory->createChangesCountProcess($file);
$process->start();
$pool['CountChanges:' . $process->getFilename()] = $process;
$process = $processFactory->createCyclomaticComplexityProcess($file);
$process->start();
$pool['Complexity:' . $process->getFilename()] = $process;
$processes = [
$processFactory->createChangesCountProcess($file),
$processFactory->createCyclomaticComplexityProcess($file),
];

foreach ($processes as $i => $process) {
$process->start();
$pool["$i:" . $file->getDisplayPath()] = $process;
}
}

/**
Expand All @@ -103,11 +106,8 @@ private function addToPool(array &$pool, File $file, ProcessFactory $processFact
*/
private function getResult(ProcessInterface $process): Result
{
if (!isset($this->completedProcesses[$process->getFileName()])) {
$this->completedProcesses[$process->getFileName()] = new Result($process->getFileName());
}

$result = $this->completedProcesses[$process->getFileName()];
$key = $process->getFile()->getDisplayPath();
$result = $this->completedProcesses[$key] = $this->completedProcesses[$key] ?? new Result($key);

if ($process instanceof ChangesCountInterface) {
$result->setCommits($process->countChanges());
Expand Down
39 changes: 32 additions & 7 deletions src/Process/Handler/SequentialProcessHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

namespace Churn\Process\Handler;

use Churn\Process\ChangesCountInterface;
use Churn\Process\CyclomaticComplexityInterface;
use Churn\Process\Observer\OnSuccess;
use Churn\Process\ProcessFactory;
use Churn\Process\ProcessInterface;
use Churn\Result\Result;
use Generator;

Expand All @@ -23,17 +26,39 @@ public function process(Generator $filesFinder, ProcessFactory $processFactory,
{
foreach ($filesFinder as $file) {
$result = new Result($file->getDisplayPath());
$process = $processFactory->createChangesCountProcess($file);
$process->start();
$processes = [
$processFactory->createChangesCountProcess($file),
$processFactory->createCyclomaticComplexityProcess($file),
];

while (!$process->isSuccessful());
foreach ($processes as $process) {
$this->executeProcess($process, $result);
}

$onSuccess($result);
}
}

/**
* Execute a process and save the result when it's done.
*
* @param ProcessInterface $process The process to execute.
* @param Result $result The result to complete.
*/
private function executeProcess(ProcessInterface $process, Result $result): Result
{
$process->start();

while (!$process->isSuccessful());

if ($process instanceof ChangesCountInterface) {
$result->setCommits($process->countChanges());
$process = $processFactory->createCyclomaticComplexityProcess($file);
$process->start();
}

while (!$process->isSuccessful());
if ($process instanceof CyclomaticComplexityInterface) {
$result->setComplexity($process->getCyclomaticComplexity());
$onSuccess($result);
}

return $result;
}
}
6 changes: 0 additions & 6 deletions src/Process/ProcessInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ public function start(): void;
*/
public function isSuccessful(): bool;

/**
* Gets the file name of the file the process
* is being executed on.
*/
public function getFilename(): string;

/**
* Gets the file the process is being executed on.
*/
Expand Down
29 changes: 29 additions & 0 deletions tests/Unit/Configuration/LoaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Churn\Tests\Unit\Configuration;

use Churn\Configuration\Config;
use Churn\Configuration\Loader;
use Churn\Tests\BaseTestCase;
use InvalidArgumentException;

class LoaderTest extends BaseTestCase
{
/** @test */
public function it_returns_the_default_values_if_there_is_no_default_file()
{
$config = Loader::fromPath('non-existing-config-file.yml', true);

$this->assertEquals(Config::createFromDefaultValues(), $config);
$this->assertNull($config->getPath());
}

/** @test */
public function it_throws_if_the_chosen_file_is_missing()
{
$this->expectException(InvalidArgumentException::class);
$config = Loader::fromPath('non-existing-config-file.yml', false);
}
}
Loading

0 comments on commit 1f80757

Please sign in to comment.