Skip to content

Commit

Permalink
feat: Add Composer commands
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry committed Oct 17, 2023
1 parent 1049437 commit cb8ea3c
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 26 deletions.
39 changes: 22 additions & 17 deletions src/Composer/ComposerOrchestrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function getVersion(): string

$this->logger->info($getVersionProcess->getCommandLine());

$getVersionProcess->run(env: $this->processFactory->getDefaultEnvVars());
$getVersionProcess->run();

if (false === $getVersionProcess->isSuccessful()) {
throw UndetectableComposerVersion::forFailedProcess($getVersionProcess);
Expand Down Expand Up @@ -108,6 +108,25 @@ public function checkVersion(): void
}
}

public function getVendorDir(): string
{
$vendorDirProcess = $this->processFactory->getVendorDirProcess();

$this->logger->info($vendorDirProcess->getCommandLine());

$vendorDirProcess->run();

if (false === $vendorDirProcess->isSuccessful()) {
throw new RuntimeException(
'Could not retrieve the vendor dir.',
0,
new ProcessFailedException($vendorDirProcess),
);
}

return trim($vendorDirProcess->getOutput());
}

public function dumpAutoload(
SymbolsRegistry $symbolsRegistry,
string $prefix,
Expand Down Expand Up @@ -135,7 +154,7 @@ private function dumpAutoloader(bool $noDev): void

$this->logger->info($dumpAutoloadProcess->getCommandLine());

$dumpAutoloadProcess->run(env: $this->processFactory->getDefaultEnvVars());
$dumpAutoloadProcess->run();

if (false === $dumpAutoloadProcess->isSuccessful()) {
throw new RuntimeException(
Expand Down Expand Up @@ -165,20 +184,6 @@ private function dumpAutoloader(bool $noDev): void

private function retrieveAutoloadFile(): string
{
$vendorDirProcess = $this->processFactory->getAutoloadFileProcess();

$this->logger->info($vendorDirProcess->getCommandLine());

$vendorDirProcess->run(env: $this->processFactory->getDefaultEnvVars());

if (false === $vendorDirProcess->isSuccessful()) {
throw new RuntimeException(
'Could not retrieve the vendor dir.',
0,
new ProcessFailedException($vendorDirProcess),
);
}

return trim($vendorDirProcess->getOutput()).'/autoload.php';
return $this->getVendorDir().'/autoload.php';
}
}
36 changes: 27 additions & 9 deletions src/Composer/ComposerProcessFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,31 @@ public static function create(
$composerExecutable ?? self::retrieveComposerExecutable(),
self::retrieveSubProcessVerbosity($io),
$io->isDecorated(),
self::getDefaultEnvVars(),
);
}

public function __construct(
public readonly string $composerExecutable,
private ?string $verbosity,
private bool $ansi,
private array $defaultEnvironmentVariables,
) {
}

public function getVersionProcess(): Process
{
// Never use ANSI support here as we want to parse the raw output.
return new Process([
$this->composerExecutable,
'--version',
'--no-ansi',
]);
return $this->createProcess(
[
$this->composerExecutable,
'--version',
'--no-ansi',
],
// Ensure that even if this command gets executed within the app with --quiet it still
// works.
['SHELL_VERBOSITY' => 0],
);
}

public function getDumpAutoloaderProcess(bool $noDev): Process
Expand All @@ -71,19 +78,30 @@ public function getDumpAutoloaderProcess(bool $noDev): Process
$composerCommand[] = '--ansi';
}

return new Process($composerCommand);
return $this->createProcess($composerCommand);
}

public function getAutoloadFileProcess(): Process
public function getVendorDirProcess(): Process
{
return new Process([
return $this->createProcess([
$this->composerExecutable,
'config',
'vendor-dir',
'--no-ansi',
]);
}

private function createProcess(array $command, array $environmentVariables = []): Process
{
return new Process(
$command,
env: [
...$this->defaultEnvironmentVariables,
...$environmentVariables,
],
);
}

private static function retrieveSubProcessVerbosity(IO $io): ?string
{
if ($io->isDebug()) {
Expand All @@ -97,7 +115,7 @@ private static function retrieveSubProcessVerbosity(IO $io): ?string
return null;
}

public function getDefaultEnvVars(): array
private static function getDefaultEnvVars(): array
{
$vars = [];

Expand Down
2 changes: 2 additions & 0 deletions src/Console/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ public function getHeader(): string
public function getCommands(): array
{
return [
new Command\Composer\ComposerCheckVersion(),
new Command\Composer\ComposerVendorDir(),
new Command\Compile($this->getHeader()),
new Command\Diff(),
new Command\Info(),
Expand Down
59 changes: 59 additions & 0 deletions src/Console/Command/Composer/ComposerCheckVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Console\Command\Composer;

use Fidry\Console\Command\Command;
use Fidry\Console\Command\Configuration;
use Fidry\Console\ExitCode;
use Fidry\Console\Input\IO;
use Fidry\FileSystem\FileSystem;
use KevinGH\Box\Composer\ComposerOrchestrator;
use KevinGH\Box\Composer\ComposerProcessFactory;
use KevinGH\Box\Console\ConfigurationLoader;
use KevinGH\Box\Console\ConfigurationLocator;
use Psr\Log\LogLevel;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @private
*/
final class ComposerCheckVersion extends ComposerCommand
{
public function getConfiguration(): Configuration
{
$parentConfig = parent::getConfiguration();

return new Configuration(
'composer:check-version',
'🎵 Checks if the Composer executable used is compatible with Box',
<<<'HELP'
The <info>%command.name%</info> command will look for the Composer binary (in the system if not configured
in the configuration file) and check if its version is compatible with Box.
HELP,
$parentConfig->getArguments(),
$parentConfig->getOptions(),
);
}

protected function orchestrate(ComposerOrchestrator $composerOrchestrator, IO $io): int
{
$composerOrchestrator->checkVersion();

return ExitCode::SUCCESS;
}
}
91 changes: 91 additions & 0 deletions src/Console/Command/Composer/ComposerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Console\Command\Composer;

use Fidry\Console\Command\Command;
use Fidry\Console\Command\Configuration;
use Fidry\Console\ExitCode;
use Fidry\Console\Input\IO;
use Fidry\FileSystem\FileSystem;
use KevinGH\Box\Composer\ComposerOrchestrator;
use KevinGH\Box\Composer\ComposerProcessFactory;
use KevinGH\Box\Console\ConfigurationLoader;
use KevinGH\Box\Console\ConfigurationLocator;
use Psr\Log\LogLevel;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @private
*/
abstract class ComposerCommand implements Command
{
private const FILE_ARGUMENT = 'file';

private const VERBOSITY_LEVEL_MAP = [
LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
LogLevel::INFO => OutputInterface::VERBOSITY_NORMAL,
LogLevel::DEBUG => OutputInterface::VERBOSITY_VERBOSE,
];

public function getConfiguration(): Configuration
{
return new Configuration(
'To configure.',
'To configure.',
'To configure.',
[
new InputArgument(
self::FILE_ARGUMENT,
InputArgument::OPTIONAL,
'The configuration file. (default: box.json, box.json.dist)',
),
],
);
}

final public function execute(IO $io): int
{
$composerOrchestrator = new ComposerOrchestrator(
ComposerProcessFactory::create(
$this->getComposerExecutable($io),
$io,
),
new ConsoleLogger($io->getOutput(), self::VERBOSITY_LEVEL_MAP),
new FileSystem(),
);

return $this->orchestrate($composerOrchestrator, $io);
}

abstract protected function orchestrate(ComposerOrchestrator $composerOrchestrator, IO $io): int;

private function getComposerExecutable(IO $io): ?string
{
try {
$config = ConfigurationLoader::getConfig(
$io->getArgument(self::FILE_ARGUMENT)->asNullableNonEmptyString() ?? ConfigurationLocator::findDefaultPath(),
$io,
false,
);

return $config->getComposerBin();
} catch (RuntimeException) {
return null;
}
}
}
59 changes: 59 additions & 0 deletions src/Console/Command/Composer/ComposerVendorDir.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Console\Command\Composer;

use Fidry\Console\Command\Command;
use Fidry\Console\Command\Configuration;
use Fidry\Console\ExitCode;
use Fidry\Console\Input\IO;
use Fidry\FileSystem\FileSystem;
use KevinGH\Box\Composer\ComposerOrchestrator;
use KevinGH\Box\Composer\ComposerProcessFactory;
use KevinGH\Box\Console\ConfigurationLoader;
use KevinGH\Box\Console\ConfigurationLocator;
use Psr\Log\LogLevel;
use RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;

/**
* @private
*/
final class ComposerVendorDir extends ComposerCommand
{
public function getConfiguration(): Configuration
{
$parentConfig = parent::getConfiguration();

return new Configuration(
'composer:vendor-dir',
'🎵 Shows the Composer vendor-dir configured',
<<<'HELP'
The <info>%command.name%</info> command will look for the Composer binary (in the system if not configured
in the configuration file) and print the vendor-dir found.
HELP,
$parentConfig->getArguments(),
$parentConfig->getOptions(),
);
}

protected function orchestrate(ComposerOrchestrator $composerOrchestrator, IO $io): int
{
$io->writeln($composerOrchestrator->getVendorDir());

return ExitCode::SUCCESS;
}
}

0 comments on commit cb8ea3c

Please sign in to comment.