1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the puli/installer package. |
5
|
|
|
* |
6
|
|
|
* (c) Bernhard Schussek <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace Puli\Installer; |
13
|
|
|
|
14
|
|
|
use Exception; |
15
|
|
|
use Humbug\SelfUpdate\VersionParser; |
16
|
|
|
use Phar; |
17
|
|
|
use PharException; |
18
|
|
|
use RuntimeException; |
19
|
|
|
use UnexpectedValueException; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Installs the puli.phar on the local system. |
23
|
|
|
* |
24
|
|
|
* Use it like this: |
25
|
|
|
* |
26
|
|
|
* ``` |
27
|
|
|
* $ curl -sS https://puli.io/installer | php |
28
|
|
|
* ``` |
29
|
|
|
* |
30
|
|
|
* This file was adapted from the installer file bundled with Composer. For the |
31
|
|
|
* original file, authors and copyright information see |
32
|
|
|
* |
33
|
|
|
* https://github.com/composer/getcomposer.org/blob/master/web/installer |
34
|
|
|
* |
35
|
|
|
* @author Nils Adermann <[email protected]> |
36
|
|
|
* @author Jordi Boggiano <[email protected]> |
37
|
|
|
* @author Thomas Rudolph <[email protected]> |
38
|
|
|
* @author Bernhard Schussek <[email protected]> |
39
|
|
|
*/ |
40
|
|
|
class Installer |
41
|
|
|
{ |
42
|
|
|
/** |
43
|
|
|
* The help text of the installer. |
44
|
|
|
*/ |
45
|
|
|
const HELP_TEXT = <<<HELP |
46
|
|
|
Puli Installer |
47
|
|
|
-------------- |
48
|
|
|
Options |
49
|
|
|
--help this help |
50
|
|
|
--check for checking environment only |
51
|
|
|
--force forces the installation even if the system requirements are not satisfied |
52
|
|
|
--ansi force ANSI color output |
53
|
|
|
--no-ansi disable ANSI color output |
54
|
|
|
--quiet do not output unimportant messages |
55
|
|
|
--install-dir="..." set the target installation directory |
56
|
|
|
--version="..." install a specific version |
57
|
|
|
--filename="..." set the target filename (default: puli.phar) |
58
|
|
|
|
59
|
|
|
HELP; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* The api url to determine the available versions of puli. |
63
|
|
|
*/ |
64
|
|
|
const VERSION_API_URL = 'https://puli.io/download/versions.json'; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* The phar download url. |
68
|
|
|
*/ |
69
|
|
|
const PHAR_DOWNLOAD_URL = 'https://puli.io/download/%s/puli.phar'; |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @var string |
73
|
|
|
*/ |
74
|
|
|
private $stability; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @var bool |
78
|
|
|
*/ |
79
|
|
|
private $check; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* @var bool |
83
|
|
|
*/ |
84
|
|
|
private $help; |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* @var bool |
88
|
|
|
*/ |
89
|
|
|
private $force; |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* @var bool |
93
|
|
|
*/ |
94
|
|
|
private $quiet; |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* @var string |
98
|
|
|
*/ |
99
|
|
|
private $installDir; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* @var string |
103
|
|
|
*/ |
104
|
|
|
private $version; |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @var string |
108
|
|
|
*/ |
109
|
|
|
private $filename; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Runs the installer. |
113
|
|
|
* |
114
|
|
|
* @param array $argv The console arguments. |
115
|
|
|
* |
116
|
|
|
* @return int The return status. |
117
|
|
|
*/ |
118
|
5 |
|
public function run(array $argv) |
119
|
|
|
{ |
120
|
5 |
|
$this->parseOptions($argv); |
121
|
|
|
|
122
|
5 |
|
if ($this->help) { |
123
|
|
|
echo self::HELP_TEXT; |
124
|
|
|
|
125
|
|
|
return 0; |
126
|
|
|
} |
127
|
|
|
|
128
|
5 |
|
$ok = $this->validateSystem() && $this->validateOptions(); |
129
|
|
|
|
130
|
5 |
|
if ($this->check) { |
131
|
|
|
return $ok ? 0 : 1; |
132
|
|
|
} |
133
|
|
|
|
134
|
5 |
|
if ($ok || $this->force) { |
135
|
5 |
|
return $this->installPuli(); |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
return 1; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Installs puli to the current working directory. |
143
|
|
|
* |
144
|
|
|
* @return int The return status. |
145
|
|
|
* |
146
|
|
|
* @throws Exception |
147
|
|
|
*/ |
148
|
5 |
|
private function installPuli() |
149
|
|
|
{ |
150
|
5 |
|
$workingDir = str_replace('\\', '/', getcwd()); |
151
|
5 |
|
$installDir = is_dir($this->installDir) ? realpath($this->installDir) : $workingDir; |
152
|
5 |
|
$installPath = str_replace('\\', '/', $installDir).'/'.$this->filename; |
153
|
5 |
|
$shortInstallPath = $installPath; |
154
|
|
|
|
155
|
|
|
// Strip the current working directory if possible |
156
|
5 |
|
if (0 === strpos($shortInstallPath, $workingDir.'/')) { |
157
|
3 |
|
$shortInstallPath = substr($shortInstallPath, strlen($workingDir.'/')); |
158
|
3 |
|
} |
159
|
|
|
|
160
|
5 |
|
if (is_readable($installPath)) { |
161
|
|
|
@unlink($installPath); |
|
|
|
|
162
|
|
|
} |
163
|
|
|
|
164
|
5 |
|
$httpClient = new HttpClient(); |
165
|
|
|
|
166
|
5 |
|
$versions = array(); |
167
|
5 |
|
for ($retries = 3; $retries > 0; --$retries) { |
168
|
5 |
|
if (!$this->quiet) { |
169
|
5 |
|
$this->info('Downloading available versions...'); |
170
|
5 |
|
} |
171
|
|
|
|
172
|
|
|
try { |
173
|
5 |
|
$versions = $this->downloadVersions($httpClient, static::VERSION_API_URL); |
174
|
5 |
|
break; |
175
|
|
|
} catch (RuntimeException $e) { |
176
|
|
|
$this->error($e->getMessage()); |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
|
180
|
5 |
|
if (0 === $retries || empty($versions)) { |
181
|
|
|
$this->error('fatal: The download failed repeatedly, aborting.'); |
182
|
|
|
|
183
|
|
|
return 1; |
184
|
|
|
} |
185
|
|
|
|
186
|
5 |
|
$versionParser = new VersionParser($versions); |
187
|
5 |
|
if (!empty($this->version)) { |
188
|
1 |
|
if (!in_array($this->version, $versions, true)) { |
189
|
|
|
$this->error(sprintf( |
190
|
|
|
'fatal: Could not find version: %s.', |
191
|
|
|
$this->version |
192
|
|
|
)); |
193
|
|
|
|
194
|
|
|
return 1; |
195
|
|
|
} |
196
|
5 |
|
} elseif ('stable' === $this->stability) { |
197
|
1 |
|
$this->version = $versionParser->getMostRecentStable(); |
198
|
1 |
|
if (false === $this->version) { |
199
|
1 |
|
$this->error('fatal: Could not find a stable version.'); |
200
|
|
|
|
201
|
1 |
|
return 1; |
202
|
|
|
} |
203
|
|
|
} else { |
204
|
3 |
|
$this->version = $versionParser->getMostRecentAll(); |
205
|
|
|
} |
206
|
|
|
|
207
|
4 |
|
$url = sprintf( |
208
|
4 |
|
static::PHAR_DOWNLOAD_URL, |
209
|
4 |
|
$this->version |
210
|
4 |
|
); |
211
|
|
|
|
212
|
4 |
|
for ($retries = 3; $retries > 0; --$retries) { |
213
|
4 |
|
if (!$this->quiet) { |
214
|
4 |
|
$this->info(sprintf( |
215
|
4 |
|
'Downloading puli.phar at version %s...', |
216
|
4 |
|
$this->version) |
217
|
4 |
|
); |
218
|
4 |
|
} |
219
|
|
|
|
220
|
4 |
|
if (!$this->downloadFile($httpClient, $url, $installPath)) { |
221
|
|
|
continue; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
try { |
225
|
4 |
|
$this->validatePhar($installPath); |
226
|
4 |
|
} catch (Exception $e) { |
227
|
|
|
unlink($installPath); |
228
|
|
|
|
229
|
|
|
if (!$e instanceof UnexpectedValueException && !$e instanceof PharException) { |
230
|
|
|
throw $e; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
if ($retries > 0) { |
234
|
|
|
if (!$this->quiet) { |
235
|
|
|
$this->error('The download is corrupt, retrying...'); |
236
|
|
|
} |
237
|
|
|
} else { |
238
|
|
|
$this->error(sprintf( |
239
|
|
|
'fatal: The download is corrupt (%s), aborting.', |
240
|
|
|
$e->getMessage() |
241
|
|
|
)); |
242
|
|
|
|
243
|
|
|
return 1; |
244
|
|
|
} |
245
|
|
|
} |
246
|
|
|
|
247
|
4 |
|
break; |
248
|
|
|
} |
249
|
|
|
|
250
|
4 |
|
if (0 === $retries) { |
251
|
|
|
$this->error('fatal: The download failed repeatedly, aborting.'); |
252
|
|
|
|
253
|
|
|
return 1; |
254
|
|
|
} |
255
|
|
|
|
256
|
4 |
|
chmod($installPath, 0755); |
257
|
|
|
|
258
|
4 |
|
if (!$this->quiet) { |
259
|
4 |
|
$this->success(PHP_EOL.'Puli successfully installed to: '.$installPath); |
260
|
4 |
|
$this->info('Use it: php '.$shortInstallPath); |
261
|
4 |
|
} |
262
|
|
|
|
263
|
4 |
|
return 0; |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Downloads a URL to a path. |
268
|
|
|
* |
269
|
|
|
* @param HttpClient $httpClient The client to use. |
270
|
|
|
* @param string $url The URL to download. |
271
|
|
|
* @param string $targetPath The path to download the URL to. |
272
|
|
|
* |
273
|
|
|
* @return bool Whether the download completed successfully. |
274
|
|
|
*/ |
275
|
4 |
|
private function downloadFile(HttpClient $httpClient, $url, $targetPath) |
276
|
|
|
{ |
277
|
4 |
|
ErrorHandler::register(); |
278
|
|
|
|
279
|
4 |
|
$fh = fopen($targetPath, 'w'); |
280
|
|
|
|
281
|
4 |
|
if (!$fh) { |
282
|
|
|
$this->error(sprintf( |
283
|
|
|
'Could not create file %s: %s', |
284
|
|
|
$targetPath, |
285
|
|
|
implode(PHP_EOL, ErrorHandler::getErrors()) |
286
|
|
|
)); |
287
|
|
|
} |
288
|
|
|
|
289
|
4 |
|
if (!fwrite($fh, $httpClient->download($url))) { |
290
|
|
|
$this->error(sprintf( |
291
|
|
|
'Download failed: %s', |
292
|
|
|
implode(PHP_EOL, ErrorHandler::getErrors()) |
293
|
|
|
)); |
294
|
|
|
} |
295
|
|
|
|
296
|
4 |
|
fclose($fh); |
297
|
|
|
|
298
|
4 |
|
ErrorHandler::unregister(); |
299
|
|
|
|
300
|
4 |
|
return !ErrorHandler::hasErrors(); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Downloads the available puli versions. |
305
|
|
|
* |
306
|
|
|
* @param HttpClient $httpClient The client to use. |
307
|
|
|
* @param string $url The URL to download. |
308
|
|
|
* |
309
|
|
|
* @return array The available versions, null if the download failed. |
310
|
|
|
* |
311
|
|
|
* @throws RuntimeException If an error occurs. |
312
|
|
|
*/ |
313
|
5 |
|
public function downloadVersions(HttpClient $httpClient, $url) |
314
|
|
|
{ |
315
|
5 |
|
ErrorHandler::register(); |
316
|
5 |
|
$versions = $httpClient->download($url); |
317
|
5 |
|
ErrorHandler::unregister(); |
318
|
|
|
|
319
|
5 |
|
if (ErrorHandler::hasErrors()) { |
320
|
|
|
throw new RuntimeException(sprintf( |
321
|
|
|
'Could not download %s:'.PHP_EOL.'%s', |
322
|
|
|
$url, |
323
|
|
|
implode(PHP_EOL, ErrorHandler::getErrors()) |
324
|
|
|
)); |
325
|
|
|
} |
326
|
|
|
|
327
|
5 |
|
$versions = json_decode($versions); |
328
|
5 |
|
if (json_last_error() !== JSON_ERROR_NONE || !is_array($versions)) { |
329
|
|
|
throw new RuntimeException(sprintf( |
330
|
|
|
'Could not download %s:'.PHP_EOL.'Malformed JSON returned.', |
331
|
|
|
$url |
332
|
|
|
)); |
333
|
|
|
} |
334
|
|
|
|
335
|
5 |
|
usort($versions, 'version_compare'); |
336
|
|
|
|
337
|
5 |
|
return $versions; |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/** |
341
|
|
|
* Validates that the given path is a valid PHAR file. |
342
|
|
|
* |
343
|
|
|
* @param string $path A path to a PHAR file. |
344
|
|
|
* |
345
|
|
|
* @throws Exception If an error occurs. |
346
|
|
|
*/ |
347
|
4 |
|
private function validatePhar($path) |
348
|
|
|
{ |
349
|
4 |
|
$tmpFile = $path; |
350
|
|
|
|
351
|
|
|
try { |
352
|
|
|
// create a temp file ending in .phar since the Phar class only accepts that |
353
|
4 |
|
if ('.phar' !== substr($path, -5)) { |
354
|
|
|
copy($path, $path.'.tmp.phar'); |
355
|
|
|
$tmpFile = $path.'.tmp.phar'; |
356
|
|
|
} |
357
|
|
|
|
358
|
4 |
|
if (!ini_get('phar.readonly')) { |
359
|
|
|
// test the phar validity |
360
|
4 |
|
$phar = new Phar($tmpFile); |
361
|
|
|
|
362
|
|
|
// free the variable to unlock the file |
363
|
4 |
|
unset($phar); |
364
|
4 |
|
} |
365
|
4 |
|
} catch (Exception $e) { |
366
|
|
|
// clean up temp file if needed |
367
|
|
|
if ($path !== $tmpFile) { |
368
|
|
|
unlink($tmpFile); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
throw $e; |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
// clean up temp file if needed |
375
|
4 |
|
if ($path !== $tmpFile) { |
376
|
|
|
unlink($tmpFile); |
377
|
|
|
} |
378
|
4 |
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Check the platform for possible issues on running Puli. |
382
|
|
|
* |
383
|
|
|
* @return bool Whether the platform requirements are satisfied. |
384
|
|
|
*/ |
385
|
5 |
|
private function validateSystem() |
386
|
|
|
{ |
387
|
5 |
|
$errors = array(); |
388
|
5 |
|
$warnings = array(); |
389
|
|
|
|
390
|
5 |
|
$iniPath = php_ini_loaded_file(); |
391
|
5 |
|
$displayIniMessage = false; |
392
|
|
|
|
393
|
5 |
|
if ($iniPath) { |
394
|
5 |
|
$iniMessage = PHP_EOL.PHP_EOL.'The php.ini used by your command-line PHP is: '.$iniPath; |
395
|
5 |
|
} else { |
396
|
|
|
$iniMessage = PHP_EOL.PHP_EOL.'A php.ini file does not exist. You will have to create one.'; |
397
|
|
|
} |
398
|
|
|
|
399
|
5 |
|
$iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.'; |
400
|
|
|
|
401
|
5 |
|
if (ini_get('detect_unicode')) { |
402
|
|
|
$errors['unicode'] = 'On'; |
403
|
|
|
} |
404
|
|
|
|
405
|
5 |
|
if (extension_loaded('suhosin')) { |
406
|
|
|
$suhosin = ini_get('suhosin.executor.include.whitelist'); |
407
|
|
|
$suhosinBlacklist = ini_get('suhosin.executor.include.blacklist'); |
408
|
|
|
if (false === stripos($suhosin, |
409
|
|
|
'phar') && (!$suhosinBlacklist || false !== stripos($suhosinBlacklist, |
410
|
|
|
'phar')) |
411
|
|
|
) { |
412
|
|
|
$errors['suhosin'] = $suhosin; |
413
|
|
|
} |
414
|
|
|
} |
415
|
|
|
|
416
|
5 |
|
if (!function_exists('json_decode')) { |
417
|
|
|
$errors['json'] = true; |
418
|
|
|
} |
419
|
|
|
|
420
|
5 |
|
if (!extension_loaded('Phar')) { |
421
|
|
|
$errors['phar'] = true; |
422
|
|
|
} |
423
|
|
|
|
424
|
5 |
|
if (!ini_get('allow_url_fopen')) { |
425
|
|
|
$errors['allow_url_fopen'] = true; |
426
|
|
|
} |
427
|
|
|
|
428
|
5 |
|
if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) { |
429
|
|
|
$errors['ioncube'] = ioncube_loader_version(); |
430
|
|
|
} |
431
|
|
|
|
432
|
5 |
|
if (version_compare(PHP_VERSION, '5.3.9', '<')) { |
433
|
|
|
$errors['php'] = PHP_VERSION; |
434
|
|
|
} |
435
|
|
|
|
436
|
5 |
|
if (!extension_loaded('openssl')) { |
437
|
|
|
$errors['openssl'] = true; |
438
|
|
|
} |
439
|
|
|
|
440
|
5 |
|
if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) { |
441
|
|
|
$warnings['apc_cli'] = true; |
442
|
|
|
} |
443
|
|
|
|
444
|
5 |
|
ob_start(); |
445
|
5 |
|
phpinfo(INFO_GENERAL); |
446
|
5 |
|
$phpinfo = ob_get_clean(); |
447
|
5 |
|
if (preg_match('{Configure Command(?: *</td><td class="v">| *=> *)(.*?)(?:</td>|$)}m', |
448
|
5 |
|
$phpinfo, $match)) { |
449
|
5 |
|
$configure = $match[1]; |
450
|
|
|
|
451
|
5 |
|
if (false !== strpos($configure, '--enable-sigchild')) { |
452
|
|
|
$warnings['sigchild'] = true; |
453
|
|
|
} |
454
|
|
|
|
455
|
5 |
|
if (false !== strpos($configure, '--with-curlwrappers')) { |
456
|
|
|
$warnings['curlwrappers'] = true; |
457
|
|
|
} |
458
|
5 |
|
} |
459
|
|
|
|
460
|
5 |
|
if (!empty($errors)) { |
461
|
|
|
$this->error('Some settings on your machine make Puli unable to work properly.'); |
462
|
|
|
$this->error('Make sure that you fix the issues listed below and run this script again:'); |
463
|
|
|
|
464
|
|
|
foreach ($errors as $error => $current) { |
465
|
|
|
$text = ''; |
466
|
|
|
switch ($error) { |
467
|
|
|
case 'json': |
468
|
|
|
$text = PHP_EOL.'The json extension is missing.'.PHP_EOL; |
469
|
|
|
$text .= 'Install it or recompile php without --disable-json'; |
470
|
|
|
break; |
471
|
|
|
|
472
|
|
|
case 'phar': |
473
|
|
|
$text = PHP_EOL.'The phar extension is missing.'.PHP_EOL; |
474
|
|
|
$text .= 'Install it or recompile php without --disable-phar'; |
475
|
|
|
break; |
476
|
|
|
|
477
|
|
View Code Duplication |
case 'unicode': |
|
|
|
|
478
|
|
|
$text = PHP_EOL.'The detect_unicode setting must be disabled.'.PHP_EOL; |
479
|
|
|
$text .= 'Add the following to the end of your `php.ini`:'.PHP_EOL; |
480
|
|
|
$text .= ' detect_unicode = Off'; |
481
|
|
|
$displayIniMessage = true; |
482
|
|
|
break; |
483
|
|
|
|
484
|
|
View Code Duplication |
case 'suhosin': |
|
|
|
|
485
|
|
|
$text = PHP_EOL.'The suhosin.executor.include.whitelist setting is incorrect.'.PHP_EOL; |
486
|
|
|
$text .= 'Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):'.PHP_EOL; |
487
|
|
|
$text .= ' suhosin.executor.include.whitelist = phar '.$current; |
488
|
|
|
$displayIniMessage = true; |
489
|
|
|
break; |
490
|
|
|
|
491
|
|
|
case 'php': |
492
|
|
|
$text = PHP_EOL."Your PHP ({$current}) is too old, you must upgrade to PHP 5.3.9 or higher."; |
|
|
|
|
493
|
|
|
break; |
494
|
|
|
|
495
|
|
View Code Duplication |
case 'allow_url_fopen': |
|
|
|
|
496
|
|
|
$text = PHP_EOL.'The allow_url_fopen setting is incorrect.'.PHP_EOL; |
497
|
|
|
$text .= 'Add the following to the end of your `php.ini`:'.PHP_EOL; |
498
|
|
|
$text .= ' allow_url_fopen = On'; |
499
|
|
|
$displayIniMessage = true; |
500
|
|
|
break; |
501
|
|
|
|
502
|
|
View Code Duplication |
case 'ioncube': |
|
|
|
|
503
|
|
|
$text = PHP_EOL."Your ionCube Loader extension ($current) is incompatible with Phar files.".PHP_EOL; |
|
|
|
|
504
|
|
|
$text .= 'Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:'.PHP_EOL; |
505
|
|
|
$text .= ' zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so'; |
506
|
|
|
$displayIniMessage = true; |
507
|
|
|
break; |
508
|
|
|
|
509
|
|
|
case 'openssl': |
510
|
|
|
$text = PHP_EOL.'The openssl extension is missing, which means that secure HTTPS transfers are impossible.'.PHP_EOL; |
511
|
|
|
$text .= 'If possible you should enable it or recompile php with --with-openssl'; |
512
|
|
|
break; |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
if ($displayIniMessage) { |
516
|
|
|
$text .= $iniMessage; |
517
|
|
|
} |
518
|
|
|
|
519
|
|
|
$this->info($text); |
520
|
|
|
} |
521
|
|
|
|
522
|
|
|
echo PHP_EOL; |
523
|
|
|
|
524
|
|
|
return false; |
525
|
|
|
} |
526
|
|
|
|
527
|
5 |
|
if (!empty($warnings)) { |
528
|
|
|
$this->error('Some settings on your machine may cause stability issues with Puli.'); |
529
|
|
|
$this->error('If you encounter issues, try to change the following:'); |
530
|
|
|
|
531
|
|
|
foreach ($warnings as $warning => $current) { |
532
|
|
|
$text = ''; |
533
|
|
|
switch ($warning) { |
534
|
|
View Code Duplication |
case 'apc_cli': |
|
|
|
|
535
|
|
|
$text = PHP_EOL.'The apc.enable_cli setting is incorrect.'.PHP_EOL; |
536
|
|
|
$text .= 'Add the following to the end of your `php.ini`:'.PHP_EOL; |
537
|
|
|
$text .= ' apc.enable_cli = Off'; |
538
|
|
|
$displayIniMessage = true; |
539
|
|
|
break; |
540
|
|
|
|
541
|
|
|
case 'sigchild': |
542
|
|
|
$text = PHP_EOL.'PHP was compiled with --enable-sigchild which can cause issues on some platforms.'.PHP_EOL; |
543
|
|
|
$text .= 'Recompile it without this flag if possible, see also:'.PHP_EOL; |
544
|
|
|
$text .= ' https://bugs.php.net/bug.php?id=22999'; |
545
|
|
|
break; |
546
|
|
|
|
547
|
|
|
case 'curlwrappers': |
548
|
|
|
$text = PHP_EOL.'PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.'.PHP_EOL; |
549
|
|
|
$text .= 'Recompile it without this flag if possible'; |
550
|
|
|
break; |
551
|
|
|
|
552
|
|
|
case 'openssl': |
553
|
|
|
$text = PHP_EOL.'The openssl extension is missing, which means that secure HTTPS transfers are impossible.'.PHP_EOL; |
554
|
|
|
$text .= 'If possible you should enable it or recompile php with --with-openssl'; |
555
|
|
|
break; |
556
|
|
|
} |
557
|
|
|
if ($displayIniMessage) { |
558
|
|
|
$text .= $iniMessage; |
559
|
|
|
} |
560
|
|
|
$this->info($text); |
561
|
|
|
} |
562
|
|
|
|
563
|
|
|
echo PHP_EOL; |
564
|
|
|
|
565
|
|
|
return true; |
566
|
|
|
} |
567
|
|
|
|
568
|
5 |
|
if (!$this->quiet) { |
569
|
5 |
|
$this->success('All settings correct for using Puli'); |
570
|
5 |
|
} |
571
|
|
|
|
572
|
5 |
|
return true; |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
/** |
576
|
|
|
* Validate whether the passed command line options are correct. |
577
|
|
|
* |
578
|
|
|
* @return bool Returns `true` if the options are valid and `false` otherwise. |
579
|
|
|
*/ |
580
|
5 |
|
private function validateOptions() |
581
|
|
|
{ |
582
|
5 |
|
$ok = true; |
583
|
|
|
|
584
|
5 |
|
if (false !== $this->installDir && !is_dir($this->installDir)) { |
585
|
|
|
$this->info(sprintf( |
586
|
|
|
'The defined install dir (%s) does not exist.', |
587
|
|
|
$this->installDir |
588
|
|
|
)); |
589
|
|
|
$ok = false; |
590
|
|
|
} |
591
|
|
|
|
592
|
5 |
|
if (false !== $this->version && 1 !== preg_match('/^\d+\.\d+\.\d+(\-(alpha|beta)\d+)*$/', $this->version)) { |
593
|
|
|
$this->info(sprintf( |
594
|
|
|
'The defined install version (%s) does not match release pattern.', |
595
|
|
|
$this->version |
596
|
|
|
)); |
597
|
|
|
$ok = false; |
598
|
|
|
} |
599
|
|
|
|
600
|
5 |
|
return $ok; |
601
|
|
|
} |
602
|
|
|
|
603
|
|
|
/** |
604
|
|
|
* Parses the command line options. |
605
|
|
|
* |
606
|
|
|
* @param string[] $argv The command line options. |
607
|
|
|
*/ |
608
|
5 |
|
private function parseOptions(array $argv) |
609
|
|
|
{ |
610
|
5 |
|
$this->check = in_array('--check', $argv); |
611
|
5 |
|
$this->help = in_array('--help', $argv); |
612
|
5 |
|
$this->force = in_array('--force', $argv); |
613
|
5 |
|
$this->quiet = in_array('--quiet', $argv); |
614
|
5 |
|
$this->installDir = false; |
|
|
|
|
615
|
5 |
|
$this->version = false; |
|
|
|
|
616
|
5 |
|
$this->filename = 'puli.phar'; |
617
|
5 |
|
$this->stability = 'unstable'; |
618
|
5 |
|
if (in_array('--stable', $argv)) { |
619
|
1 |
|
$this->stability = 'stable'; |
620
|
1 |
|
} |
621
|
|
|
|
622
|
|
|
// --no-ansi wins over --ansi |
623
|
5 |
|
if (in_array('--no-ansi', $argv)) { |
624
|
4 |
|
define('USE_ANSI', false); |
625
|
5 |
|
} elseif (in_array('--ansi', $argv)) { |
626
|
|
|
define('USE_ANSI', true); |
627
|
|
|
} else { |
628
|
|
|
// On Windows, default to no ANSI, except in ANSICON and ConEmu. |
629
|
|
|
// Everywhere else, default to ANSI if stdout is a terminal. |
630
|
1 |
|
define('USE_ANSI', ('\\' === DIRECTORY_SEPARATOR) |
631
|
1 |
|
? (false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI')) |
632
|
1 |
|
: (function_exists('posix_isatty') && posix_isatty(1))); |
633
|
|
|
} |
634
|
|
|
|
635
|
5 |
|
foreach ($argv as $key => $val) { |
636
|
5 |
View Code Duplication |
if (0 === strpos($val, '--install-dir')) { |
|
|
|
|
637
|
2 |
|
if (13 === strlen($val) && isset($argv[$key + 1])) { |
638
|
2 |
|
$this->installDir = trim($argv[$key + 1]); |
639
|
2 |
|
} else { |
640
|
|
|
$this->installDir = trim(substr($val, 14)); |
641
|
|
|
} |
642
|
2 |
|
} |
643
|
|
|
|
644
|
5 |
View Code Duplication |
if (0 === strpos($val, '--version')) { |
|
|
|
|
645
|
1 |
|
if (9 === strlen($val) && isset($argv[$key + 1])) { |
646
|
1 |
|
$this->version = trim($argv[$key + 1]); |
647
|
1 |
|
} else { |
648
|
|
|
$this->version = trim(substr($val, 10)); |
649
|
|
|
} |
650
|
1 |
|
} |
651
|
|
|
|
652
|
5 |
View Code Duplication |
if (0 === strpos($val, '--filename')) { |
|
|
|
|
653
|
|
|
if (10 === strlen($val) && isset($argv[$key + 1])) { |
654
|
|
|
$this->filename = trim($argv[$key + 1]); |
655
|
|
|
} else { |
656
|
|
|
$this->filename = trim(substr($val, 11)); |
657
|
|
|
} |
658
|
|
|
} |
659
|
5 |
|
} |
660
|
5 |
|
} |
661
|
|
|
|
662
|
|
|
/** |
663
|
|
|
* Prints output indicating a success. |
664
|
|
|
* |
665
|
|
|
* @param string $text The text to print. |
666
|
|
|
*/ |
667
|
5 |
|
private function success($text) |
668
|
|
|
{ |
669
|
5 |
|
printf(USE_ANSI ? "\033[0;32m%s\033[0m" : '%s', $text.PHP_EOL); |
670
|
5 |
|
} |
671
|
|
|
|
672
|
|
|
/** |
673
|
|
|
* Prints output indicating an error. |
674
|
|
|
* |
675
|
|
|
* @param string $text The text to print. |
676
|
|
|
*/ |
677
|
1 |
|
private function error($text) |
678
|
|
|
{ |
679
|
1 |
|
printf(USE_ANSI ? "\033[31;31m%s\033[0m" : '%s', $text.PHP_EOL); |
680
|
1 |
|
} |
681
|
|
|
|
682
|
|
|
/** |
683
|
|
|
* Prints output indicating some information. |
684
|
|
|
* |
685
|
|
|
* @param string $text The text to print. |
686
|
|
|
*/ |
687
|
5 |
|
private function info($text) |
688
|
|
|
{ |
689
|
5 |
|
printf(USE_ANSI ? "\033[33;33m%s\033[0m" : '%s', $text.PHP_EOL); |
690
|
5 |
|
} |
691
|
|
|
} |
692
|
|
|
|
If you suppress an error, we recommend checking for the error condition explicitly: