From 8e20aa3febd7d097d57a09d5527c3bd030c36195 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 9 Apr 2020 19:52:47 -0700 Subject: [PATCH 01/17] Add classmap output --- README.md | 10 +++++++- src/Console/Commands/Compose.php | 42 ++++++++++++++++++++++++++++++++ src/Replace/ClassmapReplacer.php | 14 +++++++---- src/Replace/Replacer.php | 2 +- 4 files changed, 61 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index c10e936b..793f605b 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,11 @@ Mozart requires little configuration. All you need to do is tell it where the bu "packages": [ "pimple/pimple" ] - } + }, + "classmap_output": { + "filename": "src/autoload_classmap.php", + "relative_path": "/src" + }, }, ``` @@ -41,6 +45,10 @@ The following configuration values are required: **Important:** Since Mozart automatically processes the full dependency tree of the packages you specify, you **need to specify all these configuration options**, because you can't reliably determine what kind of autoloaders are being used in the full dependency tree. A package way down the tree might suddenly use a classmap autoloader for example. Make sure you also include the namespace directory and classmap directory in your own autoloader, so they are always loaded. + The following configuration is optional: + + - `classmap_output` defines the `filename` to write the classmap autoloader to (relative to the directory where `mozart compose` is invoked from) and the `relative_path` to remove from the beginning of each file path. + After Composer has loaded the packages as defined in your `composer.json` file, you can now run `mozart compose` and Mozart will bundle your packages according to the above configuration. It is recommended to dump the autoloader after Mozart has finished running, in case there are new classes or namespaces generated that aren't included in the autoloader yet. ## Scripts diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index a7769eb4..c8f6ff33 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -53,6 +53,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->replacer->replaceParentPackage($package, null); } + $this->generateClassmapAutoloader(); + return 0; } @@ -141,4 +143,44 @@ private function findPackages($slugs) return $packages; } + + + /** + * Write a classmap to file. + */ + private function generateClassmapAutoloader() { + + if (!isset($this->config->classmap_output)) { + return; + } + + $classmap = $this->replacer->classmap; + + if( !isset($this->config->classmap_output->filename)) { + return; + } + $output_filename = $this->config->classmap_output->filename; + + $relative_path = isset( $this->config->classmap_output->relative_path ) ? $this->config->classmap_output->relative_path : null; + + $output = " $filepath) { + + if ( !is_null($relative_path) && substr($filepath, 0, strlen($relative_path)) == $relative_path) { + $filepath = substr($filepath, strlen($relative_path)); + } + + $output .= " '{$class}' => '{$filepath}',\n"; + } + + $output .= ");"; + + file_put_contents( $output_filename, $output ); + + } } diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index fddec0a3..3c379498 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -5,26 +5,30 @@ class ClassmapReplacer extends BaseReplacer { /** @var array */ - public $replacedClasses = []; + public $replacedClasses = []; + + /** @var array */ + public $classmap = []; /** @var string */ public $classmap_prefix; - public function replace($contents) + public function replace($contents, $file) { return preg_replace_callback( '/(?:[abstract]*class |interface )([a-zA-Z\_]+)(?:[ \n]*{| extends| implements)/U', - function ($matches) { + function ($matches) use ($file) { $replace = $this->classmap_prefix . $matches[1]; - $this->saveReplacedClass($matches[1], $replace); + $this->saveReplacedClass($matches[1], $replace, $file); return str_replace($matches[1], $replace, $matches[0]); }, $contents ); } - public function saveReplacedClass($classname, $replacedName) + public function saveReplacedClass($classname, $replacedName, $file) { $this->replacedClasses[ $classname ] = $replacedName; + $this->classmap[ $replacedName ] = $file; } } diff --git a/src/Replace/Replacer.php b/src/Replace/Replacer.php index c803ff65..7453970e 100644 --- a/src/Replace/Replacer.php +++ b/src/Replace/Replacer.php @@ -5,5 +5,5 @@ interface Replacer { public function setAutoloader($autoloader); - public function replace($contents); + public function replace($contents, $file); } From 0ce198d379a965ec3ab05fa8bce2a806a5470062 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 9 Apr 2020 20:15:09 -0700 Subject: [PATCH 02/17] Missed some copying and pasting --- src/Replacer.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Replacer.php b/src/Replacer.php index 3f8d8470..465a2e45 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -25,7 +25,10 @@ class Replacer /** @var array */ protected $replacedClasses = []; - /** @var Filesystem */ + /** @var array */ + public $classmap = []; + + /** @var Filesystem */ protected $filesystem; public function __construct($workingDir, $config) @@ -66,6 +69,7 @@ public function replaceInFile($targetFile, $autoloader) if ($replacer instanceof ClassmapReplacer) { $this->replacedClasses = array_merge($this->replacedClasses, $replacer->replacedClasses); + $this->classmap = array_merge($this->classmap, $replacer->classmap); } $this->filesystem->put($targetFile, $contents); From 6e4b3d4f5f4ab201c26ae1edf881851f349d28b7 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 21 May 2020 22:17:59 -0700 Subject: [PATCH 03/17] Missed a merge conflict That never should've happened! --- src/Console/Commands/Compose.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index f5f9b15c..902ee1a4 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -55,13 +55,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->replacer->replaceParentPackage($package, null); } -<<<<<<< HEAD $this->replacer->replaceParentClassesInDirectory( $this->config->classmap_directory ); - -======= + $this->generateClassmapAutoloader(); ->>>>>>> generate-classmap return 0; } From 6883b58abfc23a28203fee4ab9247bbc3630b1a1 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 21 May 2020 22:23:38 -0700 Subject: [PATCH 04/17] Update NamespaceReplacer.php --- src/Replace/NamespaceReplacer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Replace/NamespaceReplacer.php b/src/Replace/NamespaceReplacer.php index 7bdc8b5c..4f92f969 100644 --- a/src/Replace/NamespaceReplacer.php +++ b/src/Replace/NamespaceReplacer.php @@ -7,7 +7,7 @@ class NamespaceReplacer extends BaseReplacer /** @var string */ public $dep_namespace = ''; - public function replace($contents) + public function replace($contents, $file) { $searchNamespace = $this->autoloader->getSearchNamespace(); return preg_replace_callback( From ad44c39a7f683fb936eb27daf700060892f4755b Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 21 May 2020 22:28:17 -0700 Subject: [PATCH 05/17] Update Replacer.php --- src/Replacer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Replacer.php b/src/Replacer.php index 465a2e45..52138239 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -65,7 +65,7 @@ public function replaceInFile($targetFile, $autoloader) } $replacer->setAutoloader($autoloader); - $contents = $replacer->replace($contents); + $contents = $replacer->replace($contents, $targetFile); if ($replacer instanceof ClassmapReplacer) { $this->replacedClasses = array_merge($this->replacedClasses, $replacer->replacedClasses); From 39520428407ed7429016b53bf2f957f7e683feae Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 21 May 2020 23:11:30 -0700 Subject: [PATCH 06/17] classmap_output example in readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 2e8df127..b57a0e79 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ Mozart requires little configuration. All you need to do is tell it where the bu "dep_directory": "/src/Dependencies/", "classmap_directory": "/classes/dependencies/", "classmap_prefix": "CJTP_", + "classmap_output": { + "filename": "src/autoload_classmap.php", + "relative_path": "/src" + }, "packages": [ "pimple/pimple" ], From 8485089b4ef178ba7cb2bcd7bd13576837a52dd8 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 21 May 2020 23:12:34 -0700 Subject: [PATCH 07/17] readdme indentation --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b57a0e79..c15cad89 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ Mozart requires little configuration. All you need to do is tell it where the bu "classmap_directory": "/classes/dependencies/", "classmap_prefix": "CJTP_", "classmap_output": { - "filename": "src/autoload_classmap.php", - "relative_path": "/src" - }, + "filename": "src/autoload_classmap.php", + "relative_path": "/src" + }, "packages": [ "pimple/pimple" ], @@ -39,10 +39,10 @@ Mozart requires little configuration. All you need to do is tell it where the bu } } "delete_vendor_directories": true - "classmap_output": { - "filename": "src/autoload_classmap.php", + "classmap_output": { + "filename": "src/autoload_classmap.php", "relative_path": "/src" - } + } } ``` From 2ac3d14abbc123f3c6d91d0ee0b52f6dd7668415 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Sat, 6 Jun 2020 15:59:38 -0700 Subject: [PATCH 08/17] removed duplicate doc --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 52b56eeb..7578020b 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,7 @@ Mozart requires little configuration. All you need to do is tell it where the bu ] } } - "delete_vendor_directories": true, - "classmap_output": { - "filename": "src/autoload_classmap.php", - "relative_path": "/src" - } + "delete_vendor_directories": true }, ``` From 1cb6b595384fb58b7f9c731cdb88d12370c23b85 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 6 Aug 2020 20:55:52 -0700 Subject: [PATCH 09/17] phpcbf --- src/Console/Commands/Compose.php | 59 ++++++++++++++++---------------- src/Mover.php | 22 ++++++------ src/Replace/ClassmapReplacer.php | 8 ++--- src/Replacer.php | 8 ++--- 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 1c1d17cc..d0fc4ef2 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -81,9 +81,9 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->replacer->replaceParentPackage($package, null); } - $this->replacer->replaceParentClassesInDirectory( $this->config->classmap_directory ); + $this->replacer->replaceParentClassesInDirectory($this->config->classmap_directory); - $this->generateClassmapAutoloader(); + $this->generateClassmapAutoloader(); return 0; } @@ -101,7 +101,7 @@ protected function movePackages($packages) $this->movePackage($package); } - $this->mover->deleteEmptyDirs(); + $this->mover->deleteEmptyDirs(); } /** @@ -182,42 +182,41 @@ private function findPackages($slugs) } - /** - * Write a classmap to file. - */ - private function generateClassmapAutoloader() { - - if (!isset($this->config->classmap_output)) { - return; - } - - $classmap = $this->replacer->classmap; + /** + * Write a classmap to file. + */ + private function generateClassmapAutoloader() + { - if( !isset($this->config->classmap_output->filename)) { - return; - } - $output_filename = $this->config->classmap_output->filename; + if (!isset($this->config->classmap_output)) { + return; + } - $relative_path = isset( $this->config->classmap_output->relative_path ) ? $this->config->classmap_output->relative_path : null; + $classmap = $this->replacer->classmap; - $output = "config->classmap_output->filename)) { + return; + } + $output_filename = $this->config->classmap_output->filename; - $output .= "// autoload_classmap.php @generated by Mozart\n\n"; + $relative_path = isset($this->config->classmap_output->relative_path) ? $this->config->classmap_output->relative_path : null; - $output .= "return array(\n"; + $output = " $filepath) { + $output .= "// autoload_classmap.php @generated by Mozart\n\n"; - if ( !is_null($relative_path) && substr($filepath, 0, strlen($relative_path)) == $relative_path) { - $filepath = substr($filepath, strlen($relative_path)); - } + $output .= "return array(\n"; - $output .= " '{$class}' => '{$filepath}',\n"; - } + foreach ($classmap as $class => $filepath) { + if (!is_null($relative_path) && substr($filepath, 0, strlen($relative_path)) == $relative_path) { + $filepath = substr($filepath, strlen($relative_path)); + } - $output .= ");"; + $output .= " '{$class}' => '{$filepath}',\n"; + } - file_put_contents( $output_filename, $output ); + $output .= ");"; - } + file_put_contents($output_filename, $output); + } } diff --git a/src/Mover.php b/src/Mover.php index 2b9d2bbb..92649b38 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -46,17 +46,17 @@ public function deleteTargetDirs() $this->filesystem->put($this->config->classmap_directory . '/.gitkeep', ''); } - public function deleteEmptyDirs() - { - if(count($this->filesystem->listContents($this->config->dep_directory, true)) === 0) { - $this->filesystem->deleteDir($this->config->dep_directory); - } - - if(count($this->filesystem->listContents($this->config->classmap_directory, true)) === 0) { - $this->filesystem->deleteDir($this->config->classmap_directory); - } - } - + public function deleteEmptyDirs() + { + if (count($this->filesystem->listContents($this->config->dep_directory, true)) === 0) { + $this->filesystem->deleteDir($this->config->dep_directory); + } + + if (count($this->filesystem->listContents($this->config->classmap_directory, true)) === 0) { + $this->filesystem->deleteDir($this->config->classmap_directory); + } + } + public function movePackage(Package $package) { if (in_array($package->config->name, $this->movedPackages)) { diff --git a/src/Replace/ClassmapReplacer.php b/src/Replace/ClassmapReplacer.php index 3c379498..c0f349b9 100644 --- a/src/Replace/ClassmapReplacer.php +++ b/src/Replace/ClassmapReplacer.php @@ -5,10 +5,10 @@ class ClassmapReplacer extends BaseReplacer { /** @var array */ - public $replacedClasses = []; + public $replacedClasses = []; - /** @var array */ - public $classmap = []; + /** @var array */ + public $classmap = []; /** @var string */ public $classmap_prefix; @@ -29,6 +29,6 @@ function ($matches) use ($file) { public function saveReplacedClass($classname, $replacedName, $file) { $this->replacedClasses[ $classname ] = $replacedName; - $this->classmap[ $replacedName ] = $file; + $this->classmap[ $replacedName ] = $file; } } diff --git a/src/Replacer.php b/src/Replacer.php index 8c3df4b1..f6865e31 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -25,10 +25,10 @@ class Replacer /** @var array */ protected $replacedClasses = []; - /** @var array */ - public $classmap = []; + /** @var array */ + public $classmap = []; - /** @var Filesystem */ + /** @var Filesystem */ protected $filesystem; public function __construct($workingDir, $config) @@ -69,7 +69,7 @@ public function replaceInFile($targetFile, $autoloader) if ($replacer instanceof ClassmapReplacer) { $this->replacedClasses = array_merge($this->replacedClasses, $replacer->replacedClasses); - $this->classmap = array_merge($this->classmap, $replacer->classmap); + $this->classmap = array_merge($this->classmap, $replacer->classmap); } $this->filesystem->put($targetFile, $contents); From fe3247120d578e54d19c3cef7498e7edad7822d9 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 6 Aug 2020 21:27:54 -0700 Subject: [PATCH 10/17] undo deleteEmptyDirs merge --- src/Console/Commands/Compose.php | 1 - src/Mover.php | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index d0fc4ef2..3c139794 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -101,7 +101,6 @@ protected function movePackages($packages) $this->movePackage($package); } - $this->mover->deleteEmptyDirs(); } /** diff --git a/src/Mover.php b/src/Mover.php index 92649b38..c3d21ce7 100644 --- a/src/Mover.php +++ b/src/Mover.php @@ -46,17 +46,6 @@ public function deleteTargetDirs() $this->filesystem->put($this->config->classmap_directory . '/.gitkeep', ''); } - public function deleteEmptyDirs() - { - if (count($this->filesystem->listContents($this->config->dep_directory, true)) === 0) { - $this->filesystem->deleteDir($this->config->dep_directory); - } - - if (count($this->filesystem->listContents($this->config->classmap_directory, true)) === 0) { - $this->filesystem->deleteDir($this->config->classmap_directory); - } - } - public function movePackage(Package $package) { if (in_array($package->config->name, $this->movedPackages)) { From 5783434e82e5922a8455a16b07ee1e68934e295c Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 6 Aug 2020 21:28:22 -0700 Subject: [PATCH 11/17] PHPCBF --- src/Console/Commands/Compose.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 3c139794..f3dc28ab 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -100,7 +100,6 @@ protected function movePackages($packages) foreach ($packages as $package) { $this->movePackage($package); } - } /** From c99bec5f5272446645db421f30ce454ae3c2007c Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Thu, 6 Aug 2020 21:36:06 -0700 Subject: [PATCH 12/17] PHPCS --- src/Console/Commands/Compose.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index f3dc28ab..7c57aae8 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -197,7 +197,8 @@ private function generateClassmapAutoloader() } $output_filename = $this->config->classmap_output->filename; - $relative_path = isset($this->config->classmap_output->relative_path) ? $this->config->classmap_output->relative_path : null; + $relative_path = isset($this->config->classmap_output->relative_path) + ? $this->config->classmap_output->relative_path : null; $output = " Date: Thu, 6 Aug 2020 21:38:32 -0700 Subject: [PATCH 13/17] PHPCBF --- src/Console/Commands/Compose.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index 7c57aae8..8e2713a7 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -198,7 +198,7 @@ private function generateClassmapAutoloader() $output_filename = $this->config->classmap_output->filename; $relative_path = isset($this->config->classmap_output->relative_path) - ? $this->config->classmap_output->relative_path : null; + ? $this->config->classmap_output->relative_path : null; $output = " Date: Sat, 6 Feb 2021 18:33:49 -0800 Subject: [PATCH 14/17] vendor/bin/mozart dump-autoload --- README.md | 9 +- composer.json | 1 + src/Console/Application.php | 4 + src/Console/Commands/Compose.php | 40 --------- src/Console/Commands/DumpAutoload.php | 125 ++++++++++++++++++++++++++ src/Replacer.php | 6 +- 6 files changed, 134 insertions(+), 51 deletions(-) create mode 100644 src/Console/Commands/DumpAutoload.php diff --git a/README.md b/README.md index a9632555..a2511dfe 100644 --- a/README.md +++ b/README.md @@ -79,10 +79,6 @@ Mozart requires little configuration. All you need to do is tell it where the bu "dep_directory": "/src/Dependencies/", "classmap_directory": "/classes/dependencies/", "classmap_prefix": "CJTP_", - "classmap_output": { - "filename": "src/autoload_classmap.php", - "relative_path": "/src" - }, "packages": [ "pimple/pimple" ], @@ -114,8 +110,7 @@ The following configuration is optional: - `delete_vendor_directories` is a boolean flag to indicate if the packages' vendor directories should be deleted after being processed. _default: true_. - `packages` is an optional array that defines the packages to be processed by Mozart. The array requires the slugs of packages in the same format as provided in your `composer.json`. Mozart will automatically rewrite dependencies of these packages as well. You don't need to add dependencies of these packages to the list. If this field is absent, all packages listed under composer require will be included. - `exclude_packages` is an optional array that defines the packages to be excluded from the processing performed by Mozart. This is useful if some of the packages in the `packages` array define dependent packages whose namespaces you want to keep unchanged. The array requires the slugs of the packages, as in the case of the `packages` array. -- `override_autoload` a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' `composer.json` `autoload` property. -- `classmap_output` defines the `filename` to write the classmap autoloader to (relative to the directory where `mozart compose` is invoked from) and the `relative_path` to remove from the beginning of each file path. +- `override_autoload` a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' `composer.json` `autoload` property. After Composer has loaded the packages as defined in your `composer.json` file, you can now run `mozart compose` and Mozart will bundle your packages according to the above configuration. It is recommended to dump the autoloader after Mozart has finished running, in case there are new classes or namespaces generated that aren't included in the autoloader yet. @@ -137,6 +132,8 @@ Mozart is designed to install and be forgotten about. Using Composer scripts, th When using Mozart through its Docker container, you can replace the `"\"vendor/bin/mozart\" compose",` lines with the actual commands you use to [run the Docker container](#docker) for your specific project. Running Mozart from inside the Docker container is really fast and shouldn't take more than a couple seconds. +If your plugin does not use Composer's autoloader, classmaps can be generated in the `dep_directory` and `classmap_directory` by running `vendor/bin/mozart dump-autoload` + ## Background and philosophy Mozart is designed to bridge the gap between the WordPress ecosytem and the vast packages ecosystem of PHP as a whole. Since WordPress is such an end-user friendly focussed CMS (for good reasons), there is no place within the ecosystem where an end-user would be burdened with using a developers tool like Composer. Also, since WordPress has to run on basically any hosting infrastructure, running Composer to install packages from the administration panel (trust me, I've tried - it can be done) is a mission impossible to make it happen and compatible with every server out there. diff --git a/composer.json b/composer.json index c97d2253..db7d3efd 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "prefer-stable": true, "license": "MIT", "require": { + "composer/composer": "*", "php": "^7.3|^8.0", "symfony/console": "^4|^5", "symfony/finder": "^4|^5", diff --git a/src/Console/Application.php b/src/Console/Application.php index caa82dd3..75d9323c 100644 --- a/src/Console/Application.php +++ b/src/Console/Application.php @@ -3,6 +3,7 @@ namespace CoenJacobs\Mozart\Console; use CoenJacobs\Mozart\Console\Commands\Compose; +use CoenJacobs\Mozart\Console\Commands\DumpAutoload; use Symfony\Component\Console\Application as BaseApplication; class Application extends BaseApplication @@ -16,5 +17,8 @@ public function __construct($version) $composeCommand = new Compose(); $this->add($composeCommand); + + $dumpAutoloadCommand = new DumpAutoload(); + $this->add($dumpAutoloadCommand); } } diff --git a/src/Console/Commands/Compose.php b/src/Console/Commands/Compose.php index abdbe5b9..c0971f78 100644 --- a/src/Console/Commands/Compose.php +++ b/src/Console/Commands/Compose.php @@ -87,7 +87,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->replacePackages($packages); $this->replaceParentInTree($packages); $this->replacer->replaceParentClassesInDirectory($this->config->classmap_directory); - $this->generateClassmapAutoloader(); return 0; } @@ -198,45 +197,6 @@ private function findPackages(array $slugs): array return $packages; } - /** - * Write a classmap to file. - */ - private function generateClassmapAutoloader() - { - - if (!isset($this->config->classmap_output)) { - return; - } - - $classmap = $this->replacer->classmap; - - if (!isset($this->config->classmap_output->filename)) { - return; - } - $output_filename = $this->config->classmap_output->filename; - - $relative_path = isset($this->config->classmap_output->relative_path) - ? $this->config->classmap_output->relative_path : null; - - $output = " $filepath) { - if (!is_null($relative_path) && substr($filepath, 0, strlen($relative_path)) == $relative_path) { - $filepath = substr($filepath, strlen($relative_path)); - } - - $output .= " '{$class}' => '{$filepath}',\n"; - } - - $output .= ");"; - - file_put_contents($output_filename, $output); - } - /** * Get an array containing all the dependencies and dependencies * @param Package $package diff --git a/src/Console/Commands/DumpAutoload.php b/src/Console/Commands/DumpAutoload.php new file mode 100644 index 00000000..6cc7184b --- /dev/null +++ b/src/Console/Commands/DumpAutoload.php @@ -0,0 +1,125 @@ +setName('dump-autoload'); + $this->setDescription('Generates a classmap from files in the Mozart classmap and dep directories.'); + $this->setHelp(''); + } + + protected function readConfig(): object + { + $workingDir = getcwd(); + + $composerFile = $workingDir . DIRECTORY_SEPARATOR . 'composer.json'; + if (! file_exists($composerFile)) { + throw new Exception('No composer.json found at current directory: ' . $workingDir); + } + + $composer = json_decode(file_get_contents($composerFile)); + // If the json was malformed. + if (! is_object($composer)) { + throw new Exception('Unable to parse composer.json read at: ' . $workingDir); + } + + // 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)) { + throw new Exception('Mozart config not readable in composer.json at extra->mozart'); + } + $config = $composer->extra->mozart; + + $config->dep_namespace = preg_replace("/\\\{2,}$/", "\\", "$config->dep_namespace\\"); + + return $config; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + try { + $this->config = $this->readConfig(); + } catch (Exception $e) { + $output->write($e->getMessage()); + + return 1; + } + + return $this->generateClassmapAutoloader(); + } + + /** + * Write a classmap to file iun each of the classmap_directory and dep_directory. + * + * Uses Composer's `ClassMapGenerator::createMap()` to scan the directories for classes and generate the map. + * + * createMap() returns the full local path, so we then replace the root of the path with a variable. + * + * @see ClassMapGenerator::dump() + * + */ + private function generateClassmapAutoloader(): int + { + + // Hyphen used to match WordPress Coding Standards. + $output_filename = "autoload-classmap.php"; + + $classmap_directory = getcwd() + . DIRECTORY_SEPARATOR + . ltrim($this->config->classmap_directory, DIRECTORY_SEPARATOR); + + $dep_directory = getcwd() + . DIRECTORY_SEPARATOR + . ltrim($this->config->dep_directory, DIRECTORY_SEPARATOR); + + $dirs = array( + $classmap_directory, + $dep_directory + ); + + foreach ($dirs as $dir) { + if (!is_dir($dir)) { + continue; + } + + $dirMap = ClassMapGenerator::createMap($dir); + + $dirname = preg_replace('/[^a-z]/i', '', str_replace(getcwd(), '', $dir)); + + array_walk( + $dirMap, + function (&$filepath, $class) use ($dir, $dirname) { + $filepath = "\${$dirname} . '" + . DIRECTORY_SEPARATOR + . ltrim(str_replace($dir, '', $filepath), DIRECTORY_SEPARATOR) . "'"; + } + ); + + ob_start(); + + echo " $file) { + echo " '{$class}' => {$file},\n"; + } + echo ");"; + + file_put_contents($dir . $output_filename, ob_get_contents()); + } + + return 0; + } +} diff --git a/src/Replacer.php b/src/Replacer.php index 23868a9a..8fb289b6 100644 --- a/src/Replacer.php +++ b/src/Replacer.php @@ -27,9 +27,6 @@ class Replacer /** @var array */ protected $replacedClasses = []; - /** @var array */ - public $classmap = []; - /** @var Filesystem */ protected $filesystem; @@ -77,11 +74,10 @@ public function replaceInFile($targetFile, Autoloader $autoloader): void } $replacer->setAutoloader($autoloader); - $contents = $replacer->replace($contents, $targetFile); + $contents = $replacer->replace($contents); if ($replacer instanceof ClassmapReplacer) { $this->replacedClasses = array_merge($this->replacedClasses, $replacer->replacedClasses); - $this->classmap = array_merge($this->classmap, $replacer->classmap); } $this->filesystem->put($targetFile, $contents); From 7b1c104140182480aa3f502d35c2f1390c919435 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Sat, 6 Feb 2021 18:35:50 -0800 Subject: [PATCH 15/17] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a2511dfe..0a4bb19c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ This package requires PHP 7.3 or higher in order to run the tool. You can use th **Warning:** This package is very experimental and breaking changes are very likely until version 1.0.0 is tagged. Use with caution, always wear a helmet when using this in production environments. ## Installation -Mozart brings its own dependencies to the table and that potentially introduces its own problems (yes, I realise how meta that is, for a package like this). That's why installing Mozart in isolation, either through the Docker container, the available PHAR file or installing Mozart as a global dependency with Composer is prefered. In all cases, the [configuration](#configuration) still needs to be placed in the `composer.json` file of the project iself. +Mozart brings its own dependencies to the table and that potentially introduces its own problems (yes, I realise how meta that is, for a package like this). That's why installing Mozart in isolation, either through the Docker container, the available PHAR file or installing Mozart as a global dependency with Composer is preferred. In all cases, the [configuration](#configuration) still needs to be placed in the `composer.json` file of the project iself. ### Docker Pull the Docker image from the registry: @@ -91,7 +91,7 @@ Mozart requires little configuration. All you need to do is tell it where the bu "src/" ] } - } + }, "delete_vendor_directories": true }, ``` @@ -110,7 +110,7 @@ The following configuration is optional: - `delete_vendor_directories` is a boolean flag to indicate if the packages' vendor directories should be deleted after being processed. _default: true_. - `packages` is an optional array that defines the packages to be processed by Mozart. The array requires the slugs of packages in the same format as provided in your `composer.json`. Mozart will automatically rewrite dependencies of these packages as well. You don't need to add dependencies of these packages to the list. If this field is absent, all packages listed under composer require will be included. - `exclude_packages` is an optional array that defines the packages to be excluded from the processing performed by Mozart. This is useful if some of the packages in the `packages` array define dependent packages whose namespaces you want to keep unchanged. The array requires the slugs of the packages, as in the case of the `packages` array. -- `override_autoload` a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' `composer.json` `autoload` property. +- `override_autoload` a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' `composer.json` `autoload` property. After Composer has loaded the packages as defined in your `composer.json` file, you can now run `mozart compose` and Mozart will bundle your packages according to the above configuration. It is recommended to dump the autoloader after Mozart has finished running, in case there are new classes or namespaces generated that aren't included in the autoloader yet. From b743ce91518a5fb1fad9edf6bccdd35ec371ab77 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Sat, 6 Feb 2021 18:37:01 -0800 Subject: [PATCH 16/17] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0a4bb19c..daa56c25 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ Mozart requires little configuration. All you need to do is tell it where the bu } }, "delete_vendor_directories": true + } }, ``` From ccd025784907c77bebe5bf33e24f8b3639eaa0e7 Mon Sep 17 00:00:00 2001 From: Brian Henry Date: Mon, 15 Feb 2021 17:02:32 -0800 Subject: [PATCH 17/17] Use ob_get_clean() not ob_get_contents() It was printing the entire files' contents in the console. --- src/Console/Commands/DumpAutoload.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Commands/DumpAutoload.php b/src/Console/Commands/DumpAutoload.php index 6cc7184b..96d89469 100644 --- a/src/Console/Commands/DumpAutoload.php +++ b/src/Console/Commands/DumpAutoload.php @@ -117,7 +117,7 @@ function (&$filepath, $class) use ($dir, $dirname) { } echo ");"; - file_put_contents($dir . $output_filename, ob_get_contents()); + file_put_contents($dir . $output_filename, ob_get_clean()); } return 0;