Completed
Pull Request — master (#66)
by Jan
05:29
created

ParallelDownloader::getUrlFromPackage()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4.4661

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
ccs 9
cts 13
cp 0.6923
rs 9.2
cc 4
eloc 12
nc 5
nop 1
crap 4.4661
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\Package;
10
use Composer\IO;
11
use Composer\Config as CConfig;
12
13
/**
14
 *
15
 */
16
class ParallelDownloader
17
{
18
    /** @var IO/IOInterface */
19
    protected $io;
20
21
    /** @var CConfig */
22
    protected $config;
23
24
    /** @var int */
25
    protected $totalCnt = 0;
26
    protected $successCnt = 0;
27
    protected $skippedCnt = 0;
28
    protected $failureCnt = 0;
29
30 4
    public function __construct(IO\IOInterface $io, CConfig $config)
31
    {
32 4
        $this->io = $io;
33 4
        $this->config = $config;
34 4
    }
35
36
    /**
37
     * @param Package\PackageInterface[] $packages
38
     * @param array $pluginConfig
39
     * @return void
40
     */
41 3
    public function download(array $packages, array $pluginConfig)
42
    {
43 3
        $multi = new CurlMulti($pluginConfig['maxConnections']);
44 3
        $multi->setupShareHandler($pluginConfig['pipeline']);
45
46 3
        $this->totalCnt = count($packages);
47 3
        $this->successCnt = $this->skippedCnt = $this->failureCnt = 0;
48 3
        $this->io->write("    Prefetch start: <comment>total: $this->totalCnt</comment>");
49
50 3
        $multi->setTargets($this->filterPackages($packages, $pluginConfig));
51
52
        do {
53 3
            $multi->setupEventLoop();
54 3
            $multi->wait();
55
56 3
            $result = $multi->getFinishedResults();
57 3
            $this->successCnt += $result['successCnt'];
58 3
            $this->failureCnt += $result['failureCnt'];
59 3
            foreach ($result['results'] as $url) {
60 1
                $this->io->write($this->makeDownloadingText($url));
61 3
            }
62 3
        } while ($multi->remain());
63
64 3
        $this->io->write(
65 3
            "    Finished: <comment>success:$this->successCnt,"
66 3
            . " skipped:$this->skippedCnt, failure:$this->failureCnt,"
67 3
            . " total: $this->totalCnt</comment>"
68 3
        );
69 3
    }
70
71
    /**
72
     * @param Package\PackageInterface[] $packages
73
     * @param string[] $pluginConfig
74
     * @return array [{src: Aspects\HttpGetRequest, dest: OutputFile}]
75
     */
76 3
    private function filterPackages(array $packages, array $pluginConfig)
77
    {
78 3
        $cachedir = rtrim($this->config->get('cache-files-dir'), '\/');
79 3
        $targets = array();
80 3
        foreach ($packages as $p) {
81 3
            $urls = $this->getUrlFromPackage($p);
82 3
            if (!$urls) {
83 1
                continue;
84
            }
85 2
            $src = Factory::getHttpGetRequest($urls['host'], $urls['url'], $this->io, $this->config, $pluginConfig);
86 2
            if (!in_array($p->getName(), $pluginConfig['privatePackages'])) {
87 2
                $src->maybePublic = (bool)preg_match('%^(?:https|git)://github\.com%', $p->getSourceUrl());
88 2
            }
89
            // make file resource
90
            $filepath = $cachedir
91
                . DIRECTORY_SEPARATOR
92 2
                . FileDownloaderDummy::getCacheKeyCompat($p, $src->getURL());
93 2
            if (file_exists($filepath)) {
94
                ++$this->skippedCnt;
95
                continue;
96
            }
97 2
            $dest = new OutputFile($filepath);
98
99 2
            $targets[] = compact('src', 'dest');
100 3
        }
101 3
        return $targets;
102
    }
103
104 3
    private function getUrlFromPackage(Package\PackageInterface $package)
105
    {
106 3
        $url = $package->getDistUrl();
107 3
        if (!$url) {
108 1
            ++$this->skippedCnt;
109 1
            return false;
110
        }
111 2
        if ($package->getDistMirrors()) {
112
            $url = current($package->getDistUrls());
113
        }
114 2
        $host = parse_url($url, PHP_URL_HOST);
115 2
        if (!$host) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $host of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
116
            ++$this->skippedCnt;
117
            return false;
118
        }
119 2
        return compact('url', 'host');
120
    }
121
122
    /**
123
     * @param string $url
124
     * @return string
125
     */
126 1
    private function makeDownloadingText($url)
127
    {
128 1
        $request = new Aspects\HttpGetRequest('example.com', $url, $this->io);
129 1
        $request->query = array();
130 1
        return "    <comment>$this->successCnt/$this->totalCnt</comment>:    {$request->getURL()}";
131
    }
132
}
133