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[]
*/
private $unacceptableFixedOrLockedPackages = [];
/** @var string[] */
/** @var array<string> */
private $updateAllowList = [];
/** @var array<string, array<PackageInterface>> */
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
*
@ -165,6 +175,8 @@ class PoolBuilder
*/
public function buildPool(array $repositories, Request $request): Pool
{
$this->restrictedPackagesList = $request->getRestrictedPackages() !== null ? array_flip($request->getRestrictedPackages()) : null;
if ($request->getUpdateAllowList()) {
$this->updateAllowList = $request->getUpdateAllowList();
$this->warnAboutNonMatchingUpdateAllowList($request);
@ -366,6 +378,10 @@ class PoolBuilder
private function loadPackagesMarkedForLoading(Request $request, array $repositories): void
{
foreach ($this->packagesToLoad as $name => $constraint) {
if ($this->restrictedPackagesList !== null && !isset($this->restrictedPackagesList[$name])) {
unset($this->packagesToLoad[$name]);
continue;
}
$this->loadedPackages[$name] = $constraint;
}
@ -559,7 +575,7 @@ class PoolBuilder
*/
private function isUpdateAllowed(BasePackage $package): bool
{
foreach ($this->updateAllowList as $pattern => $void) {
foreach ($this->updateAllowList as $pattern) {
$patternRegexp = BasePackage::packageNameToRegexp($pattern);
if (Preg::isMatch($patternRegexp, $package->getName())) {
return true;
@ -571,7 +587,7 @@ class PoolBuilder
private function warnAboutNonMatchingUpdateAllowList(Request $request): void
{
foreach ($this->updateAllowList as $pattern => $void) {
foreach ($this->updateAllowList as $pattern) {
$patternRegexp = BasePackage::packageNameToRegexp($pattern);
// update pattern matches a locked package? => all good
foreach ($request->getLockedRepository()->getPackages() as $package) {

View File

@ -50,10 +50,12 @@ class Request
protected $lockedPackages = [];
/** @var array<string, BasePackage> */
protected $fixedLockedPackages = [];
/** @var string[] */
/** @var array<string> */
protected $updateAllowList = [];
/** @var false|self::UPDATE_* */
protected $updateAllowTransitiveDependencies = false;
/** @var non-empty-list<string>|null */
private $restrictedPackages = 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
*/
public function setUpdateAllowList(array $updateAllowList, $updateAllowTransitiveDependencies): void
@ -128,7 +130,7 @@ class Request
}
/**
* @return string[]
* @return array<string>
*/
public function getUpdateAllowList(): array
{
@ -233,4 +235,22 @@ class Request
{
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
*
* @var string[]|null
* @var non-empty-list<string>|null
*/
protected $updateAllowList = null;
/** @var Request::UPDATE_* */
@ -242,7 +242,7 @@ class Installer
gc_collect_cycles();
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.");
}
@ -436,7 +436,7 @@ class Installer
$lockedRepository = $this->locker->getLockedRepository(true);
}
} 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
throw $e;
}
@ -444,7 +444,7 @@ class Installer
// 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);
return self::ERROR_NO_LOCK_FILE_FOR_PARTIAL_UPDATE;
@ -467,7 +467,7 @@ class Installer
$this->requirePackagesForUpdate($request, $lockedRepository, true);
// 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);
}
@ -1337,7 +1337,11 @@ class Installer
*/
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;
}

View File

@ -367,12 +367,18 @@ class RepositorySet
{
$request = new Request($lockedRepo);
$allowedPackages = [];
foreach ($packageNames as $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.');
}
$request->requireName($packageName);
$allowedPackages[] = strtolower($packageName);
}
if (count($allowedPackages) > 0) {
$request->restrictPackages($allowedPackages);
}
return $this->createPool($request, new NullIO());

View File

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