1
0
Fork 0

Add support for php extension packages (#11795)

* Update schema
* Validate php-ext is only set for php-ext or php-ext-zend packages
* Make sure the pool builder excludes php-ext/php-ext-zend
pull/11902/head
Jordi Boggiano 2024-03-20 22:04:58 +01:00 committed by GitHub
parent a6947f116a
commit 07fa4255d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 100 additions and 5 deletions

View File

@ -102,6 +102,9 @@ Out of the box, Composer supports four types:
- **composer-plugin:** A package of type `composer-plugin` may provide an - **composer-plugin:** A package of type `composer-plugin` may provide an
installer for other packages that have a custom type. Read more in the installer for other packages that have a custom type. Read more in the
[dedicated article](articles/custom-installers.md). [dedicated article](articles/custom-installers.md).
- **php-ext** and **php-ext-zend**: These names are reserved for PHP extension
packages which are written in C. Do not use these types for packages written
in PHP.
Only use a custom type if you need custom logic during installation. It is Only use a custom type if you need custom logic during installation. It is
recommended to omit this field and have it default to `library`. recommended to omit this field and have it default to `library`.

View File

@ -288,6 +288,41 @@
} }
} }
}, },
"php-ext": {
"type": "object",
"description": "Settings for PHP extension packages.",
"properties": {
"priority": {
"type": "integer",
"description": "This is used to add a prefix to the INI file, e.g. `90-xdebug.ini` which affects the loading order. The priority is a number in the range 10-99 inclusive, with 10 being the highest priority (i.e. will be processed first), and 99 being the lowest priority (i.e. will be processed last). There are two digits so that the files sort correctly on any platform, whether the sorting is natural or not.",
"minimum": 10,
"maximum": 99,
"example": 80,
"default": 80
},
"configure-options": {
"type": "array",
"description": "These configure options make up the flags that can be passed to ./configure when installing the extension.",
"items": {
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string",
"description": "The name of the flag, this would typically be prefixed with `--`, for example, the value 'the-flag' would be passed as `./configure --the-flag`.",
"example": "without-xdebug-compression",
"pattern": "^[a-zA-Z0-9][a-zA-Z0-9-_]*$"
},
"description": {
"type": "string",
"description": "The description of what the flag does or means.",
"example": "Disable compression through zlib"
}
}
}
}
}
},
"config": { "config": {
"type": "object", "type": "object",
"description": "Composer options.", "description": "Composer options.",

View File

@ -106,6 +106,8 @@ class PoolBuilder
private $updateAllowList = []; private $updateAllowList = [];
/** @var array<string, array<PackageInterface>> */ /** @var array<string, array<PackageInterface>> */
private $skippedLoad = []; private $skippedLoad = [];
/** @var list<string> */
private $ignoredTypes = [];
/** /**
* If provided, only these package names are loaded * If provided, only these package names are loaded
@ -170,6 +172,14 @@ class PoolBuilder
$this->temporaryConstraints = $temporaryConstraints; $this->temporaryConstraints = $temporaryConstraints;
} }
/**
* @param list<string> $types
*/
public function setIgnoredTypes(array $types): void
{
$this->ignoredTypes = $types;
}
/** /**
* @param RepositoryInterface[] $repositories * @param RepositoryInterface[] $repositories
*/ */
@ -416,6 +426,10 @@ class PoolBuilder
*/ */
private function loadPackage(Request $request, array $repositories, BasePackage $package, bool $propagateUpdate): void private function loadPackage(Request $request, array $repositories, BasePackage $package, bool $propagateUpdate): void
{ {
if (in_array($package->getType(), $this->ignoredTypes, true)) {
return;
}
$index = $this->indexCounter++; $index = $this->indexCounter++;
$this->packages[$index] = $package; $this->packages[$index] = $package;

View File

@ -351,6 +351,11 @@ class AliasPackage extends BasePackage
return $this->aliasOf->getIncludePaths(); return $this->aliasOf->getIncludePaths();
} }
public function getPhpExt(): ?array
{
return $this->aliasOf->getPhpExt();
}
public function getReleaseDate(): ?\DateTimeInterface public function getReleaseDate(): ?\DateTimeInterface
{ {
return $this->aliasOf->getReleaseDate(); return $this->aliasOf->getReleaseDate();

View File

@ -228,6 +228,10 @@ class ArrayLoader implements LoaderInterface
$package->setIncludePaths($config['include-path']); $package->setIncludePaths($config['include-path']);
} }
if (isset($config['php-ext'])) {
$package->setPhpExt($config['php-ext']);
}
if (!empty($config['time'])) { if (!empty($config['time'])) {
$time = Preg::isMatch('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time']; $time = Preg::isMatch('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];

View File

@ -247,6 +247,12 @@ class ValidatingArrayLoader implements LoaderInterface
} }
} }
$this->validateArray('php-ext');
if (isset($this->config['php-ext']) && !in_array($this->config['type'] ?? '', ['php-ext', 'php-ext-zend'], true)) {
$this->errors[] = 'php-ext can only be set by packages of type "php-ext" or "php-ext-zend" which must be C extensions';
unset($this->config['php-ext']);
}
$unboundConstraint = new Constraint('=', '10000000-dev'); $unboundConstraint = new Constraint('=', '10000000-dev');
foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) { foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {

View File

@ -98,6 +98,8 @@ class Package extends BasePackage
protected $isDefaultBranch = false; protected $isDefaultBranch = false;
/** @var mixed[] */ /** @var mixed[] */
protected $transportOptions = []; protected $transportOptions = [];
/** @var array{priority?: int, config?: array<string, bool>}|null */
protected $phpExt = null;
/** /**
* Creates a new in memory package. * Creates a new in memory package.
@ -590,6 +592,24 @@ class Package extends BasePackage
return $this->includePaths; return $this->includePaths;
} }
/**
* Sets the list of paths added to PHP's include path.
*
* @param array{priority?: int, config?: array<string, bool>}|null $phpExt List of directories.
*/
public function setPhpExt(?array $phpExt): void
{
$this->phpExt = $phpExt;
}
/**
* @inheritDoc
*/
public function getPhpExt(): ?array
{
return $this->phpExt;
}
/** /**
* Sets the notification URL * Sets the notification URL
*/ */

View File

@ -323,6 +323,13 @@ interface PackageInterface
*/ */
public function getIncludePaths(): array; public function getIncludePaths(): array;
/**
* Returns the settings for php extension packages
*
* @return array{priority?: int, config?: array<string, bool>}|null
*/
public function getPhpExt(): ?array;
/** /**
* Stores a reference to the repository that owns the package * Stores a reference to the repository that owns the package
*/ */

View File

@ -314,6 +314,7 @@ class RepositorySet
public function createPool(Request $request, IOInterface $io, ?EventDispatcher $eventDispatcher = null, ?PoolOptimizer $poolOptimizer = null): Pool public function createPool(Request $request, IOInterface $io, ?EventDispatcher $eventDispatcher = null, ?PoolOptimizer $poolOptimizer = null): Pool
{ {
$poolBuilder = new PoolBuilder($this->acceptableStabilities, $this->stabilityFlags, $this->rootAliases, $this->rootReferences, $io, $eventDispatcher, $poolOptimizer, $this->temporaryConstraints); $poolBuilder = new PoolBuilder($this->acceptableStabilities, $this->stabilityFlags, $this->rootAliases, $this->rootReferences, $io, $eventDispatcher, $poolOptimizer, $this->temporaryConstraints);
$poolBuilder->setIgnoredTypes(['php-ext', 'php-ext-zend']);
foreach ($this->repositories as $repo) { foreach ($this->repositories as $repo) {
if (($repo instanceof InstalledRepositoryInterface || $repo instanceof InstalledRepository) && !$this->allowInstalledRepositories) { if (($repo instanceof InstalledRepositoryInterface || $repo instanceof InstalledRepository) && !$this->allowInstalledRepositories) {

View File

@ -6,17 +6,17 @@ Install package and it's replacer skips the original
{ {
"type": "package", "type": "package",
"package": [ "package": [
{ "name": "ext-foo", "version": "1.0.0" }, { "name": "example/foo", "version": "1.0.0" },
{ "name": "ext-foo/fork", "version": "0.5.0", "replace": { "ext-foo": "1.0.*" } } { "name": "example/foo-fork", "version": "0.5.0", "replace": { "example/foo": "1.0.*" } }
] ]
} }
], ],
"require": { "require": {
"ext-foo": "1.0.0", "example/foo": "1.0.0",
"ext-foo/fork": "0.5.*" "example/foo-fork": "0.5.*"
} }
} }
--RUN-- --RUN--
install install
--EXPECT-- --EXPECT--
Installing ext-foo/fork (0.5.0) Installing example/foo-fork (0.5.0)