-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from navarr/bin-command
Add "depanno" CLI command
- Loading branch information
Showing
14 changed files
with
428 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,9 @@ | |
"main": "2.x-dev" | ||
} | ||
}, | ||
"bin": [ | ||
"depanno" | ||
], | ||
"archive": { | ||
"exclude": [ | ||
".github", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#!/usr/bin/env php | ||
<?php | ||
|
||
/** | ||
* @copyright 2021 Navarr Barnier. All Rights Reserved. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
use Navarr\Depends\Controller\CliApplication; | ||
|
||
if (version_compare('7.1.0', PHP_VERSION, '>')) { | ||
fwrite( | ||
STDERR, | ||
"This version of DepAnno requires PHP 7.1.0 or greater." . PHP_EOL . | ||
"You are currently using PHP " . PHP_VERSION . PHP_EOL | ||
); | ||
die(1); | ||
} | ||
|
||
if (!ini_get('date.timezone')) { | ||
ini_set('date.timezone', 'UTC'); | ||
} | ||
|
||
$found = false; | ||
foreach ( | ||
[ | ||
__DIR__ . '/../../autoload.php', | ||
__DIR__ . '/../vendor/autoload.php', | ||
__DIR__ . '/vendor/autoload.php', | ||
] as $autoload | ||
) { | ||
if (file_exists($autoload)) { | ||
require_once($autoload); | ||
$found = true; | ||
break; | ||
} | ||
} | ||
|
||
if (!$found) { | ||
fwrite(STDERR, "You must install DepAnno using Composer"); | ||
die(1); | ||
} | ||
|
||
die(CliApplication::execute()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright 2021 Navarr Barnier. All Rights Reserved. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Navarr\Depends\Controller; | ||
|
||
use Navarr\Attribute\Dependency; | ||
use Symfony\Component\Console\Application; | ||
|
||
#[Dependency('symfony/console', '^5', 'Creates a Symfony Application')] | ||
class CliApplication | ||
{ | ||
private const VERSION = '2.1.0'; | ||
|
||
public static function execute(): int | ||
{ | ||
$application = new Application('DepAnno', static::VERSION); | ||
$application->add(new WhyBlockCommandController()); | ||
return $application->run(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright 2021 Navarr Barnier. All Rights Reserved. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Navarr\Depends\Controller; | ||
|
||
use DI\ContainerBuilder; | ||
use InvalidArgumentException; | ||
use Navarr\Attribute\Dependency; | ||
use Navarr\Depends\Command\WhyBlockCommand; | ||
use Navarr\Depends\Command\WhyBlockCommand\CsvOutputHandler; | ||
use Navarr\Depends\Command\WhyBlockCommand\JsonOutputHandler; | ||
use Navarr\Depends\Command\WhyBlockCommand\OutputHandlerInterface; | ||
use Navarr\Depends\Command\WhyBlockCommand\StandardOutputHandler; | ||
use Navarr\Depends\Command\WhyBlockCommand\XmlOutputHandler; | ||
use Navarr\Depends\IssueHandler\FailOnIssueHandler; | ||
use Navarr\Depends\IssueHandler\IssueHandlerInterface; | ||
use Navarr\Depends\IssueHandler\NotifyOnIssueHandler; | ||
use Navarr\Depends\Parser\AstParser; | ||
use Navarr\Depends\Parser\LegacyParser; | ||
use Navarr\Depends\Parser\ParserInterface; | ||
use Navarr\Depends\Parser\ParserPool; | ||
use Navarr\Depends\Proxy\StdOutWriter; | ||
use Navarr\Depends\Proxy\WriterInterface; | ||
use Navarr\Depends\ScopeDeterminer\ComposerScopeDeterminer; | ||
use Navarr\Depends\ScopeDeterminer\DirectoryScopeDeterminer; | ||
use Navarr\Depends\ScopeDeterminer\PhpFileFinder; | ||
use Navarr\Depends\ScopeDeterminer\ScopeDeterminerInterface; | ||
use Psr\Container\ContainerInterface; | ||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputArgument; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Input\InputOption; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
|
||
use function DI\autowire; | ||
use function DI\create; | ||
|
||
class WhyBlockCommandController extends Command | ||
{ | ||
private const LEGACY_ANNOTATION = 'include-legacy-annotations'; | ||
private const FAIL_ON_ERROR = 'fail-on-error'; | ||
private const OUTPUT_FORMAT = 'format'; | ||
|
||
private const FORMAT_TEXT = 'text'; | ||
private const FORMAT_CSV = 'csv'; | ||
private const FORMAT_JSON = 'json'; | ||
private const FORMAT_XML = 'xml'; | ||
|
||
private const ACCEPTABLE_FORMATS = [ | ||
self::FORMAT_CSV, | ||
self::FORMAT_TEXT, | ||
self::FORMAT_JSON, | ||
self::FORMAT_XML, | ||
]; | ||
|
||
private const FORMAT_MAPPER = [ | ||
self::FORMAT_CSV => CsvOutputHandler::class, | ||
self::FORMAT_TEXT => StandardOutputHandler::class, | ||
self::FORMAT_JSON => JsonOutputHandler::class, | ||
self::FORMAT_XML => XmlOutputHandler::class, | ||
]; | ||
|
||
// phpcs:disable Generic.Files.LineLength.TooLong -- Attribute support pre PHP 8 | ||
#[Dependency('symfony/console', '^5', 'Command\'s setName, addArgument and addOption methods as well as InputArgument\'s constants of REQUIRED and VALUE_NONE')] | ||
#[Dependency('php-di/php-di', '^6', 'DI\ContainerBuilder::addDefinitions and the existence of the DI\autowire function')] | ||
// phpcs:enable Generic.Files.LineLength.TooLong | ||
protected function configure(): void | ||
{ | ||
$this->setName('why-block') | ||
->addArgument('package', InputArgument::REQUIRED, 'Package to inspect') | ||
->addArgument('version', InputArgument::REQUIRED, 'Version you want to update it to') | ||
->addArgument('directory', InputArgument::REQUIRED, 'Directory to search in') | ||
->addOption( | ||
self::OUTPUT_FORMAT, | ||
['f'], | ||
InputOption::VALUE_OPTIONAL, | ||
'Format to output results in. Accepted values: text, csv, json, xml', | ||
'text' | ||
) | ||
->addOption( | ||
self::FAIL_ON_ERROR, | ||
['e'], | ||
InputOption::VALUE_NONE, | ||
'Immediately fail on parsing errors' | ||
) | ||
->addOption( | ||
self::LEGACY_ANNOTATION, | ||
['l'], | ||
InputOption::VALUE_NONE, | ||
'Include old @dependency/@composerDependency annotations in search' | ||
); | ||
} | ||
|
||
#[Dependency('symfony/console', '^5', 'InputInterface::getOption and OutputInterface::writeln')] | ||
protected function execute( | ||
InputInterface $input, | ||
OutputInterface $output | ||
): int { | ||
$packageToSearchFor = $input->getArgument('package'); | ||
$versionToCompareTo = $input->getArgument('version'); | ||
$directory = $input->getArgument('directory'); | ||
$outputFormat = $input->getOption(self::OUTPUT_FORMAT); | ||
|
||
if (!is_string($directory)) { | ||
throw new InvalidArgumentException('Only one directory is allowed'); | ||
} | ||
if (!is_string($packageToSearchFor)) { | ||
throw new InvalidArgumentException('Only one package is allowed'); | ||
} | ||
if (!is_string($versionToCompareTo)) { | ||
throw new InvalidArgumentException('Only one version is allowed'); | ||
} | ||
if (!is_string($outputFormat)) { | ||
throw new InvalidArgumentException('Only one output format is allowed'); | ||
} | ||
|
||
$outputFormat = strtolower($outputFormat); | ||
if (!in_array($outputFormat, static::ACCEPTABLE_FORMATS)) { | ||
$outputFormat = 'text'; | ||
} | ||
|
||
$containerBuilder = new ContainerBuilder(); | ||
$containerBuilder->addDefinitions( | ||
[ | ||
InputInterface::class => $input, | ||
OutputInterface::class => $output, | ||
IssueHandlerInterface::class => $input->getOption(static::FAIL_ON_ERROR) | ||
? FailOnIssueHandler::class | ||
: NotifyOnIssueHandler::class, | ||
ParserInterface::class => static function (ContainerInterface $container) use ($input) { | ||
$parsers = [$container->get(AstParser::class)]; | ||
if ($input->getOption(static::LEGACY_ANNOTATION)) { | ||
$parsers[] = $container->get(LegacyParser::class); | ||
} | ||
return new ParserPool($parsers); | ||
}, | ||
WriterInterface::class => autowire(StdOutWriter::class), | ||
ScopeDeterminerInterface::class => static function (ContainerInterface $container) use ($directory) { | ||
return new DirectoryScopeDeterminer( | ||
$container->get(PhpFileFinder::class), | ||
$directory | ||
); | ||
}, | ||
OutputHandlerInterface::class => autowire(static::FORMAT_MAPPER[$outputFormat]), | ||
] | ||
); | ||
$container = $containerBuilder->build(); | ||
|
||
/** @var WhyBlockCommand $command */ | ||
$command = $container->get(WhyBlockCommand::class); | ||
return $command->execute($packageToSearchFor, $versionToCompareTo); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright 2021 Navarr Barnier. All Rights Reserved. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Navarr\Depends\ScopeDeterminer; | ||
|
||
class DirectoryScopeDeterminer implements ScopeDeterminerInterface | ||
{ | ||
/** @var string */ | ||
private $directory; | ||
|
||
/** @var PhpFileFinder */ | ||
private $phpfileFinder; | ||
|
||
public function __construct(PhpFileFinder $phpfileFinder, string $directory = '.') | ||
{ | ||
$this->directory = $directory; | ||
$this->phpfileFinder = $phpfileFinder; | ||
} | ||
|
||
public function getFiles(): array | ||
{ | ||
return $this->phpfileFinder->findAll($this->directory); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright 2021 Navarr Barnier. All Rights Reserved. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Navarr\Depends\ScopeDeterminer; | ||
|
||
class PhpFileFinder | ||
{ | ||
/** @var PhpFileDeterminer */ | ||
private $phpFileDeterminer; | ||
|
||
public function __construct(PhpFileDeterminer $phpFileDeterminer) | ||
{ | ||
$this->phpFileDeterminer = $phpFileDeterminer; | ||
} | ||
|
||
/** | ||
* Find all PHP files by recursively searching a directory | ||
* | ||
* @param string $dir Directory to search recursively | ||
* @param string[] $results Array of file paths to merge with | ||
* @return string[] File paths | ||
*/ | ||
public function findAll(string $dir, array $results = []): array | ||
{ | ||
// Directories is ever expanding by the loop. We do this instead of recursion b/c I have an unhealthy fear | ||
// of recursion limits | ||
$directories = [$dir]; | ||
for ($i = 0; $i < count($directories); ++$i) { | ||
$files = scandir($directories[$i]); | ||
if ($files !== false) { | ||
foreach ($files as $value) { | ||
$path = realpath($directories[$i] . DIRECTORY_SEPARATOR . $value); | ||
if ($path === false) { | ||
continue; | ||
} | ||
|
||
if (is_file($path) && $this->phpFileDeterminer->isPhp($path)) { | ||
$results[] = $path; | ||
} elseif (is_dir($path) && !in_array($value, ['.', '..'])) { | ||
$directories[] = $path; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return $results; | ||
} | ||
} |
Oops, something went wrong.