Completed
Push — master ( 5c01aa...2b4547 )
by Hiraku
9s
created

Plugin   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 60.29%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 30
lcom 1
cbo 8
dl 0
loc 167
ccs 41
cts 68
cp 0.6029
rs 10
c 1
b 1
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A onPostDependenciesSolving() 0 12 2
A disable() 0 4 1
A isDisabled() 0 4 1
C activate() 0 41 13
A getSubscribedEvents() 0 9 1
A onPreFileDownload() 0 19 3
D prefetchComposerRepositories() 0 28 9
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)
0 ignored issues
show
Coding Style introduced by
activate uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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
            foreach ($GLOBALS['argv'] as $arg) {
77
                switch ($arg) {
78 3
                    case 'create-project':
79 3
                    case 'update':
80 3
                    case 'outdated':
81 3
                    case 'require':
82
                        $this->prefetchComposerRepositories();
83
                        break 2;
84 3
                    case 'install':
85
                        if (file_exists('composer.json') && !file_exists('composer.lock')) {
86
                            $this->prefetchComposerRepositories();
87
                        }
88 3
                        break 2;
89
                }
90
            }
91
        }
92 3
    }
93
94 1
    public static function getSubscribedEvents()
95
    {
96
        return array(
97 1
            CPlugin\PluginEvents::PRE_FILE_DOWNLOAD => 'onPreFileDownload',
98 1
            Installer\InstallerEvents::POST_DEPENDENCIES_SOLVING => array(
99 1
                array('onPostDependenciesSolving', PHP_INT_MAX),
100
            ),
101
        );
102
    }
103
104
    /**
105
     * Keep-Alived file downloader
106
     */
107
    public function onPreFileDownload(CPlugin\PreFileDownloadEvent $ev)
108
    {
109
        if ($this->disabled) {
110
            return;
111
        }
112
113
        $scheme = parse_url($ev->getProcessedUrl(), PHP_URL_SCHEME);
114
        if (!in_array($scheme, self::$supportedSchemes, true)) {
115
            return;
116
        }
117
118
        $rfs = $ev->getRemoteFilesystem();
119
        $curlrfs = new CurlRemoteFilesystem(
120
            $this->io,
121
            $this->config,
122
            $rfs->getOptions()
123
        );
124
        $ev->setRemoteFilesystem($curlrfs);
125
    }
126
127 1
    public function prefetchComposerRepositories()
128
    {
129 1
        if ($this->disabled) {
130 1
            return;
131
        }
132 1
        if ($this->cached) {
133
            return;
134
        }
135 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...
136 1
        foreach ($repos as $label => $repo) {
137
            if (isset($repo['type']) && $repo['type'] === 'composer') {
138
                if (!empty($repo['force-lazy-providers'])) {
139
                    continue;
140
                }
141
142
                if (substr($repo['url'], 0, 6) !== 'https?') {
143
                    $scheme = parse_url($repo['url'], PHP_URL_SCHEME);
144
                    if (!in_array($scheme, self::$supportedSchemes, true)) {
145
                        continue;
146
                    }
147
                }
148
149
                $r = new ParallelizedComposerRepository($repo, $this->io, $this->config);
150
                $r->prefetch();
151
            }
152
        }
153 1
        $this->cached = true;
154 1
    }
155
156
    /**
157
     * pre-fetch parallel by curl_multi
158
     */
159 1
    public function onPostDependenciesSolving(Installer\InstallerEvent $ev)
160
    {
161 1
        if ($this->disabled) {
162 1
            return;
163
        }
164 1
        $prefetcher = new Prefetcher;
165 1
        $prefetcher->fetchAllFromOperations(
166 1
            $this->io,
167 1
            $this->config,
168 1
            $ev->getOperations()
169
        );
170 1
    }
171
172 2
    public function disable()
173
    {
174 2
        $this->disabled = true;
175 2
    }
176
177 1
    public function isDisabled()
178
    {
179 1
        return $this->disabled;
180
    }
181
}
182