|
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 getcwd; |
|
15
|
|
|
use function iterator_to_array; |
|
16
|
|
|
use function json_decode; |
|
17
|
|
|
use function json_encode; |
|
18
|
|
|
use function sprintf; |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* @internal |
|
22
|
|
|
* |
|
23
|
|
|
* This is a fallback for {@see \PackageVersions\Versions::getVersion()} |
|
24
|
|
|
* Do not use this class directly: it is intended to be only used when |
|
25
|
|
|
* {@see \PackageVersions\Versions} fails to be generated, which typically |
|
26
|
|
|
* happens when running composer with `--no-scripts` flag) |
|
27
|
|
|
*/ |
|
28
|
|
|
final class FallbackVersions |
|
|
|
|
|
|
29
|
|
|
{ |
|
30
|
|
|
public const ROOT_PACKAGE_NAME = 'unknown/root-package@UNKNOWN'; |
|
31
|
|
|
|
|
32
|
|
|
private function __construct() |
|
33
|
|
|
{ |
|
34
|
|
|
} |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* @throws OutOfBoundsException If a version cannot be located. |
|
38
|
|
|
* @throws UnexpectedValueException If the composer.lock file could not be located. |
|
39
|
3 |
|
*/ |
|
40
|
|
|
public static function getVersion(string $packageName) : string |
|
41
|
3 |
|
{ |
|
42
|
|
|
$versions = iterator_to_array(self::getVersions(self::getPackageData())); |
|
43
|
2 |
|
|
|
44
|
1 |
|
if (! array_key_exists($packageName, $versions)) { |
|
45
|
1 |
|
throw new OutOfBoundsException( |
|
46
|
|
|
'Required package "' . $packageName . '" is not installed: check your ./vendor/composer/installed.json and/or ./composer.lock files' |
|
47
|
|
|
); |
|
48
|
|
|
} |
|
49
|
1 |
|
|
|
50
|
|
|
return $versions[$packageName]; |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* @throws UnexpectedValueException |
|
55
|
3 |
|
*/ |
|
56
|
|
|
private static function getPackageData() : array |
|
57
|
|
|
{ |
|
58
|
3 |
|
$checkedPaths = [ |
|
59
|
|
|
// The top-level project's ./vendor/composer/installed.json |
|
60
|
3 |
|
getcwd() . '/vendor/composer/installed.json', |
|
61
|
3 |
|
// The top-level project's ./composer.lock |
|
62
|
3 |
|
getcwd() . '/composer.lock', |
|
63
|
|
|
// This package's composer.lock |
|
64
|
|
|
__DIR__ . '/../../composer.lock', |
|
65
|
|
|
]; |
|
66
|
1 |
|
|
|
67
|
|
|
foreach ($checkedPaths as $path) { |
|
|
|
|
|
|
68
|
|
|
if (file_exists($path)) { |
|
69
|
1 |
|
switch (basename($path)) { |
|
70
|
1 |
|
case 'installed.json': |
|
71
|
|
|
return json_decode(file_get_contents($path), true); |
|
72
|
|
|
case 'composer.lock': |
|
73
|
|
|
$data = json_decode(file_get_contents($path), true); |
|
74
|
2 |
|
return array_merge($data['packages'], $data['packages-dev'] ?? []); |
|
75
|
|
|
default: |
|
|
|
|
|
|
76
|
2 |
|
// intentionally left blank |
|
77
|
|
|
} |
|
78
|
2 |
|
} |
|
79
|
|
|
} |
|
80
|
2 |
|
|
|
81
|
2 |
|
throw new UnexpectedValueException(sprintf( |
|
82
|
2 |
|
'PackageVersions could not locate the `vendor/composer/installed.json` or your `composer.lock` ' |
|
83
|
|
|
. 'location. This is assumed to be in %s. If you customized your composer vendor directory and ran composer ' |
|
84
|
|
|
. 'installation with --no-scripts or if you deployed without the required composer files, then you are on ' |
|
85
|
|
|
. 'your own, and we can\'t really help you. Fix your shit and cut the tooling some slack.', |
|
86
|
2 |
|
json_encode($checkedPaths) |
|
87
|
2 |
|
)); |
|
88
|
|
|
} |
|
|
|
|
|
|
89
|
|
|
|
|
90
|
|
|
private static function getVersions(array $packageData) : Generator |
|
91
|
|
|
{ |
|
92
|
|
|
foreach ($packageData as $package) { |
|
93
|
|
|
yield $package['name'] => $package['version'] . '@' . ( |
|
94
|
|
|
$package['source']['reference'] ?? $package['dist']['reference'] ?? '' |
|
95
|
|
|
); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
yield self::ROOT_PACKAGE_NAME; |
|
99
|
|
|
} |
|
100
|
|
|
} |
|
|
|
|
|
|
101
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.