GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( e09157...64b15f )
by Cees-Jan
03:50 queued 49s
created

Installer   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
eloc 77
c 2
b 0
f 1
dl 0
loc 177
rs 8.8798
wmc 44

8 Methods

Rating   Name   Duplication   Size   Complexity  
A uninstall() 0 2 1
A deactivate() 0 2 1
A activate() 0 2 1
A getSubscribedEvents() 0 3 1
F addMakeOnInstallOrUpdate() 0 57 18
C findEventListeners() 0 50 13
A getVendorDir() 0 8 3
A addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces() 0 20 6

How to fix   Complexity   

Complex Class

Complex classes like Installer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Installer, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace WyriHaximus\TestUtilities\Composer;
6
7
use Composer\Composer;
8
use Composer\EventDispatcher\EventSubscriberInterface;
9
use Composer\IO\IOInterface;
10
use Composer\Plugin\PluginInterface;
11
use Composer\Script\Event;
12
use Composer\Script\ScriptEvents;
13
use Exception;
14
15
use function array_key_exists;
16
use function array_keys;
17
use function dirname;
18
use function file_exists;
19
use function file_get_contents;
20
use function file_put_contents;
21
use function hash;
22
use function hash_equals;
23
use function is_array;
24
use function is_string;
25
use function json_decode;
26
use function json_encode;
27
use function preg_replace;
28
29
use const DIRECTORY_SEPARATOR;
30
use const JSON_PRETTY_PRINT;
31
use const JSON_UNESCAPED_SLASHES;
32
use const PHP_INT_MAX;
33
34
final class Installer implements PluginInterface, EventSubscriberInterface
35
{
36
    /** @return array<string, array<string|int>> */
37
    public static function getSubscribedEvents(): array
38
    {
39
        return [ScriptEvents::PRE_AUTOLOAD_DUMP => ['findEventListeners', PHP_INT_MAX]];
40
    }
41
42
    public function activate(Composer $composer, IOInterface $io): void
43
    {
44
        // does nothing, see getSubscribedEvents() instead.
45
    }
46
47
    public function deactivate(Composer $composer, IOInterface $io): void
48
    {
49
        // does nothing, see getSubscribedEvents() instead.
50
    }
51
52
    public function uninstall(Composer $composer, IOInterface $io): void
53
    {
54
        // does nothing, see getSubscribedEvents() instead.
55
    }
56
57
    /**
58
     * Called before every dump autoload, generates a fresh PHP class.
59
     *
60
     * @phpstan-ignore shipmonk.deadMethod
61
     */
62
    public static function findEventListeners(Event $event): void
63
    {
64
        $rootPackagePath = dirname(self::getVendorDir($event->getComposer())) . DIRECTORY_SEPARATOR;
65
        if (! file_exists($rootPackagePath . '/composer.json')) {
66
            return;
67
        }
68
69
        $jsonRaw = file_get_contents($rootPackagePath . '/composer.json');
70
        if (! is_string($jsonRaw)) {
0 ignored issues
show
introduced by
The condition is_string($jsonRaw) is always true.
Loading history...
71
            return;
72
        }
73
74
        $json = json_decode($jsonRaw, true);
75
        if (! is_array($json)) {
76
            return;
77
        }
78
79
        if (! array_key_exists('require-dev', $json)) {
80
            return;
81
        }
82
83
        if (! is_array($json['require-dev'])) {
84
            return;
85
        }
86
87
        $hasMakefiles = false;
88
        foreach (array_keys($json['require-dev']) as $package) {
89
            if ($package === 'wyrihaximus/makefiles') {
90
                $hasMakefiles = true;
91
                break;
92
            }
93
        }
94
95
        if (! $hasMakefiles) {
96
            return;
97
        }
98
99
        unset($hasMakefiles);
100
101
        if (array_key_exists('name', $json) && $json['name'] === 'wyrihaximus/test-utilities') {
102
            self::addMakeOnInstallOrUpdate($event->getIO(), $rootPackagePath);
103
104
            return;
105
        }
106
107
        foreach (array_keys($json['require-dev']) as $package) {
108
            if ($package === 'wyrihaximus/test-utilities') {
109
                self::addMakeOnInstallOrUpdate($event->getIO(), $rootPackagePath);
110
111
                return;
112
            }
113
        }
114
    }
115
116
    private static function addMakeOnInstallOrUpdate(IOInterface $io, string $rootPackagePath): void
117
    {
118
        $io->write('<info>wyrihaximus/test-utilities:</info> Adding <fg=cyan>make on-install-or-update || true</> to scripts');
119
        $composerJsonString = file_get_contents($rootPackagePath . '/composer.json');
120
        if (! is_string($composerJsonString)) {
0 ignored issues
show
introduced by
The condition is_string($composerJsonString) is always true.
Loading history...
121
            $io->write('<error>wyrihaximus/test-utilities:</error> Unable to read <fg=cyan>composer.json</> aborting');
122
123
            return;
124
        }
125
126
        $composerJson     = json_decode($composerJsonString, true);
127
        $composerJsonHash = hash('sha512', (string) json_encode($composerJson, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
128
        if (is_array($composerJson) && array_key_exists('scripts', $composerJson) && is_array($composerJson['scripts'])) {
129
            if (array_key_exists('post-install-cmd', $composerJson['scripts'])) {
130
                $composerJson['scripts']['post-install-cmd'] = self::addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces($composerJson['scripts']['post-install-cmd']);
131
            }
132
133
            if (array_key_exists('post-update-cmd', $composerJson['scripts'])) {
134
                $composerJson['scripts']['post-update-cmd'] = self::addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces($composerJson['scripts']['post-update-cmd']);
135
            }
136
        }
137
138
        $replacementComposerJsonString = json_encode($composerJson, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
139
        if (is_string($replacementComposerJsonString)) {
0 ignored issues
show
introduced by
The condition is_string($replacementComposerJsonString) is always true.
Loading history...
140
            $replacementComposerJsonHash = hash('sha512', $replacementComposerJsonString);
141
            if (! hash_equals($composerJsonHash, $replacementComposerJsonHash)) {
142
                $replacementComposerJsonString = preg_replace('/^(  +?)\\1(?=[^ ])/m', '$1', $replacementComposerJsonString);
143
                if (is_string($replacementComposerJsonString)) {
0 ignored issues
show
introduced by
The condition is_string($replacementComposerJsonString) is always true.
Loading history...
144
                    $io->write('<info>wyrihaximus/test-utilities:</info> Writing new <fg=cyan>composer.json</>');
145
                    file_put_contents($rootPackagePath . '/composer.json', $replacementComposerJsonString);
146
                }
147
            }
148
        }
149
150
        if (is_array($composerJson) && array_key_exists('scripts', $composerJson) && is_array($composerJson['scripts'])) {
151
            if (array_key_exists('post-install-cmd', $composerJson['scripts'])) {
152
                $composerJson['scripts']['post-install-cmd'] = self::addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces($composerJson['scripts']['post-install-cmd']);
153
            }
154
155
            if (array_key_exists('post-update-cmd', $composerJson['scripts'])) {
156
                $composerJson['scripts']['post-update-cmd'] = self::addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces($composerJson['scripts']['post-update-cmd']);
157
            }
158
        }
159
160
        $replacementComposerJsonString = json_encode($composerJson, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
161
        if (is_string($replacementComposerJsonString)) {
0 ignored issues
show
introduced by
The condition is_string($replacementComposerJsonString) is always true.
Loading history...
162
            $replacementComposerJsonHash = hash('sha512', $replacementComposerJsonString);
163
            if (! hash_equals($composerJsonHash, $replacementComposerJsonHash)) {
164
                $replacementComposerJsonString = preg_replace('/^(  +?)\\1(?=[^ ])/m', '$1', $replacementComposerJsonString);
165
                if (is_string($replacementComposerJsonString)) {
0 ignored issues
show
introduced by
The condition is_string($replacementComposerJsonString) is always true.
Loading history...
166
                    $io->write('<info>wyrihaximus/test-utilities:</info> Writing new <fg=cyan>composer.json</>');
167
                    file_put_contents($rootPackagePath . '/composer.json', $replacementComposerJsonString . "\r\n");
168
                }
169
            }
170
        }
171
172
        $io->write('<info>wyrihaximus/test-utilities:</info> Finished <fg=cyan>make on-install-or-update || true</> to scripts');
173
    }
174
175
    /**
176
     * @param array<int, string> $scriptsSection
177
     *
178
     * @return array<int, string>
179
     */
180
    private static function addMakeOnInstallOrUpdateToScriptsSectionAndRemoveCommandsItReplaces(array $scriptsSection): array
181
    {
182
        foreach ($scriptsSection as $script) {
183
            if ($script === 'make on-install-or-update || true') {
184
                return $scriptsSection;
185
            }
186
        }
187
188
        $scripts = [];
189
        foreach ($scriptsSection as $script) {
190
            if ($script === 'composer normalize' || $script === 'composer update --lock --no-scripts') {
191
                continue;
192
            }
193
194
            $scripts[] = $script;
195
        }
196
197
        $scripts[] = 'make on-install-or-update || true';
198
199
        return $scripts;
200
    }
201
202
    /** @return non-empty-string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment non-empty-string at position 0 could not be parsed: Unknown type name 'non-empty-string' at position 0 in non-empty-string.
Loading history...
203
    private static function getVendorDir(Composer $composer): string
204
    {
205
        $vendorDir = $composer->getConfig()->get('vendor-dir');
206
        if ($vendorDir === '' || ! file_exists($vendorDir)) {
207
            throw new Exception('vendor-dir must be a string');
208
        }
209
210
        return $vendorDir;
211
    }
212
}
213