Completed
Pull Request — master (#1)
by Abdul Malik
13:58 queued 11:23
created

Installer   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 165
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 14
c 2
b 0
f 0
lcom 1
cbo 9
dl 0
loc 165
ccs 0
cts 46
cp 0
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A activate() 0 4 1
A getSubscribedEvents() 0 7 1
A dumpVersionsClass() 0 16 1
A generateVersionsClass() 0 8 1
A writeVersionClassToFile() 0 12 1
A locateRootPackageInstallPath() 0 10 2
A getRootPackageAlias() 0 10 2
B getVersions() 0 16 5
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 samsonasik/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($packageName)
42
    {
43
        if (null !== 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
        $composer->getEventDispatcher()->addSubscriber($this);
61
    }
62
63
    /**
64
     * {@inheritDoc}
65
     */
66
    public static function getSubscribedEvents()
67
    {
68
        return [
69
            ScriptEvents::POST_INSTALL_CMD => 'dumpVersionsClass',
70
            ScriptEvents::POST_UPDATE_CMD  => 'dumpVersionsClass',
71
        ];
72
    }
73
74
    /**
75
     * @param Event $composerEvent
76
     *
77
     * @return void
78
     *
79
     * @throws \RuntimeException
80
     */
81
    public static function dumpVersionsClass(Event $composerEvent)
82
    {
83
        $io = $composerEvent->getIO();
84
85
        $io->write('<info>samsonasik/package-versions:</info>  Generating version class...');
86
87
        $composer = $composerEvent->getComposer();
88
89
        self::writeVersionClassToFile(
90
            self::generateVersionsClass($composer),
91
            $composer->getConfig(),
92
            $composer->getPackage()
93
        );
94
95
        $io->write('<info>samsonasik/package-versions:</info> ...done generating version class');
96
    }
97
98
    private static function generateVersionsClass(Composer $composer)
99
    {
100
        return sprintf(
101
            self::$generatedClassTemplate,
102
            'fin' . 'al ' . 'cla' . 'ss ' . 'Versions', // note: workaround for regex-based code parsers :-(
103
            var_export(iterator_to_array(self::getVersions($composer->getLocker(), $composer->getPackage())), true)
104
        );
105
    }
106
107
    /**
108
     * @param string               $versionClassSource
109
     * @param Config               $composerConfig
110
     * @param RootPackageInterface $rootPackage
111
     *
112
     * @return void
113
     *
114
     * @throws \RuntimeException
115
     */
116
    private static function writeVersionClassToFile(
117
        $versionClassSource,
118
        Config $composerConfig,
119
        RootPackageInterface $rootPackage
120
    ) {
121
        file_put_contents(
122
            self::locateRootPackageInstallPath($composerConfig, $rootPackage)
123
            . '/src/PackageVersions/Versions.php',
124
            $versionClassSource,
125
            0664
126
        );
127
    }
128
129
    /**
130
     * @param Config               $composerConfig
131
     * @param RootPackageInterface $rootPackage
132
     *
133
     * @return string
134
     *
135
     * @throws \RuntimeException
136
     */
137
    private static function locateRootPackageInstallPath(
138
        Config $composerConfig,
139
        RootPackageInterface $rootPackage
140
    ) {
141
        if ('samsonasik/package-versions' === self::getRootPackageAlias($rootPackage)->getName()) {
142
            return dirname($composerConfig->get('vendor-dir'));
143
        }
144
145
        return $composerConfig->get('vendor-dir') . '/samsonasik/package-versions';
146
    }
147
148
    private static function getRootPackageAlias(RootPackageInterface $rootPackage)
149
    {
150
        $package = $rootPackage;
151
152
        while ($package instanceof AliasPackage) {
153
            $package = $package->getAliasOf();
154
        }
155
156
        return $package;
157
    }
158
159
    /**
160
     * @param Locker               $locker
161
     * @param RootPackageInterface $rootPackage
162
     *
163
     * @return \Generator|\string[]
164
     */
165
    private static function getVersions(Locker $locker, RootPackageInterface $rootPackage)
166
    {
167
        $lockData = $locker->getLockData();
168
169
        $lockData['packages-dev'] = isset($lockData['packages-dev']) ? $lockData['packages-dev'] : [];
170
171
        foreach (array_merge($lockData['packages'], $lockData['packages-dev']) as $package) {
172
            yield $package['name'] => $package['version'] . '@' . (
173
                isset($package['source']['reference'])
174
                    ? $package['source']['reference']
175
                    : (isset($package['dist']['reference']) ? $package['dist']['reference'] : '')
176
            );
177
        }
178
179
        yield $rootPackage->getName() => $rootPackage->getVersion() . '@' . $rootPackage->getSourceReference();
180
    }
181
}
182