diff --git a/composer.json b/composer.json index d303fbfe1..b904fe80b 100644 --- a/composer.json +++ b/composer.json @@ -5,8 +5,7 @@ "license": "MIT", "require": { "php": ">=7.0", - "composer-plugin-api": "~1.0", - "composer/composer": "^1.0", + "composer-plugin-api": "^1.0", "doctrine/collections": "~1.2", "gitonomy/gitlib": "^1.0.3", "monolog/monolog": "~1.16", @@ -22,6 +21,7 @@ "symfony/yaml": "~3.0|~4.0" }, "require-dev": { + "composer/composer": "^1.0", "friendsofphp/php-cs-fixer": "~2", "jakub-onderka/php-parallel-lint": "^0.9.2", "nikic/php-parser": "~2.1", diff --git a/spec/Console/Helper/ComposerHelperSpec.php b/spec/Console/Helper/ComposerHelperSpec.php index 1c643a9ad..3c145d429 100644 --- a/spec/Console/Helper/ComposerHelperSpec.php +++ b/spec/Console/Helper/ComposerHelperSpec.php @@ -3,16 +3,16 @@ namespace spec\GrumPHP\Console\Helper; use Composer\Config; -use Composer\Package\RootPackage; use GrumPHP\Console\Helper\ComposerHelper; +use GrumPHP\Util\ComposerFile; use PhpSpec\ObjectBehavior; use Symfony\Component\Console\Helper\Helper; class ComposerHelperSpec extends ObjectBehavior { - function let(Config $config, RootPackage $rootPackage) + function let(ComposerFile $composerFile) { - $this->beConstructedWith($config, $rootPackage); + $this->beConstructedWith($composerFile); } function it_is_initializable() @@ -25,23 +25,13 @@ function it_is_a_console_helper() $this->shouldHaveType(Helper::class); } - function it_knows_if_the_composer_configuration_is_available() + function it_has_a_composer_file(ComposerFile $composerFile) { - $this->hasConfiguration()->shouldBe(true); + $this->getComposerFile()->shouldBe($composerFile); } - function it_has_composer_configuration(Config $config) + function it_has_a_name() { - $this->getConfiguration()->shouldBe($config); - } - - function it_knows_if_the_composer_root_package_is_available() - { - $this->hasRootPackage()->shouldBe(true); - } - - function it_has_composer_root_package(RootPackage $rootPackage) - { - $this->getRootPackage()->shouldBe($rootPackage); + $this->getName()->shouldBe(ComposerHelper::HELPER_NAME); } } diff --git a/spec/Locator/ConfigurationFileSpec.php b/spec/Locator/ConfigurationFileSpec.php index 8ddfa5d3c..1f64221f9 100644 --- a/spec/Locator/ConfigurationFileSpec.php +++ b/spec/Locator/ConfigurationFileSpec.php @@ -2,8 +2,8 @@ namespace spec\GrumPHP\Locator; -use Composer\Package\PackageInterface; use GrumPHP\Locator\ConfigurationFile; +use GrumPHP\Util\ComposerFile; use GrumPHP\Util\Filesystem; use PhpSpec\ObjectBehavior; use Prophecy\Argument; @@ -20,77 +20,65 @@ function it_is_initializable() $this->shouldHaveType(ConfigurationFile::class); } - function it_should_locate_config_file(Filesystem $filesystem) + function it_should_locate_config_file(Filesystem $filesystem, ComposerFile $composerFile) { $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); $filesystem->isAbsolutePath($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); - $this->locate('/composer', null)->shouldMatch($this->pathRegex('/composer/grumphp.yml')); + $this->locate('/composer', $composerFile)->shouldMatch($this->pathRegex('/composer/grumphp.yml')); } - function it_should_fall_back_on_dist_file(Filesystem $filesystem) + function it_should_fall_back_on_dist_file(Filesystem $filesystem, ComposerFile $composerFile) { $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(false); $filesystem->exists($this->pathArgument('/composer/grumphp.yml.dist'))->willReturn(true); $filesystem->isAbsolutePath($this->pathArgument('/composer/grumphp.yml.dist'))->willReturn(true); - $this->locate('/composer', null)->shouldMatch($this->pathRegex('/composer/grumphp.yml.dist')); + $this->locate('/composer', $composerFile)->shouldMatch($this->pathRegex('/composer/grumphp.yml.dist')); } - function it_should_use_the_config_file_configured_in_the_composer_file(Filesystem $filesystem, PackageInterface $package) + function it_should_use_the_config_default_path_configured_in_the_composer_file(Filesystem $filesystem, ComposerFile $composerFile) { - $package->getExtra()->willReturn([ - 'grumphp' => [ - 'config-default-path' => '/composer/exotic/path/grumphp.yml' - ] - ]); + $composerFile->getConfigDefaultPath()->willReturn('/composer/exotic/path/grumphp.yml'); $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); $filesystem->exists('/composer/exotic/path/grumphp.yml')->willReturn(true); $filesystem->isAbsolutePath('/composer/exotic/path/grumphp.yml')->willReturn(true); - $this->locate('/composer', $package)->shouldBe('/composer/exotic/path/grumphp.yml'); + $this->locate('/composer', $composerFile)->shouldBe('/composer/exotic/path/grumphp.yml'); } - function it_should_use_the_config_file_configured_in_the_composer_file_and_fall_back_on_dist(Filesystem $filesystem, PackageInterface $package) + function it_should_use_the_config_file_configured_in_the_composer_file_and_fall_back_on_dist(Filesystem $filesystem, ComposerFile $composerFile) { - $package->getExtra()->willReturn([ - 'grumphp' => [ - 'config-default-path' => '/composer/exotic/path/grumphp.yml' - ] - ]); + $composerFile->getConfigDefaultPath()->willReturn('/composer/exotic/path/grumphp.yml'); $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); $filesystem->exists('/composer/exotic/path/grumphp.yml')->willReturn(false); $filesystem->exists('/composer/exotic/path/grumphp.yml.dist')->willReturn(true); $filesystem->isAbsolutePath('/composer/exotic/path/grumphp.yml.dist')->willReturn(true); - $this->locate('/composer', $package)->shouldBe('/composer/exotic/path/grumphp.yml.dist'); + $this->locate('/composer', $composerFile)->shouldBe('/composer/exotic/path/grumphp.yml.dist'); } - function it_should_always_return_absolute_paths(Filesystem $filesystem, PackageInterface $package) + function it_should_always_return_absolute_paths(Filesystem $filesystem, ComposerFile $composerFile) { - $package->getExtra()->willReturn([ - 'grumphp' => [ - 'config-default-path' => 'exotic/path/grumphp.yml' - ] - ]); + $composerFile->getConfigDefaultPath()->willReturn('exotic/path/grumphp.yml'); $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); $filesystem->exists($this->pathArgument('exotic/path/grumphp.yml'))->willReturn(true); $filesystem->isAbsolutePath($this->pathArgument('exotic/path/grumphp.yml'))->willReturn(false); - $this->locate('/composer', $package)->shouldMatch($this->pathRegex('/composer/exotic/path/grumphp.yml')); + $this->locate('/composer', $composerFile)->shouldMatch($this->pathRegex('/composer/exotic/path/grumphp.yml')); } - function it_should_locate_config_file_on_empty_composer_configuration(Filesystem $filesystem, PackageInterface $package) + function it_should_locate_config_file_on_empty_composer_configuration(Filesystem $filesystem, ComposerFile $composerFile) { - $package->getExtra()->willReturn([]); + $composerFile->getConfigDefaultPath()->willReturn(null); $filesystem->exists($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); $filesystem->isAbsolutePath($this->pathArgument('/composer/grumphp.yml'))->willReturn(true); - $this->locate('/composer', $package)->shouldMatch($this->pathRegex('/composer/grumphp.yml')); + $this->locate('/composer', $composerFile)->shouldMatch($this->pathRegex('/composer/grumphp.yml')); } private function pathRegex($expected) diff --git a/src/Console/Application.php b/src/Console/Application.php index 338c72e5a..291a5f520 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -5,10 +5,9 @@ namespace GrumPHP\Console; use GrumPHP\Configuration\ContainerFactory; -use GrumPHP\Exception\RuntimeException; use GrumPHP\IO\ConsoleIO; use GrumPHP\Locator\ConfigurationFile; -use GrumPHP\Util\Composer; +use GrumPHP\Util\ComposerFile; use GrumPHP\Util\Filesystem; use Monolog\Handler\StreamHandler; use Monolog\Logger; @@ -171,7 +170,7 @@ protected function getDefaultConfigPath(): string $locator = new ConfigurationFile($this->filesystem); $this->configDefaultPath = $locator->locate( getcwd(), - $this->initializeComposerHelper()->getRootPackage() + $this->initializeComposerHelper()->getComposerFile() ); return $this->configDefaultPath; @@ -183,17 +182,10 @@ protected function initializeComposerHelper(): Helper\ComposerHelper return $this->composerHelper; } - try { - $composerFile = getcwd().DIRECTORY_SEPARATOR.'composer.json'; - $configuration = Composer::loadConfiguration(); - Composer::ensureProjectBinDirInSystemPath($configuration->get('bin-dir')); - $rootPackage = Composer::loadRootPackageFromJson($composerFile, $configuration); - } catch (RuntimeException $e) { - $configuration = null; - $rootPackage = null; - } + $composerFileLocation = getcwd().DIRECTORY_SEPARATOR.'composer.json'; + $composerFile = ComposerFile::createFrom($composerFileLocation); - return $this->composerHelper = new Helper\ComposerHelper($configuration, $rootPackage); + return $this->composerHelper = new Helper\ComposerHelper($composerFile); } /** diff --git a/src/Console/Command/ConfigureCommand.php b/src/Console/Command/ConfigureCommand.php index aa188c9c6..ec271a510 100644 --- a/src/Console/Command/ConfigureCommand.php +++ b/src/Console/Command/ConfigureCommand.php @@ -4,7 +4,6 @@ namespace GrumPHP\Console\Command; -use Composer\Config; use Exception; use Gitonomy\Git\Repository; use GrumPHP\Configuration\GrumPHP; @@ -183,22 +182,9 @@ protected function writeConfiguration(array $configuration): bool return false; } - /** - * Make a guess to the bin dir. - */ protected function guessBinDir(): string { - $defaultBinDir = $this->config->getBinDir(); - if (!$this->composer()->hasConfiguration()) { - return $defaultBinDir; - } - - $config = $this->composer()->getConfiguration(); - if (!$config->has('bin-dir')) { - return $defaultBinDir; - } - - return $config->get('bin-dir', Config::RELATIVE_PATHS); + return $this->composer()->getComposerFile()->getBinDir(); } protected function guessGitDir(): string @@ -213,7 +199,7 @@ protected function guessGitDir(): string return rtrim($this->paths()->getRelativePath($topLevel), '/'); } - public function pathValidator($path): bool + public function pathValidator(string $path): string { if (!$this->filesystem->exists($path)) { throw new RuntimeException(sprintf('The path %s could not be found!', $path)); diff --git a/src/Console/Helper/ComposerHelper.php b/src/Console/Helper/ComposerHelper.php index d839dee3e..ca6e0d948 100644 --- a/src/Console/Helper/ComposerHelper.php +++ b/src/Console/Helper/ComposerHelper.php @@ -4,71 +4,26 @@ namespace GrumPHP\Console\Helper; -use Composer\Config; -use Composer\Package\RootPackageInterface; +use GrumPHP\Util\ComposerFile; use Symfony\Component\Console\Helper\Helper; -/** - * This class will make the composer configurationa available for the commands. - * - * Class ComposerHelper - */ class ComposerHelper extends Helper { const HELPER_NAME = 'composer'; - /** - * @var RootPackageInterface - */ - private $rootPackage; + private $composerFile; - /** - * @var Config - */ - private $configuration; - - /** - * ComposerHelper constructor. - * - * @param Config|null $configuration - * @param RootPackageInterface|null $rootPackage - */ - public function __construct(Config $configuration = null, RootPackageInterface $rootPackage = null) - { - $this->rootPackage = $rootPackage; - $this->configuration = $configuration; - } - - /** - * @return RootPackageInterface|null - */ - public function getRootPackage() - { - return $this->rootPackage; - } - - public function hasRootPackage(): bool - { - return null !== $this->rootPackage; - } - - /** - * @return Config|null - */ - public function getConfiguration() + public function __construct(ComposerFile $composerFile) { - return $this->configuration; + $this->composerFile = $composerFile; } - public function hasConfiguration(): bool + public function getComposerFile(): ComposerFile { - return null !== $this->configuration; + return $this->composerFile; } - /** - * {@inheritdoc} - */ - public function getName() + public function getName(): string { return self::HELPER_NAME; } diff --git a/src/Locator/ConfigurationFile.php b/src/Locator/ConfigurationFile.php index 2cc81dd88..5d4d72bdd 100644 --- a/src/Locator/ConfigurationFile.php +++ b/src/Locator/ConfigurationFile.php @@ -4,7 +4,7 @@ namespace GrumPHP\Locator; -use Composer\Package\PackageInterface; +use GrumPHP\Util\ComposerFile; use GrumPHP\Util\Filesystem; class ConfigurationFile @@ -16,25 +16,16 @@ class ConfigurationFile */ private $filesystem; - /** - * ConfigurationFile constructor. - */ public function __construct(Filesystem $filesystem) { $this->filesystem = $filesystem; } - /** - * @param PackageInterface|null $package - */ - public function locate(string $workingDir, PackageInterface $package = null): string + public function locate(string $workingDir, ComposerFile $composerFile): string { $defaultPath = $workingDir.DIRECTORY_SEPARATOR.self::APP_CONFIG_FILE; $defaultPath = $this->locateConfigFileWithDistSupport($defaultPath); - - if (null !== $package) { - $defaultPath = $this->useConfigPathFromComposer($package, $defaultPath); - } + $defaultPath = $this->useConfigPathFromComposer($composerFile, $defaultPath); // Make sure to set the full path when it is declared relative // This will fix some issues in windows. @@ -45,16 +36,12 @@ public function locate(string $workingDir, PackageInterface $package = null): st return $defaultPath; } - private function useConfigPathFromComposer(PackageInterface $package, string $defaultPath): string + private function useConfigPathFromComposer(ComposerFile $composerFile, string $defaultPath): string { - $extra = $package->getExtra(); - if (!isset($extra['grumphp']['config-default-path'])) { - return $defaultPath; - } - - $composerDefaultPath = $extra['grumphp']['config-default-path']; - - return $this->locateConfigFileWithDistSupport($composerDefaultPath); + $composerDefaultPath = $composerFile->getConfigDefaultPath(); + return null === $composerDefaultPath + ? $this->locateConfigFileWithDistSupport($defaultPath) + : $this->locateConfigFileWithDistSupport($composerDefaultPath); } private function locateConfigFileWithDistSupport(string $defaultPath): string diff --git a/src/Util/Composer.php b/src/Util/Composer.php deleted file mode 100644 index e0a1a1712..000000000 --- a/src/Util/Composer.php +++ /dev/null @@ -1,80 +0,0 @@ -load($json); - } catch (Exception $e) { - throw RuntimeException::fromAnyException($e); - } - - return $package; - } - - public static function loadConfiguration(): Config - { - try { - $configuration = Factory::createConfig(); - } catch (Exception $e) { - throw RuntimeException::fromAnyException($e); - } - - return $configuration; - } - - /** - * Composer contains some logic to prepend the current bin dir to the system PATH. - * To make sure this application works the same in CLI and Composer modus, - * we'll have to ensure that the bin path is always prefixed. - * - * @see https://github.com/composer/composer/blob/1.1/src/Composer/EventDispatcher/EventDispatcher.php#L147-L160 - */ - public static function ensureProjectBinDirInSystemPath(string $binDir) - { - $pathStr = 'PATH'; - if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) { - $pathStr = 'Path'; - } - - if (!is_dir($binDir)) { - return; - } - - // add the bin dir to the PATH to make local binaries of deps usable in scripts - $binDir = realpath($binDir); - $hasBindDirInPath = preg_match( - '{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', - $_SERVER[$pathStr] - ); - - if (!$hasBindDirInPath && isset($_SERVER[$pathStr])) { - $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr); - putenv($pathStr.'='.$_SERVER[$pathStr]); - } - } -} diff --git a/src/Util/ComposerFile.php b/src/Util/ComposerFile.php new file mode 100644 index 000000000..57f184ce7 --- /dev/null +++ b/src/Util/ComposerFile.php @@ -0,0 +1,79 @@ +configuration = $configuration; + } + + public static function createFrom(string $composerFileLocation): self + { + if (!\file_exists($composerFileLocation)) { + throw new RuntimeException(sprintf('composer.json not found on location %s', $composerFileLocation)); + } + $json = \file_get_contents($composerFileLocation); + + return new self(json_decode($json, true)); + } + + /** + * Composer contains some logic to prepend the current bin dir to the system PATH. + * To make sure this application works the same in CLI and Composer mode, + * we'll have to ensure that the bin path is always prefixed. + * + * @see https://github.com/composer/composer/blob/1.1/src/Composer/EventDispatcher/EventDispatcher.php#L147-L160 + */ + private static function ensureProjectBinDirInSystemPath(string $binDir): bool + { + $pathStr = 'PATH'; + if (!isset($_SERVER[$pathStr]) && isset($_SERVER['Path'])) { + $pathStr = 'Path'; + } + + if (!is_dir($binDir)) { + return false; + } + + // add the bin dir to the PATH to make local binaries of deps usable in scripts + $binDir = realpath($binDir); + $hasBindDirInPath = preg_match( + '{(^|'.PATH_SEPARATOR.')'.preg_quote($binDir).'($|'.PATH_SEPARATOR.')}', + $_SERVER[$pathStr] + ); + + if (!$hasBindDirInPath && isset($_SERVER[$pathStr])) { + $_SERVER[$pathStr] = $binDir.PATH_SEPARATOR.getenv($pathStr); + putenv($pathStr.'='.$_SERVER[$pathStr]); + } + + return true; + } + + public function getBinDir(): string + { + $binDir = $this->configuration['bin-dir'] ?? 'vendor/bin'; + + if (self::ensureProjectBinDirInSystemPath($binDir)) { + return $binDir; + } + + throw new RuntimeException('Could not get bin dir location'); + } + + /** + * @return string|null + */ + public function getConfigDefaultPath() + { + return null; + } +}