diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index ff6e6c597..fa2b176f4 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -74,3 +74,9 @@ If your repository only has a small number of packages, and you want to avoid th `"providers-api": "https://packagist.org/providers/%package%.json",` The providers-api is optional, but if you implement it it should return packages which provide a given package name, but not the package which has that name. For example https://packagist.org/providers/monolog/monolog.json lists some package which have a "provide" rule for monolog/monolog, but it does not list monolog/monolog itself. + +### list + +This is also optional, it should accept an optional `?filter=xx` query param, which can contain `*` as wildcards matching any substring. + +It must return an array of package names as `{"packageNames": ["a/b", "c/d"]}`. See https://packagist.org/packages/list.json?filter=composer/* for example. diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index b928765f9..c39aba760 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -299,8 +299,9 @@ EOT // list packages $packages = array(); + $packageFilterRegex = null; if (null !== $packageFilter) { - $packageFilter = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i'; + $packageFilterRegex = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i'; } $packageListFilter = array(); @@ -342,10 +343,8 @@ EOT $type = 'available'; } if ($repo instanceof ComposerRepository) { - foreach ($repo->getPackageNames() as $name) { - if (!$packageFilter || preg_match($packageFilter, $name)) { - $packages[$type][$name] = $name; - } + foreach ($repo->getPackageNames($packageFilter) as $name) { + $packages[$type][$name] = $name; } } else { foreach ($repo->getPackages() as $package) { @@ -353,7 +352,7 @@ EOT || !is_object($packages[$type][$package->getName()]) || version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<') ) { - if (!$packageFilter || preg_match($packageFilter, $package->getName())) { + if (!$packageFilterRegex || preg_match($packageFilterRegex, $package->getName())) { if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) { $packages[$type][$package->getName()] = $package; } diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index f7711390f..941cf08dd 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -58,6 +58,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito protected $providersApiUrl; protected $hasProviders = false; protected $providersUrl; + protected $listUrl; protected $availablePackages; protected $lazyProvidersUrl; protected $providerListing; @@ -288,32 +289,52 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito return parent::getPackages(); } - public function getPackageNames() + public function getPackageNames($packageFilter = null) { - // TODO add getPackageNames to the RepositoryInterface perhaps? With filtering capability embedded? $hasProviders = $this->hasProviders(); + $packageFilterCb = function ($name) { + return true; + }; + if (null !== $packageFilter) { + $packageFilterRegex = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i'; + $packageFilterCb = function ($name) use ($packageFilterRegex) { + return (bool) preg_match($packageFilterRegex, $name); + }; + } + if ($this->lazyProvidersUrl) { if (is_array($this->availablePackages)) { - return array_keys($this->availablePackages); + return array_filter(array_keys($this->availablePackages), $packageFilterCb); } - // TODO implement new list API endpoint for those repos somehow? + if ($this->listUrl) { + $url = $this->listUrl; + if ($packageFilter) { + $url .= '?filter='.urlencode($packageFilter); + } + + $result = $this->httpDownloader->get($url, $this->options)->decodeJson(); + + return $result['packageNames']; + } if ($this->hasPartialPackages()) { - return array_keys($this->partialPackagesByName); + return array_filter(array_keys($this->partialPackagesByName), $packageFilterCb); } return array(); } if ($hasProviders) { - return $this->getProviderNames(); + return array_filter($this->getProviderNames(), $packageFilterCb); } $names = array(); foreach ($this->getPackages() as $package) { - $names[] = $package->getPrettyName(); + if ($packageFilterCb($package->getName())) { + $names[] = $package->getPrettyName(); + } } return $names; @@ -866,6 +887,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito $this->hasProviders = true; } + if (!empty($data['list'])) { + $this->listUrl = $this->canonicalizeUrl($data['list']); + } + if (!empty($data['providers']) || !empty($data['providers-includes'])) { $this->hasProviders = true; }