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 ( f968f3...d9c744 )
by Anton
02:00
created

functions.php ➔ set()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

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