xref: /dokuwiki/vendor/composer/InstalledVersions.php (revision 934f970a961272cf366d019f15b7c0685de4fc7e)
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    /**
30*934f970aSAndreas Gohr     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
31*934f970aSAndreas Gohr     * @internal
32*934f970aSAndreas Gohr     */
33*934f970aSAndreas Gohr    private static $selfDir = null;
34*934f970aSAndreas Gohr
35*934f970aSAndreas Gohr    /**
36d3233986SAndreas Gohr     * @var mixed[]|null
3728e9760aSAndreas 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
38d3233986SAndreas Gohr     */
39d3233986SAndreas Gohr    private static $installed;
40d3233986SAndreas Gohr
41d3233986SAndreas Gohr    /**
4283bbbbbeSAndreas Gohr     * @var bool
4383bbbbbeSAndreas Gohr     */
4483bbbbbeSAndreas Gohr    private static $installedIsLocalDir;
4583bbbbbeSAndreas Gohr
4683bbbbbeSAndreas Gohr    /**
47d3233986SAndreas Gohr     * @var bool|null
48d3233986SAndreas Gohr     */
496cb05674SAndreas Gohr    private static $canGetVendors;
50d3233986SAndreas Gohr
51d3233986SAndreas Gohr    /**
52d3233986SAndreas Gohr     * @var array[]
5328e9760aSAndreas 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[]}>}>
54d3233986SAndreas Gohr     */
556cb05674SAndreas Gohr    private static $installedByVendor = array();
566cb05674SAndreas Gohr
57d3233986SAndreas Gohr    /**
58d3233986SAndreas Gohr     * Returns a list of all package names which are present, either by being installed, replaced or provided
59d3233986SAndreas Gohr     *
60d3233986SAndreas Gohr     * @return string[]
61d3233986SAndreas Gohr     * @psalm-return list<string>
62d3233986SAndreas Gohr     */
636cb05674SAndreas Gohr    public static function getInstalledPackages()
646cb05674SAndreas Gohr    {
656cb05674SAndreas Gohr        $packages = array();
666cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
676cb05674SAndreas Gohr            $packages[] = array_keys($installed['versions']);
686cb05674SAndreas Gohr        }
696cb05674SAndreas Gohr
706cb05674SAndreas Gohr        if (1 === \count($packages)) {
716cb05674SAndreas Gohr            return $packages[0];
726cb05674SAndreas Gohr        }
736cb05674SAndreas Gohr
746cb05674SAndreas Gohr        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
756cb05674SAndreas Gohr    }
766cb05674SAndreas Gohr
77d3233986SAndreas Gohr    /**
78d3233986SAndreas Gohr     * Returns a list of all package names with a specific type e.g. 'library'
79d3233986SAndreas Gohr     *
80d3233986SAndreas Gohr     * @param  string   $type
81d3233986SAndreas Gohr     * @return string[]
82d3233986SAndreas Gohr     * @psalm-return list<string>
83d3233986SAndreas Gohr     */
84d3233986SAndreas Gohr    public static function getInstalledPackagesByType($type)
85d3233986SAndreas Gohr    {
86d3233986SAndreas Gohr        $packagesByType = array();
876cb05674SAndreas Gohr
88d3233986SAndreas Gohr        foreach (self::getInstalled() as $installed) {
89d3233986SAndreas Gohr            foreach ($installed['versions'] as $name => $package) {
90d3233986SAndreas Gohr                if (isset($package['type']) && $package['type'] === $type) {
91d3233986SAndreas Gohr                    $packagesByType[] = $name;
92d3233986SAndreas Gohr                }
93d3233986SAndreas Gohr            }
94d3233986SAndreas Gohr        }
956cb05674SAndreas Gohr
96d3233986SAndreas Gohr        return $packagesByType;
97d3233986SAndreas Gohr    }
986cb05674SAndreas Gohr
99d3233986SAndreas Gohr    /**
100d3233986SAndreas Gohr     * Checks whether the given package is installed
101d3233986SAndreas Gohr     *
102d3233986SAndreas Gohr     * This also returns true if the package name is provided or replaced by another package
103d3233986SAndreas Gohr     *
104d3233986SAndreas Gohr     * @param  string $packageName
105d3233986SAndreas Gohr     * @param  bool   $includeDevRequirements
106d3233986SAndreas Gohr     * @return bool
107d3233986SAndreas Gohr     */
108d3233986SAndreas Gohr    public static function isInstalled($packageName, $includeDevRequirements = true)
1096cb05674SAndreas Gohr    {
1106cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1116cb05674SAndreas Gohr            if (isset($installed['versions'][$packageName])) {
1122cadabe7SAndreas Gohr                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
1136cb05674SAndreas Gohr            }
1146cb05674SAndreas Gohr        }
1156cb05674SAndreas Gohr
1166cb05674SAndreas Gohr        return false;
1176cb05674SAndreas Gohr    }
1186cb05674SAndreas Gohr
119d3233986SAndreas Gohr    /**
120d3233986SAndreas Gohr     * Checks whether the given package satisfies a version constraint
121d3233986SAndreas Gohr     *
122d3233986SAndreas Gohr     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
123d3233986SAndreas Gohr     *
124d3233986SAndreas Gohr     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
125d3233986SAndreas Gohr     *
126d3233986SAndreas Gohr     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
127d3233986SAndreas Gohr     * @param  string        $packageName
128d3233986SAndreas 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
129d3233986SAndreas Gohr     * @return bool
130d3233986SAndreas Gohr     */
1316cb05674SAndreas Gohr    public static function satisfies(VersionParser $parser, $packageName, $constraint)
1326cb05674SAndreas Gohr    {
1332cadabe7SAndreas Gohr        $constraint = $parser->parseConstraints((string) $constraint);
1346cb05674SAndreas Gohr        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
1356cb05674SAndreas Gohr
1366cb05674SAndreas Gohr        return $provided->matches($constraint);
1376cb05674SAndreas Gohr    }
1386cb05674SAndreas Gohr
139d3233986SAndreas Gohr    /**
140d3233986SAndreas Gohr     * Returns a version constraint representing all the range(s) which are installed for a given package
141d3233986SAndreas Gohr     *
142d3233986SAndreas Gohr     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
143d3233986SAndreas Gohr     * whether a given version of a package is installed, and not just whether it exists
144d3233986SAndreas Gohr     *
145d3233986SAndreas Gohr     * @param  string $packageName
146d3233986SAndreas Gohr     * @return string Version constraint usable with composer/semver
147d3233986SAndreas Gohr     */
1486cb05674SAndreas Gohr    public static function getVersionRanges($packageName)
1496cb05674SAndreas Gohr    {
1506cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1516cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
1526cb05674SAndreas Gohr                continue;
1536cb05674SAndreas Gohr            }
1546cb05674SAndreas Gohr
1556cb05674SAndreas Gohr            $ranges = array();
1566cb05674SAndreas Gohr            if (isset($installed['versions'][$packageName]['pretty_version'])) {
1576cb05674SAndreas Gohr                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
1586cb05674SAndreas Gohr            }
1596cb05674SAndreas Gohr            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
1606cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
1616cb05674SAndreas Gohr            }
1626cb05674SAndreas Gohr            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
1636cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
1646cb05674SAndreas Gohr            }
1656cb05674SAndreas Gohr            if (array_key_exists('provided', $installed['versions'][$packageName])) {
1666cb05674SAndreas Gohr                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
1676cb05674SAndreas Gohr            }
1686cb05674SAndreas Gohr
1696cb05674SAndreas Gohr            return implode(' || ', $ranges);
1706cb05674SAndreas Gohr        }
1716cb05674SAndreas Gohr
1726cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
1736cb05674SAndreas Gohr    }
1746cb05674SAndreas Gohr
175d3233986SAndreas Gohr    /**
176d3233986SAndreas Gohr     * @param  string      $packageName
177d3233986SAndreas 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
178d3233986SAndreas Gohr     */
1796cb05674SAndreas Gohr    public static function getVersion($packageName)
1806cb05674SAndreas Gohr    {
1816cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
1826cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
1836cb05674SAndreas Gohr                continue;
1846cb05674SAndreas Gohr            }
1856cb05674SAndreas Gohr
1866cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['version'])) {
1876cb05674SAndreas Gohr                return null;
1886cb05674SAndreas Gohr            }
1896cb05674SAndreas Gohr
1906cb05674SAndreas Gohr            return $installed['versions'][$packageName]['version'];
1916cb05674SAndreas Gohr        }
1926cb05674SAndreas Gohr
1936cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
1946cb05674SAndreas Gohr    }
1956cb05674SAndreas Gohr
196d3233986SAndreas Gohr    /**
197d3233986SAndreas Gohr     * @param  string      $packageName
198d3233986SAndreas 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
199d3233986SAndreas Gohr     */
2006cb05674SAndreas Gohr    public static function getPrettyVersion($packageName)
2016cb05674SAndreas Gohr    {
2026cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
2036cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
2046cb05674SAndreas Gohr                continue;
2056cb05674SAndreas Gohr            }
2066cb05674SAndreas Gohr
2076cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
2086cb05674SAndreas Gohr                return null;
2096cb05674SAndreas Gohr            }
2106cb05674SAndreas Gohr
2116cb05674SAndreas Gohr            return $installed['versions'][$packageName]['pretty_version'];
2126cb05674SAndreas Gohr        }
2136cb05674SAndreas Gohr
2146cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
2156cb05674SAndreas Gohr    }
2166cb05674SAndreas Gohr
217d3233986SAndreas Gohr    /**
218d3233986SAndreas Gohr     * @param  string      $packageName
219d3233986SAndreas Gohr     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
220d3233986SAndreas Gohr     */
2216cb05674SAndreas Gohr    public static function getReference($packageName)
2226cb05674SAndreas Gohr    {
2236cb05674SAndreas Gohr        foreach (self::getInstalled() as $installed) {
2246cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
2256cb05674SAndreas Gohr                continue;
2266cb05674SAndreas Gohr            }
2276cb05674SAndreas Gohr
2286cb05674SAndreas Gohr            if (!isset($installed['versions'][$packageName]['reference'])) {
2296cb05674SAndreas Gohr                return null;
2306cb05674SAndreas Gohr            }
2316cb05674SAndreas Gohr
2326cb05674SAndreas Gohr            return $installed['versions'][$packageName]['reference'];
2336cb05674SAndreas Gohr        }
2346cb05674SAndreas Gohr
2356cb05674SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
2366cb05674SAndreas Gohr    }
2376cb05674SAndreas Gohr
238d3233986SAndreas Gohr    /**
239d3233986SAndreas Gohr     * @param  string      $packageName
240d3233986SAndreas 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.
241d3233986SAndreas Gohr     */
242d3233986SAndreas Gohr    public static function getInstallPath($packageName)
243d3233986SAndreas Gohr    {
244d3233986SAndreas Gohr        foreach (self::getInstalled() as $installed) {
245d3233986SAndreas Gohr            if (!isset($installed['versions'][$packageName])) {
246d3233986SAndreas Gohr                continue;
247d3233986SAndreas Gohr            }
2486cb05674SAndreas Gohr
249d3233986SAndreas Gohr            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
250d3233986SAndreas Gohr        }
2516cb05674SAndreas Gohr
252d3233986SAndreas Gohr        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
253d3233986SAndreas Gohr    }
2546cb05674SAndreas Gohr
255d3233986SAndreas Gohr    /**
256d3233986SAndreas Gohr     * @return array
25728e9760aSAndreas Gohr     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
258d3233986SAndreas Gohr     */
2596cb05674SAndreas Gohr    public static function getRootPackage()
2606cb05674SAndreas Gohr    {
2616cb05674SAndreas Gohr        $installed = self::getInstalled();
2626cb05674SAndreas Gohr
2636cb05674SAndreas Gohr        return $installed[0]['root'];
2646cb05674SAndreas Gohr    }
2656cb05674SAndreas Gohr
266d3233986SAndreas Gohr    /**
267d3233986SAndreas Gohr     * Returns the raw installed.php data for custom implementations
268d3233986SAndreas Gohr     *
269d3233986SAndreas 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.
270d3233986SAndreas Gohr     * @return array[]
27128e9760aSAndreas 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[]}>}
272d3233986SAndreas Gohr     */
2736cb05674SAndreas Gohr    public static function getRawData()
2746cb05674SAndreas Gohr    {
275d3233986SAndreas 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);
276d3233986SAndreas Gohr
277d3233986SAndreas Gohr        if (null === self::$installed) {
278d3233986SAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
279d3233986SAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
280d3233986SAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
281d3233986SAndreas Gohr                self::$installed = include __DIR__ . '/installed.php';
282d3233986SAndreas Gohr            } else {
283d3233986SAndreas Gohr                self::$installed = array();
284d3233986SAndreas Gohr            }
285d3233986SAndreas Gohr        }
286d3233986SAndreas Gohr
2876cb05674SAndreas Gohr        return self::$installed;
2886cb05674SAndreas Gohr    }
2896cb05674SAndreas Gohr
290d3233986SAndreas Gohr    /**
291d3233986SAndreas Gohr     * Returns the raw data of all installed.php which are currently loaded for custom implementations
292d3233986SAndreas Gohr     *
293d3233986SAndreas Gohr     * @return array[]
29428e9760aSAndreas 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[]}>}>
295d3233986SAndreas Gohr     */
296d3233986SAndreas Gohr    public static function getAllRawData()
297d3233986SAndreas Gohr    {
298d3233986SAndreas Gohr        return self::getInstalled();
299d3233986SAndreas Gohr    }
3006cb05674SAndreas Gohr
301d3233986SAndreas Gohr    /**
302d3233986SAndreas Gohr     * Lets you reload the static array from another file
303d3233986SAndreas Gohr     *
304d3233986SAndreas Gohr     * This is only useful for complex integrations in which a project needs to use
305d3233986SAndreas Gohr     * this class but then also needs to execute another project's autoloader in process,
306d3233986SAndreas Gohr     * and wants to ensure both projects have access to their version of installed.php.
307d3233986SAndreas Gohr     *
308d3233986SAndreas Gohr     * A typical case would be PHPUnit, where it would need to make sure it reads all
309d3233986SAndreas Gohr     * the data it needs from this class, then call reload() with
310d3233986SAndreas Gohr     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
311d3233986SAndreas Gohr     * the project in which it runs can then also use this class safely, without
312d3233986SAndreas Gohr     * interference between PHPUnit's dependencies and the project's dependencies.
313d3233986SAndreas Gohr     *
314d3233986SAndreas Gohr     * @param  array[] $data A vendor/composer/installed.php data set
315d3233986SAndreas Gohr     * @return void
316d3233986SAndreas Gohr     *
31728e9760aSAndreas 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
318d3233986SAndreas Gohr     */
3196cb05674SAndreas Gohr    public static function reload($data)
3206cb05674SAndreas Gohr    {
3216cb05674SAndreas Gohr        self::$installed = $data;
3226cb05674SAndreas Gohr        self::$installedByVendor = array();
32383bbbbbeSAndreas Gohr
32483bbbbbeSAndreas Gohr        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
32583bbbbbeSAndreas Gohr        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
32683bbbbbeSAndreas Gohr        // so we have to assume it does not, and that may result in duplicate data being returned when listing
32783bbbbbeSAndreas Gohr        // all installed packages for example
32883bbbbbeSAndreas Gohr        self::$installedIsLocalDir = false;
3296cb05674SAndreas Gohr    }
3306cb05674SAndreas Gohr
331d3233986SAndreas Gohr    /**
332*934f970aSAndreas Gohr     * @return string
333*934f970aSAndreas Gohr     */
334*934f970aSAndreas Gohr    private static function getSelfDir()
335*934f970aSAndreas Gohr    {
336*934f970aSAndreas Gohr        if (self::$selfDir === null) {
337*934f970aSAndreas Gohr            self::$selfDir = strtr(__DIR__, '\\', '/');
338*934f970aSAndreas Gohr        }
339*934f970aSAndreas Gohr
340*934f970aSAndreas Gohr        return self::$selfDir;
341*934f970aSAndreas Gohr    }
342*934f970aSAndreas Gohr
343*934f970aSAndreas Gohr    /**
344d3233986SAndreas Gohr     * @return array[]
34528e9760aSAndreas 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[]}>}>
346d3233986SAndreas Gohr     */
3476cb05674SAndreas Gohr    private static function getInstalled()
3486cb05674SAndreas Gohr    {
3496cb05674SAndreas Gohr        if (null === self::$canGetVendors) {
3506cb05674SAndreas Gohr            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
3516cb05674SAndreas Gohr        }
3526cb05674SAndreas Gohr
3536cb05674SAndreas Gohr        $installed = array();
3549520a435SAndreas Gohr        $copiedLocalDir = false;
3556cb05674SAndreas Gohr
3566cb05674SAndreas Gohr        if (self::$canGetVendors) {
357*934f970aSAndreas Gohr            $selfDir = self::getSelfDir();
3586cb05674SAndreas Gohr            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
35983bbbbbeSAndreas Gohr                $vendorDir = strtr($vendorDir, '\\', '/');
3606cb05674SAndreas Gohr                if (isset(self::$installedByVendor[$vendorDir])) {
3616cb05674SAndreas Gohr                    $installed[] = self::$installedByVendor[$vendorDir];
3626cb05674SAndreas Gohr                } elseif (is_file($vendorDir.'/composer/installed.php')) {
3632cadabe7SAndreas 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 */
3642cadabe7SAndreas Gohr                    $required = require $vendorDir.'/composer/installed.php';
3659520a435SAndreas Gohr                    self::$installedByVendor[$vendorDir] = $required;
3669520a435SAndreas Gohr                    $installed[] = $required;
36783bbbbbeSAndreas Gohr                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
3689520a435SAndreas Gohr                        self::$installed = $required;
36983bbbbbeSAndreas Gohr                        self::$installedIsLocalDir = true;
370d3233986SAndreas Gohr                    }
3716cb05674SAndreas Gohr                }
37283bbbbbeSAndreas Gohr                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
37383bbbbbeSAndreas Gohr                    $copiedLocalDir = true;
37483bbbbbeSAndreas Gohr                }
3756cb05674SAndreas Gohr            }
3766cb05674SAndreas Gohr        }
3776cb05674SAndreas Gohr
378d3233986SAndreas Gohr        if (null === self::$installed) {
379d3233986SAndreas Gohr            // only require the installed.php file if this file is loaded from its dumped location,
380d3233986SAndreas Gohr            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
381d3233986SAndreas Gohr            if (substr(__DIR__, -8, 1) !== 'C') {
3822cadabe7SAndreas 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 */
3832cadabe7SAndreas Gohr                $required = require __DIR__ . '/installed.php';
3842cadabe7SAndreas Gohr                self::$installed = $required;
385d3233986SAndreas Gohr            } else {
386d3233986SAndreas Gohr                self::$installed = array();
387d3233986SAndreas Gohr            }
388d3233986SAndreas Gohr        }
3892cadabe7SAndreas Gohr
3909520a435SAndreas Gohr        if (self::$installed !== array() && !$copiedLocalDir) {
3916cb05674SAndreas Gohr            $installed[] = self::$installed;
3922cadabe7SAndreas Gohr        }
3936cb05674SAndreas Gohr
3946cb05674SAndreas Gohr        return $installed;
3956cb05674SAndreas Gohr    }
3966cb05674SAndreas Gohr}
397