diff --git a/BaseCommand.php b/BaseCommand.php index dfd7f7b2db1bfd15fbfcb485b8585f21ba76ee1a..dde0fe93ec2efd0ebd455700560542be7b7dd21e 100644 --- a/BaseCommand.php +++ b/BaseCommand.php @@ -23,10 +23,11 @@ abstract class BaseCommand extends ComposerBaseCommand implements BaseCommandInt /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output) { + protected function execute(InputInterface $input, OutputInterface $output): int { $class = $this->getHandlerClass(); $this->handler = new $class($this->getComposer(), $this->getIO()); $this->handler->setInput($input); + return 0; } } diff --git a/BaseCommandInterface.php b/BaseCommandInterface.php index 62ffdde0f60cb003f315436a8e6943d3f59930a4..c825cc1e7839748d12eb1dda8a0dfee7201ccb79 100644 --- a/BaseCommandInterface.php +++ b/BaseCommandInterface.php @@ -12,6 +12,6 @@ interface BaseCommandInterface { /** * @return \LakeDrops\Component\Composer\BaseHandlerInterface */ - public function getHandlerClass(); + public function getHandlerClass(): BaseHandlerInterface; } diff --git a/BaseHandler.php b/BaseHandler.php index 0d41d745c564d8c0919952c7ee915f3da2de80b4..504c388eb6d553e250f3b6dc4d79e553bc177c55 100644 --- a/BaseHandler.php +++ b/BaseHandler.php @@ -4,6 +4,7 @@ namespace LakeDrops\Component\Composer; use Composer\Composer; use Composer\IO\IOInterface; +use Composer\Package\PackageInterface; use Composer\Script\Event; use Symfony\Component\Console\Input\InputInterface; @@ -28,6 +29,13 @@ abstract class BaseHandler implements BaseHandlerInterface { */ protected $io; + /** + * The project config. + * + * @var \LakeDrops\Component\Composer\Config + */ + protected $config; + /** * @var \Symfony\Component\Console\Input\InputInterface */ @@ -58,12 +66,20 @@ abstract class BaseHandler implements BaseHandlerInterface { public function __construct(Composer $composer, IOInterface $io) { $this->composer = $composer; $this->io = $io; + $this->config = new Config($this->configId(), $this->configDefault()); + } + + /** + * @return array + */ + protected function configDefault(): array { + return []; } /** * {@inheritdoc} */ - public function setEvent(Event $event) { + public function setEvent(Event $event): BaseHandler { $this->event = $event; return $this; } @@ -71,7 +87,7 @@ abstract class BaseHandler implements BaseHandlerInterface { /** * {@inheritdoc} */ - public function setInput(InputInterface $input) { + public function setInput(InputInterface $input): BaseHandler { $this->consoleInput = $input; return $this; } @@ -79,7 +95,7 @@ abstract class BaseHandler implements BaseHandlerInterface { /** * {@inheritdoc} */ - public function getDrupalCorePackage() { + public function getDrupalCorePackage(): PackageInterface { if (!isset($this->drupalCorePackage)) { $this->drupalCorePackage = $this->getPackage('drupal/core'); } @@ -89,7 +105,7 @@ abstract class BaseHandler implements BaseHandlerInterface { /** * {@inheritdoc} */ - public function getPackage($name) { + public function getPackage(string $name): PackageInterface { return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*'); } @@ -125,21 +141,21 @@ abstract class BaseHandler implements BaseHandlerInterface { /** * {@inheritdoc} */ - public function git($command) { + public function git(string $command): void { Utils::git($command); } /** * {@inheritdoc} */ - public function gitIgnore($pattern) { + public function gitIgnore(string $pattern): void { Utils::gitIgnore($pattern); } /** * {@inheritdoc} */ - public function gitLFS($pattern) { + public function gitLFS(string $pattern): void { Utils::gitLFS($pattern); } diff --git a/BaseHandlerInterface.php b/BaseHandlerInterface.php index e818168b86c7023340630afd2da3a9f4712bfa06..330bb2985d06182a92c6f80fc59ccbe8d80046ae 100644 --- a/BaseHandlerInterface.php +++ b/BaseHandlerInterface.php @@ -2,6 +2,7 @@ namespace LakeDrops\Component\Composer; +use Composer\Package\PackageInterface; use Composer\Script\Event; use Symfony\Component\Console\Input\InputInterface; @@ -12,6 +13,11 @@ use Symfony\Component\Console\Input\InputInterface; */ interface BaseHandlerInterface { + /** + * @return string + */ + public function configId(): string; + /** * @param \Composer\Script\Event $event */ @@ -28,7 +34,7 @@ interface BaseHandlerInterface { * @return \Composer\Package\PackageInterface * The Drupal core package. */ - public function getDrupalCorePackage(); + public function getDrupalCorePackage(): PackageInterface; /** * Retrieve a package from the current composer process. @@ -39,24 +45,24 @@ interface BaseHandlerInterface { * @return \Composer\Package\PackageInterface * The package. */ - public function getPackage($name); + public function getPackage(string $name): PackageInterface; /** * @return bool */ - public function isDevMode(); + public function isDevMode(): bool; /** * @return bool */ - public function isLocalDevMode(); + public function isLocalDevMode(): bool; /** * Determine if the current process runs in a CI/CD context. * * @return bool */ - public function isCiContext(); + public function isCiContext(): bool; /** * Wrapper for git command in the root directory. @@ -64,7 +70,7 @@ interface BaseHandlerInterface { * @param string $command * Git command name, arguments and/or options. */ - public function git($command); + public function git(string $command); /** * Add the given pattern to gitignore if necessary. @@ -72,7 +78,7 @@ interface BaseHandlerInterface { * @param string $pattern * The pattern which should be ignored. */ - public function gitIgnore($pattern); + public function gitIgnore(string $pattern); /** * Add the given pattern to git lfs if necessary. @@ -80,6 +86,6 @@ interface BaseHandlerInterface { * @param string $pattern * The pattern which should be added. */ - public function gitLFS($pattern); + public function gitLFS(string $pattern); } diff --git a/BasePlugin.php b/BasePlugin.php index ee27ba80cb4bd886912da41090e249eefebdd797..d0faaf67a5a2f862a64ac6b96f2a7797dcd7ec93 100644 --- a/BasePlugin.php +++ b/BasePlugin.php @@ -23,7 +23,7 @@ abstract class BasePlugin implements BasePluginInterface, PluginInterface, Event /** * {@inheritdoc} */ - public function activate(Composer $composer, IOInterface $io) { + public function activate(Composer $composer, IOInterface $io): void { $class = $this->getHandlerClass(); $this->handler = new $class($composer, $io); } @@ -31,11 +31,11 @@ abstract class BasePlugin implements BasePluginInterface, PluginInterface, Event /** * {@inheritdoc} */ - public function deactivate(Composer $composer, IOInterface $io) {} + public function deactivate(Composer $composer, IOInterface $io): void {} /** * {@inheritdoc} */ - public function uninstall(Composer $composer, IOInterface $io) {} + public function uninstall(Composer $composer, IOInterface $io): void {} } diff --git a/BasePluginInterface.php b/BasePluginInterface.php index 903eb902a341b6f233d4862846e7fbd69a10c7a2..cc11cb524f4b9d8302ca4827a61c8e276ec653c3 100644 --- a/BasePluginInterface.php +++ b/BasePluginInterface.php @@ -12,6 +12,6 @@ interface BasePluginInterface { /** * @return \LakeDrops\Component\Composer\BaseHandlerInterface */ - public function getHandlerClass(); + public function getHandlerClass(): BaseHandlerInterface; } diff --git a/Config.php b/Config.php new file mode 100644 index 0000000000000000000000000000000000000000..c153c6fb54fdd2bd466c23008a84021b30b3334e --- /dev/null +++ b/Config.php @@ -0,0 +1,39 @@ +<?php + +namespace LakeDrops\Component\Composer; + +use Symfony\Component\Yaml\Yaml; + +/** + * Manages project config. + */ +final class Config { + + private static $values; + + /** + * Config constructor. + * + * @param string $component + * @param array $default_values + */ + public function __construct(string $component, array $default_values) { + $this->init(); + $componentValues = self::$values[$component] ?? []; + self::$values[$component] = NestedArray::mergeDeep($default_values, $componentValues); + } + + /** + * Read project configuration if not already happened. + */ + private function init(): void { + if (self::$values === NULL) { + $configFile = getcwd() . '/.project.yaml'; + if (!file_exists($configFile)) { + file_put_contents($configFile, Yaml::dump([], 9, 2)); + } + self::$values = Yaml::parseFile($configFile); + } + } + +} diff --git a/NestedArray.php b/NestedArray.php new file mode 100644 index 0000000000000000000000000000000000000000..fc3699d19bc3cca613ea2c08f6699a92658ca138 --- /dev/null +++ b/NestedArray.php @@ -0,0 +1,51 @@ +<?php + +namespace LakeDrops\Component\Composer; + +/** + * Class NestedArray. + * + * @package LakeDrops\Docker4Drupal + */ +class NestedArray { + + /** + * Deeply merges arrays. Borrowed from drupal.org/project/core. + * + * @return array + * The merged array. + */ + public static function mergeDeep(): array { + return self::mergeDeepArray(func_get_args()); + } + + /** + * Deeply merges arrays. Borrowed from drupal.org/project/core. + * + * @param array $arrays + * An array of array that will be merged. + * @param bool $preserve_integer_keys + * Whether to preserve integer keys. + * + * @return array + * The merged array. + */ + public static function mergeDeepArray(array $arrays, $preserve_integer_keys = FALSE): array { + $result = []; + foreach ($arrays as $array) { + foreach ($array as $key => $value) { + if (is_int($key) && !$preserve_integer_keys) { + $result[] = $value; + } + elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) { + $result[$key] = self::mergeDeepArray([$result[$key], $value], $preserve_integer_keys); + } + else { + $result[$key] = $value; + } + } + } + return $result; + } + +} diff --git a/Utils.php b/Utils.php index 89c48f9e56e786a5497fd406f479dfb819a1c8e2..9ff29bcaf2f7540fa3bc04fb3b2efd2f52c0f677 100644 --- a/Utils.php +++ b/Utils.php @@ -1,44 +1,12 @@ -<?php /** @noinspection UnusedConstructorDependenciesInspection */ +<?php namespace LakeDrops\Component\Composer; -use Composer\Composer; -use Composer\Json\JsonFile; -use Exception; - /** * Manages composer.json files. */ final class Utils { - /** - * The composer object running this session. - * - * @var \Composer\Composer - */ - private $composer; - - /** - * Content of the composer.json file. - * - * @var array - */ - private $content; - - /** - * The path of the directory of the composer.json file. - * - * @var string - */ - private $sourcePath; - - /** - * The full filename of the composer.json file. - * - * @var string - */ - private $composerJsonPath; - /** * @var string[] */ @@ -49,141 +17,10 @@ final class Utils { */ private static $lfsGitPatterns; - /** - * Utils constructor. - * - * @param \Composer\Composer $composer - * The composer object running this session. - * @param string|null $sourcePath - * The path name if not the project's root directory. - */ - public function __construct(Composer $composer, $sourcePath = NULL) { - $this->composer = $composer; - $this->sourcePath = $sourcePath ?? getcwd() . $composer->getPackage()->getTargetDir(); - $this->composerJsonPath = $this->sourcePath . '/composer.json'; - $this->read(); - } - - /** - * Read the current content of the project's composer.json file. - * - * @return $this - */ - public function read(): self { - $this->content = []; - if (file_exists($this->composerJsonPath)) { - $jsonFile = new JsonFile($this->composerJsonPath); - $this->content = $jsonFile->read(); - } - return $this; - } - - /** - * Write the config to composer.json file. - * - * @return $this - */ - public function write(): self { - $jsonFile = new JsonFile($this->composerJsonPath); - if (file_exists($this->composerJsonPath)) { - $content = $jsonFile->read(); - if (md5(json_encode($content)) === md5(json_encode($this->content))) { - // Nothing has changed. - return $this; - } - } - try { - $jsonFile->write($this->content); - } - catch (Exception $ex) { - // Let's ignore this, if composer.json is read-only there is a general problem. - } - return $this; - } - - /** - * Get settings for [$key]. - * - * @param string $key - * The key for the section. - * - * @return array|string - * The settings of the key. - */ - public function getSection($key) { - return $this->content[$key] ?? []; - } - - /** - * Get settings for [$key1][$key2]. - * - * @param string $key1 - * The key for the section. - * @param string $key2 - * The key for the sub-section. - * - * @return array|string - * The settings of the key. - */ - public function getSubSection($key1, $key2) { - $section = $this->getSection($key1); - return $section[$key2] ?? []; - } - - /** - * Get settings for [$key1][$key2][$key3]. - * - * @param string $key1 - * The key for the section. - * @param string $key2 - * The key for the sub-section. - * @param string $key3 - * The key for the sub-sub-section. - * - * @return array|string - * The settings of the key. - */ - public function getSubSubSection($key1, $key2, $key3) { - $subSection = $this->getSubSection($key1, $key2); - return $subSection[$key3] ?? []; - } - - /** - * Set settings for [$key]. - * - * @param string $key - * The key for the section. - * @param array|string $value - * The value for the section. - * - * @return $this - */ - public function setSection($key, $value): self { - $this->content[$key] = $value; - return $this; - } - - /** - * Set settings for [$key1][$key2]. - * - * @param string $key1 - * The key for the section. - * @param string $key2 - * The key for the sub-section. - * @param array|string $value - * The value for the sub-section. - * - * @return $this - */ - public function setSubSection($key1, $key2, $value): self { - $this->content[$key1][$key2] = $value; - return $this; - } - /** * Make sure that git init was called. */ - protected static function gitInit() { + protected static function gitInit(): void { if (!file_exists('.git')) { passthru(escapeshellcmd('git init')); } @@ -192,7 +29,7 @@ final class Utils { /** * @param string $command */ - public static function git($command) { + public static function git(string $command): void { self::gitInit(); passthru(escapeshellcmd('git -c "user.email=composer@lakedrops.com" ' . $command)); } @@ -200,7 +37,7 @@ final class Utils { /** * @param string $pattern */ - public static function gitIgnore($pattern) { + public static function gitIgnore(string $pattern): void { if (self::$ignoredGitPatterns === NULL) { if (file_exists('.gitignore')) { self::$ignoredGitPatterns = explode(PHP_EOL, file_get_contents('.gitignore')); @@ -221,7 +58,7 @@ final class Utils { /** * @param string $pattern */ - public static function gitLFS($pattern) { + public static function gitLFS(string $pattern): void { if (self::$lfsGitPatterns === NULL) { self::gitInit(); $output = []; diff --git a/composer.json b/composer.json index 679d45f7501d47005519700c180448e618dce522..4ad938d1218e72c8bbedc00f54ad5153f566d139 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,8 @@ }, "require": { "php": ">=7.2", - "ext-json": "*" + "ext-json": "*", + "symfony/yaml": "^3.4||^4.4||^5.0" }, "require-dev": { "composer/composer": "^1||^2",