├── .gitignore ├── src └── Dflydev │ └── EmbeddedComposer │ ├── Bundle │ ├── DflydevEmbeddedComposerBundle.php │ ├── Command │ │ ├── UpdateCommand.php │ │ ├── InstallCommand.php │ │ └── DumpAutoloadCommand.php │ ├── LICENSE │ └── composer.json │ ├── Core │ ├── EmbeddedComposerAwareInterface.php │ ├── composer.json │ ├── LICENSE │ ├── Script.php │ ├── EmbeddedComposerInterface.php │ ├── EmbeddedComposer.php │ └── EmbeddedComposerBuilder.php │ └── Console │ ├── composer.json │ ├── LICENSE │ └── Command │ ├── DumpAutoloadCommand.php │ ├── InstallCommand.php │ └── UpdateCommand.php ├── LICENSE ├── composer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /src/Dflydev/EmbeddedComposer/*/vendor/ 3 | composer.lock 4 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/DflydevEmbeddedComposerBundle.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class DflydevEmbeddedComposerBundle extends Bundle 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/Command/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class UpdateCommand extends BaseUpdateCommand 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/Command/InstallCommand.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class InstallCommand extends BaseInstallCommand 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/Command/DumpAutoloadCommand.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class DumpAutoloadCommand extends BaseDumpAutoloadCommand 22 | { 23 | } 24 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/EmbeddedComposerAwareInterface.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | interface EmbeddedComposerAwareInterface 20 | { 21 | /** 22 | * Embedded Composer. 23 | * 24 | * @return EmbeddedComposer 25 | */ 26 | public function getEmbeddedComposer(); 27 | } 28 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/embedded-composer-core", 3 | "description": "Embed Composer core", 4 | "keywords": ["embedded", "composer", "extensibility"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Dragonfly Development Inc.", 9 | "email": "info@dflydev.com", 10 | "homepage": "http://dflydev.com" 11 | }, 12 | { 13 | "name": "Beau Simensen", 14 | "email": "beau@dflydev.com", 15 | "homepage": "http://beausimensen.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.3.2", 20 | "composer/composer": "1.0.*@dev", 21 | "seld/jsonlint": "1.*", 22 | 23 | "symfony/console": "~2.3@dev" 24 | }, 25 | "autoload": { 26 | "psr-0": { "Dflydev\\EmbeddedComposer\\Core": "" } 27 | }, 28 | "target-dir": "Dflydev/EmbeddedComposer/Core", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-master": "1.0-dev" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Console/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/embedded-composer-console", 3 | "description": "Embed Composer into a Symfony Console application", 4 | "keywords": ["embedded", "composer", "extensibility", "console"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Dragonfly Development Inc.", 9 | "email": "info@dflydev.com", 10 | "homepage": "http://dflydev.com" 11 | }, 12 | { 13 | "name": "Beau Simensen", 14 | "email": "beau@dflydev.com", 15 | "homepage": "http://beausimensen.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.3.2", 20 | "dflydev/embedded-composer-core": "1.*@dev", 21 | "symfony/console": "~2.3@dev", 22 | 23 | "composer/composer": "@dev" 24 | }, 25 | "autoload": { 26 | "psr-0": { "Dflydev\\EmbeddedComposer\\Console": "" } 27 | }, 28 | "target-dir": "Dflydev/EmbeddedComposer/Console", 29 | "extra": { 30 | "branch-alias": { 31 | "dev-master": "1.0-dev" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Console/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Bundle/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/embedded-composer-bundle", 3 | "description": "Embed Composer as a Symfony Bundle", 4 | "type": "symfony-bundle", 5 | "keywords": ["embedded", "composer", "extensibility", "bundle"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Dragonfly Development Inc.", 10 | "email": "info@dflydev.com", 11 | "homepage": "http://dflydev.com" 12 | }, 13 | { 14 | "name": "Beau Simensen", 15 | "email": "beau@dflydev.com", 16 | "homepage": "http://beausimensen.com" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=5.3.2", 21 | "dflydev/embedded-composer-console": "1.*@dev", 22 | "dflydev/embedded-composer-core": "1.*@dev", 23 | "symfony/http-kernel": "~2.1", 24 | 25 | "composer/composer": "@dev", 26 | "symfony/console": "~2.3@dev" 27 | }, 28 | "autoload": { 29 | "psr-0": { "Dflydev\\EmbeddedComposer\\Bundle": "" } 30 | }, 31 | "target-dir": "Dflydev/EmbeddedComposer/Bundle", 32 | "extra": { 33 | "branch-alias": { 34 | "dev-master": "1.0-dev" 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/Script.php: -------------------------------------------------------------------------------- 1 | 22 | */ 23 | class Script 24 | { 25 | public static function postAutoloadDump(Event $event) 26 | { 27 | $io = $event->getIO(); 28 | $composer = $event->getComposer(); 29 | $package = $composer->getPackage(); 30 | $config = $composer->getConfig(); 31 | $filename = $config->get('vendor-dir').'/dflydev/embedded-composer/.root_package.json'; 32 | $io->write('Adding '.$package->getName().' ('.$package->getPrettyVersion().') to '.$filename); 33 | $jsonFile = new JsonFile($filename); 34 | $repository = new InstalledFilesystemRepository($jsonFile); 35 | $repository->addPackage(clone $package); 36 | $repository->write(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/embedded-composer", 3 | "description": "Embed Composer into another application", 4 | "keywords": ["embedded", "composer", "extensibility"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Dragonfly Development Inc.", 9 | "email": "info@dflydev.com", 10 | "homepage": "http://dflydev.com" 11 | }, 12 | { 13 | "name": "Beau Simensen", 14 | "email": "beau@dflydev.com", 15 | "homepage": "http://beausimensen.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.3.2", 20 | "composer/composer": "^1.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "~3.7.10", 24 | "symfony/console": "~2.3@dev", 25 | "symfony/http-kernel": "~2.1" 26 | }, 27 | "suggest": { 28 | "symfony/console": "~2.3", 29 | "symfony/http-kernel": "~2.1" 30 | }, 31 | "replace": { 32 | "dflydev/embedded-composer-bundle": "self.version", 33 | "dflydev/embedded-composer-console": "self.version", 34 | "dflydev/embedded-composer-core": "self.version" 35 | }, 36 | "autoload": { 37 | "psr-0": { "Dflydev\\EmbeddedComposer": "src" } 38 | }, 39 | "extra": { 40 | "branch-alias": { 41 | "dev-master": "1.0-dev" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/EmbeddedComposerInterface.php: -------------------------------------------------------------------------------- 1 | 21 | */ 22 | interface EmbeddedComposerInterface 23 | { 24 | /** 25 | * Get the active class loader (may be internal or external) 26 | * 27 | * @return mixed 28 | */ 29 | public function getClassLoader(); 30 | 31 | /** 32 | * Find a package by name 33 | * 34 | * @param string $name Package name 35 | * 36 | * @return \Composer\Package\PackageInterface 37 | */ 38 | public function findPackage($name); 39 | 40 | /** 41 | * Process any additional external Composer autoloader definitions 42 | */ 43 | public function processAdditionalAutoloads(); 44 | 45 | /** 46 | * Create a Composer instance 47 | * 48 | * @param IOInterface $io IO 49 | * 50 | * @return \Composer\Composer 51 | */ 52 | public function createComposer(IOInterface $io); 53 | 54 | /** 55 | * Create an Installer instance 56 | * 57 | * @param IOInterface $io 58 | */ 59 | public function createInstaller(IOInterface $io); 60 | 61 | /** 62 | * Get a repository repository representing the external repository and 63 | * the internal repository if it exists. 64 | * 65 | * @return \Composer\Repository\RepositoryInterface 66 | */ 67 | public function getRepository(); 68 | 69 | /** 70 | * Get the external repository 71 | * 72 | * @return \Composer\Repository\RepositoryInterface 73 | */ 74 | public function getExternalRepository(); 75 | 76 | /** 77 | * Get external root directory 78 | * 79 | * @return string 80 | */ 81 | public function getExternalRootDirectory(); 82 | 83 | /** 84 | * Composer configuration 85 | * 86 | * @return \Composer\Config 87 | */ 88 | public function getExternalComposerConfig(); 89 | 90 | /** 91 | * Get the full path to the Composer file to process 92 | * 93 | * @return \Composer\Config 94 | */ 95 | public function getExternalComposerFilename(); 96 | 97 | /** 98 | * Get the internal repository 99 | * 100 | * @return \Composer\Repository\RepositoryInterface 101 | */ 102 | public function getInternalRepository(); 103 | 104 | /** 105 | * Has an internal repository? 106 | * 107 | * @return bool 108 | */ 109 | public function hasInternalRepository(); 110 | } 111 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Console/Command/DumpAutoloadCommand.php: -------------------------------------------------------------------------------- 1 | 27 | * @author Beau Simensen 28 | */ 29 | class DumpAutoloadCommand extends Command 30 | { 31 | public function __construct($commandPrefix = 'composer:') 32 | { 33 | $this->commandPrefix = $commandPrefix; 34 | parent::__construct(); 35 | } 36 | 37 | protected function configure() 38 | { 39 | $fullCommand = $this->commandPrefix.'dump-autoload'; 40 | $this 41 | ->setName($fullCommand) 42 | ->setAliases(array($this->commandPrefix.'dumpautoload')) 43 | ->setDescription('Dumps the autoloader') 44 | ->setDefinition(array( 45 | new InputOption('optimize', 'o', InputOption::VALUE_NONE, 'Optimizes PSR0 packages to be loaded with classmaps too, good for production.'), 46 | )) 47 | ->setHelp(<<${fullCommand} -o command dumps an optimized autoloader. 49 | 50 | EOT 51 | ) 52 | ; 53 | } 54 | 55 | protected function execute(InputInterface $input, OutputInterface $output) 56 | { 57 | if (!($this->getApplication() instanceof EmbeddedComposerAwareInterface)) { 58 | throw new \RuntimeException('Application must be instance of EmbeddedComposerAwareInterface'); 59 | } 60 | 61 | $embeddedComposer = $this->getApplication()->getEmbeddedComposer(); 62 | 63 | $io = new ConsoleIO($input, $output, $this->getApplication()->getHelperSet()); 64 | $composer = $embeddedComposer->createComposer($io); 65 | 66 | $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'dump-autoload', $input, $output); 67 | $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); 68 | 69 | $installationManager = $composer->getInstallationManager(); 70 | $localRepo = $composer->getRepositoryManager()->getLocalRepository(); 71 | $package = $composer->getPackage(); 72 | $config = $composer->getConfig(); 73 | 74 | $composer->getAutoloadGenerator()->dump($config, $localRepo, $package, $installationManager, 'composer', $input->getOption('optimize')); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Console/Command/InstallCommand.php: -------------------------------------------------------------------------------- 1 | 26 | * @author Ryan Weaver 27 | * @author Konstantin Kudryashov 28 | * @author Beau Simensen 29 | */ 30 | class InstallCommand extends Command 31 | { 32 | public function __construct($commandPrefix = 'composer:') 33 | { 34 | $this->commandPrefix = $commandPrefix; 35 | parent::__construct(); 36 | } 37 | 38 | protected function configure() 39 | { 40 | $fullCommand = $this->commandPrefix.'install'; 41 | $this 42 | ->setName($fullCommand) 43 | ->setDescription('Install dependencies') 44 | ->setDefinition(array( 45 | new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), 46 | new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'), 47 | new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'), 48 | new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), 49 | )) 50 | ->setHelp(<<{$fullCommand} command reads a composer.json formatted file. 52 | The file is read from the current directory. And installs its dependencies. 53 | 54 | EOT 55 | ) 56 | ; 57 | } 58 | 59 | protected function execute(InputInterface $input, OutputInterface $output) 60 | { 61 | if (!$this->getApplication() instanceof EmbeddedComposerAwareInterface) { 62 | throw new \RuntimeException('Application must be instance of EmbeddedComposerAwareInterface'); 63 | } 64 | 65 | $embeddedComposer = $this->getApplication()->getEmbeddedComposer(); 66 | 67 | $io = new ConsoleIO($input, $output, $this->getApplication()->getHelperSet()); 68 | $installer = $embeddedComposer->createInstaller($io); 69 | 70 | $installer 71 | ->setDryRun($input->getOption('dry-run')) 72 | ->setVerbose($input->getOption('verbose')) 73 | ->setPreferSource($input->getOption('prefer-source')) 74 | ->setDevMode($input->getOption('dev')) 75 | ->setRunScripts(!$input->getOption('no-scripts')) 76 | ; 77 | 78 | return $installer->run(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Console/Command/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | 27 | * @author Ryan Weaver 28 | * @author Konstantin Kudryashov 29 | * @author Beau Simensen 30 | */ 31 | class UpdateCommand extends Command 32 | { 33 | public function __construct($commandPrefix = 'composer:') 34 | { 35 | $this->commandPrefix = $commandPrefix; 36 | parent::__construct(); 37 | } 38 | 39 | protected function configure() 40 | { 41 | $fullCommand = $this->commandPrefix.'update'; 42 | $this 43 | ->setName($fullCommand) 44 | ->setDescription('Update dependencies') 45 | ->setDefinition(array( 46 | new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'Packages that should be updated, if not provided all packages are.'), 47 | new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'), 48 | new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'), 49 | new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of dev-require packages.'), 50 | new InputOption('no-scripts', null, InputOption::VALUE_NONE, 'Skips the execution of all scripts defined in composer.json file.'), 51 | )) 52 | ->setHelp(<<{$fullCommand} command reads a composer.json formatted file. 54 | The file is read from the current directory. 55 | 56 | To limit the update operation to a few packages, you can list the package(s) 57 | you want to update on the command line: 58 | 59 | {$fullCommand} vendor/package1 foo/mypackage [...] 60 | 61 | EOT 62 | ) 63 | ; 64 | } 65 | 66 | protected function execute(InputInterface $input, OutputInterface $output) 67 | { 68 | if (!($this->getApplication() instanceof EmbeddedComposerAwareInterface)) { 69 | throw new \RuntimeException('Application must be instance of EmbeddedComposerAwareInterface'); 70 | } 71 | 72 | $embeddedComposer = $this->getApplication()->getEmbeddedComposer(); 73 | 74 | $io = new ConsoleIO($input, $output, $this->getApplication()->getHelperSet()); 75 | $installer = $embeddedComposer->createInstaller($io); 76 | 77 | $installer 78 | ->setDryRun($input->getOption('dry-run')) 79 | ->setVerbose($input->getOption('verbose')) 80 | ->setPreferSource($input->getOption('prefer-source')) 81 | ->setDevMode($input->getOption('dev')) 82 | ->setRunScripts(!$input->getOption('no-scripts')) 83 | ->setUpdate(true) 84 | ->setUpdateWhitelist($input->getArgument('packages')) 85 | ; 86 | 87 | return $installer->run(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Embedded Composer 2 | ================= 3 | 4 | Embed [Composer][1] into another application. 5 | 6 | 7 | Installation 8 | ------------ 9 | 10 | Through [Composer][1] as [dflydev/embedded-composer][2]. 11 | 12 | 13 | Why Would I Want To Embed Composer? 14 | ----------------------------------- 15 | 16 | Imagine a console application shipped as a phar. If it is desired for the 17 | application to be extensible based on which directory it is in (say one set 18 | of plugins should be used in one directory but an entirely different set of 19 | plugins used in another directory) one cannot simply define a `composer.json` 20 | in both directories and run `composer install`. 21 | 22 | Why not? Because the application shipped with a specific set of dependencies. 23 | Composer cannot add more dependencies without running the risk of introducing 24 | conflicts. The answer is to embed Composer into the application so that 25 | Composer can merge the dependencies already installed for the application 26 | with the dependencies defined in a specific directory's `composer.json`. 27 | 28 | The end result is a set of dependencies that satisfy the directory specific 29 | requirements while taking into account the dependencies *already installed* 30 | for the console application. 31 | 32 | While this is required for a phar distributed application this technique can 33 | be applied to any globally installed application that needs to be runtime 34 | extensible. 35 | 36 | 37 | Usage 38 | ----- 39 | 40 | ### Basics 41 | 42 | The following is an example `bin/myapp` style script that can be used either 43 | installed via Composer (`vendor/bin/myapp`) or installed globally 44 | (`/usr/local/bin/myapp`). 45 | 46 | #### myapp.php (bin) 47 | 48 | A shared block of code to initialize Embedded Composer from an application. 49 | 50 | ```php 51 | getParameterOption('--project-dir') ?: '.'; 63 | 64 | $embeddedComposerBuilder = new EmbeddedComposerBuilder( 65 | $classLoader, 66 | $projectDir 67 | ); 68 | 69 | $embeddedComposer = $embeddedComposerBuilder 70 | ->setComposerFilename('myapp.json') 71 | ->setVendorDirectory('.myapp') 72 | ->build(); 73 | 74 | $embeddedComposer->processAdditionalAutoloads(); 75 | 76 | // application is now ready to be run taking both the embedded 77 | // dependencies and directory specific dependencies into account. 78 | ``` 79 | 80 | 81 | #### myapp (bin) 82 | 83 | Example bin script (`bin/myapp`) that requires the shared block of code 84 | after it locates the correct autoloader. 85 | 86 | ```php 87 | #!/usr/bin/env php 88 | findPackage('acme/myapp'); 136 | ``` 137 | 138 | Composer does not currently install the root package in the `installed.json` 139 | that represents the local repository. There is a PR out for this to be added 140 | to Composer core but until then the following workaround can be used. 141 | 142 | Add the following `post-autoload-dump` script to the root package's 143 | `composer.json`: 144 | 145 | ```json 146 | { 147 | "scripts": { 148 | "post-autoload-dump": "Dflydev\\EmbeddedComposer\\Core\\Script::postAutoloadDump" 149 | } 150 | } 151 | ``` 152 | 153 | This will write an additional repository to 154 | `vendor/dflydev/embedded-composer/.root_package.json` and Embedded Composer 155 | will automatically use it if it can be found. It is important to ensure 156 | that this file is a part of any phar built if the root package needs to be 157 | included in the distribution. 158 | 159 | 160 | #### Create a Composer Installer instance 161 | 162 | The Installer instance is suitable for processing `install` and `update` 163 | operations against the external configuration. It will take the internal 164 | (embedded) configuration into account when solving dependencies. 165 | 166 | ```php 167 | createInstaller($io); 170 | ``` 171 | 172 | #### Create a vanilla Composer instance 173 | 174 | ```php 175 | createComposer($io); 178 | ``` 179 | 180 | 181 | License 182 | ------- 183 | 184 | MIT, see LICENSE. 185 | 186 | 187 | Community 188 | --------- 189 | 190 | If you have questions or want to help out, join us in the **#dflydev** channel 191 | on **irc.freenode.net**. 192 | 193 | 194 | Not Invented Here 195 | ----------------- 196 | 197 | Much of the work here has been supported by the Composer team and many 198 | people in `#composer-dev`. 199 | 200 | The actual code started its life as a part of [Sculpin][3] and was spun 201 | out into a standalone project. 202 | 203 | 204 | [1]: http://getcomposer.org 205 | [2]: https://packagist.org/packages/dflydev/embedded-composer 206 | [3]: https://sculpin.io 207 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/EmbeddedComposer.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | class EmbeddedComposer implements EmbeddedComposerInterface 28 | { 29 | private $classLoader; 30 | private $externalRootDirectory; 31 | private $internalVendorDirectory; 32 | private $hasInternalRepository = false; 33 | 34 | private $repository; 35 | 36 | private $externalRepository; 37 | private $externalComposerConfig; 38 | private $externalComposerFilename; 39 | private $externalVendorDirectory; 40 | private $externalVendorDirectoryOverride = false; 41 | 42 | private $internalRepository; 43 | 44 | /** 45 | * Constructor. 46 | * 47 | * @param ClassLoader $classLoader 48 | * @param string $externalRootDirectory 49 | * @param RepositoryInterface $externalRepository, 50 | * @param string $externalComposerFilename, 51 | * @param Config $externalComposerConfig, 52 | * @param string $externalVendorDirectory, 53 | * @param bool $externalVendorDirectoryOverride, 54 | * @param RepositoryInterface $internalRepository, 55 | * @param string $internalVendorDirectory, 56 | * @param bool $hasInternalRepository, 57 | * @param RepositoryInterface $repository 58 | */ 59 | public function __construct( 60 | ClassLoader $classLoader, 61 | $externalRootDirectory, 62 | RepositoryInterface $externalRepository, 63 | $externalComposerFilename, 64 | Config $externalComposerConfig, 65 | $externalVendorDirectory, 66 | $externalVendorDirectoryOverride, 67 | RepositoryInterface $internalRepository, 68 | $internalVendorDirectory, 69 | $hasInternalRepository, 70 | RepositoryInterface $repository 71 | ) { 72 | $this->classLoader = $classLoader; 73 | $this->externalRootDirectory = $externalRootDirectory; 74 | $this->externalRepository = $externalRepository; 75 | $this->externalComposerFilename = $externalComposerFilename; 76 | $this->externalComposerConfig = $externalComposerConfig; 77 | $this->externalVendorDirectory = $externalVendorDirectory; 78 | $this->externalVendorDirectoryOverride = $externalVendorDirectoryOverride; 79 | $this->internalRepository = $internalRepository; 80 | $this->internalVendorDirectory = $internalVendorDirectory; 81 | $this->hasInternalRepository = $hasInternalRepository; 82 | $this->repository = $repository; 83 | } 84 | 85 | /** 86 | * {@inheritdoc} 87 | */ 88 | public function getClassLoader() 89 | { 90 | return $this->classLoader; 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | public function findPackage($name) 97 | { 98 | $package = null; 99 | 100 | $foundPackages = $this->repository->findPackages($name); 101 | foreach ($foundPackages as $foundPackage) { 102 | if (null === $package || $foundPackage instanceof AliasPackage) { 103 | $package = $foundPackage; 104 | } 105 | } 106 | 107 | return $package; 108 | } 109 | 110 | /** 111 | * {@inheritdoc} 112 | */ 113 | public function processAdditionalAutoloads() 114 | { 115 | if ($this->hasInternalRepository) { 116 | $externalAutoload = $this->externalVendorDirectory.'/autoload.php'; 117 | if (is_readable($externalAutoload)) { 118 | $this->classLoader->unregister(); 119 | include $externalAutoload; 120 | $this->classLoader->register(true); 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | */ 128 | public function createComposer(IOInterface $io) 129 | { 130 | if (! $this->externalVendorDirectoryOverride) { 131 | $originalComposerVendorDir = getenv('COMPOSER_VENDOR_DIR'); 132 | putenv('COMPOSER_VENDOR_DIR='.$this->externalVendorDirectory); 133 | } 134 | 135 | $composer = Factory::create($io, $this->externalComposerFilename); 136 | 137 | if (! $this->externalVendorDirectoryOverride) { 138 | if (false !== $originalComposerVendorDir) { 139 | putenv('COMPOSER_VENDOR_DIR='.$originalComposerVendorDir); 140 | } 141 | } 142 | 143 | return $composer; 144 | } 145 | 146 | /** 147 | * {@inheritdoc} 148 | */ 149 | public function createInstaller(IOInterface $io) 150 | { 151 | $composer = $this->createComposer($io); 152 | $installer = Installer::create($io, $composer); 153 | 154 | if ($this->hasInternalRepository) { 155 | $installer->setAdditionalInstalledRepository( 156 | $this->internalRepository 157 | ); 158 | $pluginManager = $composer->getPluginManager(); 159 | 160 | foreach ($this->internalRepository->getPackages() as $package) { 161 | if ($package instanceof AliasPackage || 'composer-plugin' !== $package->getType()) { 162 | continue; 163 | } 164 | 165 | $pluginManager->registerPackage($package); 166 | } 167 | } 168 | 169 | return $installer; 170 | } 171 | 172 | /** 173 | * {@inheritdoc} 174 | */ 175 | public function getRepository() 176 | { 177 | return $this->repository; 178 | } 179 | 180 | /** 181 | * {@inheritdoc} 182 | */ 183 | public function getExternalRepository() 184 | { 185 | return $this->externalRepository; 186 | } 187 | 188 | /** 189 | * {@inheritdoc} 190 | */ 191 | public function getExternalRootDirectory() 192 | { 193 | return $this->externalRootDirectory; 194 | } 195 | 196 | /** 197 | * {@inheritdoc} 198 | */ 199 | public function getExternalComposerConfig() 200 | { 201 | return $this->externalComposerConfig; 202 | } 203 | 204 | /** 205 | * {@inheritdoc} 206 | */ 207 | public function getExternalComposerFilename() 208 | { 209 | return $this->externalComposerFilename; 210 | } 211 | 212 | /** 213 | * {@inheritdoc} 214 | */ 215 | public function getInternalRepository() 216 | { 217 | return $this->internalRepository; 218 | } 219 | 220 | /** 221 | * {@inheritdoc} 222 | */ 223 | public function hasInternalRepository() 224 | { 225 | return $this->hasInternalRepository; 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/Dflydev/EmbeddedComposer/Core/EmbeddedComposerBuilder.php: -------------------------------------------------------------------------------- 1 | 26 | */ 27 | class EmbeddedComposerBuilder 28 | { 29 | private $classLoader; 30 | private $externalRootDirectory; 31 | private $internalVendorDirectory; 32 | private $hasInternalRepository = false; 33 | 34 | private $composerFilename; 35 | private $vendorDirectory; 36 | private $error = null; 37 | 38 | /** 39 | * Constructor. 40 | * 41 | * @param ClassLoader $classLoader Class loader 42 | * @param string $externalRootDirectory External root directory 43 | */ 44 | public function __construct(ClassLoader $classLoader, $externalRootDirectory = null) 45 | { 46 | $this->classLoader = $classLoader; 47 | $this->externalRootDirectory = $externalRootDirectory ?: getcwd(); 48 | 49 | $obj = new \ReflectionClass($classLoader); 50 | $this->internalVendorDirectory = dirname(dirname($obj->getFileName())); 51 | 52 | if (0 === strpos($this->internalVendorDirectory, 'phar://') || 53 | false === strpos($this->internalVendorDirectory, $this->externalRootDirectory)) { 54 | // If our vendor root does not contain our project root then we 55 | // can assume that we have an internal repository. 56 | $this->hasInternalRepository = true; 57 | } 58 | } 59 | 60 | /** 61 | * Set the name of the composer file 62 | * 63 | * Will default to \Composer\Factory::getComposerFile() if not 64 | * specified. 65 | * 66 | * @param string $composerFilename Composer filename 67 | * 68 | * @return EmbeddedComposerBuilder 69 | */ 70 | public function setComposerFilename($composerFilename) 71 | { 72 | $this->composerFilename = $composerFilename; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Set the vendor directory 79 | * 80 | * Will default to \Composer\Config::get('vendor-dir') if not 81 | * specified. 82 | * 83 | * @param string $vendorDirectory Vendor directory 84 | * 85 | * @return EmbeddedComposerBuilder 86 | */ 87 | public function setVendorDirectory($vendorDirectory) 88 | { 89 | $this->vendorDirectory = $vendorDirectory; 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * Build 96 | * 97 | * @return EmbeddedComposerInterface 98 | */ 99 | public function build() 100 | { 101 | $externalVendorDirectoryOverride = false; 102 | 103 | // 104 | // External Composer Filename 105 | // 106 | 107 | if ($this->hasInternalRepository) { 108 | $externalComposerFilename = $this->composerFilename ?: Factory::getComposerFile(); 109 | } else { 110 | $externalComposerFilename = Factory::getComposerFile(); 111 | } 112 | 113 | $pristineExternalComposerFilename = $externalComposerFilename; 114 | 115 | if (0 !== strpos($externalComposerFilename, '/') && 1 !== strpos($externalComposerFilename, ':')) { 116 | $externalComposerFilename = $this->externalRootDirectory.'/'.$externalComposerFilename; 117 | } 118 | 119 | 120 | // 121 | // External Composer Config 122 | // 123 | 124 | $externalComposerConfig = Factory::createConfig(); 125 | 126 | $configJsonFile = new JsonFile($externalComposerFilename); 127 | 128 | if ($configJsonFile->exists()) { 129 | try { 130 | $configJsonFile->validateSchema(JsonFile::LAX_SCHEMA); 131 | $localConfig = $configJsonFile->read(); 132 | if (isset($localConfig['config']['vendor-dir'])) { 133 | $externalVendorDirectoryOverride = true; 134 | } 135 | $externalComposerConfig->merge($localConfig); 136 | } catch (ParsingException $e) { 137 | $this->error = $e; 138 | } 139 | } else { 140 | if ($pristineExternalComposerFilename === 'composer.json') { 141 | $message = 'Composer could not find a composer.json file in '.realpath($this->externalRootDirectory); 142 | } else { 143 | $message = 'Composer could not find the config file: '.$externalComposerFilename; 144 | } 145 | $instructions = 'To initialize a project, please create a '. 146 | $pristineExternalComposerFilename. 147 | ' file as described in the http://getcomposer.org/ "Getting Started" section'; 148 | 149 | $this->error = new \InvalidArgumentException($message.PHP_EOL.$instructions); 150 | } 151 | 152 | // 153 | // External Vendor Directory 154 | // 155 | 156 | if ($this->hasInternalRepository) { 157 | $externalVendorDirectory = ($externalVendorDirectoryOverride || ! $this->vendorDirectory) 158 | ? $externalComposerConfig->get('vendor-dir') 159 | : $this->vendorDirectory; 160 | } else { 161 | $externalVendorDirectory = $externalComposerConfig->get('vendor-dir'); 162 | } 163 | 164 | if (0 !== strpos($externalVendorDirectory, '/') && 1 !== strpos($externalVendorDirectory, ':')) { 165 | $externalVendorDirectory = $this->externalRootDirectory.'/'.$externalVendorDirectory; 166 | } 167 | 168 | 169 | // 170 | // External Repository 171 | // 172 | 173 | $externalRepository = new InstalledFilesystemRepository( 174 | new JsonFile($externalVendorDirectory.'/composer/installed.json') 175 | ); 176 | 177 | 178 | // 179 | // Internal Repository 180 | // 181 | 182 | $internalRepository = new CompositeRepository(array()); 183 | 184 | if ($this->hasInternalRepository) { 185 | $internalInstalledRepository = new InstalledFilesystemRepository( 186 | new JsonFile( 187 | $this->internalVendorDirectory.'/composer/installed.json' 188 | ) 189 | ); 190 | 191 | $internalRepository->addRepository($internalInstalledRepository); 192 | } 193 | 194 | $rootPackageFilename = $this->internalVendorDirectory.'/dflydev/embedded-composer/.root_package.json'; 195 | if (file_exists($rootPackageFilename)) { 196 | $rootPackageRepository = new InstalledFilesystemRepository( 197 | new JsonFile($rootPackageFilename) 198 | ); 199 | 200 | $internalRepository->addRepository($rootPackageRepository); 201 | } 202 | 203 | 204 | // 205 | // Repository 206 | // 207 | 208 | $repository = new CompositeRepository(array( 209 | $externalRepository, 210 | $internalRepository 211 | )); 212 | 213 | 214 | return new EmbeddedComposer( 215 | $this->classLoader, 216 | $this->externalRootDirectory, 217 | $externalRepository, 218 | $externalComposerFilename, 219 | $externalComposerConfig, 220 | $externalVendorDirectory, 221 | $externalVendorDirectoryOverride, 222 | $internalRepository, 223 | $this->internalVendorDirectory, 224 | $this->hasInternalRepository, 225 | $repository 226 | ); 227 | } 228 | } 229 | --------------------------------------------------------------------------------