Completed
Pull Request — master (#208)
by Hiraku
03:00
created

Plugin   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 171
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 59.15%

Importance

Changes 0
Metric Value
wmc 31
lcom 1
cbo 8
dl 0
loc 171
ccs 42
cts 71
cp 0.5915
rs 9.92
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 9 1
A onPreFileDownload() 0 19 3
B prefetchComposerRepositories() 0 28 9
A onPostDependenciesSolving() 0 12 2
A disable() 0 4 1
A isDisabled() 0 4 1
C activate() 0 45 14
1
<?php
2
/*
3
 * hirak/prestissimo
4
 * @author Hiraku NAKANO
5
 * @license MIT https://github.com/hirak/prestissimo
6
 */
7
namespace Hirak\Prestissimo;
8
9
use Composer\Composer;
10
use Composer\IO;
11
use Composer\Plugin as CPlugin;
12
use Composer\EventDispatcher;
13
use Composer\Installer;
14
15
class Plugin implements
16
    CPlugin\PluginInterface,
17
    EventDispatcher\EventSubscriberInterface
18
{
19
    /** @var IO\IOInterface */
20
    private $io;
21
22
    /** @var Composer\Config */
23
    private $config;
24
25
    /** @var array */
26
    private $package;
27
    private $cached = false;
28
29
    /** @var boolean */
30
    private $disabled = false;
31
32
    private static $pluginClasses = array(
33
        'BaseRequest',
34
        'ConfigFacade',
35
        'CopyRequest',
36
        'CurlMulti',
37
        'CurlRemoteFilesystem',
38
        'FetchException',
39
        'FetchRequest',
40
        'FileDownloaderDummy',
41
        'ParallelizedComposerRepository',
42
        'Plugin',
43
        'Prefetcher',
44
        'Share',
45
    );
46
47
    private static $supportedSchemes = array(
48
        'http',
49
        'https'
50
    );
51
52 3
    public function activate(Composer $composer, IO\IOInterface $io)
53
    {
54
        // @codeCoverageIgnoreStart
55
        // guard for self-update problem
56
        if (__CLASS__ !== 'Hirak\Prestissimo\Plugin') {
57
            return $this->disable();
58
        }
59
        // guard for missing curl extension problem
60
        if (!extension_loaded('curl')) {
61
            $io->writeError('<error>Error: "curl" PHP extension not loaded; Prestissmo Composer plugin disabled.</error>');
62
            return $this->disable();
63
        }
64
        // @codeCoverageIgnoreEnd
65
66
        // load all classes
67 3
        foreach (self::$pluginClasses as $class) {
68 3
            class_exists(__NAMESPACE__ . '\\' . $class);
69
        }
70
71 3
        $this->io = $io;
72 3
        $this->config = $composer->getConfig();
0 ignored issues
show
Documentation Bug introduced by
It seems like $composer->getConfig() of type object<Composer\Config> is incompatible with the declared type object<Composer\Composer\Config> of property $config.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
73 3
        $this->package = $composer->getPackage();
0 ignored issues
show
Documentation Bug introduced by
It seems like $composer->getPackage() of type object<Composer\Package\RootPackageInterface> is incompatible with the declared type array of property $package.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
74
75 3
        if (array_key_exists('argv', $GLOBALS)) {
76 3
            if (in_array('help', $GLOBALS['argv'])) {
77
                return $this->disable();
78
            }
79
80 3
            foreach ($GLOBALS['argv'] as $arg) {
81 3
                switch ($arg) {
82 3
                    case 'create-project':
83 3
                    case 'update':
84 3
                    case 'outdated':
85 3
                    case 'require':
86
                        $this->prefetchComposerRepositories();
87
                        break 2;
88 3
                    case 'install':
89
                        if (file_exists('composer.json') && !file_exists('composer.lock')) {
90
                            $this->prefetchComposerRepositories();
91
                        }
92
                        break 2;
93
                }
94
            }
95
        }
96 3
    }
97
98 1
    public static function getSubscribedEvents()
99
    {
100
        return array(
101 1
            CPlugin\PluginEvents::PRE_FILE_DOWNLOAD => 'onPreFileDownload',
102 1
            Installer\InstallerEvents::POST_DEPENDENCIES_SOLVING => array(
103 1
                array('onPostDependenciesSolving', PHP_INT_MAX),
104
            ),
105
        );
106
    }
107
108
    /**
109
     * Keep-Alived file downloader
110
     */
111
    public function onPreFileDownload(CPlugin\PreFileDownloadEvent $ev)
112
    {
113
        if ($this->disabled) {
114
            return;
115
        }
116
117
        $scheme = parse_url($ev->getProcessedUrl(), PHP_URL_SCHEME);
118
        if (!in_array($scheme, self::$supportedSchemes, true)) {
119
            return;
120
        }
121
122
        $rfs = $ev->getRemoteFilesystem();
123
        $curlrfs = new CurlRemoteFilesystem(
124
            $this->io,
125
            $this->config,
126
            $rfs->getOptions()
127
        );
128
        $ev->setRemoteFilesystem($curlrfs);
129
    }
130
131 1
    public function prefetchComposerRepositories()
132
    {
133 1
        if ($this->disabled) {
134 1
            return;
135
        }
136 1
        if ($this->cached) {
137
            return;
138
        }
139 1
        $repos = $this->package->getRepositories();
0 ignored issues
show
Bug introduced by
The method getRepositories cannot be called on $this->package (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
140 1
        foreach ($repos as $label => $repo) {
141
            if (isset($repo['type']) && $repo['type'] === 'composer') {
142
                if (!empty($repo['force-lazy-providers'])) {
143
                    continue;
144
                }
145
146
                if (substr($repo['url'], 0, 6) !== 'https?') {
147
                    $scheme = parse_url($repo['url'], PHP_URL_SCHEME);
148
                    if (!in_array($scheme, self::$supportedSchemes, true)) {
149
                        continue;
150
                    }
151
                }
152
153
                $r = new ParallelizedComposerRepository($repo, $this->io, $this->config);
154
                $r->prefetch();
155
            }
156
        }
157 1
        $this->cached = true;
158 1
    }
159
160
    /**
161
     * pre-fetch parallel by curl_multi
162
     */
163 1
    public function onPostDependenciesSolving(Installer\InstallerEvent $ev)
164
    {
165 1
        if ($this->disabled) {
166 1
            return;
167
        }
168 1
        $prefetcher = new Prefetcher;
169 1
        $prefetcher->fetchAllFromOperations(
170 1
            $this->io,
171 1
            $this->config,
172 1
            $ev->getOperations()
173
        );
174 1
    }
175
176 2
    public function disable()
177
    {
178 2
        $this->disabled = true;
179 2
    }
180
181 1
    public function isDisabled()
182
    {
183 1
        return $this->disabled;
184
    }
185
}
186