Completed
Pull Request — master (#38)
by Pádraic
01:59
created

GithubStrategy::blockMajorVersionUpdates()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
/**
3
 * Humbug
4
 *
5
 * @category   Humbug
6
 * @package    Humbug
7
 * @copyright  Copyright (c) 2015 Pádraic Brady (http://blog.astrumfutura.com)
8
 * @license    https://github.com/padraic/phar-updater/blob/master/LICENSE New BSD License
9
 *
10
 * This class is partially patterned after Composer's self-update.
11
 */
12
13
namespace Humbug\SelfUpdate\Strategy;
14
15
use Humbug\SelfUpdate\Updater;
16
use Humbug\SelfUpdate\VersionParser;
17
use Humbug\SelfUpdate\Exception\HttpRequestException;
18
use Humbug\SelfUpdate\Exception\InvalidArgumentException;
19
use Humbug\SelfUpdate\Exception\JsonParsingException;
20
21
class GithubStrategy implements StrategyInterface
22
{
23
    const API_URL = 'https://packagist.org/packages/%s.json';
24
25
    const STABLE = 'stable';
26
27
    const UNSTABLE = 'unstable';
28
29
    const ANY = 'any';
30
31
    /**
32
     * @var string
33
     */
34
    private $localVersion;
35
36
    /**
37
     * @var string
38
     */
39
    private $remoteVersion;
40
41
    /**
42
     * @var string
43
     */
44
    private $remoteUrl;
45
46
    /**
47
     * @var string
48
     */
49
    private $pharName;
50
51
    /**
52
     * @var string
53
     */
54
    private $packageName;
55
56
    /**
57
     * @var string
58
     */
59
    private $stability = self::STABLE;
60
61
    /**
62
     * @var bool
63
     */
64
    private $allowMajor = true;
65
66
    /**
67
     * Download the remote Phar file.
68
     *
69
     * @param Updater $updater
70
     * @return void
71
     */
72 View Code Duplication
    public function download(Updater $updater)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
73
    {
74
        /** Switch remote request errors to HttpRequestExceptions */
75
        set_error_handler(array($updater, 'throwHttpRequestException'));
76
        $result = humbug_get_contents($this->remoteUrl);
77
        restore_error_handler();
78
        if (false === $result) {
79
            throw new HttpRequestException(sprintf(
80
                'Request to URL failed: %s', $this->remoteUrl
81
            ));
82
        }
83
84
        file_put_contents($updater->getTempPharFile(), $result);
85
    }
86
87
    /**
88
     * Retrieve the current version available remotely.
89
     *
90
     * @param Updater $updater
91
     * @return string|bool
92
     */
93
    public function getCurrentRemoteVersion(Updater $updater)
94
    {
95
        /** Switch remote request errors to HttpRequestExceptions */
96
        set_error_handler(array($updater, 'throwHttpRequestException'));
97
        $packageUrl = $this->getApiUrl();
98
        $package = json_decode(humbug_get_contents($packageUrl), true);
99
        restore_error_handler();
100
101
        if (null === $package || json_last_error() !== JSON_ERROR_NONE) {
102
            throw new JsonParsingException(
103
                'Error parsing JSON package data'
104
                . (function_exists('json_last_error_msg') ? ': ' . json_last_error_msg() : '')
105
            );
106
        }
107
108
        $versions = array_keys($package['package']['versions']);
109
110
        if (false === $this->allowMajor) {
111
            $versions = $this->filterByLocalMajorVersion($versions);
112
        }
113
114
        $versionParser = new VersionParser($versions);
115
        if ($this->getStability() === self::STABLE) {
116
            $this->remoteVersion = $versionParser->getMostRecentStable();
117
        } elseif ($this->getStability() === self::UNSTABLE) {
118
            $this->remoteVersion = $versionParser->getMostRecentUnstable();
119
        } else {
120
            $this->remoteVersion = $versionParser->getMostRecentAll();
121
        }
122
123
        /**
124
         * Setup remote URL if there's an actual version to download
125
         */
126
        if (!empty($this->remoteVersion)) {
127
            $this->remoteUrl = $this->getDownloadUrl($package);
128
        }
129
130
        return $this->remoteVersion;
131
    }
132
133
    /**
134
     * Retrieve the current version of the local phar file.
135
     *
136
     * @param Updater $updater
137
     * @return string
138
     */
139
    public function getCurrentLocalVersion(Updater $updater)
140
    {
141
        return $this->localVersion;
142
    }
143
144
    /**
145
     * Set version string of the local phar
146
     *
147
     * @param string $version
148
     */
149
    public function setCurrentLocalVersion($version)
150
    {
151
        $this->localVersion = $version;
152
    }
153
154
    /**
155
     * Set Package name
156
     *
157
     * @param string $name
158
     */
159
    public function setPackageName($name)
160
    {
161
        $this->packageName = $name;
162
    }
163
164
    /**
165
     * Get Package name
166
     *
167
     * @return string
168
     */
169
    public function getPackageName()
170
    {
171
        return $this->packageName;
172
    }
173
174
    /**
175
     * Set phar file's name
176
     *
177
     * @param string $name
178
     */
179
    public function setPharName($name)
180
    {
181
        $this->pharName = $name;
182
    }
183
184
    /**
185
     * Get phar file's name
186
     *
187
     * @return string
188
     */
189
    public function getPharName()
190
    {
191
        return $this->pharName;
192
    }
193
194
    public function blockMajorVersionUpdates()
195
    {
196
        $this->allowMajor = false;
197
    }
198
199
    /**
200
     * Set target stability
201
     *
202
     * @param string $stability
203
     */
204
    public function setStability($stability)
205
    {
206
        if ($stability !== self::STABLE && $stability !== self::UNSTABLE && $stability !== self::ANY) {
207
            throw new InvalidArgumentException(
208
                'Invalid stability value. Must be one of "stable", "unstable" or "any".'
209
            );
210
        }
211
        $this->stability = $stability;
212
    }
213
214
    /**
215
     * Get target stability
216
     *
217
     * @return string
218
     */
219
    public function getStability()
220
    {
221
        return $this->stability;
222
    }
223
224
    protected function getApiUrl()
225
    {
226
        return sprintf(self::API_URL, $this->getPackageName());
227
    }
228
229
    protected function getDownloadUrl(array $package)
230
    {
231
        $baseUrl = preg_replace(
232
            '{\.git$}',
233
            '',
234
            $package['package']['versions'][$this->remoteVersion]['source']['url']
235
        );
236
        $downloadUrl = sprintf(
237
            '%s/releases/download/%s/%s',
238
            $baseUrl,
239
            $this->remoteVersion,
240
            $this->getPharName()
241
        );
242
        return $downloadUrl;
243
    }
244
245
    /**
246
     * Filter a list of versions to those that match the current local version.
247
     *
248
     * @param string[] $versions
249
     * @return string[]
250
     */
251
    private function filterByLocalMajorVersion(array $versions)
252
    {
253
        list($localMajorVersion, ) = explode('.', $this->localVersion, 2);
254
255
        return array_filter($versions, function ($version) use ($localMajorVersion) {
256
            list($majorVersion, ) = explode('.', $version, 2);
257
            return $majorVersion === $localMajorVersion;
258
        });
259
    }
260
}
261