diff --git a/doc/05-repositories.md b/doc/05-repositories.md index a9e1c98e1..9308e1279 100644 --- a/doc/05-repositories.md +++ b/doc/05-repositories.md @@ -639,6 +639,9 @@ file, you can use the following configuration: } ``` +> **Note:** Repository paths can also contain wildcards like ``*`` and ``?``. +> For details, see the [PHP glob function](http://php.net/glob). + ## Disabling Packagist You can disable the default Packagist repository by adding this to your diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php index 8e0b2edca..a76a2e052 100644 --- a/src/Composer/Repository/PathRepository.php +++ b/src/Composer/Repository/PathRepository.php @@ -38,6 +38,10 @@ use Composer\Util\ProcessExecutor; * { * "type": "path", * "url": "/absolute/path/to/package/" + * }, + * { + * "type": "path", + * "url": "/absolute/path/to/several/packages/*" * } * ] * @endcode @@ -97,36 +101,45 @@ class PathRepository extends ArrayRepository { parent::initialize(); - $path = $this->getPath(); - $composerFilePath = $path.'composer.json'; - if (!file_exists($composerFilePath)) { - throw new \RuntimeException(sprintf('No `composer.json` file found in path repository "%s"', $path)); + foreach ($this->getPaths() as $path) { + $path = realpath($path) . '/'; + + $composerFilePath = $path.'composer.json'; + if (!file_exists($composerFilePath)) { + continue; + } + + $json = file_get_contents($composerFilePath); + $package = JsonFile::parseJson($json, $composerFilePath); + $package['dist'] = array( + 'type' => 'path', + 'url' => $path, + 'reference' => '', + ); + + if (!isset($package['version'])) { + $package['version'] = $this->versionGuesser->guessVersion($package, $path) ?: 'dev-master'; + } + if (is_dir($path.'/.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) { + $package['dist']['reference'] = trim($output); + } + + $package = $this->loader->load($package); + $this->addPackage($package); } - $json = file_get_contents($composerFilePath); - $package = JsonFile::parseJson($json, $composerFilePath); - $package['dist'] = array( - 'type' => 'path', - 'url' => $this->url, - 'reference' => '', - ); - - if (!isset($package['version'])) { - $package['version'] = $this->versionGuesser->guessVersion($package, $path) ?: 'dev-master'; + if (count($this->getPackages()) == 0) { + throw new \RuntimeException(sprintf('No `composer.json` file found in any path repository in "%s"', $this->url)); } - if (is_dir($path.'/.git') && 0 === $this->process->execute('git log -n1 --pretty=%H', $output, $path)) { - $package['dist']['reference'] = trim($output); - } - - $package = $this->loader->load($package); - $this->addPackage($package); } /** - * @return string + * Get a list of all path names matching given url (supports globbing). + * + * @return string[] */ - private function getPath() + private function getPaths() { - return realpath(rtrim($this->url, '/')) . '/'; + return glob($this->url, GLOB_MARK|GLOB_ONLYDIR); } } diff --git a/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json index fa853d690..985b89947 100644 --- a/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json +++ b/tests/Composer/Test/Repository/Fixtures/path/with-version/composer.json @@ -1,4 +1,4 @@ { - "name": "test/path", + "name": "test/path-versioned", "version": "0.0.2" } \ No newline at end of file diff --git a/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json b/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json index 2fcbad12a..cddefceb2 100644 --- a/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json +++ b/tests/Composer/Test/Repository/Fixtures/path/without-version/composer.json @@ -1,3 +1,3 @@ { - "name": "test/path" + "name": "test/path-unversioned" } \ No newline at end of file diff --git a/tests/Composer/Test/Repository/PathRepositoryTest.php b/tests/Composer/Test/Repository/PathRepositoryTest.php index fb64e458b..03ad46fea 100644 --- a/tests/Composer/Test/Repository/PathRepositoryTest.php +++ b/tests/Composer/Test/Repository/PathRepositoryTest.php @@ -35,7 +35,7 @@ class PathRepositoryTest extends TestCase $repository->getPackages(); $this->assertEquals(1, $repository->count()); - $this->assertTrue($repository->hasPackage($this->getPackage('test/path', '0.0.2'))); + $this->assertTrue($repository->hasPackage($this->getPackage('test/path-versioned', '0.0.2'))); } public function testLoadPackageFromFileSystemWithoutVersion() @@ -54,9 +54,31 @@ class PathRepositoryTest extends TestCase $this->assertEquals(1, $repository->count()); $package = $packages[0]; - $this->assertEquals('test/path', $package->getName()); + $this->assertEquals('test/path-unversioned', $package->getName()); $packageVersion = $package->getVersion(); $this->assertTrue(!empty($packageVersion)); } + + public function testLoadPackageFromFileSystemWithWildcard() + { + $ioInterface = $this->getMockBuilder('Composer\IO\IOInterface') + ->getMock(); + + $config = new \Composer\Config(); + $loader = new ArrayLoader(new VersionParser()); + $versionGuesser = null; + + $repositoryUrl = implode(DIRECTORY_SEPARATOR, array(__DIR__, 'Fixtures', 'path', '*')); + $repository = new PathRepository(array('url' => $repositoryUrl), $ioInterface, $config, $loader); + $packages = $repository->getPackages(); + + $this->assertEquals(2, $repository->count()); + + $package = $packages[0]; + $this->assertEquals('test/path-versioned', $package->getName()); + + $package = $packages[1]; + $this->assertEquals('test/path-unversioned', $package->getName()); + } }