Completed
Pull Request — master (#66)
by Peter
04:56
created

Installer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 94.55%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 9
dl 0
loc 167
ccs 52
cts 55
cp 0.9455
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A activate() 0 4 1
A getSubscribedEvents() 0 7 1
A dumpVersionsClass() 0 16 2
A generateVersionsClass() 0 9 1
A writeVersionClassToFile() 0 23 3
A locateRootPackageInstallPath() 0 10 2
A getRootPackageAlias() 0 10 2
B getVersions() 0 23 4
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) : void
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() : array
68
    {
69
        return [
70 1
            ScriptEvents::POST_INSTALL_CMD => 'dumpVersionsClass',
71 1
            ScriptEvents::POST_UPDATE_CMD  => 'dumpVersionsClass',
72
        ];
73
    }
74
75
    /**
76
     * @throws \RuntimeException
77
     */
78 13
    public static function dumpVersionsClass(Event $composerEvent) : void
79
    {
80 13
        $composer = $composerEvent->getComposer();
81 13
        $rootPackage = $composer->getPackage();
82 13
        $versions = iterator_to_array(self::getVersions($composer->getLocker(), $rootPackage));
83
84 13
        if (!array_key_exists('ocramius/package-versions', $versions)) {
85
            //plugin must be globally installed - we only want to generate versions for projects which specifically
86
            //require ocramius/package-versions
87 1
            return;
88
        }
89
90 12
        $versionClass = self::generateVersionsClass($rootPackage->getName(), $versions);
91
92 12
        self::writeVersionClassToFile($versionClass, $composer, $composerEvent->getIO());
93 12
    }
94
95 12
    private static function generateVersionsClass(string $rootPackageName, array $versions) : string
96
    {
97 12
        return sprintf(
98 12
            self::$generatedClassTemplate,
99 12
            'fin' . 'al ' . 'cla' . 'ss ' . 'Versions', // note: workaround for regex-based code parsers :-(
100 12
            $rootPackageName,
101 12
            var_export($versions, true)
102
        );
103
    }
104
105
    /**
106
     * @throws \RuntimeException
107
     */
108 12
    private static function writeVersionClassToFile(string $versionClassSource, Composer $composer, IOInterface $io) : void
109
    {
110 12
        $installPath = self::locateRootPackageInstallPath($composer->getConfig(), $composer->getPackage())
111 12
            . '/src/PackageVersions/Versions.php';
112
113 12
        if (! file_exists(dirname($installPath))) {
114 1
            $io->write('<info>ocramius/package-versions:</info> Package not found (probably scheduled for removal); generation of version class skipped.');
115
116 1
            return;
117
        }
118
119 11
        $io->write('<info>ocramius/package-versions:</info>  Generating version class...');
120
121
        // Delete the file prior writing the new file to ensure proper user/group setting of the file
122 11
        if(file_exists($installPath)) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after IF keyword; 0 found
Loading history...
123
            unlink($installPath);
124
        }
125
        
126 11
        file_put_contents($installPath, $versionClassSource);
127 11
        chmod($installPath, 0664);
128
129 11
        $io->write('<info>ocramius/package-versions:</info> ...done generating version class');
130 11
    }
131
132
    /**
133
     * @throws \RuntimeException
134
     */
135 12
    private static function locateRootPackageInstallPath(
136
        Config $composerConfig,
137
        RootPackageInterface $rootPackage
138
    ) : string {
139 12
        if ('ocramius/package-versions' === self::getRootPackageAlias($rootPackage)->getName()) {
140 3
            return dirname($composerConfig->get('vendor-dir'));
141
        }
142
143 9
        return $composerConfig->get('vendor-dir') . '/ocramius/package-versions';
144
    }
145
146 12
    private static function getRootPackageAlias(RootPackageInterface $rootPackage) : PackageInterface
147
    {
148 12
        $package = $rootPackage;
149
150 12
        while ($package instanceof AliasPackage) {
151 4
            $package = $package->getAliasOf();
152
        }
153
154 12
        return $package;
155
    }
156
157
    /**
158
     * @return \Generator|\string[]
159
     */
160 13
    private static function getVersions(Locker $locker, RootPackageInterface $rootPackage) : \Generator
161
    {
162 13
        $lockData = $locker->getLockData();
163
164 13
        $lockData['packages-dev'] = $lockData['packages-dev'] ?? [];
165
166 13
        foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
167 13
            yield $package['name'] => $package['version'] . '@' . (
168 13
                $package['source']['reference']?? $package['dist']['reference'] ?? ''
169
            );
170
        }
171
172 13
        foreach ($rootPackage->getReplaces() as $replace) {
173 4
            $version = $replace->getPrettyConstraint();
174 4
            if ($version === 'self.version') {
175 4
                $version = $rootPackage->getPrettyVersion();
176
            }
177
178 4
            yield $replace->getTarget() => $version . '@' . $rootPackage->getSourceReference();
179
        }
180
181 13
        yield $rootPackage->getName() => $rootPackage->getPrettyVersion() . '@' . $rootPackage->getSourceReference();
182 13
    }
183
}
184