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
Push — master ( 55fc69...722b69 )
by Anton
02:20
created

functions.php ➔ on()   C

Complexity

Conditions 7
Paths 32

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7.0283

Importance

Changes 0
Metric Value
cc 7
eloc 14
nc 32
nop 2
dl 0
loc 22
ccs 11
cts 12
cp 0.9167
crap 7.0283
rs 6.9811
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 15
    $deployer = Deployer::get();
74 15
    $hostnames = Range::expand($hostnames);
75
76 15
    if (count($hostnames) <= 1) {
77 10
        $host = count($hostnames) === 1 ? new Localhost($hostnames[0]) : new Localhost();
78 10
        $deployer->hosts->set($host->getHostname(), $host);
79 10
        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 17
    static $store = null;
119
120 17
    if ($title === null) {
121 17
        return $store;
122
    } else {
123 9
        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 17
    $deployer = Deployer::get();
140
141 17
    if (empty($body)) {
142 1
        $task = $deployer->tasks->get($name);
143 1
        return $task;
144
    }
145
146 17
    if (is_callable($body)) {
147 15
        $task = new T($name, $body);
148 17
    } elseif (is_array($body)) {
149 15
        $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 17
    $deployer->tasks->set($name, $task);
160
161 17
    if (!empty(desc())) {
162 9
        $task->desc(desc());
163 9
        desc(''); // Clear title.
164
    }
165
166 17
    return $task;
167
}
168
169
/**
170
 * Call that task before specified task runs.
171
 *
172
 * @param string $it The task before $that should be run.
173
 * @param string $that The task to be run.
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 The task after $that should be run.
187
 * @param string $that The task to be run.
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 The task which need to fail so $that should be run.
201
 * @param string $that The task to be run.
202
 */
203
function fail($it, $that)
204
{
205 9
    $deployer = Deployer::get();
206 9
    $deployer->fail->set($it, $that);
207 9
}
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 9
    Deployer::get()->getConsole()->getUserDefinition()->addOption(
238 9
        new InputOption($name, $shortcut, $mode, $description, $default)
239
    );
240 9
}
241
242
/**
243
 * Change the current working directory.
244
 *
245
 * @param string $path
246
 */
247
function cd($path)
248
{
249 7
    set('working_path', parse($path));
250 7
}
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
    try {
262
        set('working_path', parse($path));
263
        $callback();
264
    } finally {
265
        set('working_path', $lastWorkingPath);
266
    }
267
}
268
269
/**
270
 * Run command.
271
 *
272
 * @param string $command
273
 * @param array $options
274
 * @return string
275
 */
276
function run($command, $options = [])
277
{
278 9
    $client = Deployer::get()->sshClient;
279 9
    $process = Deployer::get()->processRunner;
280 9
    $host = Context::get()->getHost();
281 9
    $hostname = $host->getHostname();
282
283 9
    $command = parse($command);
284 9
    $workingPath = get('working_path', '');
285
286 9
    if (!empty($workingPath)) {
287 7
        $command = "cd $workingPath && ($command)";
288
    }
289
290 9
    $env = get('env', []) + ($options['env'] ?? []);
291 9
    if (!empty($env)) {
292 1
        $env = array_to_string($env);
293 1
        $command = "export $env; $command";
294
    }
295
296 9
    if ($host instanceof Localhost) {
297 9
        $output = $process->run($hostname, $command, $options);
298
    } else {
299
        $output = $client->run($host, $command, $options);
300
    }
301
302 9
    return rtrim($output);
303
}
304
305
/**
306
 * Execute commands on local machine
307
 *
308
 * @param string $command Command to run locally.
309
 * @param array $options
310
 * @return string Output of command.
311
 */
312
function runLocally($command, $options = [])
313
{
314 5
    $process = Deployer::get()->processRunner;
315 5
    $hostname = 'localhost';
316 5
    $command = parse($command);
317
318 5
    $env = get('env', []) + ($options['env'] ?? []);
319 5
    if (!empty($env)) {
320 1
        $env = array_to_string($env);
321 1
        $command = "export $env; $command";
322
    }
323
324 5
    $output = $process->run($hostname, $command, $options);
325
326 5
    return rtrim($output);
327
}
328
329
/**
330
 * Run test command.
331
 * Example:
332
 *
333
 *     test('[ -d {{release_path}} ]')
334
 *
335
 * @param string $command
336
 * @return bool
337
 */
338
function test($command)
339
{
340 7
    return run("if $command; then echo 'true'; fi") === 'true';
341
}
342
343
/**
344
 * Run test command locally.
345
 * Example:
346
 *
347
 *     testLocally('[ -d {{local_release_path}} ]')
348
 *
349
 * @param string $command
350
 * @return bool
351
 */
352
function testLocally($command)
353
{
354
    return runLocally("if $command; then echo 'true'; fi") === 'true';
355
}
356
357
/**
358
 * Iterate other hosts, allowing to call run func in callback.
359
 *
360
 * @experimental
361
 * @param Host|Host[] $hosts
362
 * @param callable $callback
363
 */
364
function on($hosts, callable $callback)
365
{
366 4
    $input = Context::has() ? input() : null;
367 4
    $output = Context::has() ? output() : null;
368
369 4
    if (!is_array($hosts) && !($hosts instanceof \Traversable)) {
370
        $hosts = [$hosts];
371
    }
372
373 4
    foreach ($hosts as $host) {
374 4
        if ($host instanceof Host) {
375
            try {
376 4
                Context::push(new Context($host, $input, $output));
377 4
                $callback($host);
378 4
            } finally {
379 4
                Context::pop();
380
            }
381
        } else {
382 4
            throw new \InvalidArgumentException("Function on can iterate only on Host instances.");
383
        }
384
    }
385 4
}
386
387
/**
388
 * Return hosts based on roles.
389
 *
390
 * @experimental
391
 * @param string[] $roles
392
 * @return Host[]
393
 */
394
function roles(...$roles)
395
{
396 1
    return Deployer::get()->hostSelector->getByRoles($roles);
397
}
398
399
/**
400
 * Run task
401
 *
402
 * @experimental
403
 * @param string $task
404
 */
405
function invoke($task)
406
{
407 2
    $hosts = [Context::get()->getHost()];
408 2
    $tasks = Deployer::get()->scriptManager->getTasks($task, $hosts);
409
410 2
    $executor = Deployer::get()->seriesExecutor;
411 2
    $executor->run($tasks, $hosts);
412 2
}
413
414
/**
415
 * Upload file or directory to host
416
 *
417
 * @param string $source
418
 * @param string $destination
419
 * @param array $config
420
 */
421 View Code Duplication
function upload($source, $destination, array $config = [])
422
{
423
    $rsync = Deployer::get()->rsync;
424
    $host = Context::get()->getHost();
425
    $source = parse($source);
426
    $destination = parse($destination);
427
428
    if ($host instanceof Localhost) {
429
        $rsync->call($host->getHostname(), $source, $destination, $config);
430
    } else {
431
        $sshArguments = $host->getSshArguments()->getCliArguments();
432
        if (empty($sshArguments) === false) {
433
            if (!isset($config['options']) || !is_array($config['options'])) {
434
                $config['options'] = [];
435
            }
436
            $config['options'][] = "-e 'ssh $sshArguments'";
437
        }
438
        $rsync->call($host->getHostname(), $source, "$host:$destination", $config);
439
    }
440
}
441
442
/**
443
 * Download file or directory from host
444
 *
445
 * @param string $destination
446
 * @param string $source
447
 * @param array $config
448
 */
449 View Code Duplication
function download($source, $destination, array $config = [])
450
{
451
    $rsync = Deployer::get()->rsync;
452
    $host = Context::get()->getHost();
453
    $source = parse($source);
454
    $destination = parse($destination);
455
456
    if ($host instanceof Localhost) {
457
        $rsync->call($host->getHostname(), $source, $destination, $config);
458
    } else {
459
        $sshArguments = $host->getSshArguments()->getCliArguments();
460
        if (empty($sshArguments) === false) {
461
            if (!isset($config['options']) || !is_array($config['options'])) {
462
                $config['options'] = [];
463
            }
464
            $config['options'][] = "-e 'ssh $sshArguments'";
465
        }
466
        $rsync->call($host->getHostname(), "$host:$source", $destination, $config);
467
    }
468
}
469
470
/**
471
 * Writes a message to the output and adds a newline at the end.
472
 * @param string|array $message
473
 * @param int $options
474
 */
475
function writeln($message, $options = 0)
476
{
477 10
    output()->writeln(parse($message), $options);
478 10
}
479
480
/**
481
 * Writes a message to the output.
482
 * @param string $message
483
 * @param int $options
484
 */
485
function write($message, $options = 0)
486
{
487
    output()->write(parse($message), $options);
488
}
489
490
/**
491
 * Setup configuration option.
492
 *
493
 * @param string $name
494
 * @param mixed $value
495
 */
496
function set($name, $value)
497
{
498 10
    if (!Context::has()) {
499 10
        Deployer::setDefault($name, $value);
500
    } else {
501 7
        Context::get()->getConfig()->set($name, $value);
502
    }
503 10
}
504
505
/**
506
 * Merge new config params to existing config array.
507
 *
508
 * @param string $name
509
 * @param array $array
510
 */
511
function add($name, $array)
512
{
513 1
    if (!Context::has()) {
514
        Deployer::addDefault($name, $array);
515
    } else {
516 1
        Context::get()->getConfig()->add($name, $array);
517
    }
518 1
}
519
520
/**
521
 * Get configuration value.
522
 *
523
 * @param string $name
524
 * @param mixed|null $default
525
 * @return mixed
526
 */
527
function get($name, $default = null)
528
{
529 11
    if (!Context::has()) {
530
        return Deployer::getDefault($name, $default);
531
    } else {
532 11
        return Context::get()->getConfig()->get($name, $default);
533
    }
534
}
535
536
/**
537
 * Check if there is such configuration option.
538
 *
539
 * @param string $name
540
 * @return boolean
541
 */
542
function has($name)
543
{
544 5
    if (!Context::has()) {
545
        return Deployer::hasDefault($name);
546
    } else {
547 5
        return Context::get()->getConfig()->has($name);
548
    }
549
}
550
551
/**
552
 * @param string $message
553
 * @param string|null $default
554
 * @param string[]|null $suggestedChoices
555
 * @return string
556
 * @codeCoverageIgnore
557
 */
558
function ask($message, $default = null, $suggestedChoices = null)
559
{
560
    Context::required(__FUNCTION__);
561
562
    if (($suggestedChoices !== null) && (empty($suggestedChoices))) {
563
        throw new \InvalidArgumentException('Suggested choices should not be empty');
564
    }
565
566
    if (isQuiet()) {
567
        return $default;
568
    }
569
570
    $helper = Deployer::get()->getHelper('question');
571
572
    $message = "<question>$message" . (($default === null) ? "" : " [$default]") . "</question> ";
573
574
    $question = new Question($message, $default);
575
576
    if (empty($suggestedChoices) === false) {
577
        $question->setAutocompleterValues($suggestedChoices);
578
    }
579
580
    return $helper->ask(input(), output(), $question);
581
}
582
583
/**
584
 * @param string $message
585
 * @param string[] $availableChoices
586
 * @param string|null $default
587
 * @param bool|false $multiselect
588
 * @return array
589
 * @codeCoverageIgnore
590
 */
591
function askChoice($message, array $availableChoices, $default = null, $multiselect = false)
592
{
593
    Context::required(__FUNCTION__);
594
595
    if (empty($availableChoices)) {
596
        throw new \InvalidArgumentException('Available choices should not be empty');
597
    }
598
599
    if ($default !== null && !array_key_exists($default, $availableChoices)) {
600
        throw new \InvalidArgumentException('Default choice is not available');
601
    }
602
603
    if (isQuiet()) {
604
        if ($default === null) {
605
            $default = key($availableChoices);
606
        }
607
        return [$default => $availableChoices[$default]];
608
    }
609
610
    $helper = Deployer::get()->getHelper('question');
611
612
    $message = "<question>$message" . (($default === null) ? "" : " [$default]") . "</question> ";
613
614
    $question = new ChoiceQuestion($message, $availableChoices, $default);
615
    $question->setMultiselect($multiselect);
616
617
    return $helper->ask(input(), output(), $question);
618
}
619
620
/**
621
 * @param string $message
622
 * @param bool $default
623
 * @return bool
624
 * @codeCoverageIgnore
625
 */
626
function askConfirmation($message, $default = false)
627
{
628
    Context::required(__FUNCTION__);
629
630
    if (isQuiet()) {
631
        return $default;
632
    }
633
634
    $helper = Deployer::get()->getHelper('question');
635
636
    $yesOrNo = $default ? 'Y/n' : 'y/N';
637
    $message = "<question>$message [$yesOrNo]</question> ";
638
639
    $question = new ConfirmationQuestion($message, $default);
640
641
    return $helper->ask(input(), output(), $question);
642
}
643
644
/**
645
 * @param string $message
646
 * @return string
647
 * @codeCoverageIgnore
648
 */
649
function askHiddenResponse($message)
650
{
651
    Context::required(__FUNCTION__);
652
653
    if (isQuiet()) {
654
        return '';
655
    }
656
657
    $helper = Deployer::get()->getHelper('question');
658
659
    $message = "<question>$message</question> ";
660
661
    $question = new Question($message);
662
    $question->setHidden(true);
663
    $question->setHiddenFallback(false);
664
665
    return $helper->ask(input(), output(), $question);
666
}
667
668
/**
669
 * @return InputInterface
670
 */
671
function input()
672
{
673 7
    return Context::get()->getInput();
674
}
675
676
677
/**
678
 * @return OutputInterface
679
 */
680
function output()
681
{
682 12
    return Context::get()->getOutput();
683
}
684
685
/**
686
 * @return bool
687
 */
688
function isQuiet()
689
{
690
    return OutputInterface::VERBOSITY_QUIET === output()->getVerbosity();
691
}
692
693
694
/**
695
 * @return bool
696
 */
697
function isVerbose()
698
{
699 1
    return OutputInterface::VERBOSITY_VERBOSE <= output()->getVerbosity();
700
}
701
702
703
/**
704
 * @return bool
705
 */
706
function isVeryVerbose()
707
{
708
    return OutputInterface::VERBOSITY_VERY_VERBOSE <= output()->getVerbosity();
709
}
710
711
712
/**
713
 * @return bool
714
 */
715
function isDebug()
716
{
717
    return OutputInterface::VERBOSITY_DEBUG <= output()->getVerbosity();
718
}
719
720
/**
721
 * Check if command exists
722
 *
723
 * @param string $command
724
 * @return bool
725
 */
726
function commandExist($command)
727
{
728 3
    return test("hash $command 2>/dev/null");
729
}
730
731
function commandSupportsOption($command, $option)
732
{
733 6
    return test("[[ $(man $command 2>&1 || $command -h 2>&1 || $command --help 2>&1) =~ '$option' ]]");
734
}
735
736
/**
737
 * Parse set values.
738
 *
739
 * @param string $value
740
 * @return string
741
 */
742
function parse($value)
743
{
744 14
    return Context::get()->getConfig()->parse($value);
745
}
746
747
function locateBinaryPath($name)
748
{
749 3
    $nameEscaped = escapeshellarg($name);
750
751
    // Try `command`, should cover all Bourne-like shells
752 3
    if (commandExist("command")) {
753 3
        return run("command -v $nameEscaped");
754
    }
755
756
    // Try `which`, should cover most other cases
757
    if (commandExist("which")) {
758
        return run("which $nameEscaped");
759
    }
760
761
    // Fallback to `type` command, if the rest fails
762
    if (commandExist("type")) {
763
        $result = run("type -p $nameEscaped");
764
765
        if ($result) {
766
            // Deal with issue when `type -p` outputs something like `type -ap` in some implementations
767
            return trim(str_replace("$name is", "", $result));
768
        }
769
    }
770
771
    throw new \RuntimeException("Can't locate [$nameEscaped] - neither of [command|which|type] commands are available");
772
}
773