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-zendpull/11902/head
parent
a6947f116a
commit
07fa4255d6
|
@ -102,6 +102,9 @@ Out of the box, Composer supports four types:
|
|||
- **composer-plugin:** A package of type `composer-plugin` may provide an
|
||||
installer for other packages that have a custom type. Read more in the
|
||||
[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
|
||||
recommended to omit this field and have it default to `library`.
|
||||
|
|
|
@ -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": {
|
||||
"type": "object",
|
||||
"description": "Composer options.",
|
||||
|
|
|
@ -106,6 +106,8 @@ class PoolBuilder
|
|||
private $updateAllowList = [];
|
||||
/** @var array<string, array<PackageInterface>> */
|
||||
private $skippedLoad = [];
|
||||
/** @var list<string> */
|
||||
private $ignoredTypes = [];
|
||||
|
||||
/**
|
||||
* If provided, only these package names are loaded
|
||||
|
@ -170,6 +172,14 @@ class PoolBuilder
|
|||
$this->temporaryConstraints = $temporaryConstraints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $types
|
||||
*/
|
||||
public function setIgnoredTypes(array $types): void
|
||||
{
|
||||
$this->ignoredTypes = $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RepositoryInterface[] $repositories
|
||||
*/
|
||||
|
@ -416,6 +426,10 @@ class PoolBuilder
|
|||
*/
|
||||
private function loadPackage(Request $request, array $repositories, BasePackage $package, bool $propagateUpdate): void
|
||||
{
|
||||
if (in_array($package->getType(), $this->ignoredTypes, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$index = $this->indexCounter++;
|
||||
$this->packages[$index] = $package;
|
||||
|
||||
|
|
|
@ -351,6 +351,11 @@ class AliasPackage extends BasePackage
|
|||
return $this->aliasOf->getIncludePaths();
|
||||
}
|
||||
|
||||
public function getPhpExt(): ?array
|
||||
{
|
||||
return $this->aliasOf->getPhpExt();
|
||||
}
|
||||
|
||||
public function getReleaseDate(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->aliasOf->getReleaseDate();
|
||||
|
|
|
@ -228,6 +228,10 @@ class ArrayLoader implements LoaderInterface
|
|||
$package->setIncludePaths($config['include-path']);
|
||||
}
|
||||
|
||||
if (isset($config['php-ext'])) {
|
||||
$package->setPhpExt($config['php-ext']);
|
||||
}
|
||||
|
||||
if (!empty($config['time'])) {
|
||||
$time = Preg::isMatch('/^\d++$/D', $config['time']) ? '@'.$config['time'] : $config['time'];
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
||||
foreach (array_keys(BasePackage::$supportedLinkTypes) as $linkType) {
|
||||
|
|
|
@ -98,6 +98,8 @@ class Package extends BasePackage
|
|||
protected $isDefaultBranch = false;
|
||||
/** @var mixed[] */
|
||||
protected $transportOptions = [];
|
||||
/** @var array{priority?: int, config?: array<string, bool>}|null */
|
||||
protected $phpExt = null;
|
||||
|
||||
/**
|
||||
* Creates a new in memory package.
|
||||
|
@ -590,6 +592,24 @@ class Package extends BasePackage
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -323,6 +323,13 @@ interface PackageInterface
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -314,6 +314,7 @@ class RepositorySet
|
|||
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->setIgnoredTypes(['php-ext', 'php-ext-zend']);
|
||||
|
||||
foreach ($this->repositories as $repo) {
|
||||
if (($repo instanceof InstalledRepositoryInterface || $repo instanceof InstalledRepository) && !$this->allowInstalledRepositories) {
|
||||
|
|
|
@ -6,17 +6,17 @@ Install package and it's replacer skips the original
|
|||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "ext-foo", "version": "1.0.0" },
|
||||
{ "name": "ext-foo/fork", "version": "0.5.0", "replace": { "ext-foo": "1.0.*" } }
|
||||
{ "name": "example/foo", "version": "1.0.0" },
|
||||
{ "name": "example/foo-fork", "version": "0.5.0", "replace": { "example/foo": "1.0.*" } }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"ext-foo": "1.0.0",
|
||||
"ext-foo/fork": "0.5.*"
|
||||
"example/foo": "1.0.0",
|
||||
"example/foo-fork": "0.5.*"
|
||||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
--EXPECT--
|
||||
Installing ext-foo/fork (0.5.0)
|
||||
Installing example/foo-fork (0.5.0)
|
||||
|
|
Loading…
Reference in New Issue