Completed
Pull Request — master (#56)
by Eugene
07:21
created

Installer::activate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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