├── EmbeddedComposerAwareInterface.php ├── composer.json ├── LICENSE ├── Script.php ├── EmbeddedComposerInterface.php ├── EmbeddedComposer.php └── EmbeddedComposerBuilder.php /EmbeddedComposerAwareInterface.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | interface EmbeddedComposerAwareInterface 20 | { 21 | /** 22 | * Embedded Composer. 23 | * 24 | * @return EmbeddedComposer 25 | */ 26 | public function getEmbeddedComposer(); 27 | } 28 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 159 | $composer->getPluginManager()->loadRepository( 160 | $this->internalRepository 161 | ); 162 | } 163 | 164 | return $installer; 165 | } 166 | 167 | /** 168 | * {@inheritdoc} 169 | */ 170 | public function getRepository() 171 | { 172 | return $this->repository; 173 | } 174 | 175 | /** 176 | * {@inheritdoc} 177 | */ 178 | public function getExternalRepository() 179 | { 180 | return $this->externalRepository; 181 | } 182 | 183 | /** 184 | * {@inheritdoc} 185 | */ 186 | public function getExternalRootDirectory() 187 | { 188 | return $this->externalRootDirectory; 189 | } 190 | 191 | /** 192 | * {@inheritdoc} 193 | */ 194 | public function getExternalComposerConfig() 195 | { 196 | return $this->externalComposerConfig; 197 | } 198 | 199 | /** 200 | * {@inheritdoc} 201 | */ 202 | public function getExternalComposerFilename() 203 | { 204 | return $this->externalComposerFilename; 205 | } 206 | 207 | /** 208 | * {@inheritdoc} 209 | */ 210 | public function getInternalRepository() 211 | { 212 | return $this->internalRepository; 213 | } 214 | 215 | /** 216 | * {@inheritdoc} 217 | */ 218 | public function hasInternalRepository() 219 | { 220 | return $this->hasInternalRepository; 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /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, '/')) { 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, '/')) { 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 | --------------------------------------------------------------------------------