Completed
Pull Request — master (#26)
by Stepan
05:53
created

Installer::getCapabilities()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
ccs 0
cts 0
cp 0
cc 1
eloc 3
nc 1
nop 0
crap 2
1
<?php
2
3
namespace PackageVersions;
4
5
use Composer\Composer;
6
use Composer\Config;
7
use Composer\EventDispatcher\EventSubscriberInterface;
8
use Composer\IO\IOInterface;
9
use Composer\Package\AliasPackage;
10
use Composer\Package\Locker;
11
use Composer\Package\PackageInterface;
12
use Composer\Package\RootPackageInterface;
13
use Composer\Plugin\Capability\CommandProvider as CommandProviderInterface;
14
use Composer\Plugin\Capable;
15
use Composer\Plugin\PluginInterface;
16
use Composer\Script\Event;
17
use Composer\Script\ScriptEvents;
18
19
final class Installer implements PluginInterface, EventSubscriberInterface, Capable
20
{
21
    private static $generatedClassTemplate = <<<'PHP'
22
<?php
23
24
namespace PackageVersions;
25
26
/**
27
 * This class is generated by ocramius/package-versions, specifically by
28
 * @see \PackageVersions\Installer
29
 *
30
 * This file is overwritten at every run of `composer install` or `composer update`.
31
 */
32
%s
33
{
34
    const VERSIONS = %s;
35
36
    private function __construct()
37
    {
38
    }
39
40
    /**
41
     * @throws \OutOfBoundsException if a version cannot be located
42
     */
43
    public static function getVersion(string $packageName) : string
44
    {
45
        if (! isset(self::VERSIONS[$packageName])) {
46
            throw new \OutOfBoundsException(
47
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
48
            );
49
        }
50
51
        return self::VERSIONS[$packageName];
52
    }
53
}
54
55
PHP;
56
57
    /**
58 1
     * {@inheritDoc}
59
     */
60 1
    public function activate(Composer $composer, IOInterface $io)
61 1
    {
62
        $composer->getEventDispatcher()->addSubscriber($this);
63
    }
64
65
    /**
66 1
     * {@inheritDoc}
67
     */
68
    public static function getSubscribedEvents()
69 1
    {
70 1
        return [
71
            ScriptEvents::POST_INSTALL_CMD => 'dumpVersionsClass',
72
            ScriptEvents::POST_UPDATE_CMD  => 'dumpVersionsClass',
73
        ];
74
    }
75
76
    /**
77
     * @param Event $composerEvent
78
     *
79
     * @return void
80
     *
81 9
     * @throws \RuntimeException
82
     */
83 9
    public static function dumpVersionsClass(Event $composerEvent)
84
    {
85 9
        $io = $composerEvent->getIO();
86
87 9
        $io->write('<info>ocramius/package-versions:</info>  Generating version class...');
88
89 9
        $composer = $composerEvent->getComposer();
90 9
91 9
        self::writeVersionClassToFile(
92 9
            self::generateVersionsClass($composer),
93
            $composer->getConfig(),
94
            $composer->getPackage()
95 9
        );
96 9
97
        $io->write('<info>ocramius/package-versions:</info> ...done generating version class');
98 9
    }
99
100 9
    private static function generateVersionsClass(Composer $composer) : string
101 9
    {
102 9
        return sprintf(
103 9
            self::$generatedClassTemplate,
104
            'fin' . 'al ' . 'cla' . 'ss ' . 'Versions', // note: workaround for regex-based code parsers :-(
105
            var_export(iterator_to_array(self::getVersions($composer->getLocker(), $composer->getPackage())), true)
106
        );
107
    }
108
109
    /**
110
     * @param string               $versionClassSource
111
     * @param Config               $composerConfig
112
     * @param RootPackageInterface $rootPackage
113
     *
114
     * @return void
115
     *
116 9
     * @throws \RuntimeException
117
     */
118
    private static function writeVersionClassToFile(
119
        string $versionClassSource,
120
        Config $composerConfig,
121 9
        RootPackageInterface $rootPackage
122 9
    ) {
123 9
        file_put_contents(
124
            self::locateRootPackageInstallPath($composerConfig, $rootPackage)
125 9
            . '/src/PackageVersions/Versions.php',
126
            $versionClassSource,
127 9
            0664
128
        );
129
    }
130
131
    /**
132
     * @param Config               $composerConfig
133
     * @param RootPackageInterface $rootPackage
134
     *
135
     * @return string
136
     *
137 9
     * @throws \RuntimeException
138
     */
139
    private static function locateRootPackageInstallPath(
140
        Config $composerConfig,
141 9
        RootPackageInterface $rootPackage
142 3
    ) : string {
143
        if ('ocramius/package-versions' === self::getRootPackageAlias($rootPackage)->getName()) {
144
            return dirname($composerConfig->get('vendor-dir'));
145 6
        }
146
147
        return $composerConfig->get('vendor-dir') . '/ocramius/package-versions';
148 9
    }
149
150 9
    private static function getRootPackageAlias(RootPackageInterface $rootPackage) : PackageInterface
151
    {
152 9
        $package = $rootPackage;
153 4
154
        while ($package instanceof AliasPackage) {
155
            $package = $package->getAliasOf();
156 9
        }
157
158
        return $package;
159
    }
160
161
    /**
162
     * @param Locker               $locker
163
     * @param RootPackageInterface $rootPackage
164
     *
165 9
     * @return \Generator|\string[]
166
     */
167 9
    private static function getVersions(Locker $locker, RootPackageInterface $rootPackage) : \Generator
168
    {
169 9
        $lockData = $locker->getLockData();
170
171 9
        $lockData['packages-dev'] = $lockData['packages-dev'] ?? [];
172 3
173 3
        foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
174
            yield $package['name'] => $package['version'] . '@' . (
175
                $package['source']['reference']?? $package['dist']['reference'] ?? ''
176
            );
177 9
        }
178 9
179
        yield $rootPackage->getName() => $rootPackage->getVersion() . '@' . $rootPackage->getSourceReference();
180
    }
181
182
    /**
183
     * @return array
184
     */
185
    public function getCapabilities() : array
186
    {
187
        return [
188
            CommandProviderInterface::class => CommandProvider::class,
189
        ];
190
    }
191
}
192