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.
Completed
Pull Request — master (#1261)
by Matiss
03:19
created

functions.php ➔ locateBinaryPath()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 5

Importance

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