GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#1453)
by Markus
02:27
created

functions.php ➔ has()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2.1481

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
ccs 2
cts 3
cp 0.6667
crap 2.1481
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/* (c) Anton Medvedev <[email protected]>
3
 *
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace Deployer;
9
10
use Deployer\Host\FileLoader;
11
use Deployer\Host\Host;
12
use Deployer\Host\Localhost;
13
use Deployer\Host\Range;
14
use Deployer\Support\Proxy;
15
use Deployer\Task\Context;
16
use Deployer\Task\GroupTask;
17
use Deployer\Task\Task as T;
18
use Symfony\Component\Console\Input\InputArgument;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Question\ChoiceQuestion;
23
use Symfony\Component\Console\Question\ConfirmationQuestion;
24
use Symfony\Component\Console\Question\Question;
25
use function Deployer\Support\array_to_string;
26
27
// There are two types of functions: Deployer dependent and Context dependent.
28
// Deployer dependent function uses in definition stage of recipe and may require Deployer::get() method.
29
// Context dependent function uses while task execution and must require only Context::get() method.
30
// But there is also a third type of functions: mixed. Mixed function uses in definition stage and in task
31
// execution stage. They are acts like two different function, but have same name. Example of such function
32
// is set() func. This function determine in which stage it was called by Context::get() method.
33
34
/**
35
 * @param array ...$hostnames
36
 * @return Host|Host[]|Proxy
37
 */
38
function host(...$hostnames)
39
{
40 2
    $deployer = Deployer::get();
41 2
    $hostnames = Range::expand($hostnames);
42
43
    // Return hosts if has
44 2
    if ($deployer->hosts->has($hostnames[0])) {
45 2
        if (count($hostnames) === 1) {
46 1
            return $deployer->hosts->get($hostnames[0]);
47
        } else {
48 1
            return array_map([$deployer->hosts, 'get'], $hostnames);
49
        }
50
    }
51
52
    // Add otherwise
53 1
    if (count($hostnames) === 1) {
54 1
        $host = new Host($hostnames[0]);
55 1
        $deployer->hosts->set($hostnames[0], $host);
56 1
        return $host;
57
    } else {
58
        $hosts = array_map(function ($hostname) use ($deployer) {
59 1
            $host = new Host($hostname);
60 1
            $deployer->hosts->set($hostname, $host);
61 1
            return $host;
62 1
        }, $hostnames);
63 1
        return new Proxy($hosts);
64
    }
65
}
66
67
/**
68
 * @param array ...$hostnames
69
 * @return Localhost|Localhost[]|Proxy
70
 */
71
function localhost(...$hostnames)
72
{
73 13
    $deployer = Deployer::get();
74 13
    $hostnames = Range::expand($hostnames);
75
76 13
    if (count($hostnames) <= 1) {
77 8
        $host = count($hostnames) === 1 ? new Localhost($hostnames[0]) : new Localhost();
78 8
        $deployer->hosts->set($host->getHostname(), $host);
79 8
        return $host;
80
    } else {
81
        $hosts = array_map(function ($hostname) use ($deployer) {
82 5
            $host = new Localhost($hostname);
83 5
            $deployer->hosts->set($host->getHostname(), $host);
84 5
            return $host;
85 5
        }, $hostnames);
86 5
        return new Proxy($hosts);
87
    }
88
}
89
90
/**
91
 * Load list of hosts from file
92
 *
93
 * @param string $file
94
 * @return Proxy
95
 */
96
function inventory($file)
97
{
98 1
    $deployer = Deployer::get();
99 1
    $fileLoader = new FileLoader();
100 1
    $fileLoader->load($file);
101
102 1
    $hosts = $fileLoader->getHosts();
103 1
    foreach ($hosts as $host) {
104 1
        $deployer->hosts->set($host->getHostname(), $host);
105
    }
106
107 1
    return new Proxy($hosts);
108
}
109
110
/**
111
 * Set task description.
112
 *
113
 * @param string $title
114
 * @return string
115
 */
116
function desc($title = null)
117
{
118 15
    static $store = null;
119
120 15
    if ($title === null) {
121 15
        return $store;
122
    } else {
123 7
        return $store = $title;
124
    }
125
}
126
127
/**
128
 * Define a new task and save to tasks list.
129
 *
130
 * Alternatively get a defined task.
131
 *
132
 * @param string $name Name of current task.
133
 * @param callable|array|string|null $body Callable task, array of other tasks names or nothing to get a defined tasks
134
 * @return Task\Task
135
 * @throws \InvalidArgumentException
136
 */
137
function task($name, $body = null)
138
{
139 15
    $deployer = Deployer::get();
140
141 15
    if (empty($body)) {
142 1
        $task = $deployer->tasks->get($name);
143 1
        return $task;
144
    }
145
146 15
    if (is_callable($body)) {
147 13
        $task = new T($name, $body);
148 15
    } elseif (is_array($body)) {
149 13
        $task = new GroupTask($name, $body);
150 10
    } elseif (is_string($body)) {
151
        $task = new T($name, function () use ($body) {
152 1
            cd('{{release_path}}');
153 1
            run($body);
154 10
        });
155
    } else {
156
        throw new \InvalidArgumentException('Task should be an closure or array of other tasks.');
157
    }
158
159 15
    $deployer->tasks->set($name, $task);
160
161 15
    if (!empty(desc())) {
162 7
        $task->desc(desc());
163 7
        desc(''); // Clear title.
164
    }
165
166 15
    return $task;
167
}
168
169
/**
170
 * Call that task before specified task runs.
171
 *
172
 * @param string $it
173
 * @param string $that
174
 */
175
function before($it, $that)
176
{
177 1
    $deployer = Deployer::get();
178 1
    $beforeTask = $deployer->tasks->get($it);
179
180 1
    $beforeTask->addBefore($that);
181 1
}
182
183
/**
184
 * Call that task after specified task runs.
185
 *
186
 * @param string $it
187
 * @param string $that
188
 */
189
function after($it, $that)
190
{
191 1
    $deployer = Deployer::get();
192 1
    $afterTask = $deployer->tasks->get($it);
193
194 1
    $afterTask->addAfter($that);
195 1
}
196
197
/**
198
 * Setup which task run on failure of first.
199
 *
200
 * @param string $it
201
 * @param string $that
202
 */
203
function fail($it, $that)
204
{
205 7
    $deployer = Deployer::get();
206 7
    $deployer['fail']->set($it, $that);
207 7
}
208
209
/**
210
 * Add users arguments.
211
 *
212
 * Note what Deployer already has one argument: "stage".
213
 *
214
 * @param string $name
215
 * @param int $mode
216
 * @param string $description
217
 * @param mixed $default
218
 */
219
function argument($name, $mode = null, $description = '', $default = null)
220
{
221
    Deployer::get()->getConsole()->getUserDefinition()->addArgument(
222
        new InputArgument($name, $mode, $description, $default)
223
    );
224
}
225
226
/**
227
 * Add users options.
228
 *
229
 * @param string $name
230
 * @param string $shortcut
231
 * @param int $mode
232
 * @param string $description
233
 * @param mixed $default
234
 */
235
function option($name, $shortcut = null, $mode = null, $description = '', $default = null)
236
{
237 7
    Deployer::get()->getConsole()->getUserDefinition()->addOption(
238 7
        new InputOption($name, $shortcut, $mode, $description, $default)
239
    );
240 7
}
241
242
/**
243
 * Change the current working directory.
244
 *
245
 * @param string $path
246
 */
247
function cd($path)
248
{
249 5
    set('working_path', parse($path));
250 5
}
251
252
/**
253
 * Execute a callback within a specific directory and revert back to the initial working directory.
254
 *
255
 * @param string $path
256
 * @param callable $callback
257
 */
258
function within($path, $callback)
259
{
260
    $lastWorkingPath = get('working_path', '');
261
    set('working_path', parse($path));
262
    $callback();
263
    set('working_path', $lastWorkingPath);
264
}
265
266
/**
267
 * Run command.
268
 *
269
 * @param string $command
270
 * @param array $options
271
 * @return string
272
 */
273
function run($command, $options = [])
274
{
275 7
    $client = Deployer::get()->sshClient;
276 7
    $process = Deployer::get()->processRunner;
277 7
    $host = Context::get()->getHost();
278 7
    $hostname = $host->getHostname();
279
280 7
    $command = parse($command);
281 7
    $workingPath = get('working_path', '');
282
283 7
    if (!empty($workingPath)) {
284 5
        $command = "cd $workingPath && ($command)";
285
    }
286
287 7
    $env = get('env', []) + ($options['env'] ?? []);
288 7
    if (!empty($env)) {
289 1
        $env = array_to_string($env);
290 1
        $command = "export $env; $command";
291
    }
292
293 7
    if ($host instanceof Localhost) {
294 7
        $output = $process->run($hostname, $command, $options);
295
    } else {
296
        $output = $client->run($host, $command, $options);
297
    }
298
299 7
    return rtrim($output);
300
}
301
302
/**
303
 * Execute commands on local machine
304
 *
305
 * @param string $command Command to run locally.
306
 * @param array $options
307
 * @return string Output of command.
308
 */
309
function runLocally($command, $options = [])
310
{
311 5
    $process = Deployer::get()->processRunner;
312 5
    $hostname = 'localhost';
313 5
    $command = parse($command);
314
315 5
    $env = get('env', []) + ($options['env'] ?? []);
316 5
    if (!empty($env)) {
317 1
        $env = array_to_string($env);
318 1
        $command = "export $env; $command";
319
    }
320
321 5
    $output = $process->run($hostname, $command, $options);
322
323 5
    return rtrim($output);
324
}
325
326
/**
327
 * Run test command.
328
 * Example:
329
 *
330
 *     test('[ -d {{release_path}} ]')
331
 *
332
 * @param string $command
333
 * @return bool
334
 */
335
function test($command)
336
{
337 5
    return run("if $command; then echo 'true'; fi") === 'true';
338
}
339
340
/**
341
 * Run test command locally.
342
 * Example:
343
 *
344
 *     testLocally('[ -d {{local_release_path}} ]')
345
 *
346
 * @param string $command
347
 * @return bool
348
 */
349
function testLocally($command)
350
{
351
    return runLocally("if $command; then echo 'true'; fi") === 'true';
352
}
353
354
/**
355
 * Iterate other hosts, allowing to call run func in callback.
356
 *
357
 * @experimental
358
 * @param Host|Host[] $hosts
359
 * @param callable $callback
360
 */
361
function on($hosts, callable $callback)
362
{
363 4
    $input = Context::has() ? input() : null;
364 4
    $output = Context::has() ? output() : null;
365
366 4
    if (!is_array($hosts) && !($hosts instanceof \Traversable)) {
367
        $hosts = [$hosts];
368
    }
369
370 4
    foreach ($hosts as $host) {
371 4
        if ($host instanceof Host) {
372 4
            Context::push(new Context($host, $input, $output));
373 4
            $callback($host);
374 4
            Context::pop();
375
        } else {
376 4
            throw new \InvalidArgumentException("Function on can iterate only on Host instances.");
377
        }
378
    }
379 4
}
380
381
/**
382
 * Return hosts based on roles.
383
 *
384
 * @experimental
385
 * @param string[] $roles
386
 * @return Host[]
387
 */
388
function roles(...$roles)
389
{
390 1
    return Deployer::get()->hostSelector->getByRoles($roles);
391
}
392
393
/**
394
 * Run task
395
 *
396
 * @experimental
397
 * @param string $task
398
 */
399
function invoke($task)
400
{
401 2
    $hosts = [Context::get()->getHost()];
402 2
    $tasks = Deployer::get()->scriptManager->getTasks($task, $hosts);
403
404 2
    $executor = Deployer::get()->seriesExecutor;
405 2
    $executor->run($tasks, $hosts);
406 2
}
407
408
/**
409
 * Upload file or directory to host
410
 *
411
 * @param string $source
412
 * @param string $destination
413
 * @param array $config
414
 */
415 View Code Duplication
function upload($source, $destination, array $config = [])
416
{
417
    $rsync = Deployer::get()->rsync;
418
    $host = Context::get()->getHost();
419
    $source = parse($source);
420
    $destination = parse($destination);
421
422
    if ($host instanceof Localhost) {
423
        $rsync->call($host->getHostname(), $source, $destination, $config);
424
    } else {
425
        $sshArguments = $host->getSshArguments()->getCliArguments();
426
        if (empty($sshArguments) === false) {
427
            if (!isset($config['options']) || !is_array($config['options'])) {
428
                $config['options'] = [];
429
            }
430
            $config['options'][] = "-e 'ssh $sshArguments'";
431
        }
432
        $rsync->call($host->getHostname(), $source, "$host:$destination", $config);
433
    }
434
}
435
436
/**
437
 * Download file or directory from host
438
 *
439
 * @param string $destination
440
 * @param string $source
441
 * @param array $config
442
 */
443 View Code Duplication
function download($source, $destination, array $config = [])
444
{
445
    $rsync = Deployer::get()->rsync;
446
    $host = Context::get()->getHost();
447
    $source = parse($source);
448
    $destination = parse($destination);
449
450
    if ($host instanceof Localhost) {
451
        $rsync->call($host->getHostname(), $source, $destination, $config);
452
    } else {
453
        $sshArguments = $host->getSshArguments()->getCliArguments();
454
        if (empty($sshArguments) === false) {
455
            if (!isset($config['options']) || !is_array($config['options'])) {
456
                $config['options'] = [];
457
            }
458
            $config['options'][] = "-e 'ssh $sshArguments'";
459
        }
460
        $rsync->call($host->getHostname(), "$host:$source", $destination, $config);
461
    }
462
}
463
464
/**
465
 * Writes a message to the output and adds a newline at the end.
466
 * @param string|array $message
467
 * @param int $options
468
 */
469
function writeln($message, $options = 0)
470
{
471 8
    output()->writeln(parse($message), $options);
472 8
}
473
474
/**
475
 * Writes a message to the output.
476
 * @param string $message
477
 * @param int $options
478
 */
479
function write($message, $options = 0)
480
{
481
    output()->write(parse($message), $options);
482
}
483
484
/**
485
 * Setup configuration option.
486
 *
487
 * @param string $name
488
 * @param mixed $value
489
 */
490
function set($name, $value)
491
{
492 8
    if (!Context::has()) {
493 8
        Deployer::setDefault($name, $value);
494
    } else {
495 5
        Context::get()->getConfig()->set($name, $value);
496
    }
497 8
}
498
499
/**
500
 * Merge new config params to existing config array.
501
 *
502
 * @param string $name
503
 * @param array $array
504
 */
505
function add($name, $array)
506
{
507 1
    if (!Context::has()) {
508
        Deployer::addDefault($name, $array);
509
    } else {
510 1
        Context::get()->getConfig()->add($name, $array);
511
    }
512 1
}
513
514
/**
515
 * Get configuration value.
516
 *
517
 * @param string $name
518
 * @param mixed|null $default
519
 * @return mixed
520
 */
521
function get($name, $default = null)
522
{
523 9
    if (!Context::has()) {
524
        return Deployer::getDefault($name, $default);
525
    } else {
526 9
        return Context::get()->getConfig()->get($name, $default);
527
    }
528
}
529
530
/**
531
 * Check if there is such configuration option.
532
 *
533
 * @param string $name
534
 * @return boolean
535
 */
536
function has($name)
537
{
538 3
    if (!Context::has()) {
539
        return Deployer::hasDefault($name);
540
    } else {
541 3
        return Context::get()->getConfig()->has($name);
542
    }
543
}
544
545
/**
546
 * @param string $message
547
 * @param string|null $default
548
 * @param string[]|null $suggestedChoices
549
 * @return string
550
 * @codeCoverageIgnore
551
 */
552
function ask($message, $default = null, $suggestedChoices = null)
553
{
554
    Context::required(__FUNCTION__);
555
556
    if (($suggestedChoices !== null) && (empty($suggestedChoices))) {
557
        throw new \InvalidArgumentException('Suggested choices should not be empty');
558
    }
559
560
    if (isQuiet()) {
561
        return $default;
562
    }
563
564
    $helper = Deployer::get()->getHelper('question');
565
566
    $message = "<question>$message" . (($default === null) ? "" : " [$default]") . "</question> ";
567
568
    $question = new Question($message, $default);
569
570
    if (empty($suggestedChoices) === false) {
571
        $question->setAutocompleterValues($suggestedChoices);
572
    }
573
574
    return $helper->ask(input(), output(), $question);
575
}
576
577
/**
578
 * @param string $message
579
 * @param string[] $availableChoices
580
 * @param string|null $default
581
 * @param bool|false $multiselect
582
 * @return array
583
 * @codeCoverageIgnore
584
 */
585
function askChoice($message, array $availableChoices, $default = null, $multiselect = false)
586
{
587
    Context::required(__FUNCTION__);
588
589
    if (empty($availableChoices)) {
590
        throw new \InvalidArgumentException('Available choices should not be empty');
591
    }
592
593
    if ($default !== null && !array_key_exists($default, $availableChoices)) {
594
        throw new \InvalidArgumentException('Default choice is not available');
595
    }
596
597
    if (isQuiet()) {
598
        if ($default === null) {
599
            $default = key($availableChoices);
600
        }
601
        return [$default => $availableChoices[$default]];
602
    }
603
604
    $helper = Deployer::get()->getHelper('question');
605
606
    $message = "<question>$message" . (($default === null) ? "" : " [$default]") . "</question> ";
607
608
    $question = new ChoiceQuestion($message, $availableChoices, $default);
609
    $question->setMultiselect($multiselect);
610
611
    return $helper->ask(input(), output(), $question);
612
}
613
614
/**
615
 * @param string $message
616
 * @param bool $default
617
 * @return bool
618
 * @codeCoverageIgnore
619
 */
620
function askConfirmation($message, $default = false)
621
{
622
    Context::required(__FUNCTION__);
623
624
    if (isQuiet()) {
625
        return $default;
626
    }
627
628
    $helper = Deployer::get()->getHelper('question');
629
630
    $yesOrNo = $default ? 'Y/n' : 'y/N';
631
    $message = "<question>$message [$yesOrNo]</question> ";
632
633
    $question = new ConfirmationQuestion($message, $default);
634
635
    return $helper->ask(input(), output(), $question);
636
}
637
638
/**
639
 * @param string $message
640
 * @return string
641
 * @codeCoverageIgnore
642
 */
643
function askHiddenResponse($message)
644
{
645
    Context::required(__FUNCTION__);
646
647
    if (isQuiet()) {
648
        return '';
649
    }
650
651
    $helper = Deployer::get()->getHelper('question');
652
653
    $message = "<question>$message</question> ";
654
655
    $question = new Question($message);
656
    $question->setHidden(true);
657
    $question->setHiddenFallback(false);
658
659
    return $helper->ask(input(), output(), $question);
660
}
661
662
/**
663
 * @return InputInterface
664
 */
665
function input()
666
{
667 7
    return Context::get()->getInput();
668
}
669
670
671
/**
672
 * @return OutputInterface
673
 */
674
function output()
675
{
676 10
    return Context::get()->getOutput();
677
}
678
679
/**
680
 * @return bool
681
 */
682
function isQuiet()
683
{
684
    return OutputInterface::VERBOSITY_QUIET === output()->getVerbosity();
685
}
686
687
688
/**
689
 * @return bool
690
 */
691
function isVerbose()
692
{
693 1
    return OutputInterface::VERBOSITY_VERBOSE <= output()->getVerbosity();
694
}
695
696
697
/**
698
 * @return bool
699
 */
700
function isVeryVerbose()
701
{
702
    return OutputInterface::VERBOSITY_VERY_VERBOSE <= output()->getVerbosity();
703
}
704
705
706
/**
707
 * @return bool
708
 */
709
function isDebug()
710
{
711
    return OutputInterface::VERBOSITY_DEBUG <= output()->getVerbosity();
712
}
713
714
/**
715
 * Check if command exists
716
 *
717
 * @param string $command
718
 * @return bool
719
 */
720
function commandExist($command)
721
{
722 3
    return test("hash $command 2>/dev/null");
723
}
724
725
function commandSupportsOption($command, $option)
726
{
727 4
    return test("[[ $(man $command 2>&1 || $command -h 2>&1 || $command --help 2>&1) =~ '$option' ]]");
728
}
729
730
/**
731
 * Parse set values.
732
 *
733
 * @param string $value
734
 * @return string
735
 */
736
function parse($value)
737
{
738 12
    return Context::get()->getConfig()->parse($value);
739
}
740
741
function locateBinaryPath($name)
742
{
743 3
    $nameEscaped = escapeshellarg($name);
744
745
    // Try `command`, should cover all Bourne-like shells
746 3
    if (commandExist("command")) {
747 3
        return run("command -v $nameEscaped");
748
    }
749
750
    // Try `which`, should cover most other cases
751
    if (commandExist("which")) {
752
        return run("which $nameEscaped");
753
    }
754
755
    // Fallback to `type` command, if the rest fails
756
    if (commandExist("type")) {
757
        $result = run("type -p $nameEscaped");
758
759
        if ($result) {
760
            // Deal with issue when `type -p` outputs something like `type -ap` in some implementations
761
            return trim(str_replace("$name is", "", $result));
762
        }
763
    }
764
765
    throw new \RuntimeException("Can't locate [$nameEscaped] - neither of [command|which|type] commands are available");
766
}
767