Skip to content

Commit

Permalink
Introduces new component ConfigResolver (#166)
Browse files Browse the repository at this point in the history
* introduces a new component Configuration/ConfigResolver to solve issue #163

* fix for issue #167
  • Loading branch information
llaville authored Dec 22, 2022
1 parent 3b485f1 commit 6e820ea
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 93 deletions.
3 changes: 2 additions & 1 deletion .phplint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ extensions:
exclude:
- vendor
warning: true
#memory_limit: -1
#memory-limit: -1
no-cache: false
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"ext-json": "*",
"symfony/console": "^5.3.11 || ^6.0",
"symfony/finder": "^5.3.7 || ^6.0",
"symfony/options-resolver": "^5.4 || ^6.0",
"symfony/process": "^5.3.12 || ^6.0",
"symfony/yaml": "^5.3.11 || ^6.0",
"n98/junit-xml": "1.1.0"
Expand Down
134 changes: 42 additions & 92 deletions src/Command/LintCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
namespace Overtrue\PHPLint\Command;

use DateTime;
use Overtrue\PHPLint\Configuration\ConfigResolver;
use Overtrue\PHPLint\Cache;
use Overtrue\PHPLint\Linter;
use PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor;
use PHP_Parallel_Lint\PhpConsoleColor\InvalidStyleException;
use PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter;
use N98\JUnitXml\Document;
use Overtrue\PHPLint\Cache;
use Overtrue\PHPLint\Linter;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Helper;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -17,23 +18,9 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Terminal;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

class LintCommand extends Command
{
private const DEFAULT_EXTENSIONS = ['php'];
private const DEFAULT_JOBS = 5;
private const DEFAULT_PATH = '.';

protected array $defaults = [
'jobs' => self::DEFAULT_JOBS,
'path' => self::DEFAULT_PATH,
'exclude' => [],
'extensions' => self::DEFAULT_EXTENSIONS,
'warning' => false
];

protected InputInterface $input;
protected OutputInterface $output;

Expand All @@ -45,7 +32,8 @@ protected function configure(): void
->addArgument(
'path',
InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
'Path to file or directory to lint.'
'Path to file or directory to lint',
[ConfigResolver::DEFAULT_PATH]
)
->addOption(
'exclude',
Expand All @@ -58,21 +46,21 @@ protected function configure(): void
null,
InputOption::VALUE_REQUIRED,
'Check only files with selected extensions',
self::DEFAULT_EXTENSIONS
ConfigResolver::DEFAULT_EXTENSIONS
)
->addOption(
'jobs',
'j',
InputOption::VALUE_REQUIRED,
'Number of paralleled jobs to run',
self::DEFAULT_JOBS
ConfigResolver::DEFAULT_JOBS
)
->addOption(
'configuration',
'c',
InputOption::VALUE_REQUIRED,
'Read configuration from config file',
$this->getConfigFile([self::DEFAULT_PATH])
ConfigResolver::DEFAULT_CONFIG_FILE
)
->addOption(
'no-configuration',
Expand All @@ -89,8 +77,9 @@ protected function configure(): void
->addOption(
'cache',
null,
InputOption::VALUE_REQUIRED,
'Path to the cache file.'
InputOption::VALUE_OPTIONAL,
'Path to the cache file.',
ConfigResolver::DEFAULT_CACHE_FILE
)
->addOption(
'no-progress',
Expand Down Expand Up @@ -124,7 +113,7 @@ protected function configure(): void
)
->addOption(
'no-files-exit-code',
'nf',
null,
InputOption::VALUE_NONE,
'Throw error if no files processed.'
);
Expand All @@ -137,7 +126,7 @@ public function initialize(InputInterface $input, OutputInterface $output): void
}

/**
* @throws InvalidStyleException
* @throws InvalidStyleException|\Throwable
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
Expand All @@ -151,30 +140,38 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$options = $this->mergeOptions();
$verbosity = $output->getVerbosity();

if (!empty($options['configuration'])) {
$output->writeln(\sprintf('Configuration : <comment>%s</comment>', $options['configuration']));
if (!empty($options[ConfigResolver::OPTION_CONFIG_FILE])) {
$output->writeln(\sprintf('Configuration : <comment>%s</comment>', $options[ConfigResolver::OPTION_CONFIG_FILE]));
}

if ($verbosity >= OutputInterface::VERBOSITY_DEBUG) {
$output->writeln('Options : <comment>' . json_encode($options) . "</comment>\n");
$output->writeln('Options :');
foreach ($options as $name => $value) {
$output->writeln(\sprintf("<comment>%18s</comment> > <info>%s</info>", $name, \json_encode($value, \JSON_UNESCAPED_SLASHES)));
}
}
$output->writeln('');

$linter = new Linter($options['path'], $options['exclude'], $options['extensions'], $options['warning']);
$linter->setProcessLimit($options['jobs']);
$linter = new Linter(
$options[ConfigResolver::OPTION_PATH],
$options[ConfigResolver::OPTION_EXCLUDE],
$options[ConfigResolver::OPTION_EXTENSIONS],
$options[ConfigResolver::OPTION_WARNING]
);
$linter->setProcessLimit($options[ConfigResolver::OPTION_JOBS]);

if (!empty($options['cache'])) {
Cache::setFilename($options['cache']);
if (!empty($options[ConfigResolver::OPTION_CACHE_FILE])) {
Cache::setFilename($options[ConfigResolver::OPTION_CACHE_FILE]);
}

$usingCache = 'No';
if (!$input->getOption('no-cache') && Cache::isCached()) {
if (!$options[ConfigResolver::OPTION_NO_CACHE] && Cache::isCached()) {
$usingCache = 'Yes';
$linter->setCache(Cache::get());
}

if (!empty($options['memory_limit'])) {
$linter->setMemoryLimit($options['memory_limit']);
if (!empty($options[ConfigResolver::OPTION_MEMORY_LIMIT])) {
$linter->setMemoryLimit($options[ConfigResolver::OPTION_MEMORY_LIMIT]);
}

$fileCount = count($linter->getFiles());
Expand All @@ -183,7 +180,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
if ($fileCount <= 0) {
$output->writeln('<info>Could not find files to lint</info>');

if (!empty($options['no-files-exit-code'])) {
if (!empty($options[ConfigResolver::OPTION_NO_FILES_EXIT_CODE])) {
$code = 1;
}

Expand All @@ -209,7 +206,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln("<error>Files: {$fileCount}, Failures: {$errCount}</error>");
$this->showErrors($errors);

if (empty($options['quiet'])) {
if (empty($options[ConfigResolver::OPTION_QUIET])) {
$code = 1;
}
} else {
Expand All @@ -223,12 +220,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
'files_count' => $fileCount,
];

if (!empty($options['json'])) {
$this->dumpJsonResult((string) $options['json'], $errors, $options, $context);
if (!empty($options[ConfigResolver::OPTION_JSON_FILE])) {
$this->dumpJsonResult((string) $options[ConfigResolver::OPTION_JSON_FILE], $errors, $options, $context);
}

if (!empty($options['xml'])) {
$this->dumpXmlResult((string) $options['xml'], $errors, $options, $context);
if (!empty($options[ConfigResolver::OPTION_XML_FILE])) {
$this->dumpXmlResult((string) $options[ConfigResolver::OPTION_XML_FILE], $errors, $options, $context);
}

return $code;
Expand Down Expand Up @@ -365,61 +362,14 @@ public function getHighlightedCodeSnippet(string $filePath, int $lineNumber, int

protected function mergeOptions(): array
{
$options = $this->input->getOptions();
$options['path'] = $this->input->getArgument('path');
$options['cache'] = $this->input->getOption('cache');
if ($options['warning'] === false) {
unset($options['warning']);
}

$config = [];
$configResolver = new ConfigResolver($this->input);
$options = $configResolver->resolve();
$failures = $configResolver->getNestedExceptions();

if (!$this->input->getOption('no-configuration')) {
$inputPath = $this->input->getArgument('path');
$filename = $this->getConfigFile($inputPath);

if (empty($options['configuration']) && $filename) {
$options['configuration'] = $filename;
}

if (!empty($options['configuration'])) {
$config = $this->loadConfiguration($options['configuration']);
}
if (!empty($failures)) {
throw $failures[0];
}

$options = array_merge($this->defaults, array_filter($config), array_filter($options));

is_array($options['extensions']) || $options['extensions'] = explode(',', $options['extensions']);

return $options;
}

protected function getConfigFile(array $inputPath): false|string
{
if (1 == count($inputPath) && $first = reset($inputPath)) {
$dir = is_dir($first) ? $first : dirname($first);
} else {
$dir = \getcwd() . DIRECTORY_SEPARATOR;
}

$filename = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '.phplint.yml';

return realpath($filename);
}

protected function loadConfiguration(string $path): array
{
try {
$configuration = Yaml::parse(file_get_contents($path));
if (!is_array($configuration)) {
throw new ParseException('Invalid content.', 1);
}

return $configuration;
} catch (ParseException $e) {
$this->output->writeln(sprintf('<error>Unable to parse the YAML string: %s</error>', $e->getMessage()));

return [];
}
}
}
Loading

0 comments on commit 6e820ea

Please sign in to comment.