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

Installer   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 95.56%

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 8
dl 0
loc 166
ccs 43
cts 45
cp 0.9556
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 7 1
A activate() 0 4 1
A dumpVersionsClass() 0 13 2
A generateVersionsClass() 0 8 1
A writeVersionClassToFile() 0 18 2
A locateRootPackageInstallPath() 0 10 2
A getRootPackageAlias() 0 10 2
A getVersions() 0 14 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 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
        self::writeVersionClassToFile(self::generateVersionsClass($versions), $composer, $composerEvent->getIO());
93 11
    }
94
95 11
    private static function generateVersionsClass(array $versions) : string
96
    {
97 11
        return sprintf(
98 11
            self::$generatedClassTemplate,
99 11
            'fin' . 'al ' . 'cla' . 'ss ' . 'Versions', // note: workaround for regex-based code parsers :-(
100 11
            var_export($versions, true)
101
        );
102
    }
103
104
    /**
105
     * @param string $versionClassSource
106
     * @param Composer $composer
107
     * @param IOInterface $io
108
     *
109
     * @return void
110
     *
111
     * @throws \RuntimeException
112
     */
113 11
    private static function writeVersionClassToFile(string $versionClassSource, Composer $composer, IOInterface $io)
114
    {
115 11
        $installPath = self::locateRootPackageInstallPath($composer->getConfig(), $composer->getPackage())
116 11
            . '/src/PackageVersions/Versions.php';
117
118 11
        if (! file_exists(dirname($installPath))) {
119 1
            $io->write('<info>ocramius/package-versions:</info> Package not found (probably scheduled for removal); generation of version class skipped.');
120
            
121 1
            return;
122
        }
123
124 10
        $io->write('<info>ocramius/package-versions:</info>  Generating version class...');
125
126 10
        file_put_contents($installPath, $versionClassSource);
127 10
        chmod($installPath, 0664);
128
129 10
        $io->write('<info>ocramius/package-versions:</info> ...done generating version class');
130 10
    }
131
132
    /**
133
     * @param Config               $composerConfig
134
     * @param RootPackageInterface $rootPackage
135
     *
136
     * @return string
137
     *
138
     * @throws \RuntimeException
139
     */
140 11
    private static function locateRootPackageInstallPath(
141
        Config $composerConfig,
142
        RootPackageInterface $rootPackage
143
    ) : string {
144 11
        if ('ocramius/package-versions' === self::getRootPackageAlias($rootPackage)->getName()) {
145 3
            return dirname($composerConfig->get('vendor-dir'));
146
        }
147
148 8
        return $composerConfig->get('vendor-dir') . '/ocramius/package-versions';
149
    }
150
151 11
    private static function getRootPackageAlias(RootPackageInterface $rootPackage) : PackageInterface
152
    {
153 11
        $package = $rootPackage;
154
155 11
        while ($package instanceof AliasPackage) {
156 4
            $package = $package->getAliasOf();
157
        }
158
159 11
        return $package;
160
    }
161
162
    /**
163
     * @param Locker               $locker
164
     * @param RootPackageInterface $rootPackage
165
     *
166
     * @return \Generator|\string[]
167
     */
168 12
    private static function getVersions(Locker $locker, RootPackageInterface $rootPackage) : \Generator
169
    {
170 12
        $lockData = $locker->getLockData();
171
172 12
        $lockData['packages-dev'] = $lockData['packages-dev'] ?? [];
173
174 12
        foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
175 12
            yield $package['name'] => $package['version'] . '@' . (
176 12
                $package['source']['reference']?? $package['dist']['reference'] ?? ''
177
            );
178
        }
179
180 12
        yield $rootPackage->getName() => $rootPackage->getVersion() . '@' . $rootPackage->getSourceReference();
181 12
    }
182
}
183