From e0400773f7a7a7d4e5911e81cebdad95d2bb82cb Mon Sep 17 00:00:00 2001 From: Ant Cunningham Date: Tue, 15 Nov 2011 15:46:41 -0500 Subject: [PATCH] Adding support for configurable vendor path in composer.json. --- README.md | 17 ++++++++- bin/composer | 31 ++++++++++----- src/Composer/Autoload/AutoloadGenerator.php | 5 ++- src/Composer/Command/InstallCommand.php | 2 +- .../Installer/InstallationManager.php | 38 ++++++++++++++++++- .../Installer/InstallationManagerTest.php | 23 ++++++++--- 6 files changed, 97 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 7e0b9af62..de8a65a58 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ themselves. To create libraries/packages please read the [guidelines](http://pac } } ``` - + 3. Run Composer: `php composer.phar install` 4. Browse for more packages on [Packagist](http://packagist.org). @@ -46,6 +46,21 @@ in a system wide way. 3. Change into a project directory `cd /path/to/my/project` 4. Use composer as you normally would `composer.phar install` +Configuration +------------- + +Additional options for composer can be configured in `composer.json` by using the `config` section. + +``` json +{ + "config": { + "vendor-dir": "custom/path/for/vendor" + } +} +``` + +* `vendor-dir`: The location to install vendor packages. The location can be supplied as an absolute or relative path but **must** be within the current working directory. + Contributing ------------ diff --git a/bin/composer b/bin/composer index b188aa337..70c9a901b 100755 --- a/bin/composer +++ b/bin/composer @@ -16,7 +16,27 @@ use Composer\Package; use Composer\Json\JsonFile; use Composer\Console\Application as ComposerApplication; -$vendorPath = 'vendor'; +// load Composer configuration +$file = new JsonFile('composer.json'); +if (!$file->exists()) { + echo 'Composer could not find a composer.json file in '.getcwd().PHP_EOL; + echo 'To initialize a project, please create a composer.json file as described on the http://packagist.org/ "Getting Started" section'.PHP_EOL; + exit(1); +} + +// Configuration defaults +$composerConfig = array('vendor-dir' => 'vendor'); + +$packageConfig = $file->read(); + +if (isset($packageConfig['config']) && is_array($packageConfig['config'])) { + $packageConfig['config'] = array_merge($composerConfig, $packageConfig['config']); +} else { + $packageConfig['config'] = $composerConfig; +} + +// easy local access +$vendorPath = $packageConfig['config']['vendor-dir']; // initialize repository manager $rm = new Repository\RepositoryManager(); @@ -33,19 +53,12 @@ $dm->setDownloader('pear', new Downloader\PearDownloader()); $dm->setDownloader('zip', new Downloader\ZipDownloader()); // initialize installation manager -$im = new Installer\InstallationManager(); +$im = new Installer\InstallationManager($vendorPath); $im->addInstaller(new Installer\LibraryInstaller($vendorPath, $dm, $rm->getLocalRepository(), null)); $im->addInstaller(new Installer\InstallerInstaller($vendorPath, $dm, $rm->getLocalRepository(), $im)); // load package $loader = new Package\Loader\ArrayLoader($rm); -$file = new JsonFile('composer.json'); -if (!$file->exists()) { - echo 'Composer could not find a composer.json file in '.getcwd().PHP_EOL; - echo 'To initialize a project, please create a composer.json file as described on the http://packagist.org/ "Getting Started" section'.PHP_EOL; - exit(1); -} -$packageConfig = $file->read(); $package = $loader->load($packageConfig); // load default repository unless it's explicitly disabled diff --git a/src/Composer/Autoload/AutoloadGenerator.php b/src/Composer/Autoload/AutoloadGenerator.php index 88bf58a0f..a95ea66fb 100644 --- a/src/Composer/Autoload/AutoloadGenerator.php +++ b/src/Composer/Autoload/AutoloadGenerator.php @@ -71,12 +71,13 @@ EOF; $packageMap[] = array($mainPackage, ''); $autoloads = $this->parseAutoloads($packageMap); + $vendorPath = $installationManager->getVendorPath(); if (isset($autoloads['psr-0'])) { foreach ($autoloads['psr-0'] as $def) { if (!$this->isAbsolutePath($def['path'])) { - $baseDir = 'dirname(dirname(__DIR__)).'; - $def['path'] = '/'.$def['path']; + $def['path'] = substr($def['path'], strlen($vendorPath)); + $baseDir = "dirname(__DIR__)."; } else { $baseDir = ''; } diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index a632a3255..fa64cbf34 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -154,7 +154,7 @@ EOT $output->writeln('> Generating autoload files'); $generator = new AutoloadGenerator; - $generator->dump($localRepo, $composer->getPackage(), $installationManager, 'vendor/.composer/'); + $generator->dump($localRepo, $composer->getPackage(), $installationManager, $installationManager->getVendorPath().'/.composer'); $output->writeln('> Done'); } diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 4bf207b76..f2d3f5af2 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -28,6 +28,27 @@ class InstallationManager { private $installers = array(); private $cache = array(); + private $vendorPath; + + /** + * Creates an instance of InstallationManager + * + * @param string $vendorPath Relative path to the vendor directory + * @throws \InvalidArgumentException + */ + public function __construct($vendorPath = 'vendor') + { + if (substr($vendorPath, 0, 1) === '/' || substr($vendorPath, 1, 1) === ':') { + $basePath = getcwd(); + if (0 !== strpos($vendorPath, $basePath)) { + throw new \InvalidArgumentException("Vendor path ($vendorPath) must be within the current working directory ($basePath)."); + } + // convert to relative path + $this->vendorPath = substr($vendorPath, strlen($basePath)+1); + } else { + $this->vendorPath = $vendorPath; + } + } /** * Adds installer @@ -150,4 +171,19 @@ class InstallationManager $installer = $this->getInstaller($package->getType()); return $installer->getInstallPath($package); } -} + + /** + * Returns the vendor path + * + * @param boolean $absolute Whether or not to return an absolute path + * @return string path + */ + public function getVendorPath($absolute = false) + { + if (!$absolute) { + return $this->vendorPath; + } + + return getcwd().DIRECTORY_SEPARATOR.$this->vendorPath; + } +} \ No newline at end of file diff --git a/tests/Composer/Test/Installer/InstallationManagerTest.php b/tests/Composer/Test/Installer/InstallationManagerTest.php index 99c2f8bdf..73c547066 100644 --- a/tests/Composer/Test/Installer/InstallationManagerTest.php +++ b/tests/Composer/Test/Installer/InstallationManagerTest.php @@ -30,7 +30,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase return $arg === 'vendor'; })); - $manager = new InstallationManager(); + $manager = new InstallationManager('vendor'); $manager->addInstaller($installer); $this->assertSame($installer, $manager->getInstaller('vendor')); @@ -43,6 +43,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase { $manager = $this->getMockBuilder('Composer\Installer\InstallationManager') ->setMethods(array('install', 'update', 'uninstall')) + ->setConstructorArgs(array('vendor')) ->getMock(); $installOperation = new InstallOperation($this->createPackageMock()); @@ -72,7 +73,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase public function testInstall() { $installer = $this->createInstallerMock(); - $manager = new InstallationManager(); + $manager = new InstallationManager('vendor'); $manager->addInstaller($installer); $package = $this->createPackageMock(); @@ -100,7 +101,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase public function testUpdateWithEqualTypes() { $installer = $this->createInstallerMock(); - $manager = new InstallationManager(); + $manager = new InstallationManager('vendor'); $manager->addInstaller($installer); $initial = $this->createPackageMock(); @@ -134,7 +135,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase { $libInstaller = $this->createInstallerMock(); $bundleInstaller = $this->createInstallerMock(); - $manager = new InstallationManager(); + $manager = new InstallationManager('vendor'); $manager->addInstaller($libInstaller); $manager->addInstaller($bundleInstaller); @@ -180,7 +181,7 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase public function testUninstall() { $installer = $this->createInstallerMock(); - $manager = new InstallationManager(); + $manager = new InstallationManager('vendor'); $manager->addInstaller($installer); $package = $this->createPackageMock(); @@ -205,6 +206,18 @@ class InstallationManagerTest extends \PHPUnit_Framework_TestCase $manager->uninstall($operation); } + public function testGetVendorPathAbsolute() + { + $manager = new InstallationManager('vendor'); + $this->assertEquals(realpath('').DIRECTORY_SEPARATOR.'vendor', $manager->getVendorPath(true)); + } + + public function testGetVendorPathRelative() + { + $manager = new InstallationManager('vendor'); + $this->assertEquals('vendor', $manager->getVendorPath()); + } + private function createInstallerMock() { return $this->getMockBuilder('Composer\Installer\InstallerInterface')