From 34434e50d0162b2426ab397a34608c98ab2630fd Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 23 May 2020 15:01:54 +0200 Subject: [PATCH 01/27] Basic data store value object for config file --- src/Composer/Config.php | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/Composer/Config.php diff --git a/src/Composer/Config.php b/src/Composer/Config.php new file mode 100644 index 00000000..f9471459 --- /dev/null +++ b/src/Composer/Config.php @@ -0,0 +1,39 @@ +data = $data; + } + + /** + * @param string $key + * @return bool|mixed + */ + public function get($key) + { + if (isset($this->data[ $key ])) { + return $this->data[ $key ]; + } + + return false; + } + + /** + * @param string $key + * @param mixed $data + */ + public function set($key, $data) + { + $this->data[$key] = $data; + } +} From a1c94674f8ddb4c0532f42d390e047607ea289f0 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 23 May 2020 15:02:08 +0200 Subject: [PATCH 02/27] Logic uses new config value object --- src/Composer/Package.php | 27 ++++++++++++++++------ src/Console/Commands/Compose.php | 33 +++++++++++++++------------ src/Mover.php | 39 ++++++++++++++++---------------- src/Replacer.php | 21 +++++++++-------- 4 files changed, 71 insertions(+), 49 deletions(-) diff --git a/src/Composer/Package.php b/src/Composer/Package.php index d3790a00..7291fab7 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -3,13 +3,14 @@ namespace CoenJacobs\Mozart\Composer; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; +use Mozart\Composer\Config; class Package { /** @var string */ public $path = ''; - /** @var */ + /** @var Config */ public $config; /** @var array */ @@ -18,13 +19,18 @@ class Package /** @var array */ public $dependencies = []; - public function __construct($path, $overrideAutoload = null) + public function __construct($path, Config $config = null, $overrideAutoload = null) { $this->path = $path; - $this->config = json_decode(file_get_contents($this->path . '/composer.json')); + + if (isset($config)) { + $config = json_decode(file_get_contents($this->path . '/composer.json')); + $config = new Config($config); + } + $this->config = $config; if (isset($overrideAutoload)) { - $this->config->autoload = $overrideAutoload; + $this->config->set('autoload', $overrideAutoload); } } @@ -36,16 +42,18 @@ public function findAutoloaders() 'classmap' => 'CoenJacobs\Mozart\Composer\Autoload\Classmap', ); - if (! isset($this->config->autoload)) { + $autoload = $this->config->get('autoload'); + + if ($autoload === false) { return; } foreach ($namespace_autoloaders as $key => $value) { - if (! isset($this->config->autoload->$key)) { + if (! isset($autoload->$key)) { continue; } - $autoconfigs = (array)$this->config->autoload->$key; + $autoconfigs = (array)$autoload->$key; /** @var $autoloader Autoloader */ $autoloader = new $value(); @@ -54,4 +62,9 @@ public function findAutoloaders() array_push($this->autoloaders, $autoloader); } } + + public function setConfig(Config $config) + { + $this->config = $config; + } } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 38369c65..091633db 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -2,11 +2,10 @@ namespace CoenJacobs\Mozart\Console\Commands; -use CoenJacobs\Mozart\Composer\Autoload\Classmap; -use CoenJacobs\Mozart\Composer\Autoload\NamespaceAutoloader; use CoenJacobs\Mozart\Composer\Package; use CoenJacobs\Mozart\Mover; use CoenJacobs\Mozart\Replacer; +use Mozart\Composer\Config; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -22,7 +21,7 @@ class Compose extends Command /** @var string */ private $workingDir; - /** @var */ + /** @var Config */ private $config; protected function configure() @@ -40,14 +39,16 @@ protected function execute(InputInterface $input, OutputInterface $output) $config = json_decode(file_get_contents($workingDir . '/composer.json')); $config = $config->extra->mozart; - $config->dep_namespace = preg_replace("/\\\{2,}$/", "\\", "$config->dep_namespace\\"); - - $this->config = $config; + $this->config = new Config($config); + $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", "$config->get('dep_namespace')\\")); $this->mover = new Mover($workingDir, $config); $this->replacer = new Replacer($workingDir, $config); - $require = empty($config->packages) ? array_keys(get_object_vars($composer->require)) : $config->packages; + $require = $config->get('packages'); + if ($require !== false) { + $require = array_keys(get_object_vars($this->config->get('require'))); + } $packages = $this->findPackages($require); @@ -131,18 +132,22 @@ private function findPackages($slugs) } $autoloaders = null; - if (isset($this->config->override_autoload) && isset($this->config->override_autoload->$package_slug)) { - $autoloaders = $this->config->override_autoload->$package_slug; + $override_autoload = $this->config->get('override_autoload'); + if ($override_autoload !== false && isset($override_autoload->$package_slug)) { + $autoloaders = $override_autoload->$package_slug; } - $package = new Package($packageDir, $autoloaders); - $package->findAutoloaders(); - $config = json_decode(file_get_contents($packageDir . 'composer.json')); + $config = new Config($config); + + $package = new Package($packageDir, $config, $autoloaders); + $package->findAutoloaders(); $dependencies = []; - if (isset($config->require)) { - $dependencies = array_keys((array)$config->require); + $require = $config->get('require'); + + if ($require !== false) { + $dependencies = array_keys((array)$require); } $package->dependencies = $this->findPackages($dependencies); diff --git a/src/Mover.php b/src/Mover.php index f038b0bd..e3586088 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -8,6 +8,7 @@ use CoenJacobs\Mozart\Composer\Package; use League\Flysystem\Adapter\Local; use League\Flysystem\Filesystem; +use Mozart\Composer\Config; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; @@ -19,7 +20,7 @@ class Mover /** @var string */ protected $targetDir; - /** @var \stdClass */ + /** @var Config */ protected $config; /** @var Filesystem */ @@ -28,26 +29,26 @@ class Mover /** @var array */ protected $movedPackages = []; - public function __construct($workingDir, $config) + public function __construct($workingDir, Config $config) { - $this->workingDir = $workingDir; - $this->targetDir = $config->dep_directory; $this->config = $config; + $this->workingDir = $workingDir; + $this->targetDir = $this->config->get('dep_directory'); $this->filesystem = new Filesystem(new Local($this->workingDir)); } public function deleteTargetDirs() { - $this->filesystem->deleteDir($this->config->dep_directory); - $this->filesystem->createDir($this->config->dep_directory); - $this->filesystem->deleteDir($this->config->classmap_directory); - $this->filesystem->createDir($this->config->classmap_directory); + $this->filesystem->deleteDir($this->config->get('dep_directory')); + $this->filesystem->createDir($this->config->get('dep_directory')); + $this->filesystem->deleteDir($this->config->get('classmap_directory')); + $this->filesystem->createDir($this->config->get('classmap_directory')); } public function movePackage(Package $package) { - if (in_array($package->config->name, $this->movedPackages)) { + if (in_array($package->config->get('name'), $this->movedPackages)) { return; } @@ -56,7 +57,7 @@ public function movePackage(Package $package) $finder = new Finder(); foreach ($autoloader->paths as $path) { - $source_path = $this->workingDir . '/vendor/' . $package->config->name . '/' . $path; + $source_path = $this->workingDir . '/vendor/' . $package->config->get('name') . '/' . $path; $finder->files()->in($source_path); @@ -68,7 +69,7 @@ public function movePackage(Package $package) $finder = new Finder(); foreach ($autoloader->files as $file) { - $source_path = $this->workingDir . '/vendor/' . $package->config->name; + $source_path = $this->workingDir . '/vendor/' . $package->config->get('name'); $finder->files()->name($file)->in($source_path); foreach ($finder as $foundFile) { @@ -79,7 +80,7 @@ public function movePackage(Package $package) $finder = new Finder(); foreach ($autoloader->paths as $path) { - $source_path = $this->workingDir . '/vendor/' . $package->config->name . '/' . $path; + $source_path = $this->workingDir . '/vendor/' . $package->config->get('name') . '/' . $path; $finder->files()->in($source_path); @@ -89,10 +90,10 @@ public function movePackage(Package $package) } } - $this->movedPackages[] = $package->config->name; + $this->movedPackages[] = $package->config->get('name'); } - if (!isset($this->config->delete_vendor_directories) || $this->config->delete_vendor_directories === true) { + if ($this->config->get('delete_vendor_directories')) { $this->deletePackageVendorDirectories(); } } @@ -108,18 +109,18 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') { if ($autoloader instanceof NamespaceAutoloader) { $namespacePath = $autoloader->getNamespacePath(); - $replaceWith = $this->config->dep_directory . $namespacePath; + $replaceWith = $this->config->get('dep_directory') . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = '/vendor/' . $package->config->name . '/' . $path; + $packageVendorPath = '/vendor/' . $package->config->get('name') . '/' . $path; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, '', $targetFile); } else { - $namespacePath = $package->config->name; - $replaceWith = $this->config->classmap_directory . '/' . $namespacePath; + $namespacePath = $package->config->get('name'); + $replaceWith = $this->config->get('classmap_directory') . '/' . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = '/vendor/' . $package->config->name . '/'; + $packageVendorPath = '/vendor/' . $package->config->get('name') . '/'; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); } diff --git a/src/Replacer.php b/src/Replacer.php index 6ebe120b..84119263 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -9,6 +9,7 @@ use CoenJacobs\Mozart\Replace\NamespaceReplacer; use League\Flysystem\Adapter\Local; use League\Flysystem\Filesystem; +use Mozart\Composer\Config; use Symfony\Component\Finder\Finder; class Replacer @@ -19,7 +20,7 @@ class Replacer /** @var string */ protected $targetDir; - /** @var \stdClass */ + /** @var Config */ protected $config; /** @var array */ @@ -28,11 +29,11 @@ class Replacer /** @var Filesystem */ protected $filesystem; - public function __construct($workingDir, $config) + public function __construct($workingDir, Config $config) { - $this->workingDir = $workingDir; - $this->targetDir = $config->dep_directory; $this->config = $config; + $this->workingDir = $workingDir; + $this->targetDir = $this->config->get('dep_directory'); $this->filesystem = new Filesystem(new Local($this->workingDir)); } @@ -55,10 +56,10 @@ public function replaceInFile($targetFile, $autoloader) if ($autoloader instanceof NamespaceAutoloader) { $replacer = new NamespaceReplacer(); - $replacer->dep_namespace = $this->config->dep_namespace; + $replacer->dep_namespace = $this->config->get('dep_namespace'); } else { $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = $this->config->classmap_prefix; + $replacer->classmap_prefix = $this->config->get('classmap_prefix'); } $replacer->setAutoloader($autoloader); @@ -82,7 +83,8 @@ public function replacePackageByAutoloader(Package $package, $autoloader) $this->replaceInDirectory($autoloader, $source_path); } elseif ($autoloader instanceof Classmap) { $finder = new Finder(); - $source_path = $this->workingDir . $this->config->classmap_directory . '/' . $package->config->name; + $classmap_dir = $this->config->get('classmap_directory'); + $source_path = $this->workingDir . $classmap_dir . '/' . $package->config->get('name'); $finder->files()->in($source_path); foreach ($finder as $foundFile) { @@ -157,7 +159,7 @@ public function replaceParentPackage(Package $package, $parent) foreach ($package->autoloaders as $autoloader) { if ($parentAutoloader instanceof NamespaceAutoloader) { $namespace = str_replace('\\', '/', $parentAutoloader->namespace); - $directory = $this->workingDir . $this->config->dep_directory . $namespace . '/'; + $directory = $this->workingDir . $this->config->get('dep_directory') . $namespace . '/'; if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); @@ -166,7 +168,8 @@ public function replaceParentPackage(Package $package, $parent) $this->replaceParentClassesInDirectory($directory); } } else { - $directory = $this->workingDir . $this->config->classmap_directory . $parent->config->name; + $classmap_dir = $this->config->get('classmap_directory'); + $directory = $this->workingDir . $classmap_dir . $parent->config->get('name'); if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); From ef05be4acc18320715f4f0bc15acbfa79f62b1fd Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 23 May 2020 15:08:27 +0200 Subject: [PATCH 03/27] Static method to directly load a config from a file --- src/Composer/Config.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index f9471459..1f2337ff 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -15,6 +15,12 @@ public function __construct(array $data) $this->data = $data; } + public static function loadFromFile($filePath) + { + $config = json_decode(file_get_contents($filePath)); + return new self($config); + } + /** * @param string $key * @return bool|mixed From 3921bc0aa18a6966eb8a5b04f9a52be2a80c6d41 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 23 May 2020 15:08:54 +0200 Subject: [PATCH 04/27] Load config from file directly where possible --- src/Composer/Package.php | 3 +-- src/Console/Commands/Compose.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Composer/Package.php b/src/Composer/Package.php index 7291fab7..742b68f0 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -24,8 +24,7 @@ public function __construct($path, Config $config = null, $overrideAutoload = nu $this->path = $path; if (isset($config)) { - $config = json_decode(file_get_contents($this->path . '/composer.json')); - $config = new Config($config); + $config = Config::loadFromFile($this->path . '/composer.json'); } $this->config = $config; diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 091633db..bb0496ed 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -137,8 +137,7 @@ private function findPackages($slugs) $autoloaders = $override_autoload->$package_slug; } - $config = json_decode(file_get_contents($packageDir . 'composer.json')); - $config = new Config($config); + $config = Config::loadFromFile($packageDir . 'composer.json'); $package = new Package($packageDir, $config, $autoloaders); $package->findAutoloaders(); From 13d79205e7dc990ebe416cdf5e9d359ae808d3ea Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 23 May 2020 20:50:01 +0200 Subject: [PATCH 05/27] Fix config object namespace --- src/Composer/Config.php | 2 +- src/Composer/Package.php | 1 - src/Console/Commands/Compose.php | 2 +- src/Mover.php | 2 +- src/Replacer.php | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 1f2337ff..8b004708 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -1,6 +1,6 @@ Date: Tue, 23 Jul 2024 09:16:53 +0000 Subject: [PATCH 06/27] Fix config object implementations --- src/Composer/Config.php | 15 ++++---- src/Composer/Package.php | 6 ++-- src/Console/Commands/Compose.php | 20 +++++------ tests/MoverTest.php | 61 ++++++++++++++++---------------- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 8b004708..b2cfb3d1 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -4,28 +4,29 @@ class Config { - /** @var array */ + /** @var array */ private $data; /** - * @param array $data + * @param array $data */ public function __construct(array $data) { $this->data = $data; } - public static function loadFromFile($filePath) + public static function loadFromFile(string $filePath): Config { - $config = json_decode(file_get_contents($filePath)); - return new self($config); + $fileContents = file_get_contents($filePath); + $config = ( ! $fileContents ) ? $config = array() : json_decode( $fileContents ); + return new self((array)$config); } /** * @param string $key * @return bool|mixed */ - public function get($key) + public function get(string $key) { if (isset($this->data[ $key ])) { return $this->data[ $key ]; @@ -38,7 +39,7 @@ public function get($key) * @param string $key * @param mixed $data */ - public function set($key, $data) + public function set($key, $data): void { $this->data[$key] = $data; } diff --git a/src/Composer/Package.php b/src/Composer/Package.php index 63b06c86..4a1c0b6e 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -29,9 +29,9 @@ class Package */ public function __construct($path, Config $config = null, $overrideAutoload = null) { - $this->path = $path; + $this->path = $path; - if (isset($config)) { + if (empty($config)) { $config = Config::loadFromFile($this->path . '/composer.json'); } $this->config = $config; @@ -73,7 +73,7 @@ public function findAutoloaders() } } - public function setConfig(Config $config) + public function setConfig(Config $config): void { $this->config = $config; } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 3d7f68e0..401851fd 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -60,18 +60,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $config = $composer->extra->mozart; - $this->config = new Config($config); - $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", "$config->get('dep_namespace')\\")); + $this->config = new Config((array)$config); + $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", $this->config->get('dep_namespace')."\\")); $require = array(); - if (isset($config->packages) && is_array($config->packages)) { - $require = $config->packages; + if (is_array($this->config->get('packages'))) { + $require = $this->config->get('packages'); } elseif (isset($composer->require) && is_object($composer->require)) { $require = array_keys(get_object_vars($composer->require)); } $packagesByName = $this->findPackages($require); - $excludedPackagesNames = isset($config->excluded_packages) ? $config->excluded_packages : []; + $excludedPackagesNames = is_array($this->config->get('excluded_packages')) ? $this->config->get('excluded_packages') : []; $packagesToMoveByName = array_diff_key($packagesByName, array_flip($excludedPackagesNames)); $packages = array_values($packagesToMoveByName); @@ -79,13 +79,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $package->dependencies = array_diff_key($package->dependencies, array_flip($excludedPackagesNames)); } - $this->mover = new Mover($workingDir, $config); - $this->replacer = new Replacer($workingDir, $config); + $this->mover = new Mover($workingDir, $this->config); + $this->replacer = new Replacer($workingDir, $this->config); - $require = $config->get('packages'); - if ($require !== false) { - $require = array_keys(get_object_vars($this->config->get('require'))); - } + $require = $this->config->get('packages'); + $require = (is_array($require)) ? array_keys($require) : array(); $packages = $this->findPackages($require); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 4577cc90..b0f4a00f 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -1,6 +1,7 @@ extra->mozart settings * - * @var stdClass + * @var Config */ protected $config; @@ -38,23 +39,23 @@ public function setUp(): void mkdir($this->testsWorkingDir); } - $config = new class() { - }; - $config->dep_directory = "/dep_directory/"; - $config->classmap_directory = "/classmap_directory/"; - $config->packages = array( - "pimple/pimple", - "ezyang/htmlpurifier" - ); - $pimpleAutoload = json_decode("{ \"psr-0\" : { \"Pimple\" : [ \"src/\" ] } }"); $htmlpurifierAutoload = json_decode("{ \"classmap\" : { \"Pimple\" => [ \"library/\" ] } }"); - $config->override_autoload = array(); - $config->override_autoload["pimple/pimple"] = $pimpleAutoload; - $config->override_autoload["ezyang/htmlpurifier"] = $htmlpurifierAutoload; + $configArgs = array( + 'dep_directory' => "/dep_directory/", + 'classmap_directory' => "/classmap_directory/", + 'packages' => array( + "pimple/pimple", + "ezyang/htmlpurifier", + ), + 'override_autoload' => array( + 'pimple/pimple' => $pimpleAutoload, + 'ezyang/htmlpurifier' => $htmlpurifierAutoload, + ), + ); - $this->config = $config; + $this->config = new Config( $configArgs ); } /** @@ -72,9 +73,9 @@ public function it_creates_absent_dirs(): void $mover->deleteTargetDirs($packages); $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR - . $this->config->dep_directory)); + . $this->config->get('dep_directory'))); $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR - . $this->config->classmap_directory)); + . $this->config->get('classmap_directory'))); } /** @@ -87,15 +88,15 @@ public function it_is_unpertrubed_by_existing_dirs(): void { $mover = new Mover($this->testsWorkingDir, $this->config); - if (!file_exists($this->testsWorkingDir . $this->config->dep_directory)) { - mkdir($this->testsWorkingDir . $this->config->dep_directory); + if (!file_exists($this->testsWorkingDir . $this->config->get('dep_directory'))) { + mkdir($this->testsWorkingDir . $this->config->get('dep_directory')); } - if (!file_exists($this->testsWorkingDir . $this->config->classmap_directory)) { - mkdir($this->testsWorkingDir . $this->config->classmap_directory); + if (!file_exists($this->testsWorkingDir . $this->config->get('classmap_directory'))) { + mkdir($this->testsWorkingDir . $this->config->get('classmap_directory')); } - $this->assertDirectoryExists($this->testsWorkingDir . $this->config->dep_directory); - $this->assertDirectoryExists($this->testsWorkingDir . $this->config->classmap_directory); + $this->assertDirectoryExists($this->testsWorkingDir . $this->config->get('dep_directory')); + $this->assertDirectoryExists($this->testsWorkingDir . $this->config->get('classmap_directory')); $packages = array(); @@ -119,14 +120,14 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void { $mover = new Mover($this->testsWorkingDir, $this->config); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->dep_directory); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->classmap_directory); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('dep_directory')); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory')); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->dep_directory . 'Pimple'); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->classmap_directory . 'ezyang'); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('dep_directory') . 'Pimple'); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory') . 'ezyang'); $packages = array(); - foreach ($this->config->packages as $packageString) { + foreach ($this->config->get('packages') as $packageString) { $testDummyComposerDir = $this->testsWorkingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $packageString; @mkdir($testDummyComposerDir, 0777, true); @@ -134,15 +135,15 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $testDummyComposerContents = json_encode(new stdClass()); file_put_contents($testDummyComposerPath, $testDummyComposerContents); - $parsedPackage = new Package($testDummyComposerDir, $this->config->override_autoload[$packageString]); + $parsedPackage = new Package($testDummyComposerDir, $this->config, $this->config->get('override_autoload')[$packageString]); $parsedPackage->findAutoloaders(); $packages[] = $parsedPackage; } $mover->deleteTargetDirs($packages); - $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->dep_directory . 'Pimple'); - $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->dep_directory . 'ezyang'); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->get('dep_directory') . 'Pimple'); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->get('dep_directory') . 'ezyang'); } /** From 18ddaa2313530f1b95ae0c1a3123b8e1c705ceaf Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Tue, 23 Jul 2024 11:20:09 +0200 Subject: [PATCH 07/27] Coding standards line length fixes --- src/Composer/Config.php | 2 +- src/Console/Commands/Compose.php | 3 ++- src/Replacer.php | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index b2cfb3d1..69af26c3 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -18,7 +18,7 @@ public function __construct(array $data) public static function loadFromFile(string $filePath): Config { $fileContents = file_get_contents($filePath); - $config = ( ! $fileContents ) ? $config = array() : json_decode( $fileContents ); + $config = ( ! $fileContents ) ? $config = array() : json_decode($fileContents); return new self((array)$config); } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 401851fd..2df4628d 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -71,7 +71,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $packagesByName = $this->findPackages($require); - $excludedPackagesNames = is_array($this->config->get('excluded_packages')) ? $this->config->get('excluded_packages') : []; + $excludedPackagesNames = is_array($this->config->get('excluded_packages')) ? + $this->config->get('excluded_packages') : []; $packagesToMoveByName = array_diff_key($packagesByName, array_flip($excludedPackagesNames)); $packages = array_values($packagesToMoveByName); diff --git a/src/Replacer.php b/src/Replacer.php index 918fdfa1..5162f03b 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -218,7 +218,8 @@ public function replaceParentPackage(Package $package, Package $parent): void $this->replaceParentClassesInDirectory($directory); } } else { - $directory = $this->workingDir . $this->config->get('classmap_directory') . $parent->config->get('name'); + $directory = $this->workingDir . + $this->config->get('classmap_directory') . $parent->config->get('name'); if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); From 95944210627e358fad56c4296eb20fbd6e07b5a3 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 6 Sep 2024 13:50:14 +0200 Subject: [PATCH 08/27] Require jsonmapper to automate reading Composer config --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4f37687f..9c6c8a63 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "prefer-stable": true, "license": "MIT", "require": { - "php": "^8.0" + "php": "^8.0", + "netresearch/jsonmapper": "^4.4" }, "autoload": { "psr-4": { From 187e1f63482d5da749a6005f188ae1abfac54c5b Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 6 Sep 2024 13:50:52 +0200 Subject: [PATCH 09/27] Added xdebug and config to builder Docker image --- Dockerfile | 10 ++++++++-- docker-compose.yml | 1 - docker/php/error_reporting.ini | 1 + docker/php/xdebug.ini | 6 ++++++ 4 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 docker/php/error_reporting.ini create mode 100644 docker/php/xdebug.ini diff --git a/Dockerfile b/Dockerfile index c9073b9d..90428729 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,20 @@ FROM composer:2.7.7 FROM php:8.3.9-cli-alpine AS base -FROM base as builder +FROM base AS builder RUN apk update && apk add git +RUN apk add --update linux-headers +RUN apk add --no-cache $PHPIZE_DEPS \ + && pecl install xdebug-3.3.2 \ + && docker-php-ext-enable xdebug +COPY ./docker/php/xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini +COPY ./docker/php/error_reporting.ini /usr/local/etc/php/conf.d/error_reporting.ini COPY --from=composer /usr/bin/composer /usr/bin/composer COPY ./composer.json /mozart/ WORKDIR /mozart/ RUN composer install -FROM builder as packager +FROM builder AS packager RUN rm -rf vendor RUN composer install --no-dev -o diff --git a/docker-compose.yml b/docker-compose.yml index 1def9525..a02aea6e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.4' services: builder: build: diff --git a/docker/php/error_reporting.ini b/docker/php/error_reporting.ini new file mode 100644 index 00000000..7e566f46 --- /dev/null +++ b/docker/php/error_reporting.ini @@ -0,0 +1 @@ +error_reporting=E_ALL diff --git a/docker/php/xdebug.ini b/docker/php/xdebug.ini new file mode 100644 index 00000000..9c37b9c1 --- /dev/null +++ b/docker/php/xdebug.ini @@ -0,0 +1,6 @@ +zend_extension=xdebug + +[xdebug] +xdebug.mode=develop,debug +xdebug.client_host=host.docker.internal +xdebug.start_with_request=yes From eb99bd75a7fda4265eb43d0746e8c535c56cad3d Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 6 Sep 2024 13:52:05 +0200 Subject: [PATCH 10/27] Implement new config object based on mapped json --- src/Composer/Autoload/NamespaceAutoloader.php | 9 ++- src/Composer/Autoload/Psr0.php | 7 -- src/Composer/Config.php | 46 ------------ src/Composer/Package.php | 67 +++++++++-------- src/Config/Autoload.php | 63 ++++++++++++++++ .../Autoload => Config}/Classmap.php | 4 +- src/Config/Composer.php | 41 +++++++++++ src/Config/ConfigAccessor.php | 24 +++++++ src/Config/Extra.php | 15 ++++ src/Config/Mozart.php | 60 ++++++++++++++++ src/Config/OverrideAutoload.php | 31 ++++++++ src/Config/Psr0.php | 9 +++ src/{Composer/Autoload => Config}/Psr4.php | 4 +- src/Config/ReadsConfig.php | 57 +++++++++++++++ src/Console/Commands/Compose.php | 72 +++++++++---------- src/Mover.php | 26 +++---- src/Replacer.php | 20 +++--- 17 files changed, 401 insertions(+), 154 deletions(-) delete mode 100644 src/Composer/Autoload/Psr0.php delete mode 100644 src/Composer/Config.php create mode 100644 src/Config/Autoload.php rename src/{Composer/Autoload => Config}/Classmap.php (89%) create mode 100644 src/Config/Composer.php create mode 100644 src/Config/ConfigAccessor.php create mode 100644 src/Config/Extra.php create mode 100644 src/Config/Mozart.php create mode 100644 src/Config/OverrideAutoload.php create mode 100644 src/Config/Psr0.php rename src/{Composer/Autoload => Config}/Psr4.php (78%) create mode 100644 src/Config/ReadsConfig.php diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index f8393995..8725998f 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -25,9 +25,12 @@ abstract class NamespaceAutoloader implements Autoloader */ public function processConfig($autoloadConfig) { - foreach ($autoloadConfig as $key => $value) { - $this->namespace = $key; - array_push($this->paths, $value); + if (is_array($autoloadConfig)) { + foreach ($autoloadConfig as $path) { + array_push($this->paths, $path); + } + } else { + array_push($this->paths, $autoloadConfig); } } diff --git a/src/Composer/Autoload/Psr0.php b/src/Composer/Autoload/Psr0.php deleted file mode 100644 index 2a009821..00000000 --- a/src/Composer/Autoload/Psr0.php +++ /dev/null @@ -1,7 +0,0 @@ - */ - private $data; - - /** - * @param array $data - */ - public function __construct(array $data) - { - $this->data = $data; - } - - public static function loadFromFile(string $filePath): Config - { - $fileContents = file_get_contents($filePath); - $config = ( ! $fileContents ) ? $config = array() : json_decode($fileContents); - return new self((array)$config); - } - - /** - * @param string $key - * @return bool|mixed - */ - public function get(string $key) - { - if (isset($this->data[ $key ])) { - return $this->data[ $key ]; - } - - return false; - } - - /** - * @param string $key - * @param mixed $data - */ - public function set($key, $data): void - { - $this->data[$key] = $data; - } -} diff --git a/src/Composer/Package.php b/src/Composer/Package.php index 4a1c0b6e..d725a596 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -3,6 +3,8 @@ namespace CoenJacobs\Mozart\Composer; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; +use CoenJacobs\Mozart\Config\Autoload; +use CoenJacobs\Mozart\Config\Composer; use stdClass; class Package @@ -10,14 +12,11 @@ class Package /** @var string */ public $path = ''; - /** @var Config */ + /** @var Composer */ public $config; - /** @var Autoloader[] */ - public $autoloaders = []; - - /** @var array */ - public $dependencies = []; + /** @var Package[] */ + public $requirePackages = []; /** * Create a PHP object to represent a composer package. @@ -27,54 +26,54 @@ class Package * @param stdClass $overrideAutoload Optional configuration to replace the package's own autoload definition with * another which Mozart can use. */ - public function __construct($path, Config $config = null, $overrideAutoload = null) + public function __construct($path, Composer $config = null, $overrideAutoload = null) { $this->path = $path; if (empty($config)) { - $config = Config::loadFromFile($this->path . '/composer.json'); + $config = Composer::loadFromFile($this->path . '/composer.json'); } + $this->config = $config; if (isset($overrideAutoload)) { - $this->config->set('autoload', $overrideAutoload); + $autoload = new Autoload(); + $autoload->setupAutoloaders($overrideAutoload); + $this->config->set('autoload', $autoload); } } + public function getName(): string + { + return $this->config->name; + } + /** - * @return void + * @return Autoloader[] */ - public function findAutoloaders() + public function getAutoloaders(): array { - $namespace_autoloaders = array( - 'psr-0' => 'CoenJacobs\Mozart\Composer\Autoload\Psr0', - 'psr-4' => 'CoenJacobs\Mozart\Composer\Autoload\Psr4', - 'classmap' => 'CoenJacobs\Mozart\Composer\Autoload\Classmap', - ); - - $autoload = $this->config->get('autoload'); - - if ($autoload === false) { - return; + if (empty($this->config->autoload)) { + return array(); } - foreach ($namespace_autoloaders as $key => $value) { - if (! isset($autoload->$key)) { - continue; - } - - $autoloadConfig = (array)$autoload->$key; + return $this->config->autoload->getAutoloaders(); + } - /** @var Autoloader $autoloader */ - $autoloader = new $value(); - $autoloader->processConfig($autoloadConfig); + public function getDependencies(): array + { + return $this->requirePackages; + } - array_push($this->autoloaders, $autoloader); - } + public function registerRequirePackage(Package $package): void + { + array_push($this->requirePackages, $package); } - public function setConfig(Config $config): void + public function registerRequirePackages(array $packages): void { - $this->config = $config; + foreach ($packages as $package) { + $this->registerRequirePackage($package); + } } } diff --git a/src/Config/Autoload.php b/src/Config/Autoload.php new file mode 100644 index 00000000..89bcc79f --- /dev/null +++ b/src/Config/Autoload.php @@ -0,0 +1,63 @@ +{'psr-4'})) { + $psr4Autoloaders = (array) $autoloadData->{'psr-4'}; + foreach ($psr4Autoloaders as $key => $value) { + $autoloader = new Psr4(); + $autoloader->namespace = $key; + $autoloader->processConfig($value); + $autoloaders[] = $autoloader; + } + } + + if (isset($autoloadData->{'psr-0'})) { + $psr0Autoloaders = (array) $autoloadData->{'psr-0'}; + foreach ($psr0Autoloaders as $key => $value) { + $autoloader = new Psr0(); + $autoloader->namespace = $key; + $autoloader->processConfig($value); + $autoloaders[] = $autoloader; + } + } + + if (isset($autoloadData->classmap)) { + $autoloader = new Classmap(); + $autoloader->processConfig($autoloadData->classmap); + $autoloaders[] = $autoloader; + } + + $this->setAutoloaders($autoloaders); + } + + public function setAutoloaders(array $autoloaders): void + { + foreach ($autoloaders as $autoloader) { + if (! $autoloader instanceof Autoloader) { + continue; + } + + array_push($this->autoloaders, $autoloader); + } + } + + /** + * @return Autoloader[] + */ + public function getAutoloaders(): array + { + return $this->autoloaders; + } +} diff --git a/src/Composer/Autoload/Classmap.php b/src/Config/Classmap.php similarity index 89% rename from src/Composer/Autoload/Classmap.php rename to src/Config/Classmap.php index 981df843..013cf097 100644 --- a/src/Composer/Autoload/Classmap.php +++ b/src/Config/Classmap.php @@ -1,6 +1,8 @@ setupAutoloaders($data); + $this->autoload = $autoload; + } + + public function getExtra(): ?Extra + { + return $this->extra; + } + + public function isValidMozartConfig(): bool + { + if (empty($this->getExtra())) { + return false; + } + + if (empty($this->getExtra()->getMozart())) { + return false; + } + + return $this->getExtra()->getMozart()->isValidMozartConfig(); + } +} diff --git a/src/Config/ConfigAccessor.php b/src/Config/ConfigAccessor.php new file mode 100644 index 00000000..e5329942 --- /dev/null +++ b/src/Config/ConfigAccessor.php @@ -0,0 +1,24 @@ +$key)) { + throw new \Exception('Can\'t get setting: '. $key .' not set'); + } + + return $this->$key; + } + + public function set(string $key, mixed $value): void + { + if (! property_exists($this, $key)) { + throw new \Exception('Can\'t set setting: '. $key . ' not set'); + } + + $this->$key = $value; + } +} diff --git a/src/Config/Extra.php b/src/Config/Extra.php new file mode 100644 index 00000000..497f7161 --- /dev/null +++ b/src/Config/Extra.php @@ -0,0 +1,15 @@ +mozart; + } +} diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php new file mode 100644 index 00000000..fd83964a --- /dev/null +++ b/src/Config/Mozart.php @@ -0,0 +1,60 @@ + */ + public array $excluded_packages = []; + + public OverrideAutoload $override_autoload; + + public bool $delete_vendor_directories; + + public function setPackages(array $packages): void + { + $this->packages = $packages; + } + + public function setExcludedPackages(array $excluded_packages): void + { + $this->excluded_packages = $excluded_packages; + } + + public function setOverrideAutoload(stdClass $object): void + { + $this->override_autoload = new OverrideAutoload($object); + } + + public function isValidMozartConfig(): bool + { + $required = [ 'dep_namespace', 'dep_directory', 'classmap_directory', 'classmap_prefix' ]; + + foreach ($required as $requiredProp) { + if (empty($this->$requiredProp)) { + return false; + } + } + + return true; + } + + public function isExcludedPackage(Package $package) + { + return in_array($package->getName(), $this->excluded_packages); + } +} diff --git a/src/Config/OverrideAutoload.php b/src/Config/OverrideAutoload.php new file mode 100644 index 00000000..10a95b6c --- /dev/null +++ b/src/Config/OverrideAutoload.php @@ -0,0 +1,31 @@ + $object) { + $storage[$key] = $object; + } + + parent::__construct($storage); + } + + public function getByKey(string $key): mixed + { + if (! isset($this[$key])) { + return null; + } + + return $this[$key]; + } +} diff --git a/src/Config/Psr0.php b/src/Config/Psr0.php new file mode 100644 index 00000000..6f664d22 --- /dev/null +++ b/src/Config/Psr0.php @@ -0,0 +1,9 @@ + $config + */ + public static function loadFromArray(array $config): self + { + $encoded = json_encode($config); + + if (! $encoded) { + throw new Exception('Could not read config from provided array.'); + } + + $config = json_decode($encoded, false); + + if (! $config) { + throw new Exception('Could not read config from provided array.'); + } + + return self::loadFromStdClass($config); + } + + public static function loadFromStdClass(stdClass $config): self + { + $mapper = new JsonMapper(); + $mapper->bEnforceMapType = false; + return $mapper->map($config, self::class); + } + + public static function loadFromString(string $config): self + { + $config = json_decode($config); + + $mapper = new JsonMapper(); + $mapper->bEnforceMapType = false; + return $mapper->map($config, self::class); + } +} diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 2df4628d..fcde5f1f 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -2,10 +2,12 @@ namespace CoenJacobs\Mozart\Console\Commands; +use CoenJacobs\Mozart\Config\Mozart; +use CoenJacobs\Mozart\Config\Composer; use CoenJacobs\Mozart\Composer\Package; use CoenJacobs\Mozart\Mover; use CoenJacobs\Mozart\Replacer; -use CoenJacobs\Mozart\Composer\Config; +use Exception; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -21,13 +23,13 @@ class Compose extends Command /** @var string */ private $workingDir; - /** @var Config */ + /** @var Mozart */ private $config; /** * @return void */ - protected function configure() + protected function configure(): void { $this->setName('compose'); $this->setDescription('Composes all dependencies as a package inside a WordPress plugin.'); @@ -37,30 +39,29 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output): int { $workingDir = getcwd(); + + if (! $workingDir) { + throw new Exception('Could not determine working directory.'); + } + $this->workingDir = $workingDir; $composerFile = $workingDir . DIRECTORY_SEPARATOR. 'composer.json'; - if (!file_exists($composerFile)) { - $output->write('No composer.json found at current directory: ' . $workingDir); + try { + $composerConfig = Composer::loadFromFile($composerFile); + } catch (Exception $e) { + $output->write('Unable to read the composer.json file'); return 1; } - $composer = json_decode(file_get_contents($composerFile)); - // If the json was malformed. - if (!is_object($composer)) { - $output->write('Unable to parse composer.json read at: ' . $workingDir); - return 1; - } + // var_dump($composerConfig); die(); - // if `extra` is missing or not an object or if it does not have a `mozart` key which is an object. - if (!isset($composer->extra) || !is_object($composer->extra) - || !isset($composer->extra->mozart) || !is_object($composer->extra->mozart)) { + if (! $composerConfig->isValidMozartConfig()) { $output->write('Mozart config not readable in composer.json at extra->mozart'); return 1; } - $config = $composer->extra->mozart; - $this->config = new Config((array)$config); + $this->config = $composerConfig->getExtra()->getMozart(); $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", $this->config->get('dep_namespace')."\\")); $require = array(); @@ -76,15 +77,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int $packagesToMoveByName = array_diff_key($packagesByName, array_flip($excludedPackagesNames)); $packages = array_values($packagesToMoveByName); - foreach ($packages as $package) { - $package->dependencies = array_diff_key($package->dependencies, array_flip($excludedPackagesNames)); - } - $this->mover = new Mover($workingDir, $this->config); $this->replacer = new Replacer($workingDir, $this->config); $require = $this->config->get('packages'); - $require = (is_array($require)) ? array_keys($require) : array(); + $require = (is_array($require)) ? array_values($require) : array(); $packages = $this->findPackages($require); @@ -132,7 +129,7 @@ protected function replacePackages($packages): void * * @return void */ - public function movePackage($package): void + public function movePackage(Package $package): void { if (! empty($package->dependencies)) { foreach ($package->dependencies as $dependency) { @@ -148,7 +145,7 @@ public function movePackage($package): void * * @return void */ - public function replacePackage($package): void + public function replacePackage(Package $package): void { if (! empty($package->dependencies)) { foreach ($package->dependencies as $dependency) { @@ -185,19 +182,15 @@ private function findPackages(array $slugs): array $autoloaders = $override_autoload->$package_slug; } - $config = Config::loadFromFile($packageDir . 'composer.json'); + $package = new Package($packageDir, null, $autoloaders); - $package = new Package($packageDir, $config, $autoloaders); - $package->findAutoloaders(); - - $dependencies = []; - $require = $config->get('require'); - - if ($require !== false) { - $dependencies = array_keys((array)$require); + if ($this->config->isExcludedPackage($package)) { + continue; } - $package->dependencies = $this->findPackages($dependencies); + $dependencies = $package->getDependencies(); + + $package->registerRequirePackages($this->findPackages($dependencies)); $packages[$package_slug] = $package; } @@ -212,16 +205,21 @@ private function findPackages(array $slugs): array */ private function getAllDependenciesOfPackage(Package $package, $dependencies = []): array { - if (empty($package->dependencies)) { + if ($this->config->isExcludedPackage($package)) { + return $dependencies; + ; + } + + if (empty($package->getDependencies())) { return $dependencies; } /** @var Package $dependency */ - foreach ($package->dependencies as $dependency) { + foreach ($package->getDependencies() as $dependency) { $dependencies[] = $dependency; } - foreach ($package->dependencies as $dependency) { + foreach ($package->getDependencies() as $dependency) { $dependencies = $this->getAllDependenciesOfPackage($dependency, $dependencies); } @@ -242,7 +240,7 @@ private function replaceParentInTree(array $packages): void $this->replacer->replaceParentPackage($dependency, $package); } - $this->replaceParentInTree($package->dependencies); + $this->replaceParentInTree($package->getDependencies()); } } } diff --git a/src/Mover.php b/src/Mover.php index 10ea22e8..aff37d7b 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -3,14 +3,14 @@ namespace CoenJacobs\Mozart; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; -use CoenJacobs\Mozart\Composer\Autoload\Classmap; use CoenJacobs\Mozart\Composer\Autoload\NamespaceAutoloader; -use CoenJacobs\Mozart\Composer\Autoload\Psr0; -use CoenJacobs\Mozart\Composer\Autoload\Psr4; use CoenJacobs\Mozart\Composer\Package; +use CoenJacobs\Mozart\Config\Classmap; +use CoenJacobs\Mozart\Config\Mozart; +use CoenJacobs\Mozart\Config\Psr0; +use CoenJacobs\Mozart\Config\Psr4; use League\Flysystem\Local\LocalFilesystemAdapter; use League\Flysystem\Filesystem; -use CoenJacobs\Mozart\Composer\Config; use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\SplFileInfo; @@ -22,16 +22,16 @@ class Mover /** @var string */ protected $targetDir; - /** @var Config */ + /** @var Mozart */ protected $config; /** @var Filesystem */ protected $filesystem; - /** @var array */ + /** @var array */ protected $movedPackages = []; - public function __construct($workingDir, Config $config) + public function __construct(string $workingDir, Mozart $config) { $this->config = $config; $this->workingDir = $workingDir; @@ -66,14 +66,10 @@ public function deleteTargetDirs($packages): void * Delete the directories about to be used for packages earmarked for Mozart namespacing. * * @visibility private to allow recursion through packages and subpackages. - * - * @param Package $package - * - * @return void */ - private function deleteDepTargetDirs($package): void + private function deleteDepTargetDirs(Package $package): void { - foreach ($package->autoloaders as $packageAutoloader) { + foreach ($package->getAutoloaders() as $packageAutoloader) { $autoloaderType = get_class($packageAutoloader); switch ($autoloaderType) { @@ -91,7 +87,7 @@ private function deleteDepTargetDirs($package): void } } - foreach ($package->dependencies as $subPackage) { + foreach ($package->getDependencies() as $subPackage) { $this->deleteDepTargetDirs($subPackage); } } @@ -116,7 +112,7 @@ public function movePackage(Package $package) return; } - foreach ($package->autoloaders as $autoloader) { + foreach ($package->getAutoloaders() as $autoloader) { if ($autoloader instanceof NamespaceAutoloader) { $finder = new Finder(); diff --git a/src/Replacer.php b/src/Replacer.php index 5162f03b..8f248257 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -3,7 +3,7 @@ namespace CoenJacobs\Mozart; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; -use CoenJacobs\Mozart\Composer\Autoload\Classmap; +use CoenJacobs\Mozart\Config\Classmap; use CoenJacobs\Mozart\Composer\Autoload\NamespaceAutoloader; use CoenJacobs\Mozart\Composer\Package; use CoenJacobs\Mozart\Replace\ClassmapReplacer; @@ -11,7 +11,7 @@ use League\Flysystem\Local\LocalFilesystemAdapter; use League\Flysystem\UnableToReadFile; use League\Flysystem\Filesystem; -use CoenJacobs\Mozart\Composer\Config; +use CoenJacobs\Mozart\Config\Mozart; use Symfony\Component\Finder\Finder; class Replacer @@ -22,7 +22,7 @@ class Replacer /** @var string */ protected $targetDir; - /** @var Config */ + /** @var Mozart */ protected $config; /** @var array */ @@ -31,7 +31,7 @@ class Replacer /** @var Filesystem */ protected $filesystem; - public function __construct($workingDir, Config $config) + public function __construct(string $workingDir, Mozart $config) { $this->config = $config; $this->workingDir = $workingDir; @@ -47,7 +47,7 @@ public function __construct($workingDir, Config $config) public function replacePackage(Package $package): void { - foreach ($package->autoloaders as $autoloader) { + foreach ($package->getAutoloaders() as $autoloader) { $this->replacePackageByAutoloader($package, $autoloader); } } @@ -58,7 +58,7 @@ public function replacePackage(Package $package): void * * @return void */ - public function replaceInFile($targetFile, Autoloader $autoloader): void + public function replaceInFile(string $targetFile, Autoloader $autoloader): void { $targetFile = str_replace($this->workingDir, '', $targetFile); try { @@ -67,7 +67,7 @@ public function replaceInFile($targetFile, Autoloader $autoloader): void return; } - if (empty($contents) || false === $contents) { + if (!$contents) { return; } @@ -146,7 +146,7 @@ public function replaceParentClassesInDirectory(string $directory): void continue; } - if (empty($contents) || false === $contents) { + if (!$contents) { continue; } @@ -204,8 +204,8 @@ public function replaceInDirectory(NamespaceAutoloader $autoloader, string $dire */ public function replaceParentPackage(Package $package, Package $parent): void { - foreach ($parent->autoloaders as $parentAutoloader) { - foreach ($package->autoloaders as $autoloader) { + foreach ($parent->getAutoloaders() as $parentAutoloader) { + foreach ($package->getAutoloaders() as $autoloader) { if ($parentAutoloader instanceof NamespaceAutoloader) { $namespace = str_replace('\\', DIRECTORY_SEPARATOR, $parentAutoloader->namespace); $directory = $this->workingDir . $this->config->get('dep_directory') . $namespace From c906eeba0693581dcc71a62a9816e6ab50fb74a8 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 6 Sep 2024 13:52:54 +0200 Subject: [PATCH 11/27] Updated and expanded automated tests to cover config object --- tests/Config/ConfigMapperTest.php | 22 +++++++ tests/Config/config-mapper-test.json | 31 ++++++++++ tests/Console/Commands/ComposeTest.php | 6 -- tests/Integration/ExcludedPackagesTest.php | 67 ++++++++++++++++++++++ tests/Integration/excluded-packages.json | 26 +++++++++ tests/MoverTest.php | 15 +++-- tests/replacers/NamespaceReplacerTest.php | 2 +- 7 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 tests/Config/ConfigMapperTest.php create mode 100644 tests/Config/config-mapper-test.json create mode 100644 tests/Integration/ExcludedPackagesTest.php create mode 100644 tests/Integration/excluded-packages.json diff --git a/tests/Config/ConfigMapperTest.php b/tests/Config/ConfigMapperTest.php new file mode 100644 index 00000000..e548135e --- /dev/null +++ b/tests/Config/ConfigMapperTest.php @@ -0,0 +1,22 @@ +assertInstanceOf(Composer::class, $config); + $this->assertInstanceOf(Mozart::class, $config->getExtra()->getMozart()); + $this->assertCount(4, $config->autoload->getAutoloaders()); + } +} diff --git a/tests/Config/config-mapper-test.json b/tests/Config/config-mapper-test.json new file mode 100644 index 00000000..1f53c4ad --- /dev/null +++ b/tests/Config/config-mapper-test.json @@ -0,0 +1,31 @@ +{ + "require": { + "pimple/pimple": "^3.5" + }, + "autoload": { + "psr-0": { + "Mozart\\RandomDir\\": "old_files/", + "Mozart\\Multiples\\": [ "another_dir", "more_dirs" ] + }, + "psr-4": { + "Mozart\\TestProject\\": "src/", + "Mozart\\MultipleDirs\\": [ "packages/test/src/", "packages/more/src/" ] + } + }, + "extra": { + "mozart": { + "dep_namespace": "Mozart\\TestProject\\Dependencies", + "dep_directory": "/src/dependencies", + "classmap_directory": "/classes/", + "classmap_prefix": "MozartDependency_", + "packages": [ + "pimple/pimple" + ], + "excluded_packages": [ + ], + "override_autoload": { + }, + "delete_vendor_directories": true + } + } + } diff --git a/tests/Console/Commands/ComposeTest.php b/tests/Console/Commands/ComposeTest.php index ea283cfc..325ea3bc 100644 --- a/tests/Console/Commands/ComposeTest.php +++ b/tests/Console/Commands/ComposeTest.php @@ -39,7 +39,6 @@ public function setUp(): void #[Test] public function it_fails_gracefully_when_composer_json_absent(): void { - $inputInterfaceMock = $this->createMock(InputInterface::class); $outputInterfaceMock = $this->createMock(OutputInterface::class); @@ -66,7 +65,6 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) #[Test] public function it_handles_malformed_json_with_grace(): void { - $badComposerJson = '{ "name": "coenjacobs/mozart", }'; file_put_contents(__DIR__ . '/composer.json', $badComposerJson); @@ -97,7 +95,6 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) #[Test] public function it_handles_absent_extra_config_with_grace(): void { - $badComposerJson = '{ "name": "coenjacobs/mozart" }'; file_put_contents(__DIR__ . '/composer.json', $badComposerJson); @@ -129,7 +126,6 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) #[Test] public function it_handles_malformed_extra_config_with_grace(): void { - $badComposerJson = '{ "name": "coenjacobs/mozart", "extra": [] }'; file_put_contents(__DIR__ . '/composer.json', $badComposerJson); @@ -160,7 +156,6 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) #[Test] public function it_handles_absent_mozart_config_with_grace(): void { - $badComposerJson = '{ "name": "coenjacobs/mozart", "extra": { "moozart": {} } }'; file_put_contents(__DIR__ . '/composer.json', $badComposerJson); @@ -193,7 +188,6 @@ public function __construct($inputInterfaceMock, $outputInterfaceMock) #[Test] public function it_handles_malformed_mozart_config__with_grace(): void { - $badComposerJson = '{ "name": "coenjacobs/mozart", "extra": { "mozart": [] } }'; file_put_contents(__DIR__ . '/composer.json', $badComposerJson); diff --git a/tests/Integration/ExcludedPackagesTest.php b/tests/Integration/ExcludedPackagesTest.php new file mode 100644 index 00000000..6d022b85 --- /dev/null +++ b/tests/Integration/ExcludedPackagesTest.php @@ -0,0 +1,67 @@ +testsWorkingDir = __DIR__ . '/temptestdir'; + if (!file_exists($this->testsWorkingDir)) { + mkdir($this->testsWorkingDir); + } + } + + /** + * @test + */ + #[Test] + public function it_excludes_handling_specified_packages(): void + { + copy(__DIR__ . '/excluded-packages.json', $this->testsWorkingDir . '/composer.json'); + + chdir($this->testsWorkingDir); + + exec('composer update'); + + $inputInterfaceMock = $this->createMock(InputInterface::class); + $outputInterfaceMock = $this->createMock(OutputInterface::class); + + $mozartCompose = new Compose(); + + $result = $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock); + $this->assertEquals(0, $result); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . '/vendor/pimple/pimple'); + $this->assertDirectoryExists($this->testsWorkingDir . '/vendor/psr/container'); + } + + public function tearDown(): void + { + parent::tearDown(); + + $dir = $this->testsWorkingDir; + + $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS); + $files = new RecursiveIteratorIterator( + $it, + RecursiveIteratorIterator::CHILD_FIRST + ); + foreach ($files as $file) { + if ($file->isDir()) { + rmdir($file->getRealPath()); + } else { + unlink($file->getRealPath()); + } + } + rmdir($dir); + chdir(__DIR__); + } +} diff --git a/tests/Integration/excluded-packages.json b/tests/Integration/excluded-packages.json new file mode 100644 index 00000000..f0165703 --- /dev/null +++ b/tests/Integration/excluded-packages.json @@ -0,0 +1,26 @@ +{ + "require": { + "pimple/pimple": "^3.5" + }, + "autoload": { + "psr-4": { + "Mozart\\TestProject\\": "src/" + } + }, + "extra": { + "mozart": { + "dep_namespace": "Mozart\\TestProject\\Dependencies", + "dep_directory": "/src/dependencies", + "classmap_directory": "/classes/", + "classmap_prefix": "MozartDependency_", + "packages": [ + "pimple/pimple" + ], + "excluded_packages": [ + "psr/container" + ], + "override_autoload": {}, + "delete_vendor_directories": true + } + } +} diff --git a/tests/MoverTest.php b/tests/MoverTest.php index b0f4a00f..1d712993 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -1,7 +1,7 @@ extra->mozart settings * - * @var Config + * @var Mozart */ protected $config; @@ -55,7 +54,7 @@ public function setUp(): void ), ); - $this->config = new Config( $configArgs ); + $this->config = Mozart::loadFromString( json_encode($configArgs) ); } /** @@ -135,8 +134,12 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $testDummyComposerContents = json_encode(new stdClass()); file_put_contents($testDummyComposerPath, $testDummyComposerContents); - $parsedPackage = new Package($testDummyComposerDir, $this->config, $this->config->get('override_autoload')[$packageString]); - $parsedPackage->findAutoloaders(); + + $overrideAutoload = $this->config->get('override_autoload'); + if ( ! empty( $overrideAutoload ) ) { + $overrideAutoload = $overrideAutoload->getByKey( $packageString ); + } + $parsedPackage = new Package($testDummyComposerDir, null, $overrideAutoload ); $packages[] = $parsedPackage; } diff --git a/tests/replacers/NamespaceReplacerTest.php b/tests/replacers/NamespaceReplacerTest.php index f5856ede..7694c44d 100644 --- a/tests/replacers/NamespaceReplacerTest.php +++ b/tests/replacers/NamespaceReplacerTest.php @@ -1,7 +1,7 @@ Date: Fri, 6 Sep 2024 15:28:45 +0200 Subject: [PATCH 12/27] Coding standards fixes --- src/Composer/Autoload/Autoloader.php | 7 +++++-- src/Composer/Autoload/NamespaceAutoloader.php | 14 ++++---------- src/Composer/Package.php | 6 ++++++ src/Config/Autoload.php | 4 ++++ src/Config/Classmap.php | 12 +++++------- src/Config/Composer.php | 6 ++++-- src/Config/Extra.php | 4 +--- src/Config/Mozart.php | 11 ++++++++--- src/Config/Psr4.php | 10 ++-------- src/Console/Commands/Compose.php | 19 ++++++++++++------- 10 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/Composer/Autoload/Autoloader.php b/src/Composer/Autoload/Autoloader.php index 9aa6b218..15f190a9 100644 --- a/src/Composer/Autoload/Autoloader.php +++ b/src/Composer/Autoload/Autoloader.php @@ -4,6 +4,9 @@ interface Autoloader { - public function processConfig($autoloadConfig); - public function getSearchNamespace(); + /** + * @param mixed $autoloadConfig + */ + public function processConfig($autoloadConfig): void; + public function getSearchNamespace(): string; } diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 8725998f..3e66694b 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -12,7 +12,7 @@ abstract class NamespaceAutoloader implements Autoloader * * e.g. src/ * - * @var string[] + * @var array */ public $paths = []; @@ -23,7 +23,7 @@ abstract class NamespaceAutoloader implements Autoloader * * @return void */ - public function processConfig($autoloadConfig) + public function processConfig($autoloadConfig): void { if (is_array($autoloadConfig)) { foreach ($autoloadConfig as $path) { @@ -34,18 +34,12 @@ public function processConfig($autoloadConfig) } } - /** - * @return string - */ - public function getSearchNamespace() + public function getSearchNamespace(): string { return $this->namespace; } - /** - * @return string - */ - public function getNamespacePath() + public function getNamespacePath(): string { return ''; } diff --git a/src/Composer/Package.php b/src/Composer/Package.php index d725a596..a23ea8da 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -60,6 +60,9 @@ public function getAutoloaders(): array return $this->config->autoload->getAutoloaders(); } + /** + * @return array + */ public function getDependencies(): array { return $this->requirePackages; @@ -70,6 +73,9 @@ public function registerRequirePackage(Package $package): void array_push($this->requirePackages, $package); } + /** + * @param array $packages + */ public function registerRequirePackages(array $packages): void { foreach ($packages as $package) { diff --git a/src/Config/Autoload.php b/src/Config/Autoload.php index 89bcc79f..55fd1aae 100644 --- a/src/Config/Autoload.php +++ b/src/Config/Autoload.php @@ -7,6 +7,7 @@ class Autoload { + /** @var array */ public array $autoloaders = []; public function setupAutoloaders(stdClass $autoloadData): void @@ -42,6 +43,9 @@ public function setupAutoloaders(stdClass $autoloadData): void $this->setAutoloaders($autoloaders); } + /** + * @param array $autoloaders + */ public function setAutoloaders(array $autoloaders): void { foreach ($autoloaders as $autoloader) { diff --git a/src/Config/Classmap.php b/src/Config/Classmap.php index 013cf097..f6c1ab04 100644 --- a/src/Config/Classmap.php +++ b/src/Config/Classmap.php @@ -6,16 +6,16 @@ class Classmap implements Autoloader { - /** @var array */ + /** @var string[] */ public $files = []; - /** @var array */ + /** @var string[] */ public $paths = []; /** - * @return void + * @inheritdoc */ - public function processConfig($autoloadConfig) + public function processConfig($autoloadConfig): void { foreach ($autoloadConfig as $value) { if ('.php' == substr($value, -4, 4)) { @@ -28,10 +28,8 @@ public function processConfig($autoloadConfig) /** * @throws \Exception - * - * @return void */ - public function getSearchNamespace() + public function getSearchNamespace(): string { throw new \Exception('Classmap autoloaders do not contain a namespace and this method can not be used.'); } diff --git a/src/Config/Composer.php b/src/Config/Composer.php index 4c5332ef..fd9e9843 100644 --- a/src/Config/Composer.php +++ b/src/Config/Composer.php @@ -9,12 +9,14 @@ class Composer use ReadsConfig, ConfigAccessor; public string $name; - public array $require = []; + + /** @var string[] */ + public array $require; public ?Autoload $autoload = null; public ?Extra $extra = null; - public function setAutoload(stdClass $data) + public function setAutoload(stdClass $data): void { $autoload = new Autoload(); $autoload->setupAutoloaders($data); diff --git a/src/Config/Extra.php b/src/Config/Extra.php index 497f7161..327482b3 100644 --- a/src/Config/Extra.php +++ b/src/Config/Extra.php @@ -2,13 +2,11 @@ namespace CoenJacobs\Mozart\Config; -use stdClass; - class Extra { public ?Mozart $mozart = null; - public function getMozart() + public function getMozart(): ?Mozart { return $this->mozart; } diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index fd83964a..ffea03c9 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -18,18 +18,23 @@ class Mozart /** @var string[] */ public array $packages = []; - /** @var string[]> */ + /** @var string[] */ public array $excluded_packages = []; public OverrideAutoload $override_autoload; - public bool $delete_vendor_directories; + /** + * @param string[] $packages + */ public function setPackages(array $packages): void { $this->packages = $packages; } + /** + * @param string[] $excluded_packages + */ public function setExcludedPackages(array $excluded_packages): void { $this->excluded_packages = $excluded_packages; @@ -53,7 +58,7 @@ public function isValidMozartConfig(): bool return true; } - public function isExcludedPackage(Package $package) + public function isExcludedPackage(Package $package): bool { return in_array($package->getName(), $this->excluded_packages); } diff --git a/src/Config/Psr4.php b/src/Config/Psr4.php index 33f0ed0d..f09c1ef9 100644 --- a/src/Config/Psr4.php +++ b/src/Config/Psr4.php @@ -6,18 +6,12 @@ class Psr4 extends NamespaceAutoloader { - /** - * @return string - */ - public function getSearchNamespace() + public function getSearchNamespace(): string { return trim($this->namespace, '\\'); } - /** - * @return string - */ - public function getNamespacePath() + public function getNamespacePath(): string { return str_replace('\\', DIRECTORY_SEPARATOR, $this->namespace); } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index fcde5f1f..5bbd054c 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -54,21 +54,26 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 1; } - // var_dump($composerConfig); die(); + if (! $composerConfig->isValidMozartConfig() || empty($composerConfig->getExtra())) { + $output->write('Mozart config not readable in composer.json at extra->mozart'); + return 1; + } + + $mozartConfig = $composerConfig->getExtra()->getMozart(); - if (! $composerConfig->isValidMozartConfig()) { + if (empty($mozartConfig)) { $output->write('Mozart config not readable in composer.json at extra->mozart'); return 1; } - $this->config = $composerConfig->getExtra()->getMozart(); + $this->config = $mozartConfig; $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", $this->config->get('dep_namespace')."\\")); $require = array(); if (is_array($this->config->get('packages'))) { $require = $this->config->get('packages'); - } elseif (isset($composer->require) && is_object($composer->require)) { - $require = array_keys(get_object_vars($composer->require)); + } else { + $require = $composerConfig->require; } $packagesByName = $this->findPackages($require); @@ -132,7 +137,7 @@ protected function replacePackages($packages): void public function movePackage(Package $package): void { if (! empty($package->dependencies)) { - foreach ($package->dependencies as $dependency) { + foreach ($package->getDependencies() as $dependency) { $this->movePackage($dependency); } } @@ -148,7 +153,7 @@ public function movePackage(Package $package): void public function replacePackage(Package $package): void { if (! empty($package->dependencies)) { - foreach ($package->dependencies as $dependency) { + foreach ($package->getDependencies() as $dependency) { $this->replacePackage($dependency); } } From 3c3b120fe7c3b6c5a5b872937ab1b743848597a2 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Fri, 6 Sep 2024 15:44:53 +0200 Subject: [PATCH 13/27] Fixed generic ArrayObject types setting --- src/Config/OverrideAutoload.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Config/OverrideAutoload.php b/src/Config/OverrideAutoload.php index 10a95b6c..42967cb5 100644 --- a/src/Config/OverrideAutoload.php +++ b/src/Config/OverrideAutoload.php @@ -5,6 +5,9 @@ use ArrayObject; use stdClass; +/** + * @extends ArrayObject + */ class OverrideAutoload extends ArrayObject { public function __construct(stdClass $objects) From 59f1f69f6785a60b62b9b0c7aa3780fadf86b4e9 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 7 Sep 2024 14:33:08 +0200 Subject: [PATCH 14/27] Fixed missing trailing directory separator on dependency directory --- src/Config/Mozart.php | 9 +++++++++ src/Mover.php | 12 ++++++------ src/Replacer.php | 4 ++-- tests/Integration/ExcludedPackagesTest.php | 5 ++++- tests/MoverTest.php | 16 ++++++++-------- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index ffea03c9..3a3e89b6 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -62,4 +62,13 @@ public function isExcludedPackage(Package $package): bool { return in_array($package->getName(), $this->excluded_packages); } + + /** + * Returns the configured dependency directory, with an appended directory + * separator, if one isn't at the end of the configured string yet. + */ + public function getDepDirectory(): string + { + return rtrim($this->dep_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + } } diff --git a/src/Mover.php b/src/Mover.php index aff37d7b..e5ba71c5 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -35,7 +35,7 @@ public function __construct(string $workingDir, Mozart $config) { $this->config = $config; $this->workingDir = $workingDir; - $this->targetDir = $this->config->get('dep_directory'); + $this->targetDir = $this->config->getDepDirectory(); $adapter = new LocalFilesystemAdapter( $this->workingDir @@ -54,7 +54,7 @@ public function __construct(string $workingDir, Mozart $config) */ public function deleteTargetDirs($packages): void { - $this->filesystem->createDirectory($this->config->get('dep_directory')); + $this->filesystem->createDirectory($this->config->getDepDirectory()); $this->filesystem->createDirectory($this->config->get('classmap_directory')); foreach ($packages as $package) { @@ -75,7 +75,7 @@ private function deleteDepTargetDirs(Package $package): void switch ($autoloaderType) { case Psr0::class: case Psr4::class: - $outputDir = $this->config->get('dep_directory') . $packageAutoloader->namespace; + $outputDir = $this->config->getDepDirectory() . $packageAutoloader->namespace; $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); $this->filesystem->deleteDirectory($outputDir); break; @@ -94,8 +94,8 @@ private function deleteDepTargetDirs(Package $package): void public function deleteEmptyDirs(): void { - if (count($this->filesystem->listContents($this->config->get('dep_directory'), true)->toArray()) === 0) { - $this->filesystem->deleteDirectory($this->config->get('dep_directory')); + if (count($this->filesystem->listContents($this->config->getDepDirectory(), true)->toArray()) === 0) { + $this->filesystem->deleteDirectory($this->config->getDepDirectory()); } if (count($this->filesystem->listContents($this->config->get('classmap_directory'), true)->toArray()) === 0) { @@ -184,7 +184,7 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') { if ($autoloader instanceof NamespaceAutoloader) { $namespacePath = $autoloader->getNamespacePath(); - $replaceWith = $this->config->get('dep_directory') . $namespacePath; + $replaceWith = $this->config->getDepDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->config->get('name') diff --git a/src/Replacer.php b/src/Replacer.php index 8f248257..44b4d866 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -35,7 +35,7 @@ public function __construct(string $workingDir, Mozart $config) { $this->config = $config; $this->workingDir = $workingDir; - $this->targetDir = $this->config->get('dep_directory'); + $this->targetDir = $this->config->getDepDirectory(); $adapter = new LocalFilesystemAdapter( $this->workingDir @@ -208,7 +208,7 @@ public function replaceParentPackage(Package $package, Package $parent): void foreach ($package->getAutoloaders() as $autoloader) { if ($parentAutoloader instanceof NamespaceAutoloader) { $namespace = str_replace('\\', DIRECTORY_SEPARATOR, $parentAutoloader->namespace); - $directory = $this->workingDir . $this->config->get('dep_directory') . $namespace + $directory = $this->workingDir . $this->config->getDepDirectory() . $namespace . DIRECTORY_SEPARATOR; if ($autoloader instanceof NamespaceAutoloader) { diff --git a/tests/Integration/ExcludedPackagesTest.php b/tests/Integration/ExcludedPackagesTest.php index 6d022b85..d2a09d49 100644 --- a/tests/Integration/ExcludedPackagesTest.php +++ b/tests/Integration/ExcludedPackagesTest.php @@ -24,7 +24,7 @@ public function setUp(): void * @test */ #[Test] - public function it_excludes_handling_specified_packages(): void + public function it_excludes_moving_specified_packages(): void { copy(__DIR__ . '/excluded-packages.json', $this->testsWorkingDir . '/composer.json'); @@ -40,7 +40,10 @@ public function it_excludes_handling_specified_packages(): void $result = $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock); $this->assertEquals(0, $result); $this->assertDirectoryDoesNotExist($this->testsWorkingDir . '/vendor/pimple/pimple'); + $this->assertDirectoryExists($this->testsWorkingDir . '/src/dependencies/Pimple'); + $this->assertDirectoryExists($this->testsWorkingDir . '/vendor/psr/container'); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . '/src/dependencies/Psr'); } public function tearDown(): void diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 1d712993..651ddc53 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -72,7 +72,7 @@ public function it_creates_absent_dirs(): void $mover->deleteTargetDirs($packages); $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR - . $this->config->get('dep_directory'))); + . $this->config->getDepDirectory())); $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory'))); } @@ -87,14 +87,14 @@ public function it_is_unpertrubed_by_existing_dirs(): void { $mover = new Mover($this->testsWorkingDir, $this->config); - if (!file_exists($this->testsWorkingDir . $this->config->get('dep_directory'))) { - mkdir($this->testsWorkingDir . $this->config->get('dep_directory')); + if (!file_exists($this->testsWorkingDir . $this->config->getDepDirectory())) { + mkdir($this->testsWorkingDir . $this->config->getDepDirectory()); } if (!file_exists($this->testsWorkingDir . $this->config->get('classmap_directory'))) { mkdir($this->testsWorkingDir . $this->config->get('classmap_directory')); } - $this->assertDirectoryExists($this->testsWorkingDir . $this->config->get('dep_directory')); + $this->assertDirectoryExists($this->testsWorkingDir . $this->config->getDepDirectory()); $this->assertDirectoryExists($this->testsWorkingDir . $this->config->get('classmap_directory')); $packages = array(); @@ -119,10 +119,10 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void { $mover = new Mover($this->testsWorkingDir, $this->config); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('dep_directory')); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory()); mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory')); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('dep_directory') . 'Pimple'); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory() . 'Pimple'); mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory') . 'ezyang'); $packages = array(); @@ -145,8 +145,8 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $mover->deleteTargetDirs($packages); - $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->get('dep_directory') . 'Pimple'); - $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->get('dep_directory') . 'ezyang'); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->getDepDirectory() . 'Pimple'); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->getDepDirectory() . 'ezyang'); } /** From 87ac2634b3fe625684b695fca3d3218429940a17 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 7 Sep 2024 14:58:58 +0200 Subject: [PATCH 15/27] Test to verify excluded package classes aren't rewritten in included packages --- tests/Integration/ExcludedPackagesTest.php | 39 ++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/tests/Integration/ExcludedPackagesTest.php b/tests/Integration/ExcludedPackagesTest.php index d2a09d49..646f5dba 100644 --- a/tests/Integration/ExcludedPackagesTest.php +++ b/tests/Integration/ExcludedPackagesTest.php @@ -21,6 +21,13 @@ public function setUp(): void } /** + * Verifies that the explicitely excluded packages from the Mozart config + * are _not_ being moved to the provided dependency directory and the files + * will stay present in the vendor directory. At the same time, the other + * package is being moved to the dependency directory and after that the + * originating directory in the vendor directory is deleted (as the + * `delete_vendor_directories` parameter is set to `true`). + * * @test */ #[Test] @@ -39,6 +46,7 @@ public function it_excludes_moving_specified_packages(): void $result = $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock); $this->assertEquals(0, $result); + $this->assertDirectoryDoesNotExist($this->testsWorkingDir . '/vendor/pimple/pimple'); $this->assertDirectoryExists($this->testsWorkingDir . '/src/dependencies/Pimple'); @@ -46,6 +54,37 @@ public function it_excludes_moving_specified_packages(): void $this->assertDirectoryDoesNotExist($this->testsWorkingDir . '/src/dependencies/Psr'); } + /** + * Verifies that the excluded package `psr/container` is _not_ having its + * classes replaced in the implementing `pimple/pimple` package when the + * former is explicitely excluded and the latter is added to the list of + * packages for Mozart to rewrite. + * + * @test + */ + #[Test] + public function it_excludes_replacing_classes_from_specified_packages(): void + { + copy(__DIR__ . '/excluded-packages.json', $this->testsWorkingDir . '/composer.json'); + + chdir($this->testsWorkingDir); + + exec('composer update'); + + $inputInterfaceMock = $this->createMock(InputInterface::class); + $outputInterfaceMock = $this->createMock(OutputInterface::class); + + $mozartCompose = new Compose(); + + $result = $mozartCompose->run($inputInterfaceMock, $outputInterfaceMock); + $this->assertEquals(0, $result); + + $testFile = file_get_contents($this->testsWorkingDir . '/src/dependencies/Pimple/Psr11/Container.php'); + $this->assertStringContainsString('namespace Mozart\TestProject\Dependencies\Pimple\Psr11;', $testFile); + $this->assertStringContainsString('use Mozart\TestProject\Dependencies\Pimple\Container as PimpleContainer;', $testFile); + $this->assertStringContainsString('use Psr\Container\ContainerInterface;', $testFile); + } + public function tearDown(): void { parent::tearDown(); From e34a1705492b7005495f591bb65d9faf7304ba1a Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sat, 7 Sep 2024 15:28:13 +0200 Subject: [PATCH 16/27] Method to always suffix trailing directory separator after classmap path --- src/Config/Mozart.php | 5 +++++ src/Console/Commands/Compose.php | 2 +- src/Mover.php | 10 +++++----- src/Replacer.php | 5 ++--- tests/MoverTest.php | 12 ++++++------ 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 3a3e89b6..994f3736 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -71,4 +71,9 @@ public function getDepDirectory(): string { return rtrim($this->dep_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } + + public function getClassmapDirectory(): string + { + return rtrim($this->classmap_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; + } } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 5bbd054c..7f565b46 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -94,7 +94,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->movePackages($packages); $this->replacePackages($packages); $this->replaceParentInTree($packages); - $this->replacer->replaceParentClassesInDirectory($this->config->get('classmap_directory')); + $this->replacer->replaceParentClassesInDirectory($this->config->getClassmapDirectory()); return 0; } diff --git a/src/Mover.php b/src/Mover.php index e5ba71c5..80d62493 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -55,7 +55,7 @@ public function __construct(string $workingDir, Mozart $config) public function deleteTargetDirs($packages): void { $this->filesystem->createDirectory($this->config->getDepDirectory()); - $this->filesystem->createDirectory($this->config->get('classmap_directory')); + $this->filesystem->createDirectory($this->config->getClassmapDirectory()); foreach ($packages as $package) { $this->deleteDepTargetDirs($package); @@ -80,7 +80,7 @@ private function deleteDepTargetDirs(Package $package): void $this->filesystem->deleteDirectory($outputDir); break; case Classmap::class: - $outputDir = $this->config->get('classmap_directory') . $package->config->get('name'); + $outputDir = $this->config->getClassmapDirectory() . $package->config->get('name'); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); $this->filesystem->deleteDirectory($outputDir); break; @@ -98,8 +98,8 @@ public function deleteEmptyDirs(): void $this->filesystem->deleteDirectory($this->config->getDepDirectory()); } - if (count($this->filesystem->listContents($this->config->get('classmap_directory'), true)->toArray()) === 0) { - $this->filesystem->deleteDirectory($this->config->get('classmap_directory')); + if (count($this->filesystem->listContents($this->config->getClassmapDirectory(), true)->toArray()) === 0) { + $this->filesystem->deleteDirectory($this->config->getClassmapDirectory()); } } @@ -193,7 +193,7 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') $targetFile = str_replace($packageVendorPath, '', $targetFile); } else { $namespacePath = $package->config->get('name'); - $replaceWith = $this->config->get('classmap_directory') . DIRECTORY_SEPARATOR . $namespacePath; + $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->config->get('name') diff --git a/src/Replacer.php b/src/Replacer.php index 44b4d866..71686326 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -104,8 +104,7 @@ public function replacePackageByAutoloader(Package $package, Composer\Autoload\A $this->replaceInDirectory($autoloader, $source_path); } elseif ($autoloader instanceof Classmap) { $finder = new Finder(); - $source_path = $this->workingDir . $this->config->get('classmap_directory') . DIRECTORY_SEPARATOR - . $package->config->get('name'); + $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->config->get('name'); $finder->files()->in($source_path); foreach ($finder as $foundFile) { @@ -219,7 +218,7 @@ public function replaceParentPackage(Package $package, Package $parent): void } } else { $directory = $this->workingDir . - $this->config->get('classmap_directory') . $parent->config->get('name'); + $this->config->getClassmapDirectory() . $parent->config->get('name'); if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 651ddc53..6e569683 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -74,7 +74,7 @@ public function it_creates_absent_dirs(): void $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory())); $this->assertTrue(file_exists($this->testsWorkingDir . DIRECTORY_SEPARATOR - . $this->config->get('classmap_directory'))); + . $this->config->getClassmapDirectory())); } /** @@ -90,12 +90,12 @@ public function it_is_unpertrubed_by_existing_dirs(): void if (!file_exists($this->testsWorkingDir . $this->config->getDepDirectory())) { mkdir($this->testsWorkingDir . $this->config->getDepDirectory()); } - if (!file_exists($this->testsWorkingDir . $this->config->get('classmap_directory'))) { - mkdir($this->testsWorkingDir . $this->config->get('classmap_directory')); + if (!file_exists($this->testsWorkingDir . $this->config->getClassmapDirectory())) { + mkdir($this->testsWorkingDir . $this->config->getClassmapDirectory()); } $this->assertDirectoryExists($this->testsWorkingDir . $this->config->getDepDirectory()); - $this->assertDirectoryExists($this->testsWorkingDir . $this->config->get('classmap_directory')); + $this->assertDirectoryExists($this->testsWorkingDir . $this->config->getClassmapDirectory()); $packages = array(); @@ -120,10 +120,10 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void $mover = new Mover($this->testsWorkingDir, $this->config); mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory()); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory')); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getClassmapDirectory()); mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory() . 'Pimple'); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->get('classmap_directory') . 'ezyang'); + mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getClassmapDirectory() . 'ezyang'); $packages = array(); foreach ($this->config->get('packages') as $packageString) { From cb12e0454f49d7e3d715f8b5d475af3549a67952 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Sun, 8 Sep 2024 14:05:05 +0200 Subject: [PATCH 17/27] Merge main Composer config and Package file into one --- src/Composer/Package.php | 62 ++++++++++++++++++++++--------- src/Config/Composer.php | 43 --------------------- src/Config/PackageFactory.php | 20 ++++++++++ src/Console/Commands/Compose.php | 32 +++++++--------- src/Mover.php | 20 +++++----- src/Replacer.php | 8 ++-- tests/Config/ConfigMapperTest.php | 11 +++--- tests/MoverTest.php | 7 ++-- 8 files changed, 101 insertions(+), 102 deletions(-) delete mode 100644 src/Config/Composer.php create mode 100644 src/Config/PackageFactory.php diff --git a/src/Composer/Package.php b/src/Composer/Package.php index a23ea8da..096d98dc 100644 --- a/src/Composer/Package.php +++ b/src/Composer/Package.php @@ -4,20 +4,29 @@ use CoenJacobs\Mozart\Composer\Autoload\Autoloader; use CoenJacobs\Mozart\Config\Autoload; -use CoenJacobs\Mozart\Config\Composer; +use CoenJacobs\Mozart\Config\ConfigAccessor; +use CoenJacobs\Mozart\Config\Extra; +use CoenJacobs\Mozart\Config\ReadsConfig; use stdClass; class Package { + use ReadsConfig, ConfigAccessor; + /** @var string */ public $path = ''; - /** @var Composer */ - public $config; - /** @var Package[] */ public $requirePackages = []; + public string $name; + + /** @var string[] */ + public array $require; + + public ?Autoload $autoload = null; + public ?Extra $extra = null; + /** * Create a PHP object to represent a composer package. * @@ -26,26 +35,45 @@ class Package * @param stdClass $overrideAutoload Optional configuration to replace the package's own autoload definition with * another which Mozart can use. */ - public function __construct($path, Composer $config = null, $overrideAutoload = null) + public function __construct($path, $overrideAutoload = null) { $this->path = $path; - if (empty($config)) { - $config = Composer::loadFromFile($this->path . '/composer.json'); - } - - $this->config = $config; - if (isset($overrideAutoload)) { $autoload = new Autoload(); $autoload->setupAutoloaders($overrideAutoload); - $this->config->set('autoload', $autoload); + $this->set('autoload', $autoload); } } + public function setAutoload(stdClass $data): void + { + $autoload = new Autoload(); + $autoload->setupAutoloaders($data); + $this->autoload = $autoload; + } + + public function getExtra(): ?Extra + { + return $this->extra; + } + + public function isValidMozartConfig(): bool + { + if (empty($this->getExtra())) { + return false; + } + + if (empty($this->getExtra()->getMozart())) { + return false; + } + + return $this->getExtra()->getMozart()->isValidMozartConfig(); + } + public function getName(): string { - return $this->config->name; + return $this->name; } /** @@ -53,15 +81,15 @@ public function getName(): string */ public function getAutoloaders(): array { - if (empty($this->config->autoload)) { + if (empty($this->autoload)) { return array(); } - return $this->config->autoload->getAutoloaders(); + return $this->autoload->getAutoloaders(); } /** - * @return array + * @return Package[] */ public function getDependencies(): array { @@ -74,7 +102,7 @@ public function registerRequirePackage(Package $package): void } /** - * @param array $packages + * @param Package[] $packages */ public function registerRequirePackages(array $packages): void { diff --git a/src/Config/Composer.php b/src/Config/Composer.php deleted file mode 100644 index fd9e9843..00000000 --- a/src/Config/Composer.php +++ /dev/null @@ -1,43 +0,0 @@ -setupAutoloaders($data); - $this->autoload = $autoload; - } - - public function getExtra(): ?Extra - { - return $this->extra; - } - - public function isValidMozartConfig(): bool - { - if (empty($this->getExtra())) { - return false; - } - - if (empty($this->getExtra()->getMozart())) { - return false; - } - - return $this->getExtra()->getMozart()->isValidMozartConfig(); - } -} diff --git a/src/Config/PackageFactory.php b/src/Config/PackageFactory.php new file mode 100644 index 00000000..b6cb9f79 --- /dev/null +++ b/src/Config/PackageFactory.php @@ -0,0 +1,20 @@ +setAutoload($overrideAutoload); + } + + return $package; + } +} diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 7f565b46..d6f8e6c1 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -5,6 +5,7 @@ use CoenJacobs\Mozart\Config\Mozart; use CoenJacobs\Mozart\Config\Composer; use CoenJacobs\Mozart\Composer\Package; +use CoenJacobs\Mozart\Config\PackageFactory; use CoenJacobs\Mozart\Mover; use CoenJacobs\Mozart\Replacer; use Exception; @@ -48,32 +49,32 @@ protected function execute(InputInterface $input, OutputInterface $output): int $composerFile = $workingDir . DIRECTORY_SEPARATOR. 'composer.json'; try { - $composerConfig = Composer::loadFromFile($composerFile); + $package = PackageFactory::createPackage($composerFile); } catch (Exception $e) { $output->write('Unable to read the composer.json file'); return 1; } - if (! $composerConfig->isValidMozartConfig() || empty($composerConfig->getExtra())) { + if (! $package->isValidMozartConfig() || empty($package->getExtra())) { $output->write('Mozart config not readable in composer.json at extra->mozart'); return 1; } - $mozartConfig = $composerConfig->getExtra()->getMozart(); + $config = $package->getExtra()->getMozart(); - if (empty($mozartConfig)) { + if (empty($config)) { $output->write('Mozart config not readable in composer.json at extra->mozart'); return 1; } - $this->config = $mozartConfig; + $this->config = $config; $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", $this->config->get('dep_namespace')."\\")); $require = array(); if (is_array($this->config->get('packages'))) { $require = $this->config->get('packages'); } else { - $require = $composerConfig->require; + $require = $package->require; } $packagesByName = $this->findPackages($require); @@ -100,9 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } /** - * @param $workingDir - * @param $config - * @param array $packages + * @param Package[] $packages * * @return void */ @@ -116,9 +115,7 @@ protected function movePackages($packages): void } /** - * @param $workingDir - * @param $config - * @param array $packages + * @param Package[] $packages * * @return void */ @@ -187,7 +184,7 @@ private function findPackages(array $slugs): array $autoloaders = $override_autoload->$package_slug; } - $package = new Package($packageDir, null, $autoloaders); + $package = PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders); if ($this->config->isExcludedPackage($package)) { continue; @@ -204,8 +201,8 @@ private function findPackages(array $slugs): array /** * Get an array containing all the dependencies and dependencies - * @param Package $package - * @param array $dependencies + * @param Package $package + * @param Package[] $dependencies * @return array */ private function getAllDependenciesOfPackage(Package $package, $dependencies = []): array @@ -219,7 +216,6 @@ private function getAllDependenciesOfPackage(Package $package, $dependencies = [ return $dependencies; } - /** @var Package $dependency */ foreach ($package->getDependencies() as $dependency) { $dependencies[] = $dependency; } @@ -232,15 +228,13 @@ private function getAllDependenciesOfPackage(Package $package, $dependencies = [ } /** - * @param array $packages + * @param Package[] $packages */ private function replaceParentInTree(array $packages): void { - /** @var Package $package */ foreach ($packages as $package) { $dependencies = $this->getAllDependenciesOfPackage($package); - /** @var Package $dependency */ foreach ($dependencies as $dependency) { $this->replacer->replaceParentPackage($dependency, $package); } diff --git a/src/Mover.php b/src/Mover.php index 80d62493..4787bad8 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -80,7 +80,7 @@ private function deleteDepTargetDirs(Package $package): void $this->filesystem->deleteDirectory($outputDir); break; case Classmap::class: - $outputDir = $this->config->getClassmapDirectory() . $package->config->get('name'); + $outputDir = $this->config->getClassmapDirectory() . $package->get('name'); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); $this->filesystem->deleteDirectory($outputDir); break; @@ -108,7 +108,7 @@ public function deleteEmptyDirs(): void */ public function movePackage(Package $package) { - if (in_array($package->config->get('name'), $this->movedPackages)) { + if (in_array($package->get('name'), $this->movedPackages)) { return; } @@ -118,7 +118,7 @@ public function movePackage(Package $package) foreach ($autoloader->paths as $path) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR - . $package->config->get('name') . DIRECTORY_SEPARATOR . $path; + . $package->get('name') . DIRECTORY_SEPARATOR . $path; $source_path = str_replace('/', DIRECTORY_SEPARATOR, $source_path); @@ -135,7 +135,7 @@ public function movePackage(Package $package) foreach ($autoloader->files as $file) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->config->get('name'); + . DIRECTORY_SEPARATOR . $package->get('name'); $finder->files()->name($file)->in($source_path); foreach ($finder as $foundFile) { @@ -148,7 +148,7 @@ public function movePackage(Package $package) foreach ($autoloader->paths as $path) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->config->get('name') . DIRECTORY_SEPARATOR . $path; + . DIRECTORY_SEPARATOR . $package->get('name') . DIRECTORY_SEPARATOR . $path; $finder->files()->in($source_path); @@ -163,8 +163,8 @@ public function movePackage(Package $package) } } - if (!in_array($package->config->get('name'), $this->movedPackages)) { - $this->movedPackages[] = $package->config->get('name'); + if (!in_array($package->get('name'), $this->movedPackages)) { + $this->movedPackages[] = $package->get('name'); } } @@ -187,16 +187,16 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') $replaceWith = $this->config->getDepDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->config->get('name') + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->get('name') . DIRECTORY_SEPARATOR . $path; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, '', $targetFile); } else { - $namespacePath = $package->config->get('name'); + $namespacePath = $package->get('name'); $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->config->get('name') + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->get('name') . DIRECTORY_SEPARATOR; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); diff --git a/src/Replacer.php b/src/Replacer.php index 71686326..85b6ad22 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -33,9 +33,9 @@ class Replacer public function __construct(string $workingDir, Mozart $config) { - $this->config = $config; $this->workingDir = $workingDir; - $this->targetDir = $this->config->getDepDirectory(); + $this->config = $config; + $this->targetDir = $this->config->getDepDirectory(); $adapter = new LocalFilesystemAdapter( $this->workingDir @@ -104,7 +104,7 @@ public function replacePackageByAutoloader(Package $package, Composer\Autoload\A $this->replaceInDirectory($autoloader, $source_path); } elseif ($autoloader instanceof Classmap) { $finder = new Finder(); - $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->config->get('name'); + $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->get('name'); $finder->files()->in($source_path); foreach ($finder as $foundFile) { @@ -218,7 +218,7 @@ public function replaceParentPackage(Package $package, Package $parent): void } } else { $directory = $this->workingDir . - $this->config->getClassmapDirectory() . $parent->config->get('name'); + $this->config->getClassmapDirectory() . $parent->get('name'); if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); diff --git a/tests/Config/ConfigMapperTest.php b/tests/Config/ConfigMapperTest.php index e548135e..c60c9cb6 100644 --- a/tests/Config/ConfigMapperTest.php +++ b/tests/Config/ConfigMapperTest.php @@ -2,8 +2,9 @@ declare(strict_types=1); -use CoenJacobs\Mozart\Config\Composer; +use CoenJacobs\Mozart\Composer\Package; use CoenJacobs\Mozart\Config\Mozart; +use CoenJacobs\Mozart\Config\PackageFactory; use PHPUnit\Framework\TestCase; class ConfigMapperTest extends TestCase @@ -14,9 +15,9 @@ class ConfigMapperTest extends TestCase #[Test] public function it_creates_a_valid_config_object_based_on_composer_file() { - $config = Composer::loadFromFile(__DIR__ . '/config-mapper-test.json'); - $this->assertInstanceOf(Composer::class, $config); - $this->assertInstanceOf(Mozart::class, $config->getExtra()->getMozart()); - $this->assertCount(4, $config->autoload->getAutoloaders()); + $package = PackageFactory::createPackage(__DIR__ . '/config-mapper-test.json'); + $this->assertInstanceOf(Package::class, $package); + $this->assertInstanceOf(Mozart::class, $package->getExtra()->getMozart()); + $this->assertCount(4, $package->autoload->getAutoloaders()); } } diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 6e569683..2cb6a276 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); use CoenJacobs\Mozart\Config\Mozart; -use CoenJacobs\Mozart\Composer\Package; +use CoenJacobs\Mozart\Config\PackageFactory; use CoenJacobs\Mozart\Console\Commands\Compose; use CoenJacobs\Mozart\Mover; use PHPUnit\Framework\TestCase; @@ -117,8 +117,6 @@ public function it_is_unpertrubed_by_existing_dirs(): void #[Test] public function it_deletes_subdirs_for_packages_about_to_be_moved(): void { - $mover = new Mover($this->testsWorkingDir, $this->config); - mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getDepDirectory()); mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getClassmapDirectory()); @@ -139,10 +137,11 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void if ( ! empty( $overrideAutoload ) ) { $overrideAutoload = $overrideAutoload->getByKey( $packageString ); } - $parsedPackage = new Package($testDummyComposerDir, null, $overrideAutoload ); + $parsedPackage = PackageFactory::createPackage($testDummyComposerPath, $overrideAutoload); $packages[] = $parsedPackage; } + $mover = new Mover($this->testsWorkingDir, $this->config); $mover->deleteTargetDirs($packages); $this->assertDirectoryDoesNotExist($this->testsWorkingDir . $this->config->getDepDirectory() . 'Pimple'); From 1257e9e3a3e3d45a7f08fe7a2fd36c0e4d186874 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 09:50:58 +0200 Subject: [PATCH 18/27] Cap PHP version compatibility to 8.0-8.3 for now --- phpcs.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 27d5af45..a83ef6c4 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -5,7 +5,7 @@ - + ./src From 0ac0e879057b94a1052bcb710326432fe34b1e27 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 09:54:31 +0200 Subject: [PATCH 19/27] Make sure config reading returns requested object --- src/Config/ReadsConfig.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Config/ReadsConfig.php b/src/Config/ReadsConfig.php index 5840f3f6..4e7f3d30 100644 --- a/src/Config/ReadsConfig.php +++ b/src/Config/ReadsConfig.php @@ -43,7 +43,13 @@ public static function loadFromStdClass(stdClass $config): self { $mapper = new JsonMapper(); $mapper->bEnforceMapType = false; - return $mapper->map($config, self::class); + $object = $mapper->map($config, self::class); + + if (! $object instanceof self) { + throw new Exception('Could not read config from provided array.'); + } + + return $object; } public static function loadFromString(string $config): self @@ -52,6 +58,12 @@ public static function loadFromString(string $config): self $mapper = new JsonMapper(); $mapper->bEnforceMapType = false; - return $mapper->map($config, self::class); + $object = $mapper->map($config, self::class); + + if (! $object instanceof self) { + throw new Exception('Could not read config from provided array.'); + } + + return $object; } } From 98831c991ade381d2779e9a4e3e7a087f7540127 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 12:02:44 +0200 Subject: [PATCH 20/27] Put Package class in Config namespace --- src/Config/Mozart.php | 2 +- src/{Composer => Config}/Package.php | 2 +- src/Config/PackageFactory.php | 2 +- src/Console/Commands/Compose.php | 3 +-- src/Mover.php | 2 +- src/Replacer.php | 6 +++--- tests/Config/ConfigMapperTest.php | 2 +- 7 files changed, 9 insertions(+), 10 deletions(-) rename src/{Composer => Config}/Package.php (98%) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 994f3736..0e89322c 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -2,9 +2,9 @@ namespace CoenJacobs\Mozart\Config; -use CoenJacobs\Mozart\Composer\Package; use stdClass; use CoenJacobs\Mozart\Config\OverrideAutoload; +use CoenJacobs\Mozart\Config\Package; class Mozart { diff --git a/src/Composer/Package.php b/src/Config/Package.php similarity index 98% rename from src/Composer/Package.php rename to src/Config/Package.php index 096d98dc..d79cd9a4 100644 --- a/src/Composer/Package.php +++ b/src/Config/Package.php @@ -1,6 +1,6 @@ Date: Mon, 9 Sep 2024 12:14:31 +0200 Subject: [PATCH 21/27] Abstract direct accessors to config values via methods --- src/Config/Mozart.php | 30 +++++++++++++++++++++++++++++- src/Console/Commands/Compose.php | 11 +++++++---- src/Mover.php | 2 +- src/Replacer.php | 4 ++-- tests/MoverTest.php | 2 +- 5 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 0e89322c..dc010ca2 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -60,7 +60,7 @@ public function isValidMozartConfig(): bool public function isExcludedPackage(Package $package): bool { - return in_array($package->getName(), $this->excluded_packages); + return in_array($package->getName(), $this->getExcludedPackages()); } /** @@ -76,4 +76,32 @@ public function getClassmapDirectory(): string { return rtrim($this->classmap_directory, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; } + + public function getDeleteVendorDirectories(): bool + { + return $this->delete_vendor_directories; + } + + public function getDependencyNamespace(): string + { + return $this->dep_namespace; + } + + public function getClassmapPrefix(): string + { + return $this->classmap_prefix; + } + + public function getOverrideAutoload(): OverrideAutoload + { + return $this->override_autoload; + } + + /** + * @return string[] + */ + public function getExcludedPackages(): array + { + return $this->excluded_packages; + } } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 0ae427d2..24944709 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -67,7 +67,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $this->config = $config; - $this->config->set('dep_namespace', preg_replace("/\\\{2,}$/", "\\", $this->config->get('dep_namespace')."\\")); + $this->config->set('dep_namespace', preg_replace( + "/\\\{2,}$/", + "\\", + $this->config->getDependencyNamespace()."\\" + )); $require = array(); if (is_array($this->config->get('packages'))) { @@ -77,8 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $packagesByName = $this->findPackages($require); - $excludedPackagesNames = is_array($this->config->get('excluded_packages')) ? - $this->config->get('excluded_packages') : []; + $excludedPackagesNames = $this->config->getExcludedPackages(); $packagesToMoveByName = array_diff_key($packagesByName, array_flip($excludedPackagesNames)); $packages = array_values($packagesToMoveByName); @@ -178,7 +181,7 @@ private function findPackages(array $slugs): array } $autoloaders = null; - $override_autoload = $this->config->get('override_autoload'); + $override_autoload = $this->config->getOverrideAutoload(); if ($override_autoload !== false && isset($override_autoload->$package_slug)) { $autoloaders = $override_autoload->$package_slug; } diff --git a/src/Mover.php b/src/Mover.php index b0cf0d9f..bf7e048e 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -168,7 +168,7 @@ public function movePackage(Package $package) } } - if ($this->config->get('delete_vendor_directories')) { + if ($this->config->getDeleteVendorDirectories()) { $this->deletePackageVendorDirectories(); } } diff --git a/src/Replacer.php b/src/Replacer.php index 4a651b59..5629dca9 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -73,10 +73,10 @@ public function replaceInFile(string $targetFile, Autoloader $autoloader): void if ($autoloader instanceof NamespaceAutoloader) { $replacer = new NamespaceReplacer(); - $replacer->dep_namespace = $this->config->get('dep_namespace'); + $replacer->dep_namespace = $this->config->getDependencyNamespace(); } else { $replacer = new ClassmapReplacer(); - $replacer->classmap_prefix = $this->config->get('classmap_prefix'); + $replacer->classmap_prefix = $this->config->getClassmapPrefix(); } $replacer->setAutoloader($autoloader); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 2cb6a276..c7a2153a 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -133,7 +133,7 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void file_put_contents($testDummyComposerPath, $testDummyComposerContents); - $overrideAutoload = $this->config->get('override_autoload'); + $overrideAutoload = $this->config->getOverrideAutoload(); if ( ! empty( $overrideAutoload ) ) { $overrideAutoload = $overrideAutoload->getByKey( $packageString ); } From 6e2aeeb8743f954327864fcec030b3459a3de416 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 12:23:58 +0200 Subject: [PATCH 22/27] Abstract away direct package slugs string access into methods --- src/Config/Mozart.php | 8 ++++++++ src/Config/Package.php | 8 ++++++++ src/Console/Commands/Compose.php | 24 +++++++++++------------- tests/MoverTest.php | 2 +- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index dc010ca2..55a26e2e 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -24,6 +24,14 @@ class Mozart public OverrideAutoload $override_autoload; public bool $delete_vendor_directories; + /** + * @return string[] + */ + public function getPackages(): array + { + return $this->packages; + } + /** * @param string[] $packages */ diff --git a/src/Config/Package.php b/src/Config/Package.php index d79cd9a4..d78a8c93 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -88,6 +88,14 @@ public function getAutoloaders(): array return $this->autoload->getAutoloaders(); } + /** + * @return string[] + */ + public function getPackages(): array + { + return $this->require; + } + /** * @return Package[] */ diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 24944709..0ac68fb9 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -73,24 +73,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->config->getDependencyNamespace()."\\" )); - $require = array(); - if (is_array($this->config->get('packages'))) { - $require = $this->config->get('packages'); - } else { - $require = $package->require; + $require = $this->config->getPackages(); + if (empty($require)) { + $require = $package->getPackages(); } - $packagesByName = $this->findPackages($require); - $excludedPackagesNames = $this->config->getExcludedPackages(); - $packagesToMoveByName = array_diff_key($packagesByName, array_flip($excludedPackagesNames)); - $packages = array_values($packagesToMoveByName); - $this->mover = new Mover($workingDir, $this->config); $this->replacer = new Replacer($workingDir, $this->config); - $require = $this->config->get('packages'); - $require = (is_array($require)) ? array_values($require) : array(); - $packages = $this->findPackages($require); $this->mover->deleteTargetDirs($packages); @@ -135,6 +125,10 @@ protected function replacePackages($packages): void */ public function movePackage(Package $package): void { + if ($this->config->isExcludedPackage($package)) { + return; + } + if (! empty($package->dependencies)) { foreach ($package->getDependencies() as $dependency) { $this->movePackage($dependency); @@ -151,6 +145,10 @@ public function movePackage(Package $package): void */ public function replacePackage(Package $package): void { + if ($this->config->isExcludedPackage($package)) { + return; + } + if (! empty($package->dependencies)) { foreach ($package->getDependencies() as $dependency) { $this->replacePackage($dependency); diff --git a/tests/MoverTest.php b/tests/MoverTest.php index c7a2153a..01890c7c 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -124,7 +124,7 @@ public function it_deletes_subdirs_for_packages_about_to_be_moved(): void mkdir($this->testsWorkingDir . DIRECTORY_SEPARATOR . $this->config->getClassmapDirectory() . 'ezyang'); $packages = array(); - foreach ($this->config->get('packages') as $packageString) { + foreach ($this->config->getPackages() as $packageString) { $testDummyComposerDir = $this->testsWorkingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $packageString; @mkdir($testDummyComposerDir, 0777, true); From 15a5bcbb6b58985eb468524784f4c9a81ab6ba29 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 12:28:09 +0200 Subject: [PATCH 23/27] Abstract direct package name method away --- src/Mover.php | 20 ++++++++++---------- src/Replacer.php | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Mover.php b/src/Mover.php index bf7e048e..8c264276 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -80,7 +80,7 @@ private function deleteDepTargetDirs(Package $package): void $this->filesystem->deleteDirectory($outputDir); break; case Classmap::class: - $outputDir = $this->config->getClassmapDirectory() . $package->get('name'); + $outputDir = $this->config->getClassmapDirectory() . $package->getName(); $outputDir = str_replace('\\', DIRECTORY_SEPARATOR, $outputDir); $this->filesystem->deleteDirectory($outputDir); break; @@ -108,7 +108,7 @@ public function deleteEmptyDirs(): void */ public function movePackage(Package $package) { - if (in_array($package->get('name'), $this->movedPackages)) { + if (in_array($package->getName(), $this->movedPackages)) { return; } @@ -118,7 +118,7 @@ public function movePackage(Package $package) foreach ($autoloader->paths as $path) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR - . $package->get('name') . DIRECTORY_SEPARATOR . $path; + . $package->getName() . DIRECTORY_SEPARATOR . $path; $source_path = str_replace('/', DIRECTORY_SEPARATOR, $source_path); @@ -135,7 +135,7 @@ public function movePackage(Package $package) foreach ($autoloader->files as $file) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->get('name'); + . DIRECTORY_SEPARATOR . $package->getName(); $finder->files()->name($file)->in($source_path); foreach ($finder as $foundFile) { @@ -148,7 +148,7 @@ public function movePackage(Package $package) foreach ($autoloader->paths as $path) { $source_path = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package->get('name') . DIRECTORY_SEPARATOR . $path; + . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; $finder->files()->in($source_path); @@ -163,8 +163,8 @@ public function movePackage(Package $package) } } - if (!in_array($package->get('name'), $this->movedPackages)) { - $this->movedPackages[] = $package->get('name'); + if (!in_array($package->getName(), $this->movedPackages)) { + $this->movedPackages[] = $package->getName(); } } @@ -187,16 +187,16 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') $replaceWith = $this->config->getDepDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->get('name') + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR . $path; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, '', $targetFile); } else { - $namespacePath = $package->get('name'); + $namespacePath = $package->getName(); $replaceWith = $this->config->getClassmapDirectory() . $namespacePath; $targetFile = str_replace($this->workingDir, $replaceWith, $file->getPathname()); - $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->get('name') + $packageVendorPath = DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . $package->getName() . DIRECTORY_SEPARATOR; $packageVendorPath = str_replace('/', DIRECTORY_SEPARATOR, $packageVendorPath); $targetFile = str_replace($packageVendorPath, DIRECTORY_SEPARATOR, $targetFile); diff --git a/src/Replacer.php b/src/Replacer.php index 5629dca9..ef19b73e 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -104,7 +104,7 @@ public function replacePackageByAutoloader(Package $package, Composer\Autoload\A $this->replaceInDirectory($autoloader, $source_path); } elseif ($autoloader instanceof Classmap) { $finder = new Finder(); - $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->get('name'); + $source_path = $this->workingDir . $this->config->getClassmapDirectory() . $package->getName(); $finder->files()->in($source_path); foreach ($finder as $foundFile) { @@ -218,7 +218,7 @@ public function replaceParentPackage(Package $package, Package $parent): void } } else { $directory = $this->workingDir . - $this->config->getClassmapDirectory() . $parent->get('name'); + $this->config->getClassmapDirectory() . $parent->getName(); if ($autoloader instanceof NamespaceAutoloader) { $this->replaceInDirectory($autoloader, $directory); From 2cbde92617e7247ce9cda7e85172ec38e2b6c2b8 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 12:45:28 +0200 Subject: [PATCH 24/27] Simplify getting target namespace by including appending \ --- src/Config/Mozart.php | 9 ++++++++- src/Config/Package.php | 4 +--- src/Console/Commands/Compose.php | 5 ----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 55a26e2e..9d26c194 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -5,6 +5,7 @@ use stdClass; use CoenJacobs\Mozart\Config\OverrideAutoload; use CoenJacobs\Mozart\Config\Package; +use Exception; class Mozart { @@ -92,7 +93,13 @@ public function getDeleteVendorDirectories(): bool public function getDependencyNamespace(): string { - return $this->dep_namespace; + $namespace = preg_replace("/\\\{2,}$/", "\\", $this->dep_namespace."\\"); + + if (empty($namespace)) { + throw new Exception('Could not get target dependency namespace'); + } + + return $namespace; } public function getClassmapPrefix(): string diff --git a/src/Config/Package.php b/src/Config/Package.php index d78a8c93..abf464a5 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -40,9 +40,7 @@ public function __construct($path, $overrideAutoload = null) $this->path = $path; if (isset($overrideAutoload)) { - $autoload = new Autoload(); - $autoload->setupAutoloaders($overrideAutoload); - $this->set('autoload', $autoload); + $this->setAutoload($overrideAutoload); } } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 0ac68fb9..cb1cb0cd 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -67,11 +67,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $this->config = $config; - $this->config->set('dep_namespace', preg_replace( - "/\\\{2,}$/", - "\\", - $this->config->getDependencyNamespace()."\\" - )); $require = $this->config->getPackages(); if (empty($require)) { From 8b453e2f503d871dec8c861e1f49cfbd0517276a Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 12:47:48 +0200 Subject: [PATCH 25/27] ConfigAccessor has now been made redundant by explicit getters and setters --- src/Config/ConfigAccessor.php | 24 ------------------------ src/Config/Mozart.php | 2 +- src/Config/Package.php | 2 +- 3 files changed, 2 insertions(+), 26 deletions(-) delete mode 100644 src/Config/ConfigAccessor.php diff --git a/src/Config/ConfigAccessor.php b/src/Config/ConfigAccessor.php deleted file mode 100644 index e5329942..00000000 --- a/src/Config/ConfigAccessor.php +++ /dev/null @@ -1,24 +0,0 @@ -$key)) { - throw new \Exception('Can\'t get setting: '. $key .' not set'); - } - - return $this->$key; - } - - public function set(string $key, mixed $value): void - { - if (! property_exists($this, $key)) { - throw new \Exception('Can\'t set setting: '. $key . ' not set'); - } - - $this->$key = $value; - } -} diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 9d26c194..83358818 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -9,7 +9,7 @@ class Mozart { - use ReadsConfig, ConfigAccessor; + use ReadsConfig; public string $dep_namespace; public string $dep_directory; diff --git a/src/Config/Package.php b/src/Config/Package.php index abf464a5..33fe9cb6 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -11,7 +11,7 @@ class Package { - use ReadsConfig, ConfigAccessor; + use ReadsConfig; /** @var string */ public $path = ''; From 57c0b610c20574dfa80219591af5b5310df7f754 Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Mon, 9 Sep 2024 19:48:30 +0200 Subject: [PATCH 26/27] Cleanup of unused logic and code standards --- src/Composer/Autoload/NamespaceAutoloader.php | 2 -- src/Config/Classmap.php | 5 +-- src/Config/Package.php | 21 ------------- src/Console/Commands/Compose.php | 14 +-------- src/Mover.php | 18 ++--------- src/Replace/BaseReplacer.php | 3 +- src/Replace/ClassmapReplacer.php | 12 +++---- src/Replace/NamespaceReplacer.php | 4 +-- src/Replacer.php | 31 +------------------ tests/replacers/NamespaceReplacerTest.php | 5 --- 10 files changed, 14 insertions(+), 101 deletions(-) diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 3e66694b..955d8ab0 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -20,8 +20,6 @@ abstract class NamespaceAutoloader implements Autoloader * A package's composer.json config autoload key's value, where $key is `psr-1`|`psr-4`|`classmap`. * * @param $autoloadConfig - * - * @return void */ public function processConfig($autoloadConfig): void { diff --git a/src/Config/Classmap.php b/src/Config/Classmap.php index f6c1ab04..c53529ed 100644 --- a/src/Config/Classmap.php +++ b/src/Config/Classmap.php @@ -3,6 +3,7 @@ namespace CoenJacobs\Mozart\Config; use CoenJacobs\Mozart\Composer\Autoload\Autoloader; +use Exception; class Classmap implements Autoloader { @@ -27,10 +28,10 @@ public function processConfig($autoloadConfig): void } /** - * @throws \Exception + * @throws Exception */ public function getSearchNamespace(): string { - throw new \Exception('Classmap autoloaders do not contain a namespace and this method can not be used.'); + throw new Exception('Classmap autoloaders do not contain a namespace and this method can not be used.'); } } diff --git a/src/Config/Package.php b/src/Config/Package.php index 33fe9cb6..a34d85ce 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -4,7 +4,6 @@ use CoenJacobs\Mozart\Composer\Autoload\Autoloader; use CoenJacobs\Mozart\Config\Autoload; -use CoenJacobs\Mozart\Config\ConfigAccessor; use CoenJacobs\Mozart\Config\Extra; use CoenJacobs\Mozart\Config\ReadsConfig; use stdClass; @@ -13,9 +12,6 @@ class Package { use ReadsConfig; - /** @var string */ - public $path = ''; - /** @var Package[] */ public $requirePackages = []; @@ -27,23 +23,6 @@ class Package public ?Autoload $autoload = null; public ?Extra $extra = null; - /** - * Create a PHP object to represent a composer package. - * - * @param string $path The path to the vendor folder with the composer.json "name", i.e. the domain/package - * definition, which is the vendor subdir from where the package's composer.json should be read. - * @param stdClass $overrideAutoload Optional configuration to replace the package's own autoload definition with - * another which Mozart can use. - */ - public function __construct($path, $overrideAutoload = null) - { - $this->path = $path; - - if (isset($overrideAutoload)) { - $this->setAutoload($overrideAutoload); - } - } - public function setAutoload(stdClass $data): void { $autoload = new Autoload(); diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index cb1cb0cd..11ae219e 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -26,9 +26,6 @@ class Compose extends Command /** @var Mozart */ private $config; - /** - * @return void - */ protected function configure(): void { $this->setName('compose'); @@ -89,8 +86,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int /** * @param Package[] $packages - * - * @return void */ protected function movePackages($packages): void { @@ -103,8 +98,6 @@ protected function movePackages($packages): void /** * @param Package[] $packages - * - * @return void */ protected function replacePackages($packages): void { @@ -115,8 +108,6 @@ protected function replacePackages($packages): void /** * Move all the packages over, one by one, starting on the deepest level of dependencies. - * - * @return void */ public function movePackage(Package $package): void { @@ -135,8 +126,6 @@ public function movePackage(Package $package): void /** * Replace contents of all the packages, one by one, starting on the deepest level of dependencies. - * - * @return void */ public function replacePackage(Package $package): void { @@ -198,13 +187,12 @@ private function findPackages(array $slugs): array * Get an array containing all the dependencies and dependencies * @param Package $package * @param Package[] $dependencies - * @return array + * @return Package[] */ private function getAllDependenciesOfPackage(Package $package, $dependencies = []): array { if ($this->config->isExcludedPackage($package)) { return $dependencies; - ; } if (empty($package->getDependencies())) { diff --git a/src/Mover.php b/src/Mover.php index 8c264276..f0d45184 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -49,8 +49,6 @@ public function __construct(string $workingDir, Mozart $config) * Create the required `dep_directory` and `classmap_directory` and delete targetDirs of packages about to be moved. * * @param Package[] $packages The packages that, in the next step, will be moved. - * - * @return void */ public function deleteTargetDirs($packages): void { @@ -103,10 +101,7 @@ public function deleteEmptyDirs(): void } } - /** - * @return void - */ - public function movePackage(Package $package) + public function movePackage(Package $package): void { if (in_array($package->getName(), $this->movedPackages)) { return; @@ -173,14 +168,7 @@ public function movePackage(Package $package) } } - /** - * @param Package $package - * @param Autoloader $autoloader - * @param SplFileInfo $file - * @param string $path - * @return string - */ - public function moveFile(Package $package, $autoloader, $file, $path = '') + public function moveFile(Package $package, Autoloader $autoloader, SplFileInfo $file, string $path = ''): string { if ($autoloader instanceof NamespaceAutoloader) { $namespacePath = $autoloader->getNamespacePath(); @@ -214,8 +202,6 @@ public function moveFile(Package $package, $autoloader, $file, $path = '') * Deletes all the packages that are moved from the /vendor/ directory to * prevent packages that are prefixed/namespaced from being used or * influencing the output of the code. They just need to be gone. - * - * @return void */ protected function deletePackageVendorDirectories(): void { diff --git a/src/Replace/BaseReplacer.php b/src/Replace/BaseReplacer.php index 442551e8..3298c5d6 100644 --- a/src/Replace/BaseReplacer.php +++ b/src/Replace/BaseReplacer.php @@ -11,9 +11,8 @@ abstract class BaseReplacer implements Replacer /** * @param Autoloader $autoloader - * @return void */ - public function setAutoloader(Autoloader $autoloader) + public function setAutoloader(Autoloader $autoloader): void { $this->autoloader = $autoloader; } diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 2cc297ed..41323fa3 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -17,8 +17,6 @@ class ClassmapReplacer extends BaseReplacer /** * @param false|string $contents - * - * @return string */ public function replace($contents): string { @@ -29,16 +27,16 @@ public function replace($contents): string return preg_replace_callback( " / # Start the pattern - namespace\s+[a-zA-Z0-9_\x7f-\xff\\\\]+[;{\s\n]{1}.*?(?=namespace|$) - # Look for a preceeding namespace declaration, up until + namespace\s+[a-zA-Z0-9_\x7f-\xff\\\\]+[;{\s\n]{1}.*?(?=namespace|$) + # Look for a preceeding namespace declaration, up until # a potential second namespace declaration - | # if found, match that much before repeating the search + | # if found, match that much before repeating the search # on the remainder of the string (?:abstract\sclass|class|interface)\s+ # Look behind for class, abstract class, interface - ([a-zA-Z0-9_\x7f-\xff]+) # Match the word until the first + ([a-zA-Z0-9_\x7f-\xff]+) # Match the word until the first # non-classname-valid character \s? # Allow a space after - (?:{|extends|implements|\n) # Class declaration can be followed by {, extends, + (?:{|extends|implements|\n) # Class declaration can be followed by {, extends, # implements, or a new line /sx", // # dot matches newline, ignore whitespace in regex. function ($matches) use ($contents) { diff --git a/src/Replace/NamespaceReplacer.php b/src/Replace/NamespaceReplacer.php index 711ec086..680fb413 100644 --- a/src/Replace/NamespaceReplacer.php +++ b/src/Replace/NamespaceReplacer.php @@ -14,10 +14,8 @@ class NamespaceReplacer extends BaseReplacer /** * @param string $contents The text to make replacements in. * @param null $file Only used in ClassmapReplacer (for recording which files were changed). - * - * @return string The updated text. */ - public function replace($contents, $file = null) + public function replace($contents, $file = null): string { $searchNamespace = preg_quote($this->autoloader->getSearchNamespace(), '/'); $dependencyNamespace = preg_quote($this->dep_namespace, '/'); diff --git a/src/Replacer.php b/src/Replacer.php index ef19b73e..95d82590 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -52,12 +52,6 @@ public function replacePackage(Package $package): void } } - /** - * @param $targetFile - * @param $autoloader - * - * @return void - */ public function replaceInFile(string $targetFile, Autoloader $autoloader): void { $targetFile = str_replace($this->workingDir, '', $targetFile); @@ -89,13 +83,7 @@ public function replaceInFile(string $targetFile, Autoloader $autoloader): void $this->filesystem->write($targetFile, $contents); } - /** - * @param Package $package - * @param $autoloader - * - * @return void - */ - public function replacePackageByAutoloader(Package $package, Composer\Autoload\Autoloader $autoloader): void + public function replacePackageByAutoloader(Package $package, Autoloader $autoloader): void { if ($autoloader instanceof NamespaceAutoloader) { $source_path = $this->workingDir . $this->targetDir @@ -117,12 +105,6 @@ public function replacePackageByAutoloader(Package $package, Composer\Autoload\A } } - /** - * @param $autoloader - * @param $directory - * - * @return void - */ public function replaceParentClassesInDirectory(string $directory): void { if (count($this->replacedClasses)===0) { @@ -171,12 +153,6 @@ function ($matches) use ($replacement) { } } - /** - * @param $autoloader - * @param $directory - * - * @return void - */ public function replaceInDirectory(NamespaceAutoloader $autoloader, string $directory): void { $finder = new Finder(); @@ -195,11 +171,6 @@ public function replaceInDirectory(NamespaceAutoloader $autoloader, string $dire * Replace everything in parent package, based on the dependency package. * This is done to ensure that package A (which requires package B), is also * updated with the replacements being made in package B. - * - * @param Package $package - * @param Package $parent - * - * @return void */ public function replaceParentPackage(Package $package, Package $parent): void { diff --git a/tests/replacers/NamespaceReplacerTest.php b/tests/replacers/NamespaceReplacerTest.php index 7694c44d..b0651bc7 100644 --- a/tests/replacers/NamespaceReplacerTest.php +++ b/tests/replacers/NamespaceReplacerTest.php @@ -20,11 +20,6 @@ protected function setUp(): void /** * Creates a NamespaceReplacer, given a namespace and a prefix. - * - * @param string $namespace - * @param string $prefix - * - * @return Psr0 */ protected static function createReplacer(string $namespace, string $prefix = self::PREFIX) : NamespaceReplacer { From 6cf4b13d0ce5dbe6a7648bc74dccb8bd76530e5c Mon Sep 17 00:00:00 2001 From: Coen Jacobs Date: Wed, 11 Sep 2024 16:33:23 +0200 Subject: [PATCH 27/27] Rewritten logic to load packages and their dependencies --- src/Composer/Autoload/NamespaceAutoloader.php | 7 +- src/Config/Mozart.php | 12 ++ src/Config/Package.php | 37 +++- src/Config/PackageFactory.php | 20 -- src/Console/Commands/Compose.php | 197 +++--------------- src/Mover.php | 17 ++ src/PackageFactory.php | 35 ++++ src/PackageFinder.php | 93 +++++++++ src/Replacer.php | 65 +++++- tests/Config/ConfigMapperTest.php | 2 +- tests/Config/config-mapper-test.json | 1 - tests/MoverTest.php | 2 +- 12 files changed, 285 insertions(+), 203 deletions(-) delete mode 100644 src/Config/PackageFactory.php create mode 100644 src/PackageFactory.php create mode 100644 src/PackageFinder.php diff --git a/src/Composer/Autoload/NamespaceAutoloader.php b/src/Composer/Autoload/NamespaceAutoloader.php index 955d8ab0..62ef6328 100644 --- a/src/Composer/Autoload/NamespaceAutoloader.php +++ b/src/Composer/Autoload/NamespaceAutoloader.php @@ -32,9 +32,14 @@ public function processConfig($autoloadConfig): void } } + public function getNamespace(): string + { + return rtrim($this->namespace, '\\') . '\\'; + } + public function getSearchNamespace(): string { - return $this->namespace; + return rtrim($this->namespace, '\\'); } public function getNamespacePath(): string diff --git a/src/Config/Mozart.php b/src/Config/Mozart.php index 83358818..a07c5b5b 100644 --- a/src/Config/Mozart.php +++ b/src/Config/Mozart.php @@ -25,6 +25,8 @@ class Mozart public OverrideAutoload $override_autoload; public bool $delete_vendor_directories; + public string $workingDir = ''; + /** * @return string[] */ @@ -119,4 +121,14 @@ public function getExcludedPackages(): array { return $this->excluded_packages; } + + public function setWorkingDir(string $workingDir): void + { + $this->workingDir = $workingDir; + } + + public function getWorkingDir(): string + { + return $this->workingDir; + } } diff --git a/src/Config/Package.php b/src/Config/Package.php index a34d85ce..c466ee9f 100644 --- a/src/Config/Package.php +++ b/src/Config/Package.php @@ -6,6 +6,8 @@ use CoenJacobs\Mozart\Config\Autoload; use CoenJacobs\Mozart\Config\Extra; use CoenJacobs\Mozart\Config\ReadsConfig; +use CoenJacobs\Mozart\PackageFinder; +use Exception; use stdClass; class Package @@ -13,12 +15,12 @@ class Package use ReadsConfig; /** @var Package[] */ - public $requirePackages = []; + public $dependencies = []; public string $name; /** @var string[] */ - public array $require; + public array $require = []; public ?Autoload $autoload = null; public ?Extra $extra = null; @@ -68,9 +70,9 @@ public function getAutoloaders(): array /** * @return string[] */ - public function getPackages(): array + public function getRequire(): array { - return $this->require; + return array_keys($this->require); } /** @@ -78,21 +80,38 @@ public function getPackages(): array */ public function getDependencies(): array { - return $this->requirePackages; + return $this->dependencies; } - public function registerRequirePackage(Package $package): void + public function loadDependencies(): void { - array_push($this->requirePackages, $package); + $finder = PackageFinder::instance(); + if ($this->isValidMozartConfig() && !empty($this->getExtra())) { + $mozart = $this->getExtra()->getMozart(); + + if (empty($mozart)) { + throw new Exception("Couldn't load dependencies because config not set."); + } + $finder->setConfig($mozart); + } + + $dependencies = $finder->getPackagesBySlugs($this->getRequire()); + + $this->registerDependencies($dependencies); + } + + public function registerDependency(Package $package): void + { + array_push($this->dependencies, $package); } /** * @param Package[] $packages */ - public function registerRequirePackages(array $packages): void + public function registerDependencies(array $packages): void { foreach ($packages as $package) { - $this->registerRequirePackage($package); + $this->registerDependency($package); } } } diff --git a/src/Config/PackageFactory.php b/src/Config/PackageFactory.php deleted file mode 100644 index e84adf38..00000000 --- a/src/Config/PackageFactory.php +++ /dev/null @@ -1,20 +0,0 @@ -setAutoload($overrideAutoload); - } - - return $package; - } -} diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 11ae219e..aad21e6a 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -3,9 +3,9 @@ namespace CoenJacobs\Mozart\Console\Commands; use CoenJacobs\Mozart\Config\Mozart; -use CoenJacobs\Mozart\Config\Package; -use CoenJacobs\Mozart\Config\PackageFactory; use CoenJacobs\Mozart\Mover; +use CoenJacobs\Mozart\PackageFactory; +use CoenJacobs\Mozart\PackageFinder; use CoenJacobs\Mozart\Replacer; use Exception; use Symfony\Component\Console\Command\Command; @@ -14,17 +14,17 @@ class Compose extends Command { - /** @var Mover */ - private $mover; + private Mover $mover; + private Replacer $replacer; + private Mozart $config; + private PackageFinder $finder; + private string $workingDir; - /** @var Replacer */ - private $replacer; - - /** @var string */ - private $workingDir; - - /** @var Mozart */ - private $config; + public function __construct() + { + $this->workingDir = getcwd(); + parent::__construct(); + } protected function configure(): void { @@ -35,17 +35,13 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $workingDir = getcwd(); - - if (! $workingDir) { + if (! $this->workingDir) { throw new Exception('Could not determine working directory.'); } - $this->workingDir = $workingDir; - - $composerFile = $workingDir . DIRECTORY_SEPARATOR. 'composer.json'; + $composerFile = $this->workingDir . DIRECTORY_SEPARATOR. 'composer.json'; try { - $package = PackageFactory::createPackage($composerFile); + $package = PackageFactory::createPackage($composerFile, null, false); } catch (Exception $e) { $output->write('Unable to read the composer.json file'); return 1; @@ -64,165 +60,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $this->config = $config; + $this->config->setWorkingDir($this->workingDir); $require = $this->config->getPackages(); if (empty($require)) { - $require = $package->getPackages(); + $require = $package->getRequire(); } - $this->mover = new Mover($workingDir, $this->config); - $this->replacer = new Replacer($workingDir, $this->config); + $this->finder = PackageFinder::instance(); + $this->finder->setConfig($this->config); + + $package->loadDependencies(); + + $packages = $this->finder->getPackagesBySlugs($require); + $packages = $this->finder->findPackages($packages); - $packages = $this->findPackages($require); + $this->mover = new Mover($this->workingDir, $this->config); + $this->replacer = new Replacer($this->workingDir, $this->config); $this->mover->deleteTargetDirs($packages); - $this->movePackages($packages); - $this->replacePackages($packages); - $this->replaceParentInTree($packages); + $this->mover->movePackages($packages); + $this->replacer->replacePackages($packages); + $this->replacer->replaceParentInTree($packages); $this->replacer->replaceParentClassesInDirectory($this->config->getClassmapDirectory()); return 0; } - - /** - * @param Package[] $packages - */ - protected function movePackages($packages): void - { - foreach ($packages as $package) { - $this->movePackage($package); - } - - $this->mover->deleteEmptyDirs(); - } - - /** - * @param Package[] $packages - */ - protected function replacePackages($packages): void - { - foreach ($packages as $package) { - $this->replacePackage($package); - } - } - - /** - * Move all the packages over, one by one, starting on the deepest level of dependencies. - */ - public function movePackage(Package $package): void - { - if ($this->config->isExcludedPackage($package)) { - return; - } - - if (! empty($package->dependencies)) { - foreach ($package->getDependencies() as $dependency) { - $this->movePackage($dependency); - } - } - - $this->mover->movePackage($package); - } - - /** - * Replace contents of all the packages, one by one, starting on the deepest level of dependencies. - */ - public function replacePackage(Package $package): void - { - if ($this->config->isExcludedPackage($package)) { - return; - } - - if (! empty($package->dependencies)) { - foreach ($package->getDependencies() as $dependency) { - $this->replacePackage($dependency); - } - } - - $this->replacer->replacePackage($package); - } - - /** - * Loops through all dependencies and their dependencies and so on... - * will eventually return a list of all packages required by the full tree. - * - * @param ((int|string)|mixed)[] $slugs - * - * @return Package[] - */ - private function findPackages(array $slugs): array - { - $packages = []; - - foreach ($slugs as $package_slug) { - $packageDir = $this->workingDir . DIRECTORY_SEPARATOR . 'vendor' - . DIRECTORY_SEPARATOR . $package_slug . DIRECTORY_SEPARATOR; - - if (! is_dir($packageDir)) { - continue; - } - - $autoloaders = null; - $override_autoload = $this->config->getOverrideAutoload(); - if ($override_autoload !== false && isset($override_autoload->$package_slug)) { - $autoloaders = $override_autoload->$package_slug; - } - - $package = PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders); - - if ($this->config->isExcludedPackage($package)) { - continue; - } - - $dependencies = $package->getDependencies(); - - $package->registerRequirePackages($this->findPackages($dependencies)); - $packages[$package_slug] = $package; - } - - return $packages; - } - - /** - * Get an array containing all the dependencies and dependencies - * @param Package $package - * @param Package[] $dependencies - * @return Package[] - */ - private function getAllDependenciesOfPackage(Package $package, $dependencies = []): array - { - if ($this->config->isExcludedPackage($package)) { - return $dependencies; - } - - if (empty($package->getDependencies())) { - return $dependencies; - } - - foreach ($package->getDependencies() as $dependency) { - $dependencies[] = $dependency; - } - - foreach ($package->getDependencies() as $dependency) { - $dependencies = $this->getAllDependenciesOfPackage($dependency, $dependencies); - } - - return $dependencies; - } - - /** - * @param Package[] $packages - */ - private function replaceParentInTree(array $packages): void - { - foreach ($packages as $package) { - $dependencies = $this->getAllDependenciesOfPackage($package); - - foreach ($dependencies as $dependency) { - $this->replacer->replaceParentPackage($dependency, $package); - } - - $this->replaceParentInTree($package->getDependencies()); - } - } } diff --git a/src/Mover.php b/src/Mover.php index f0d45184..4f3d65d6 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -101,12 +101,29 @@ public function deleteEmptyDirs(): void } } + /** + * @param Package[] $packages + */ + public function movePackages($packages): void + { + foreach ($packages as $package) { + $this->movePackages($package->getDependencies()); + $this->movePackage($package); + } + + $this->deleteEmptyDirs(); + } + public function movePackage(Package $package): void { if (in_array($package->getName(), $this->movedPackages)) { return; } + if ($this->config->isExcludedPackage($package)) { + return; + } + foreach ($package->getAutoloaders() as $autoloader) { if ($autoloader instanceof NamespaceAutoloader) { $finder = new Finder(); diff --git a/src/PackageFactory.php b/src/PackageFactory.php new file mode 100644 index 00000000..da67d61e --- /dev/null +++ b/src/PackageFactory.php @@ -0,0 +1,35 @@ + */ + public static array $cache = []; + + public static function createPackage( + string $path, + stdClass $overrideAutoload = null, + bool $loadDependencies = true + ): Package { + if (isset(self::$cache[$path])) { + return self::$cache[$path]; + } + + $package = Package::loadFromFile($path); + + if (! empty($overrideAutoload)) { + $package->setAutoload($overrideAutoload); + } + + if ($loadDependencies) { + $package->loadDependencies(); + } + + self::$cache[$path] = $package; + return $package; + } +} diff --git a/src/PackageFinder.php b/src/PackageFinder.php new file mode 100644 index 00000000..9f162c63 --- /dev/null +++ b/src/PackageFinder.php @@ -0,0 +1,93 @@ +config = $config; + } + + public function getPackageBySlug(string $slug): ?Package + { + /** + * This case prevents issues where the requirements array can contain + * non-package like lines, for example: php or extensions. + */ + if (!strstr($slug, '/')) { + return null; + } + + if (empty($this->config)) { + throw new Exception("Config not set to find packages"); + } + + $packageDir = $this->config->getWorkingDir() . DIRECTORY_SEPARATOR . 'vendor' + . DIRECTORY_SEPARATOR . $slug . DIRECTORY_SEPARATOR; + + if (! is_dir($packageDir)) { + throw new Exception("Couldn't load package based on provided slug: " . $slug); + } + + $autoloaders = null; + $override_autoload = $this->config->getOverrideAutoload(); + if ($override_autoload !== false && isset($override_autoload->$slug)) { + $autoloaders = $override_autoload->$slug; + } + + return PackageFactory::createPackage($packageDir . 'composer.json', $autoloaders, true); + } + + /** + * @param string[] $slugs + * @return Package[] + */ + public function getPackagesBySlugs(array $slugs): array + { + $packages = array_map(function (string $slug) { + return $this->getPackageBySlug($slug); + }, $slugs); + + return array_filter($packages, function ($package) { + return $package instanceof Package; + }); + } + + /** + * Loops through all dependencies and their dependencies and so on... + * will eventually return a list of all packages required by the full tree. + * + * @param Package[] $packages + * + * @return Package[] + */ + public function findPackages(array $packages): array + { + foreach ($packages as $package) { + $dependencies = $package->getDependencies(); + + $package->registerDependencies($this->findPackages($dependencies)); + $packages[$package->getName()] = $package; + } + + return $packages; + } +} diff --git a/src/Replacer.php b/src/Replacer.php index 95d82590..bc2668b2 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -45,6 +45,17 @@ public function __construct(string $workingDir, Mozart $config) $this->filesystem = new Filesystem($adapter); } + /** + * @param Package[] $packages + */ + public function replacePackages($packages): void + { + foreach ($packages as $package) { + $this->replacePackages($package->getDependencies()); + $this->replacePackage($package); + } + } + public function replacePackage(Package $package): void { foreach ($package->getAutoloaders() as $autoloader) { @@ -85,10 +96,13 @@ public function replaceInFile(string $targetFile, Autoloader $autoloader): void public function replacePackageByAutoloader(Package $package, Autoloader $autoloader): void { + if ($this->config->isExcludedPackage($package)) { + return; + } + if ($autoloader instanceof NamespaceAutoloader) { $source_path = $this->workingDir . $this->targetDir - . str_replace('\\', DIRECTORY_SEPARATOR, $autoloader->namespace) - . DIRECTORY_SEPARATOR; + . str_replace('\\', DIRECTORY_SEPARATOR, $autoloader->getNamespace()); $this->replaceInDirectory($autoloader, $source_path); } elseif ($autoloader instanceof Classmap) { $finder = new Finder(); @@ -174,6 +188,10 @@ public function replaceInDirectory(NamespaceAutoloader $autoloader, string $dire */ public function replaceParentPackage(Package $package, Package $parent): void { + if ($this->config->isExcludedPackage($package)) { + return; + } + foreach ($parent->getAutoloaders() as $parentAutoloader) { foreach ($package->getAutoloaders() as $autoloader) { if ($parentAutoloader instanceof NamespaceAutoloader) { @@ -201,4 +219,47 @@ public function replaceParentPackage(Package $package, Package $parent): void } } } + + /** + * Get an array containing all the dependencies and dependencies + * @param Package $package + * @param Package[] $dependencies + * @return Package[] + */ + private function getAllDependenciesOfPackage(Package $package, $dependencies = []): array + { + if (empty($package->getDependencies())) { + return $dependencies; + } + + foreach ($package->getDependencies() as $dependency) { + $dependencies[] = $dependency; + } + + foreach ($package->getDependencies() as $dependency) { + $dependencies = $this->getAllDependenciesOfPackage($dependency, $dependencies); + } + + return $dependencies; + } + + /** + * @param Package[] $packages + */ + public function replaceParentInTree(array $packages): void + { + foreach ($packages as $package) { + if ($this->config->isExcludedPackage($package)) { + continue; + } + + $dependencies = $this->getAllDependenciesOfPackage($package); + + foreach ($dependencies as $dependency) { + $this->replaceParentPackage($dependency, $package); + } + + $this->replaceParentInTree($package->getDependencies()); + } + } } diff --git a/tests/Config/ConfigMapperTest.php b/tests/Config/ConfigMapperTest.php index 846ae249..42e1ed7a 100644 --- a/tests/Config/ConfigMapperTest.php +++ b/tests/Config/ConfigMapperTest.php @@ -4,7 +4,7 @@ use CoenJacobs\Mozart\Config\Mozart; use CoenJacobs\Mozart\Config\Package; -use CoenJacobs\Mozart\Config\PackageFactory; +use CoenJacobs\Mozart\PackageFactory; use PHPUnit\Framework\TestCase; class ConfigMapperTest extends TestCase diff --git a/tests/Config/config-mapper-test.json b/tests/Config/config-mapper-test.json index 1f53c4ad..b043f34b 100644 --- a/tests/Config/config-mapper-test.json +++ b/tests/Config/config-mapper-test.json @@ -1,6 +1,5 @@ { "require": { - "pimple/pimple": "^3.5" }, "autoload": { "psr-0": { diff --git a/tests/MoverTest.php b/tests/MoverTest.php index 01890c7c..8945f49e 100644 --- a/tests/MoverTest.php +++ b/tests/MoverTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); use CoenJacobs\Mozart\Config\Mozart; -use CoenJacobs\Mozart\Config\PackageFactory; +use CoenJacobs\Mozart\PackageFactory; use CoenJacobs\Mozart\Console\Commands\Compose; use CoenJacobs\Mozart\Mover; use PHPUnit\Framework\TestCase;