Completed
Pull Request — master (#46)
by Alessandro
03:02
created

Installer::dumpVersionsClass()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

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