1
0
Fork 0

Optimize show -a by loading only the requested package (#11659)

Fixes #11648
pull/11670/head
Jordi Boggiano 2023-09-27 11:28:33 +02:00 committed by GitHub
parent c7e696dbde
commit 892eaacedf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 13 deletions

View File

@ -102,11 +102,21 @@ class PoolBuilder
* @var BasePackage[] * @var BasePackage[]
*/ */
private $unacceptableFixedOrLockedPackages = []; private $unacceptableFixedOrLockedPackages = [];
/** @var string[] */ /** @var array<string> */
private $updateAllowList = []; private $updateAllowList = [];
/** @var array<string, array<PackageInterface>> */ /** @var array<string, array<PackageInterface>> */
private $skippedLoad = []; private $skippedLoad = [];
/**
* If provided, only these package names are loaded
*
* This is a special-use functionality of the Request class to optimize the pool creation process
* when only a minimal subset of packages is needed and we do not need their dependencies.
*
* @var array<string, int>|null
*/
private $restrictedPackagesList = null;
/** /**
* Keeps a list of dependencies which are locked but were auto-unlocked as they are path repositories * Keeps a list of dependencies which are locked but were auto-unlocked as they are path repositories
* *
@ -165,6 +175,8 @@ class PoolBuilder
*/ */
public function buildPool(array $repositories, Request $request): Pool public function buildPool(array $repositories, Request $request): Pool
{ {
$this->restrictedPackagesList = $request->getRestrictedPackages() !== null ? array_flip($request->getRestrictedPackages()) : null;
if ($request->getUpdateAllowList()) { if ($request->getUpdateAllowList()) {
$this->updateAllowList = $request->getUpdateAllowList(); $this->updateAllowList = $request->getUpdateAllowList();
$this->warnAboutNonMatchingUpdateAllowList($request); $this->warnAboutNonMatchingUpdateAllowList($request);
@ -366,6 +378,10 @@ class PoolBuilder
private function loadPackagesMarkedForLoading(Request $request, array $repositories): void private function loadPackagesMarkedForLoading(Request $request, array $repositories): void
{ {
foreach ($this->packagesToLoad as $name => $constraint) { foreach ($this->packagesToLoad as $name => $constraint) {
if ($this->restrictedPackagesList !== null && !isset($this->restrictedPackagesList[$name])) {
unset($this->packagesToLoad[$name]);
continue;
}
$this->loadedPackages[$name] = $constraint; $this->loadedPackages[$name] = $constraint;
} }
@ -559,7 +575,7 @@ class PoolBuilder
*/ */
private function isUpdateAllowed(BasePackage $package): bool private function isUpdateAllowed(BasePackage $package): bool
{ {
foreach ($this->updateAllowList as $pattern => $void) { foreach ($this->updateAllowList as $pattern) {
$patternRegexp = BasePackage::packageNameToRegexp($pattern); $patternRegexp = BasePackage::packageNameToRegexp($pattern);
if (Preg::isMatch($patternRegexp, $package->getName())) { if (Preg::isMatch($patternRegexp, $package->getName())) {
return true; return true;
@ -571,7 +587,7 @@ class PoolBuilder
private function warnAboutNonMatchingUpdateAllowList(Request $request): void private function warnAboutNonMatchingUpdateAllowList(Request $request): void
{ {
foreach ($this->updateAllowList as $pattern => $void) { foreach ($this->updateAllowList as $pattern) {
$patternRegexp = BasePackage::packageNameToRegexp($pattern); $patternRegexp = BasePackage::packageNameToRegexp($pattern);
// update pattern matches a locked package? => all good // update pattern matches a locked package? => all good
foreach ($request->getLockedRepository()->getPackages() as $package) { foreach ($request->getLockedRepository()->getPackages() as $package) {

View File

@ -50,10 +50,12 @@ class Request
protected $lockedPackages = []; protected $lockedPackages = [];
/** @var array<string, BasePackage> */ /** @var array<string, BasePackage> */
protected $fixedLockedPackages = []; protected $fixedLockedPackages = [];
/** @var string[] */ /** @var array<string> */
protected $updateAllowList = []; protected $updateAllowList = [];
/** @var false|self::UPDATE_* */ /** @var false|self::UPDATE_* */
protected $updateAllowTransitiveDependencies = false; protected $updateAllowTransitiveDependencies = false;
/** @var non-empty-list<string>|null */
private $restrictedPackages = null;
public function __construct(?LockArrayRepository $lockedRepository = null) public function __construct(?LockArrayRepository $lockedRepository = null)
{ {
@ -118,7 +120,7 @@ class Request
} }
/** /**
* @param string[] $updateAllowList * @param array<string> $updateAllowList
* @param false|self::UPDATE_* $updateAllowTransitiveDependencies * @param false|self::UPDATE_* $updateAllowTransitiveDependencies
*/ */
public function setUpdateAllowList(array $updateAllowList, $updateAllowTransitiveDependencies): void public function setUpdateAllowList(array $updateAllowList, $updateAllowTransitiveDependencies): void
@ -128,7 +130,7 @@ class Request
} }
/** /**
* @return string[] * @return array<string>
*/ */
public function getUpdateAllowList(): array public function getUpdateAllowList(): array
{ {
@ -233,4 +235,22 @@ class Request
{ {
return $this->lockedRepository; return $this->lockedRepository;
} }
/**
* Restricts the pool builder from loading other packages than those listed here
*
* @param non-empty-list<string> $names
*/
public function restrictPackages(array $names): void
{
$this->restrictedPackages = $names;
}
/**
* @return list<string>
*/
public function getRestrictedPackages(): ?array
{
return $this->restrictedPackages;
}
} }

View File

@ -180,7 +180,7 @@ class Installer
/** /**
* Array of package names/globs flagged for update * Array of package names/globs flagged for update
* *
* @var string[]|null * @var non-empty-list<string>|null
*/ */
protected $updateAllowList = null; protected $updateAllowList = null;
/** @var Request::UPDATE_* */ /** @var Request::UPDATE_* */
@ -242,7 +242,7 @@ class Installer
gc_collect_cycles(); gc_collect_cycles();
gc_disable(); gc_disable();
if ($this->updateAllowList && $this->updateMirrors) { if ($this->updateAllowList !== null && $this->updateMirrors) {
throw new \RuntimeException("The installer options updateMirrors and updateAllowList are mutually exclusive."); throw new \RuntimeException("The installer options updateMirrors and updateAllowList are mutually exclusive.");
} }
@ -436,7 +436,7 @@ class Installer
$lockedRepository = $this->locker->getLockedRepository(true); $lockedRepository = $this->locker->getLockedRepository(true);
} }
} catch (\Seld\JsonLint\ParsingException $e) { } catch (\Seld\JsonLint\ParsingException $e) {
if ($this->updateAllowList || $this->updateMirrors) { if ($this->updateAllowList !== null || $this->updateMirrors) {
// in case we are doing a partial update or updating mirrors, the lock file is needed so we error // in case we are doing a partial update or updating mirrors, the lock file is needed so we error
throw $e; throw $e;
} }
@ -444,7 +444,7 @@ class Installer
// doing a full update // doing a full update
} }
if (($this->updateAllowList || $this->updateMirrors) && !$lockedRepository) { if (($this->updateAllowList !== null || $this->updateMirrors) && !$lockedRepository) {
$this->io->writeError('<error>Cannot update ' . ($this->updateMirrors ? 'lock file information' : 'only a partial set of packages') . ' without a lock file present. Run `composer update` to generate a lock file.</error>', true, IOInterface::QUIET); $this->io->writeError('<error>Cannot update ' . ($this->updateMirrors ? 'lock file information' : 'only a partial set of packages') . ' without a lock file present. Run `composer update` to generate a lock file.</error>', true, IOInterface::QUIET);
return self::ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE; return self::ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE;
@ -467,7 +467,7 @@ class Installer
$this->requirePackagesForUpdate($request, $lockedRepository, true); $this->requirePackagesForUpdate($request, $lockedRepository, true);
// pass the allow list into the request, so the pool builder can apply it // pass the allow list into the request, so the pool builder can apply it
if ($this->updateAllowList) { if ($this->updateAllowList !== null) {
$request->setUpdateAllowList($this->updateAllowList, $this->updateAllowTransitiveDependencies); $request->setUpdateAllowList($this->updateAllowList, $this->updateAllowTransitiveDependencies);
} }
@ -1337,7 +1337,11 @@ class Installer
*/ */
public function setUpdateAllowList(array $packages): self public function setUpdateAllowList(array $packages): self
{ {
$this->updateAllowList = array_flip(array_map('strtolower', $packages)); if (count($packages) === 0) {
$this->updateAllowList = null;
} else {
$this->updateAllowList = array_values(array_unique(array_map('strtolower', $packages)));
}
return $this; return $this;
} }

View File

@ -367,12 +367,18 @@ class RepositorySet
{ {
$request = new Request($lockedRepo); $request = new Request($lockedRepo);
$allowedPackages = [];
foreach ($packageNames as $packageName) { foreach ($packageNames as $packageName) {
if (PlatformRepository::isPlatformPackage($packageName)) { if (PlatformRepository::isPlatformPackage($packageName)) {
throw new \LogicException('createPoolForPackage(s) can not be used for platform packages, as they are never loaded by the PoolBuilder which expects them to be fixed. Use createPoolWithAllPackages or pass in a proper request with the platform packages you need fixed in it.'); throw new \LogicException('createPoolForPackage(s) can not be used for platform packages, as they are never loaded by the PoolBuilder which expects them to be fixed. Use createPoolWithAllPackages or pass in a proper request with the platform packages you need fixed in it.');
} }
$request->requireName($packageName); $request->requireName($packageName);
$allowedPackages[] = strtolower($packageName);
}
if (count($allowedPackages) > 0) {
$request->restrictPackages($allowedPackages);
} }
return $this->createPool($request, new NullIO()); return $this->createPool($request, new NullIO());

View File

@ -126,7 +126,7 @@ class PoolBuilderTest extends TestCase
if (isset($requestData['allowTransitiveDeps']) && $requestData['allowTransitiveDeps']) { if (isset($requestData['allowTransitiveDeps']) && $requestData['allowTransitiveDeps']) {
$transitiveDeps = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS; $transitiveDeps = Request::UPDATE_LISTED_WITH_TRANSITIVE_DEPS;
} }
$request->setUpdateAllowList(array_flip($requestData['allowList']), $transitiveDeps); $request->setUpdateAllowList($requestData['allowList'], $transitiveDeps);
} }
foreach ($fixed as $fixedPackage) { foreach ($fixed as $fixedPackage) {