Completed
Pull Request — master (#82)
by
unknown
02:15
created

FallbackVersions::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PackageVersions;
6
7
use Generator;
8
use OutOfBoundsException;
9
use UnexpectedValueException;
10
use function array_key_exists;
11
use function array_merge;
12
use function file_exists;
13
use function file_get_contents;
14
use function iterator_to_array;
15
use function json_decode;
16
use function json_encode;
17
use function sprintf;
18
19
/**
20
 * @internal
21
 *
22
 * This is a fallback for {@see \PackageVersions\Versions::getVersion()}
23
 * Do not use this class directly: it is intended to be only used when
24
 * {@see \PackageVersions\Versions} fails to be generated, which typically
25
 * happens when running composer with `--no-scripts` flag)
26
 */
27
final class FallbackVersions
28
{
29
    public const ROOT_PACKAGE_NAME = 'unknown/root-package@UNKNOWN';
30
31
    private function __construct()
32
    {
33
    }
34
35
    /**
36
     * @param string $packageName
37
     * @return string
38
     * @throws OutOfBoundsException If a version cannot be located.
39
     * @throws UnexpectedValueException If the composer.lock file could not be located.
40
     */
41 3
    public static function getVersion(string $packageName) : string
42
    {
43 3
        $versions = iterator_to_array(self::getVersions(self::getComposerLockPath()));
44
45 2
        if (! array_key_exists($packageName, $versions)) {
46 1
            throw new OutOfBoundsException(
47 1
                'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files'
48
            );
49
        }
50
51 1
        return $versions[$packageName];
52
    }
53
54
    /**
55
     * @throws UnexpectedValueException
56
     */
57 3
    private static function getComposerLockPath() : string
58
    {
59
        $checkedPaths = [
60
            // The top-level project's ./vendor/composer/installed.json
61 3
            getcwd() . '/vendor/composer/installed.json',
62
            // The top-level project's ./composer.lock
63 3
            getcwd() . '/composer.lock',
64
            // This package's composer.lock
65
            __DIR__ . '/../../composer.lock',
66
        ];
67
68 3
        foreach ($checkedPaths as $path) {
69 3
            if (file_exists($path)) {
70 3
                return $path;
71
            }
72
        }
73
74 1
        throw new UnexpectedValueException(sprintf(
75
            'PackageVersions could not locate the `vendor/composer/installed.json` or your `composer.lock` '
76
            . 'location. This is assumed to be in %s. If you customized your composer vendor directory and ran composer '
77
            . 'installation with --no-scripts or if you deployed without the required composer files, then you are on '
78 1
            . 'your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.',
79 1
            json_encode($checkedPaths)
80
        ));
81
    }
82
83 2
    private static function getVersions(string $composerLockFile) : Generator
84
    {
85 2
        $lockData = json_decode(file_get_contents($composerLockFile), true);
86
87 2
        if (array_key_exists('content-hash', $lockData)) {
88
            // assume a composer.lock file and merge the packages and packages-dev into an array
89
            $lockData = array_merge($lockData['packages'], $lockData['packages-dev'] ?? []);
90
        }
91
92 2
        foreach ($lockData as $package) {
93 2
            yield $package['name'] => $package['version'] . '@' . (
94 2
                $package['source']['reference'] ?? $package['dist']['reference'] ?? ''
95
            );
96
        }
97
98 2
        yield self::ROOT_PACKAGE_NAME;
99 2
    }
100
}
101