xref: /dokuwiki/vendor/composer/InstalledVersions.php (revision 83bbbbbe80e83566fddb651affb54e5ca8aac179)
16cb05674SAndreas Gohr<?php
26cb05674SAndreas Gohr
3d3233986SAndreas Gohr/*
4d3233986SAndreas Gohr * This file is part of Composer.
5d3233986SAndreas Gohr *
6d3233986SAndreas Gohr * (c) Nils Adermann <naderman@naderman.de>
7d3233986SAndreas Gohr *     Jordi Boggiano <j.boggiano@seld.be>
8d3233986SAndreas Gohr *
9d3233986SAndreas Gohr * For the full copyright and license information, please view the LICENSE
10d3233986SAndreas Gohr * file that was distributed with this source code.
11d3233986SAndreas Gohr */
126cb05674SAndreas Gohr
136cb05674SAndreas Gohrnamespace Composer;
146cb05674SAndreas Gohr
156cb05674SAndreas Gohruse Composer\Autoload\ClassLoader;
166cb05674SAndreas Gohruse Composer\Semver\VersionParser;
176cb05674SAndreas Gohr
18d3233986SAndreas Gohr/**
19d3233986SAndreas Gohr * This class is copied in every Composer installed project and available to all
20d3233986SAndreas Gohr *
21d3233986SAndreas Gohr * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
22d3233986SAndreas Gohr *
23d3233986SAndreas Gohr * To require its presence, you can require `composer-runtime-api ^2.0`
24d3233986SAndreas Gohr *
25d3233986SAndreas Gohr * @final
26d3233986SAndreas Gohr */
276cb05674SAndreas Gohrclass InstalledVersions
286cb05674SAndreas Gohr{
29d3233986SAndreas Gohr    /**
30d3233986SAndreas Gohr     * @var mixed[]|null
3128e9760aSAndreas Gohr     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
32d3233986SAndreas Gohr     */
33d3233986SAndreas Gohr    private static $installed;
34d3233986SAndreas Gohr
35d3233986SAndreas Gohr    /**
36*83bbbbbeSAndreas Gohr     * @var bool
37*83bbbbbeSAndreas Gohr     */
38*83bbbbbeSAndreas Gohr    private static $installedIsLocalDir;
39*83bbbbbeSAndreas Gohr
40*83bbbbbeSAndreas Gohr    /**
41d3233986SAndreas Gohr     * @var bool|null
42d3233986SAndreas Gohr     */
436cb05674SAndreas Gohr    private static $canGetVendors;
44d3233986SAndreas Gohr
45d3233986SAndreas Gohr    /**
46d3233986SAndreas Gohr     * @var array[]
4728e9760aSAndreas Gohr     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
48d3233986SAndreas Gohr     */
496cb05674SAndreas Gohr    private static $installedByVendor = array();
506cb05674SAndreas Gohr
51d3233986SAndreas Gohr    /**
52d3233986SAndreas Gohr     * Returns a list of all package names which are present, either by being installed, replaced or provided
53d3233986SAndreas Gohr     *
54d3233986SAndreas Gohr     * @return string[]
55d3233986SAndreas Gohr     * @psalm-return list<string>
56d3233986SAndreas Gohr     */
576cb05674SAndreas Gohr    public static function getInstalledPackages()
586cb05674SAndreas Gohr    {
596cb05674SAndreas Gohr        $packages = array();
606cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
616cb05674SAndreas Gohr            $packages[] = array_keys($installed['versions']);
626cb05674SAndreas Gohr        }
636cb05674SAndreas Gohr
646cb05674SAndreas Gohr        if (1 === \count($packages)) {
656cb05674SAndreas Gohr            return $packages[0];
666cb05674SAndreas Gohr        }
676cb05674SAndreas Gohr
686cb05674SAndreas Gohr        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
696cb05674SAndreas Gohr    }
706cb05674SAndreas Gohr
71d3233986SAndreas Gohr    /**
72d3233986SAndreas Gohr     * Returns a list of all package names with a specific type e.g. 'library'
73d3233986SAndreas Gohr     *
74d3233986SAndreas Gohr     * @param  string   $type
75d3233986SAndreas Gohr     * @return string[]
76d3233986SAndreas Gohr     * @psalm-return list<string>
77d3233986SAndreas Gohr     */
78d3233986SAndreas Gohr    public static function getInstalledPackagesByType($type)
79d3233986SAndreas Gohr    {
80d3233986SAndreas Gohr        $packagesByType = array();
816cb05674SAndreas Gohr
82d3233986SAndreas Gohr        foreach (self::getInstalled() as $installed) {
83d3233986SAndreas Gohr            foreach ($installed['versions'] as $name => $package) {
84d3233986SAndreas Gohr                if (isset($package['type']) && $package['type'] === $type) {
85d3233986SAndreas Gohr                    $packagesByType[] = $name;
86d3233986SAndreas Gohr                }
87d3233986SAndreas Gohr            }
88d3233986SAndreas Gohr        }
896cb05674SAndreas Gohr
90d3233986SAndreas Gohr        return $packagesByType;
91d3233986SAndreas Gohr    }
926cb05674SAndreas Gohr
93d3233986SAndreas Gohr    /**
94d3233986SAndreas Gohr     * Checks whether the given package is installed
95d3233986SAndreas Gohr     *
96d3233986SAndreas Gohr     * This also returns true if the package name is provided or replaced by another package
97d3233986SAndreas Gohr     *
98d3233986SAndreas Gohr     * @param  string $packageName
99d3233986SAndreas Gohr     * @param  bool   $includeDevRequirements
100d3233986SAndreas Gohr     * @return bool
101d3233986SAndreas Gohr     */
102d3233986SAndreas Gohr    public static function isInstalled($packageName, $includeDevRequirements = true)
1036cb05674SAndreas Gohr    {
1046cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1056cb05674SAndreas Gohr            if (isset($installed['versions'][$packageName])) {
1062cadabe7SAndreas Gohr                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
1076cb05674SAndreas Gohr            }
1086cb05674SAndreas Gohr        }
1096cb05674SAndreas Gohr
1106cb05674SAndreas Gohr        return false;
1116cb05674SAndreas Gohr    }
1126cb05674SAndreas Gohr
113d3233986SAndreas Gohr    /**
114d3233986SAndreas Gohr     * Checks whether the given package satisfies a version constraint
115d3233986SAndreas Gohr     *
116d3233986SAndreas Gohr     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
117d3233986SAndreas Gohr     *
118d3233986SAndreas Gohr     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
119d3233986SAndreas Gohr     *
120d3233986SAndreas Gohr     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
121d3233986SAndreas Gohr     * @param  string        $packageName
122d3233986SAndreas Gohr     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
123d3233986SAndreas Gohr     * @return bool
124d3233986SAndreas Gohr     */
1256cb05674SAndreas Gohr    public static function satisfies(VersionParser $parser, $packageName, $constraint)
1266cb05674SAndreas Gohr    {
1272cadabe7SAndreas Gohr        $constraint = $parser->parseConstraints((string) $constraint);
1286cb05674SAndreas Gohr        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
1296cb05674SAndreas Gohr
1306cb05674SAndreas Gohr        return $provided->matches($constraint);
1316cb05674SAndreas Gohr    }
1326cb05674SAndreas Gohr
133d3233986SAndreas Gohr    /**
134d3233986SAndreas Gohr     * Returns a version constraint representing all the range(s) which are installed for a given package
135d3233986SAndreas Gohr     *
136d3233986SAndreas Gohr     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
137d3233986SAndreas Gohr     * whether a given version of a package is installed, and not just whether it exists
138d3233986SAndreas Gohr     *
139d3233986SAndreas Gohr     * @param  string $packageName
140d3233986SAndreas Gohr     * @return string Version constraint usable with composer/semver
141d3233986SAndreas Gohr     */
1426cb05674SAndreas Gohr    public static function getVersionRanges($packageName)
1436cb05674SAndreas Gohr    {
1446cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1456cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
1466cb05674SAndreas Gohr                continue;
1476cb05674SAndreas Gohr            }
1486cb05674SAndreas Gohr
1496cb05674SAndreas Gohr            $ranges = array();
1506cb05674SAndreas Gohr            if (isset($installed['versions'][$packageName]['pretty_version'])) {
1516cb05674SAndreas Gohr                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
1526cb05674SAndreas Gohr            }
1536cb05674SAndreas Gohr            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
1546cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
1556cb05674SAndreas Gohr            }
1566cb05674SAndreas Gohr            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
1576cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
1586cb05674SAndreas Gohr            }
1596cb05674SAndreas Gohr            if (array_key_exists('provided', $installed['versions'][$packageName])) {
1606cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
1616cb05674SAndreas Gohr            }
1626cb05674SAndreas Gohr
1636cb05674SAndreas Gohr            return implode(' || ', $ranges);
1646cb05674SAndreas Gohr        }
1656cb05674SAndreas Gohr
1666cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
1676cb05674SAndreas Gohr    }
1686cb05674SAndreas Gohr
169d3233986SAndreas Gohr    /**
170d3233986SAndreas Gohr     * @param  string      $packageName
171d3233986SAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
172d3233986SAndreas Gohr     */
1736cb05674SAndreas Gohr    public static function getVersion($packageName)
1746cb05674SAndreas Gohr    {
1756cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1766cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
1776cb05674SAndreas Gohr                continue;
1786cb05674SAndreas Gohr            }
1796cb05674SAndreas Gohr
1806cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['version'])) {
1816cb05674SAndreas Gohr                return null;
1826cb05674SAndreas Gohr            }
1836cb05674SAndreas Gohr
1846cb05674SAndreas Gohr            return $installed['versions'][$packageName]['version'];
1856cb05674SAndreas Gohr        }
1866cb05674SAndreas Gohr
1876cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
1886cb05674SAndreas Gohr    }
1896cb05674SAndreas Gohr
190d3233986SAndreas Gohr    /**
191d3233986SAndreas Gohr     * @param  string      $packageName
192d3233986SAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
193d3233986SAndreas Gohr     */
1946cb05674SAndreas Gohr    public static function getPrettyVersion($packageName)
1956cb05674SAndreas Gohr    {
1966cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1976cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
1986cb05674SAndreas Gohr                continue;
1996cb05674SAndreas Gohr            }
2006cb05674SAndreas Gohr
2016cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
2026cb05674SAndreas Gohr                return null;
2036cb05674SAndreas Gohr            }
2046cb05674SAndreas Gohr
2056cb05674SAndreas Gohr            return $installed['versions'][$packageName]['pretty_version'];
2066cb05674SAndreas Gohr        }
2076cb05674SAndreas Gohr
2086cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
2096cb05674SAndreas Gohr    }
2106cb05674SAndreas Gohr
211d3233986SAndreas Gohr    /**
212d3233986SAndreas Gohr     * @param  string      $packageName
213d3233986SAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
214d3233986SAndreas Gohr     */
2156cb05674SAndreas Gohr    public static function getReference($packageName)
2166cb05674SAndreas Gohr    {
2176cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
2186cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
2196cb05674SAndreas Gohr                continue;
2206cb05674SAndreas Gohr            }
2216cb05674SAndreas Gohr
2226cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['reference'])) {
2236cb05674SAndreas Gohr                return null;
2246cb05674SAndreas Gohr            }
2256cb05674SAndreas Gohr
2266cb05674SAndreas Gohr            return $installed['versions'][$packageName]['reference'];
2276cb05674SAndreas Gohr        }
2286cb05674SAndreas Gohr
2296cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
2306cb05674SAndreas Gohr    }
2316cb05674SAndreas Gohr
232d3233986SAndreas Gohr    /**
233d3233986SAndreas Gohr     * @param  string      $packageName
234d3233986SAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
235d3233986SAndreas Gohr     */
236d3233986SAndreas Gohr    public static function getInstallPath($packageName)
237d3233986SAndreas Gohr    {
238d3233986SAndreas Gohr        foreach (self::getInstalled() as $installed) {
239d3233986SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
240d3233986SAndreas Gohr                continue;
241d3233986SAndreas Gohr            }
2426cb05674SAndreas Gohr
243d3233986SAndreas Gohr            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
244d3233986SAndreas Gohr        }
2456cb05674SAndreas Gohr
246d3233986SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
247d3233986SAndreas Gohr    }
2486cb05674SAndreas Gohr
249d3233986SAndreas Gohr    /**
250d3233986SAndreas Gohr     * @return array
25128e9760aSAndreas Gohr     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
252d3233986SAndreas Gohr     */
2536cb05674SAndreas Gohr    public static function getRootPackage()
2546cb05674SAndreas Gohr    {
2556cb05674SAndreas Gohr        $installed = self::getInstalled();
2566cb05674SAndreas Gohr
2576cb05674SAndreas Gohr        return $installed[0]['root'];
2586cb05674SAndreas Gohr    }
2596cb05674SAndreas Gohr
260d3233986SAndreas Gohr    /**
261d3233986SAndreas Gohr     * Returns the raw installed.php data for custom implementations
262d3233986SAndreas Gohr     *
263d3233986SAndreas Gohr     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
264d3233986SAndreas Gohr     * @return array[]
26528e9760aSAndreas Gohr     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
266d3233986SAndreas Gohr     */
2676cb05674SAndreas Gohr    public static function getRawData()
2686cb05674SAndreas Gohr    {
269d3233986SAndreas Gohr        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
270d3233986SAndreas Gohr
271d3233986SAndreas Gohr        if (null === self::$installed) {
272d3233986SAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
273d3233986SAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
274d3233986SAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
275d3233986SAndreas Gohr                self::$installed = include __DIR__ . '/installed.php';
276d3233986SAndreas Gohr            } else {
277d3233986SAndreas Gohr                self::$installed = array();
278d3233986SAndreas Gohr            }
279d3233986SAndreas Gohr        }
280d3233986SAndreas Gohr
2816cb05674SAndreas Gohr        return self::$installed;
2826cb05674SAndreas Gohr    }
2836cb05674SAndreas Gohr
284d3233986SAndreas Gohr    /**
285d3233986SAndreas Gohr     * Returns the raw data of all installed.php which are currently loaded for custom implementations
286d3233986SAndreas Gohr     *
287d3233986SAndreas Gohr     * @return array[]
28828e9760aSAndreas Gohr     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
289d3233986SAndreas Gohr     */
290d3233986SAndreas Gohr    public static function getAllRawData()
291d3233986SAndreas Gohr    {
292d3233986SAndreas Gohr        return self::getInstalled();
293d3233986SAndreas Gohr    }
2946cb05674SAndreas Gohr
295d3233986SAndreas Gohr    /**
296d3233986SAndreas Gohr     * Lets you reload the static array from another file
297d3233986SAndreas Gohr     *
298d3233986SAndreas Gohr     * This is only useful for complex integrations in which a project needs to use
299d3233986SAndreas Gohr     * this class but then also needs to execute another project's autoloader in process,
300d3233986SAndreas Gohr     * and wants to ensure both projects have access to their version of installed.php.
301d3233986SAndreas Gohr     *
302d3233986SAndreas Gohr     * A typical case would be PHPUnit, where it would need to make sure it reads all
303d3233986SAndreas Gohr     * the data it needs from this class, then call reload() with
304d3233986SAndreas Gohr     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
305d3233986SAndreas Gohr     * the project in which it runs can then also use this class safely, without
306d3233986SAndreas Gohr     * interference between PHPUnit's dependencies and the project's dependencies.
307d3233986SAndreas Gohr     *
308d3233986SAndreas Gohr     * @param  array[] $data A vendor/composer/installed.php data set
309d3233986SAndreas Gohr     * @return void
310d3233986SAndreas Gohr     *
31128e9760aSAndreas Gohr     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
312d3233986SAndreas Gohr     */
3136cb05674SAndreas Gohr    public static function reload($data)
3146cb05674SAndreas Gohr    {
3156cb05674SAndreas Gohr        self::$installed = $data;
3166cb05674SAndreas Gohr        self::$installedByVendor = array();
317*83bbbbbeSAndreas Gohr
318*83bbbbbeSAndreas Gohr        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
319*83bbbbbeSAndreas Gohr        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
320*83bbbbbeSAndreas Gohr        // so we have to assume it does not, and that may result in duplicate data being returned when listing
321*83bbbbbeSAndreas Gohr        // all installed packages for example
322*83bbbbbeSAndreas Gohr        self::$installedIsLocalDir = false;
3236cb05674SAndreas Gohr    }
3246cb05674SAndreas Gohr
325d3233986SAndreas Gohr    /**
326d3233986SAndreas Gohr     * @return array[]
32728e9760aSAndreas Gohr     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
328d3233986SAndreas Gohr     */
3296cb05674SAndreas Gohr    private static function getInstalled()
3306cb05674SAndreas Gohr    {
3316cb05674SAndreas Gohr        if (null === self::$canGetVendors) {
3326cb05674SAndreas Gohr            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
3336cb05674SAndreas Gohr        }
3346cb05674SAndreas Gohr
3356cb05674SAndreas Gohr        $installed = array();
3369520a435SAndreas Gohr        $copiedLocalDir = false;
3376cb05674SAndreas Gohr
3386cb05674SAndreas Gohr        if (self::$canGetVendors) {
339*83bbbbbeSAndreas Gohr            $selfDir = strtr(__DIR__, '\\', '/');
3406cb05674SAndreas Gohr            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
341*83bbbbbeSAndreas Gohr                $vendorDir = strtr($vendorDir, '\\', '/');
3426cb05674SAndreas Gohr                if (isset(self::$installedByVendor[$vendorDir])) {
3436cb05674SAndreas Gohr                    $installed[] = self::$installedByVendor[$vendorDir];
3446cb05674SAndreas Gohr                } elseif (is_file($vendorDir.'/composer/installed.php')) {
3452cadabe7SAndreas Gohr                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
3462cadabe7SAndreas Gohr                    $required = require $vendorDir.'/composer/installed.php';
3479520a435SAndreas Gohr                    self::$installedByVendor[$vendorDir] = $required;
3489520a435SAndreas Gohr                    $installed[] = $required;
349*83bbbbbeSAndreas Gohr                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
3509520a435SAndreas Gohr                        self::$installed = $required;
351*83bbbbbeSAndreas Gohr                        self::$installedIsLocalDir = true;
352d3233986SAndreas Gohr                    }
3536cb05674SAndreas Gohr                }
354*83bbbbbeSAndreas Gohr                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
355*83bbbbbeSAndreas Gohr                    $copiedLocalDir = true;
356*83bbbbbeSAndreas Gohr                }
3576cb05674SAndreas Gohr            }
3586cb05674SAndreas Gohr        }
3596cb05674SAndreas Gohr
360d3233986SAndreas Gohr        if (null === self::$installed) {
361d3233986SAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
362d3233986SAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
363d3233986SAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
3642cadabe7SAndreas Gohr                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
3652cadabe7SAndreas Gohr                $required = require __DIR__ . '/installed.php';
3662cadabe7SAndreas Gohr                self::$installed = $required;
367d3233986SAndreas Gohr            } else {
368d3233986SAndreas Gohr                self::$installed = array();
369d3233986SAndreas Gohr            }
370d3233986SAndreas Gohr        }
3712cadabe7SAndreas Gohr
3729520a435SAndreas Gohr        if (self::$installed !== array() && !$copiedLocalDir) {
3736cb05674SAndreas Gohr            $installed[] = self::$installed;
3742cadabe7SAndreas Gohr        }
3756cb05674SAndreas Gohr
3766cb05674SAndreas Gohr        return $installed;
3776cb05674SAndreas Gohr    }
3786cb05674SAndreas Gohr}
379