diff --git a/doc/composer-schema.json b/doc/composer-schema.json index ecd07840e..750eb85db 100644 --- a/doc/composer-schema.json +++ b/doc/composer-schema.json @@ -13,6 +13,10 @@ "type": "string", "optional": true }, + "installAs": { + "description": "Override install location of package", + "type": "string" + }, "description": { "type": "string", "description": "Package description", @@ -102,6 +106,10 @@ "type": ["object", "array"], "additionalProperties": true, "optional": true + }, + "autoload": { + "type": "object", + "additionalProperties": true } } } diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index cf0c56018..a376d017b 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -108,6 +108,104 @@ EOT } $localRepo->write(); + + $output->writeln('> Generating autoload.php'); + $this->generateAutoload($composer, $installationManager); + $output->writeln('> Done'); } + + private function generateAutoload(\Composer\Composer $composer, + \Composer\Installer\InstallationManager $installationManager) + { + $localRepo = new \Composer\Repository\FilesystemRepository( + new \Composer\Json\JsonFile('.composer/installed.json')); + + $installPaths = array(); + foreach ($localRepo->getPackages() as $package) { + $installPaths[] = array( + $this->getFullPackage($package, $installationManager), + $installationManager->getInstallPath($package) + ); + } + $installPaths[] = array($composer->getPackage(), ''); + + $autoloads = array(); + foreach ($installPaths as $item) { + list($package, $installPath) = $item; + + if (null !== $package->getInstallAs()) { + $installPath = substr($installPath, 0, -strlen('/'.$package->getInstallAs())); + } + + foreach ($package->getAutoload() as $type => $mapping) { + $autoloads[$type] = isset($autoloads[$type]) ? $autoloads[$type] : array(); + $autoloads[$type][] = array( + 'mapping' => $mapping, + 'path' => $installPath, + ); + } + } + + $this->dumpAutoload($autoloads); + } + + private function dumpAutoload(array $autoloads) + { + $file = <<<'EOF' + $path) { + $exportedNamespace = var_export($namespace, true); + $exportedPath = var_export(($def['path'] ? '/'.$def['path'] : '').'/'.$path, true); + $file .= <<registerNamespace($exportedNamespace, dirname(__DIR__).$exportedPath); + +EOF; + } + } + } + + if (isset($autoloads['pear'])) { + foreach ($autoloads['pear'] as $def) { + foreach ($def['mapping'] as $prefix => $path) { + $exportedPrefix = var_export($prefix, true); + $exportedPath = var_export(($def['path'] ? '/'.$def['path'] : '').'/'.$path, true); + $file .= <<registerPrefix($exportedPrefix, dirname(__DIR__).$exportedPath); + +EOF; + } + } + } + + $file .= <<<'EOF' +$loader->register(); + +EOF; + + file_put_contents('.composer/autoload.php', $file); + } + + private function getFullPackage(\Composer\Package\PackageInterface $package, + \Composer\Installer\InstallationManager $installationManager) + { + $path = $installationManager->getInstallPath($package); + + $loader = new \Composer\Package\Loader\JsonLoader(); + $fullPackage = $loader->load(new \Composer\Json\JsonFile($path.'/composer.json')); + + return $fullPackage; + } } diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index e27f1c52e..74f108b25 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -128,4 +128,10 @@ class InstallationManager $installer = $this->getInstaller($operation->getPackage()->getType()); $installer->uninstall($operation->getPackage()); } + + public function getInstallPath(PackageInterface $package) + { + $installer = $this->getInstaller($package->getType()); + return $installer->getInstallPath($package); + } } diff --git a/src/Composer/Installer/InstallerInterface.php b/src/Composer/Installer/InstallerInterface.php index 9fbacbc36..23eab2a8b 100644 --- a/src/Composer/Installer/InstallerInterface.php +++ b/src/Composer/Installer/InstallerInterface.php @@ -54,4 +54,6 @@ interface InstallerInterface * @param PackageInterface $package package instance */ function uninstall(PackageInterface $package); + + function getInstallPath(PackageInterface $package); } diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 251dac945..ae6bf0020 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -78,7 +78,7 @@ class LibraryInstaller implements InstallerInterface */ public function install(PackageInterface $package) { - $downloadPath = $this->directory.DIRECTORY_SEPARATOR.$package->getName(); + $downloadPath = $this->getInstallPath($package); $this->downloadManager->download($package, $downloadPath); $this->repository->addPackage(clone $package); @@ -98,7 +98,7 @@ class LibraryInstaller implements InstallerInterface throw new \InvalidArgumentException('Package is not installed: '.$initial); } - $downloadPath = $this->directory.DIRECTORY_SEPARATOR.$initial->getName(); + $downloadPath = $this->getInstallPath($initial); $this->downloadManager->update($initial, $target, $downloadPath); $this->repository->removePackage($initial); @@ -118,9 +118,18 @@ class LibraryInstaller implements InstallerInterface throw new \InvalidArgumentException('Package is not installed: '.$package); } - $downloadPath = $this->directory.DIRECTORY_SEPARATOR.$package->getName(); + $downloadPath = $this->getInstallPath($package); $this->downloadManager->remove($package, $downloadPath); $this->repository->removePackage($package); } + + public function getInstallPath(PackageInterface $package) + { + if (null === $package->getInstallAs()) { + return ($this->directory ? $this->directory.'/' : '').$package->getName(); + } else { + return ($this->directory ? $this->directory.'/' : '').$package->getInstallAs(); + } + } } diff --git a/src/Composer/Package/Dumper/ArrayDumper.php b/src/Composer/Package/Dumper/ArrayDumper.php index 123d0fa86..4d980f278 100644 --- a/src/Composer/Package/Dumper/ArrayDumper.php +++ b/src/Composer/Package/Dumper/ArrayDumper.php @@ -38,7 +38,9 @@ class ArrayDumper 'provides', 'replaces', 'recommends', - 'suggests' + 'suggests', + 'autoload', + 'installAs', ); $data = array(); diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php index dffd24145..76f83a1a4 100644 --- a/src/Composer/Package/Loader/ArrayLoader.php +++ b/src/Composer/Package/Loader/ArrayLoader.php @@ -46,6 +46,10 @@ class ArrayLoader $package->setType(isset($config['type']) ? $config['type'] : 'library'); + if (isset($config['installAs'])) { + $package->setInstallAs($config['installAs']); + } + if (isset($config['extra'])) { $package->setExtra($config['extra']); } @@ -91,6 +95,10 @@ class ArrayLoader } } + if (isset($config['autoload'])) { + $package->setAutoload($config['autoload']); + } + return $package; } diff --git a/src/Composer/Package/MemoryPackage.php b/src/Composer/Package/MemoryPackage.php index 325403f91..618cb3db8 100644 --- a/src/Composer/Package/MemoryPackage.php +++ b/src/Composer/Package/MemoryPackage.php @@ -20,6 +20,7 @@ namespace Composer\Package; class MemoryPackage extends BasePackage { protected $type; + protected $installAs; protected $installationSource; protected $sourceType; protected $sourceUrl; @@ -39,6 +40,7 @@ class MemoryPackage extends BasePackage protected $replaces = array(); protected $recommends = array(); protected $suggests = array(); + protected $autoload = array(); /** * Creates a new in memory package. @@ -71,6 +73,22 @@ class MemoryPackage extends BasePackage return $this->type ?: 'library'; } + /** + * @param string $installAs + */ + public function setInstallAs($installAs) + { + $this->installAs = $installAs; + } + + /** + * {@inheritDoc} + */ + public function getInstallAs() + { + return $this->installAs; + } + /** * @param array $extra */ @@ -376,4 +394,22 @@ class MemoryPackage extends BasePackage { return $this->suggests; } + + /** + * Set the autoload mapping + * + * @param array $autoload Mapping of autoloading rules + */ + public function setAutoload(array $autoload) + { + $this->autoload = $autoload; + } + + /** + * {@inheritDoc} + */ + public function getAutoload() + { + return $this->autoload; + } } diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index 54750d907..e23340dbc 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -75,6 +75,13 @@ interface PackageInterface */ function getType(); + /** + * Returns the package installAs property + * + * @return string The package installAs + */ + function getInstallAs(); + /** * Returns the package extra data * @@ -209,6 +216,18 @@ interface PackageInterface */ function getSuggests(); + /** + * Returns an associative array of autoloading rules + * + * {"": {""}} + * + * Type is either "psr0" or "pear". Namespaces are mapped to directories + * for autoloading using the type specified. + * + * @return array Mapping of autoloading rules + */ + function getAutoload(); + /** * Stores a reference to the repository that owns the package * diff --git a/src/Composer/Repository/GitRepository.php b/src/Composer/Repository/GitRepository.php index a2780f0d4..cad9e20d7 100644 --- a/src/Composer/Repository/GitRepository.php +++ b/src/Composer/Repository/GitRepository.php @@ -67,6 +67,10 @@ class GitRepository extends ArrayRepository $package->setSourceType('git'); $package->setSourceUrl($this->url); + if (isset($data['installAs'])) { + $package->setInstallAs($data['installAs']); + } + if (isset($data['license'])) { $package->setLicense($data['license']); } @@ -85,6 +89,11 @@ class GitRepository extends ArrayRepository $package->{$method}($this->createLinks($data['name'], $link.'s', $data[$link])); } } + + if (isset($data['autoload'])) { + $package->setAutoload($data['autoload']); + } + $this->addPackage($package); }