Composer integration improvements

This commit is contained in:
Daniil Gentili 2020-11-03 22:01:34 +01:00
parent 0b572094f7
commit d22df4bd9c
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 184 additions and 84 deletions

View File

@ -0,0 +1,27 @@
<?php
namespace Phabel\Composer;
use Composer\Package\Link;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Repository\ComposerRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\ArrayRepository as ComposerArrayRepository;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
/**
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*
* @property ComposerArrayRepository $repository
*/
trait ArrayRepository
{
public function addPackage(PackageInterface $package)
{
$this->repository->addPackage($package);
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace Phabel\Composer;
use Composer\DependencyResolver\Pool;
use Composer\Package\PackageInterface;
use Composer\Repository\ComposerRepository as ComposerComposerRepository;
use Composer\Repository\RepositoryInterface;
use ReflectionObject;
/**
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*
* @property ComposerComposerRepository $repository
*/
class ComposerRepository extends ComposerComposerRepository
{
use Repository;
use ArrayRepository;
use ConfigurableRepository;
/**
* Configuration prefix.
*/
const CONFIG_PREFIX = 'phabel-config';
/**
* @param Pool $pool
* @param string $name package name
* @param bool $bypassFilters If set to true, this bypasses the stability filtering, and forces a recompute without cache
* @return array|mixed
*/
public function whatProvides(Pool $pool, $name, $bypassFilters = false)
{
$whatProvides = $this->reflect->getMethod('whatProvides')->invokeArgs($this->repository, [$pool, $name, $bypassFilters]);
foreach ($whatProvides as $package => &$versions) {
foreach ($versions as &$version) {
if (!isset($version['require']['phabel/phabel'])) {
continue;
}
$config = $version['extra']['phabel'] ?? [];
if (!isset($config['target']) && isset($version['require']['php'])) {
$config['target'] = $version['require']['php'];
}
foreach ($version['require'] as $package => &$version) {
$version = self::CONFIG_PREFIX.\json_encode($config)."\n".$version;
}
}
}
return $whatProvides;
}
public function getProviderNames()
{
return $this->repository->getProviderNames();
}
public function hasProviders()
{
return $this->repository->hasProviders();
}
public function resetPackageIds()
{
return $this->repository->resetPackageIds();
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Phabel\Composer;
use Composer\Package\Link;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Repository\ComposerRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Repository\ConfigurableRepositoryInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
/**
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*
* @property ConfigurableRepositoryInterface $repository
*/
trait ConfigurableRepository
{
/**
* Get repository configuration.
*
* @return mixed
*/
public function getRepoConfig()
{
return $this->repository->getRepoConfig();
}
}

View File

@ -10,6 +10,11 @@ use Composer\Installer\PackageEvent;
use Composer\Installer\PackageEvents;
use Composer\IO\IOInterface;
use Composer\Plugin\PluginInterface;
use Composer\Repository\ArrayRepository as ComposerArrayRepository;
use Composer\Repository\ConfigurableRepository as ComposerConfigurableRepository;
use Composer\Repository\ComposerRepository as ComposerComposerRepository;
use Composer\Repository\RepositoryInterface;
use ReflectionObject;
/**
* @author Daniil Gentili <daniil@daniil.it>
@ -33,7 +38,44 @@ class Plugin implements PluginInterface, EventSubscriberInterface
{
$repoManager = $composer->getRepositoryManager();
$repos = $repoManager->getRepositories();
$repoManager->prependRepository(new Repository($repos[0]));
$reflect = (new ReflectionObject($repoManager))->getProperty('repositories');
$reflect->setAccessible(true);
$reflect->setValue($repoManager, []);
foreach ($repos as $repo) {
if ($repo instanceof ComposerComposerRepository) {
$repo = new ComposerRepository($repo);
} else {
$traits = [];
foreach ([
ComposerArrayRepository::class => ArrayRepository::class,
ComposerConfigurableRepository::class => ConfigurableRepository::class,
] as $class => $trait) {
if ($repo instanceof $class) {
$traits []= $trait;
}
}
sort($traits);
if ($traits === [ArrayRepository::class]) {
$repo = new class($repo) extends ComposerArrayRepository {
use Repository;
use ArrayRepository;
};
} else if ($traits === [ConfigurableRepository::class]) {
$repo = new class($repo) extends ComposerRepository {
use Repository;
use ConfigurableRepository;
};
} else {
$repo = new class($repo) extends ComposerArrayRepository {
use Repository;
use ArrayRepository;
use ConfigurableRepository;
};
}
}
$repoManager->prependRepository($repo);
}
var_dump(array_map('get_class', $repoManager->getRepositories()));
$this->io = $io;
}
@ -69,8 +111,6 @@ class Plugin implements PluginInterface, EventSubscriberInterface
public static function getSubscribedEvents()
{
return [
InstallerEvents::PRE_DEPENDENCIES_SOLVING =>
['onDependencySolve', 100000],
PackageEvents::POST_PACKAGE_INSTALL =>
['onInstall', 100000],
];
@ -78,7 +118,6 @@ class Plugin implements PluginInterface, EventSubscriberInterface
public function onInstall(PackageEvent $event): void
{
\var_dumP($event);
}
/**
@ -90,6 +129,5 @@ class Plugin implements PluginInterface, EventSubscriberInterface
*/
public function onDependencySolve(InstallerEvent $event): void
{
\var_dump($event);
}
}

View File

@ -2,59 +2,39 @@
namespace Phabel\Composer;
use Composer\DependencyResolver\Pool;
use Composer\Package\Link;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Repository\ComposerRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Semver\Constraint\Constraint;
use Composer\Semver\Constraint\ConstraintInterface;
use ReflectionObject;
/**
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*/
class Repository extends ComposerRepository
trait Repository
{
/**
* Configuration prefix.
*/
private const CONFIG_PREFIX = 'phabel-config';
/**
* Previous repository .
*/
private ComposerRepository $repository;
protected RepositoryInterface $repository;
/**
* Reflection object
*/
protected ReflectionObject $reflect;
/**
* Constructor.
*
* @param RepositoryInterface[] $repositories Previous repositories
* @param RepositoryInterface $repository Previous repository
*/
public function __construct(ComposerRepository $repository)
public function __construct(RepositoryInterface $repository)
{
$this->reflect = new ReflectionObject($repository);
$this->repository = $repository;
$this->packages = [];
}
/**
* Get repository configuration.
*
* @return mixed
*/
public function getRepoConfig()
{
return $this->repository->getRepoConfig();
}
/**
* Set root aliases.
*
* @param array $rootAliases Root aliases
*
* @return void
*/
public function setRootAliases(array $rootAliases): void
{
$this->repository->setRootAliases($rootAliases);
}
/**
* Checks if specified package registered (installed).
*
@ -80,11 +60,11 @@ class Repository extends ComposerRepository
return [];
}
$constraint = (string) $constraint;
if (!str_starts_with($constraint, self::CONFIG_PREFIX)) {
if (!str_starts_with($constraint, ComposerRepository::CONFIG_PREFIX)) {
return [];
}
[$config, $constraint] = \explode("\n", $constraint, 2);
return \json_decode(\substr($config, 0, \strlen(self::CONFIG_PREFIX)), true) ?: [];
return \json_decode(\substr($config, 0, \strlen(ComposerRepository::CONFIG_PREFIX)), true) ?: [];
}
/**
* Prepare package.
@ -119,7 +99,7 @@ class Repository extends ComposerRepository
// Config merging logic here...
$links = [];
foreach ($package->getRequires() as $link) {
$version = self::CONFIG_PREFIX.\json_encode($config)."\n".($link->getConstraint() ?? '');
$version = ComposerRepository::CONFIG_PREFIX.\json_encode($config)."\n".($link->getConstraint() ?? '');
$links []= new Link($link->getSource(), $link->getTarget(), new Constraint('>=', $version), $link->getDescription());
}
$package->setRequires($links);
@ -133,7 +113,7 @@ class Repository extends ComposerRepository
*
* @return PackageInterface|null
*/
public function findPackage(string $name, $constraint): ?PackageInterface
public function findPackage($name, $constraint)
{
$config = self::prepareConstraint($constraint);
if (!$package = $this->repository->findPackage($name, $constraint)) {
@ -180,47 +160,4 @@ class Repository extends ComposerRepository
{
return $this->repository->search($query, $mode, $type);
}
public function getProviderNames()
{
return $this->repository->getProviderNames();
}
public function hasProviders()
{
return $this->repository->hasProviders();
}
public function resetPackageIds()
{
return $this->repository->resetPackageIds();
}
public function addPackage(PackageInterface $package)
{
$this->repository->addPackage($package);
}
/**
* @param Pool $pool
* @param string $name package name
* @param bool $bypassFilters If set to true, this bypasses the stability filtering, and forces a recompute without cache
* @return array|mixed
*/
public function whatProvides(Pool $pool, $name, $bypassFilters = false)
{
$whatProvides = $this->repository->whatProvides($pool, $name, $bypassFilters);
foreach ($whatProvides as $package => &$versions) {
foreach ($versions as &$version) {
if (!isset($version['require']['phabel/phabel'])) {
continue;
}
$config = $version['extra']['phabel'] ?? [];
if (!isset($config['target']) && isset($version['require']['php'])) {
$config['target'] = $version['require']['php'];
}
foreach ($version['require'] as $package => &$version) {
$version = self::CONFIG_PREFIX.\json_encode($config)."\n".$version;
}
}
}
return $whatProvides;
}
}