1
0
Fork 0

Add install-path and type to installedVersions.php and installed.php, add method to get installed packages by type

Issue https://github.com/composer/composer/issues/9648
pull/9699/head
Jochen Roth 2021-02-25 10:00:36 +01:00 committed by Jordi Boggiano
parent 31cc102850
commit b6c9d34125
No known key found for this signature in database
GPG Key ID: 7BBD42C429EC80BC
6 changed files with 131 additions and 6 deletions

View File

@ -24,10 +24,15 @@ use Composer\Semver\VersionParser;
*/ */
class InstalledVersions class InstalledVersions
{ {
private static $installed; private static $installed = array();
private static $canGetVendors; private static $canGetVendors;
private static $installedByVendor = array(); private static $installedByVendor = array();
/**
* Initialize $installed array
*/
public static function initializeInstalled() {}
/** /**
* Returns a list of all package names which are present, either by being installed, replaced or provided * Returns a list of all package names which are present, either by being installed, replaced or provided
* *
@ -48,6 +53,28 @@ class InstalledVersions
return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
} }
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/** /**
* Checks whether the given package is installed * Checks whether the given package is installed
* *
@ -274,3 +301,5 @@ class InstalledVersions
return $installed; return $installed;
} }
} }
InstalledVersions::initializeInstalled();

View File

@ -14,6 +14,7 @@ namespace Composer\Repository;
use Composer\Json\JsonFile; use Composer\Json\JsonFile;
use Composer\Package\Loader\ArrayLoader; use Composer\Package\Loader\ArrayLoader;
use Composer\Package\PackageInterface;
use Composer\Package\RootPackageInterface; use Composer\Package\RootPackageInterface;
use Composer\Package\AliasPackage; use Composer\Package\AliasPackage;
use Composer\Package\Dumper\ArrayDumper; use Composer\Package\Dumper\ArrayDumper;
@ -102,11 +103,15 @@ class FilesystemRepository extends WritableArrayRepository
$dumper = new ArrayDumper(); $dumper = new ArrayDumper();
$fs = new Filesystem(); $fs = new Filesystem();
$repoDir = dirname($fs->normalizePath($this->file->getPath())); $repoDir = dirname($fs->normalizePath($this->file->getPath()));
$installPaths = array();
foreach ($this->getCanonicalPackages() as $package) { foreach ($this->getCanonicalPackages() as $package) {
$pkgArray = $dumper->dump($package); $pkgArray = $dumper->dump($package);
$path = $installationManager->getInstallPath($package); $path = $installationManager->getInstallPath($package);
$pkgArray['install-path'] = ('' !== $path && null !== $path) ? $fs->findShortestPath($repoDir, $fs->isAbsolutePath($path) ? $path : getcwd() . '/' . $path, true) : null; $installPath = ('' !== $path && null !== $path) ? $fs->findShortestPath($repoDir, $fs->isAbsolutePath($path) ? $path : getcwd() . '/' . $path, true) : null;
$installPaths[$package->getName()] = $installPath;
$pkgArray['install-path'] = $installPath;
$data['packages'][] = $pkgArray; $data['packages'][] = $pkgArray;
// only write to the files the names which are really installed, as we receive the full list // only write to the files the names which are really installed, as we receive the full list
@ -124,24 +129,56 @@ class FilesystemRepository extends WritableArrayRepository
$this->file->write($data); $this->file->write($data);
if ($this->dumpVersions) { if ($this->dumpVersions) {
$versions = $this->generateInstalledVersions($installationManager, $devMode); $versions = $this->generateInstalledVersions($installationManager, $installPaths, $devMode, $repoDir);
$fs->filePutContentsIfModified($repoDir.'/installed.php', '<?php return '.var_export($versions, true).';'."\n"); $fs->filePutContentsIfModified($repoDir.'/installed.php', '<?php return ' . $this->dumpVersion($versions) . ';'."\n");
$installedVersionsClass = file_get_contents(__DIR__.'/../InstalledVersions.php'); $installedVersionsClass = file_get_contents(__DIR__.'/../InstalledVersions.php');
// while not strictly needed since https://github.com/composer/composer/pull/9635 - we keep this for BC // while not strictly needed since https://github.com/composer/composer/pull/9635 - we keep this for BC
// and overall broader compatibility with people that may not use Composer's ClassLoader. They can // and overall broader compatibility with people that may not use Composer's ClassLoader. They can
// simply include InstalledVersions.php manually and have it working in a basic way. // simply include InstalledVersions.php manually and have it working in a basic way.
$installedVersionsClass = str_replace('private static $installed;', 'private static $installed = '.var_export($versions, true).';', $installedVersionsClass); $installedVersionsClass = str_replace('public static function initializeInstalled() {}', 'public static function initializeInstalled() {' . PHP_EOL . 'self::$installed = ' . $this->dumpVersion($versions) . ';' . PHP_EOL . '}', $installedVersionsClass);
$fs->filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass); $fs->filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass);
\Composer\InstalledVersions::reload($versions); \Composer\InstalledVersions::reload($versions);
} }
} }
private function dumpVersion(array $array = array(), $level = 0)
{
$lines = "array(\n";
$level++;
foreach ($array as $key => $value) {
$lines .= str_repeat(' ', $level);
$lines .= is_int($key) ? $key . ' => ' : '\'' . $key . '\' => ';
if (is_array($value)) {
if (!empty($value)) {
$lines .= self::dumpVersion($value, $level);
} else {
$lines .= "array(),\n";
}
} elseif (is_null($value)) {
$lines .= 'null';
$lines .= ",\n";
} elseif (is_bool($value)) {
$lines .= $value ? 'true' : 'false';
$lines .= ",\n";
} else {
$stringContent = str_replace(array('\\', '\''), array('\\\\', '\\\''), $value);
$folder = $key === 'install_path' ? '__DIR__ . DIRECTORY_SEPARATOR . ' : '';
$lines .= $folder . "'" . $stringContent . "',\n";
}
}
$lines .= str_repeat(' ', $level - 1) . ')' . ($level - 1 == 0 ? '' : ",\n");
return $lines;
}
/** /**
* @return ?array * @return ?array
*/ */
private function generateInstalledVersions(InstallationManager $installationManager, $devMode) private function generateInstalledVersions(InstallationManager $installationManager, $installPaths, $devMode, $repoDir)
{ {
if (!$this->dumpVersions) { if (!$this->dumpVersions) {
return null; return null;
@ -170,9 +207,19 @@ class FilesystemRepository extends WritableArrayRepository
$reference = ($package->getSourceReference() ?: $package->getDistReference()) ?: null; $reference = ($package->getSourceReference() ?: $package->getDistReference()) ?: null;
} }
if($package instanceof RootPackageInterface) {
$fs = new Filesystem();
$to = getcwd();
$installPath = $fs->findShortestPath($repoDir, $to, true);
} else {
$installPath = $installPaths[$package->getName()];
}
$versions['versions'][$package->getName()] = array( $versions['versions'][$package->getName()] = array(
'pretty_version' => $package->getPrettyVersion(), 'pretty_version' => $package->getPrettyVersion(),
'version' => $package->getVersion(), 'version' => $package->getVersion(),
'type' => $package->getType(),
'install_path' => $installPath,
'aliases' => array(), 'aliases' => array(),
'reference' => $reference, 'reference' => $reference,
'dev-requirement' => isset($devPackages[$package->getName()]), 'dev-requirement' => isset($devPackages[$package->getName()]),

View File

@ -17,6 +17,8 @@ use Composer\Semver\VersionParser;
class InstalledVersionsTest extends TestCase class InstalledVersionsTest extends TestCase
{ {
private $root;
public static function setUpBeforeClass() public static function setUpBeforeClass()
{ {
// disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no // disable multiple-ClassLoader-based checks of InstalledVersions by making it seem like no
@ -33,6 +35,9 @@ class InstalledVersionsTest extends TestCase
public function setUp() public function setUp()
{ {
$this->root = $this->getUniqueTmpDirectory();
$dir = $this->root;
InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php'); InstalledVersions::reload(require __DIR__.'/Repository/Fixtures/installed.php');
} }
@ -187,6 +192,8 @@ class InstalledVersionsTest extends TestCase
$this->assertSame(array( $this->assertSame(array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'type' => 'library',
'install_path' => $this->root . DIRECTORY_SEPARATOR . './',
'aliases' => array( 'aliases' => array(
'1.10.x-dev', '1.10.x-dev',
), ),
@ -198,6 +205,7 @@ class InstalledVersionsTest extends TestCase
public function testGetRawData() public function testGetRawData()
{ {
$dir = $this->root;
$this->assertSame(require __DIR__.'/Repository/Fixtures/installed.php', InstalledVersions::getRawData()); $this->assertSame(require __DIR__.'/Repository/Fixtures/installed.php', InstalledVersions::getRawData());
} }
@ -222,4 +230,17 @@ class InstalledVersionsTest extends TestCase
array(null, 'c/c'), array(null, 'c/c'),
); );
} }
public function testGetInstalledPackagesByType()
{
$names = array(
'__root__',
'a/provider',
'a/provider2',
'b/replacer',
'c/c',
);
$this->assertSame($names, \Composer\InstalledVersions::getInstalledPackagesByType('library'));
}
} }

View File

@ -119,4 +119,9 @@ class InstallationManagerMock extends InstallationManager
{ {
// noop // noop
} }
public function getInstalledPackagesByType()
{
return $this->installed;
}
} }

View File

@ -18,6 +18,8 @@ use Composer\Json\JsonFile;
class FilesystemRepositoryTest extends TestCase class FilesystemRepositoryTest extends TestCase
{ {
private $root;
public function testRepositoryRead() public function testRepositoryRead()
{ {
$json = $this->createJsonFileMock(); $json = $this->createJsonFileMock();
@ -121,6 +123,9 @@ class FilesystemRepositoryTest extends TestCase
public function testRepositoryWritesInstalledPhp() public function testRepositoryWritesInstalledPhp()
{ {
$dir = $this->getUniqueTmpDirectory(); $dir = $this->getUniqueTmpDirectory();
$this->root = $dir;
chdir($dir);
$json = new JsonFile($dir.'/installed.json'); $json = new JsonFile($dir.'/installed.json');
$rootPackage = $this->getPackage('__root__', 'dev-master', 'Composer\Package\RootPackage'); $rootPackage = $this->getPackage('__root__', 'dev-master', 'Composer\Package\RootPackage');

View File

@ -14,6 +14,9 @@ return array(
'root' => array( 'root' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . './',
'aliases' => array( 'aliases' => array(
'1.10.x-dev', '1.10.x-dev',
), ),
@ -25,6 +28,9 @@ return array(
'__root__' => array( '__root__' => array(
'pretty_version' => 'dev-master', 'pretty_version' => 'dev-master',
'version' => 'dev-master', 'version' => 'dev-master',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . './',
'aliases' => array( 'aliases' => array(
'1.10.x-dev', '1.10.x-dev',
), ),
@ -34,6 +40,9 @@ return array(
'a/provider' => array( 'a/provider' => array(
'pretty_version' => '1.1', 'pretty_version' => '1.1',
'version' => '1.1.0.0', 'version' => '1.1.0.0',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . '/foo/bar/vendor/woop/woop',
'aliases' => array(), 'aliases' => array(),
'reference' => 'distref-as-no-source', 'reference' => 'distref-as-no-source',
'dev-requirement' => false, 'dev-requirement' => false,
@ -41,6 +50,9 @@ return array(
'a/provider2' => array( 'a/provider2' => array(
'pretty_version' => '1.2', 'pretty_version' => '1.2',
'version' => '1.2.0.0', 'version' => '1.2.0.0',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . '/foo/bar/vendor/woop/woop',
'aliases' => array( 'aliases' => array(
'1.4', '1.4',
), ),
@ -50,6 +62,9 @@ return array(
'b/replacer' => array( 'b/replacer' => array(
'pretty_version' => '2.2', 'pretty_version' => '2.2',
'version' => '2.2.0.0', 'version' => '2.2.0.0',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . '/foo/bar/vendor/woop/woop',
'aliases' => array(), 'aliases' => array(),
'reference' => null, 'reference' => null,
'dev-requirement' => false, 'dev-requirement' => false,
@ -57,6 +72,9 @@ return array(
'c/c' => array( 'c/c' => array(
'pretty_version' => '3.0', 'pretty_version' => '3.0',
'version' => '3.0.0.0', 'version' => '3.0.0.0',
'type' => 'library',
// @phpstan-ignore-next-line
'install_path' => $dir . DIRECTORY_SEPARATOR . '/foo/bar/vendor/woop/woop',
'aliases' => array(), 'aliases' => array(),
'reference' => null, 'reference' => null,
'dev-requirement' => true, 'dev-requirement' => true,