php-extension-check/src/Command/CheckCommand.php

170 lines
5.6 KiB
PHP

<?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Command;
use Closure;
use Fbrinker\ExtensionCheck\Extension\ExtensionCheck;
use Fbrinker\ExtensionCheck\Output\SymfonyStyleFactory;
use Fbrinker\ExtensionCheck\Parser\FileParser;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputDefinition;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CheckCommand extends Command
{
private const ARG_DIRECTORY = 'directory';
private const OPT_EXCLUDE = 'exclude';
protected static $defaultName = 'check';
private $symfonyStyleFactory;
private $fileParser;
private $extensionCheck;
public function __construct(
SymfonyStyleFactory $symfonyStyleFactory,
FileParser $fileParser,
ExtensionCheck $extensionCheck
) {
parent::__construct();
$this->symfonyStyleFactory = $symfonyStyleFactory;
$this->fileParser = $fileParser;
$this->extensionCheck = $extensionCheck;
}
protected function configure(): void
{
$this
->setDescription('Checks extensions...')
->setHelp('This command allows you to check your extensions...')
->setDefinition(
new InputDefinition([
new InputArgument(self::ARG_DIRECTORY, InputArgument::OPTIONAL, "The directory to scan", "./"),
new InputOption(self::OPT_EXCLUDE, null, InputArgument::OPTIONAL | InputOption::VALUE_IS_ARRAY, "Exclude specific extensions", []),
])
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = ($this->symfonyStyleFactory)($input, $output);
$io->section("Analyzing Files");
$scanDir = $input->getArgument(self::ARG_DIRECTORY);
if (empty($scanDir) || !\is_string($scanDir)) {
$scanDir = './';
}
$excludedExtensionOpts = $input->getOption(self::OPT_EXCLUDE);
$excludedExtensions = [];
if (is_array($excludedExtensionOpts) && !empty($excludedExtensionOpts)) {
foreach ($excludedExtensionOpts as $excludedExtensionOpt) {
$extensions = explode(",", $excludedExtensionOpt);
foreach ($extensions as $extension) {
$excludedExtensions[] = \strtolower(trim($extension));
}
}
$this->extensionCheck->setExcludedExtenstions($excludedExtensions);
}
$this->fileParser->scanForFiles($scanDir);
$fileCount = $this->fileParser->getFileCount();
$io->text(sprintf('Files: %d', $fileCount));
$io->newLine();
$progressBar = $this->getStyledProgressBar($output, $fileCount);
$progressBar->start();
[$classes, $functions, $constants] = $this->fileParser->parseFiles(
$this->getProgressBarClosure($progressBar)
);
$progressBar->finish();
$io->newLine(2);
$io->text("Calls to check:");
$io->text(sprintf(
"%d Classes, %d Functions, %d Constants",
count($classes),
count($functions),
count($constants)
));
$io->section("Checking Extension Usages");
$io->text(sprintf('Loaded Extensions: %d', $this->extensionCheck->getLoadedExtensionsCount()));
if (!empty($excludedExtensions)) {
$io->text(sprintf("Excluded Extensions: %s", implode(", ", $excludedExtensions)));
}
$io->newLine();
$totalUsagesToCheck = count($classes) + count($functions);
$progressBar = $this->getStyledProgressBar($output, $totalUsagesToCheck);
$progressBar->start();
$usedExtensions = $this->extensionCheck->checkUsages(
$classes,
$functions,
$constants,
$this->getProgressBarClosure($progressBar)
);
$progressBar->finish();
$io->newLine(2);
$unusedExtensions = $this->extensionCheck->getUnused(array_keys($usedExtensions));
$io->text(sprintf(
"<fg=green>%d</> Used, <fg=red>%d</> Unused",
count($usedExtensions),
count($unusedExtensions)
));
$io->section("Result");
$io->text("Used Extensions:");
$tmp = array_keys($usedExtensions);
natcasesort($tmp);
foreach ($tmp as $usedExtension) {
$reason = $usedExtensions[$usedExtension];
$io->text(sprintf(
' <fg=green>%s</> %s <comment>[Usage: %s]</>',
"\u{2713}",
$usedExtension,
implode(", ", array_keys($reason))
));
}
$io->newLine();
$io->text("Unused Extensions:");
foreach ($unusedExtensions as $unusedExtension) {
$io->text(sprintf(
' <fg=red>%s</> %s',
"\u{2717}",
$unusedExtension
));
}
return Command::SUCCESS;
}
private function getProgressBarClosure(ProgressBar $progressBar): Closure
{
return function () use ($progressBar) {
$progressBar->advance();
};
}
private function getStyledProgressBar(OutputInterface $output, int $maxValue): ProgressBar
{
$progressBar = new ProgressBar($output, $maxValue);
$progressBar->setBarCharacter('<info>=</info>');
$progressBar->setEmptyBarCharacter(' ');
$progressBar->setProgressCharacter('>');
return $progressBar;
}
}