Skip to content

Commit

Permalink
Add support for php extension packages (#11795)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Seldaek committed Mar 20, 2024
1 parent a6947f1 commit 07fa425
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 5 deletions.
3 changes: 3 additions & 0 deletions doc/04-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
35 changes: 35 additions & 0 deletions res/composer-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
14 changes: 14 additions & 0 deletions src/Composer/DependencyResolver/PoolBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -170,6 +172,14 @@ public function __construct(array $acceptableStabilities, array $stabilityFlags,
$this->temporaryConstraints = $temporaryConstraints;
}

/**
* @param list<string> $types
*/
public function setIgnoredTypes(array $types): void
{
$this->ignoredTypes = $types;
}

/**
* @param RepositoryInterface[] $repositories
*/
Expand Down Expand Up @@ -416,6 +426,10 @@ private function loadPackagesMarkedForLoading(Request $request, array $repositor
*/
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;

Expand Down
5 changes: 5 additions & 0 deletions src/Composer/Package/AliasPackage.php
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ public function getIncludePaths(): array
return $this->aliasOf->getIncludePaths();
}

public function getPhpExt(): ?array
{
return $this->aliasOf->getPhpExt();
}

public function getReleaseDate(): ?\DateTimeInterface
{
return $this->aliasOf->getReleaseDate();
Expand Down
4 changes: 4 additions & 0 deletions src/Composer/Package/Loader/ArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ private function configureObject(PackageInterface $package, array $config): Base
$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'];

Expand Down
6 changes: 6 additions & 0 deletions src/Composer/Package/Loader/ValidatingArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,12 @@ public function load(array $config, string $class = 'Composer\Package\CompletePa
}
}

$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) {
Expand Down
20 changes: 20 additions & 0 deletions src/Composer/Package/Package.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -590,6 +592,24 @@ public function getIncludePaths(): array
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
*/
Expand Down
7 changes: 7 additions & 0 deletions src/Composer/Package/PackageInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ public function getDevAutoload(): 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
*/
Expand Down
1 change: 1 addition & 0 deletions src/Composer/Repository/RepositorySet.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ public function isPackageAcceptable(array $names, string $stability): bool
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 07fa425

Please sign in to comment.