1
0
Fork 0

Add support for list URL in composer repos, fixes #9009

pull/9035/head
Jordi Boggiano 2020-07-01 11:16:18 +02:00
parent 45f228a375
commit 70f211923b
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
3 changed files with 43 additions and 13 deletions

View File

@ -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",` `"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. 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.

View File

@ -299,8 +299,9 @@ EOT
// list packages // list packages
$packages = array(); $packages = array();
$packageFilterRegex = null;
if (null !== $packageFilter) { if (null !== $packageFilter) {
$packageFilter = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i'; $packageFilterRegex = '{^'.str_replace('\\*', '.*?', preg_quote($packageFilter)).'$}i';
} }
$packageListFilter = array(); $packageListFilter = array();
@ -342,10 +343,8 @@ EOT
$type = 'available'; $type = 'available';
} }
if ($repo instanceof ComposerRepository) { if ($repo instanceof ComposerRepository) {
foreach ($repo->getPackageNames() as $name) { foreach ($repo->getPackageNames($packageFilter) as $name) {
if (!$packageFilter || preg_match($packageFilter, $name)) { $packages[$type][$name] = $name;
$packages[$type][$name] = $name;
}
} }
} else { } else {
foreach ($repo->getPackages() as $package) { foreach ($repo->getPackages() as $package) {
@ -353,7 +352,7 @@ EOT
|| !is_object($packages[$type][$package->getName()]) || !is_object($packages[$type][$package->getName()])
|| version_compare($packages[$type][$package->getName()]->getVersion(), $package->getVersion(), '<') || 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)) { if (!$packageListFilter || in_array($package->getName(), $packageListFilter, true)) {
$packages[$type][$package->getName()] = $package; $packages[$type][$package->getName()] = $package;
} }

View File

@ -58,6 +58,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
protected $providersApiUrl; protected $providersApiUrl;
protected $hasProviders = false; protected $hasProviders = false;
protected $providersUrl; protected $providersUrl;
protected $listUrl;
protected $availablePackages; protected $availablePackages;
protected $lazyProvidersUrl; protected $lazyProvidersUrl;
protected $providerListing; protected $providerListing;
@ -288,32 +289,52 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
return parent::getPackages(); 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(); $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 ($this->lazyProvidersUrl) {
if (is_array($this->availablePackages)) { 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()) { if ($this->hasPartialPackages()) {
return array_keys($this->partialPackagesByName); return array_filter(array_keys($this->partialPackagesByName), $packageFilterCb);
} }
return array(); return array();
} }
if ($hasProviders) { if ($hasProviders) {
return $this->getProviderNames(); return array_filter($this->getProviderNames(), $packageFilterCb);
} }
$names = array(); $names = array();
foreach ($this->getPackages() as $package) { foreach ($this->getPackages() as $package) {
$names[] = $package->getPrettyName(); if ($packageFilterCb($package->getName())) {
$names[] = $package->getPrettyName();
}
} }
return $names; return $names;
@ -866,6 +887,10 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
$this->hasProviders = true; $this->hasProviders = true;
} }
if (!empty($data['list'])) {
$this->listUrl = $this->canonicalizeUrl($data['list']);
}
if (!empty($data['providers']) || !empty($data['providers-includes'])) { if (!empty($data['providers']) || !empty($data['providers-includes'])) {
$this->hasProviders = true; $this->hasProviders = true;
} }