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.
Test Failed
Pull Request — master (#1904)
by Anton
02:21
created

Client::exec()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 23
ccs 0
cts 20
cp 0
crap 6
rs 9.552
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\Component\Ssh;
9
10
use Deployer\Deployer;
11
use Deployer\Exception\RunException;
12
use Deployer\Host\Host;
13
use Deployer\Component\ProcessRunner\Printer;
14
use Deployer\Logger\Logger;
15
use Symfony\Component\Console\Output\OutputInterface;
16
use Symfony\Component\Process\Process;
17
18
class Client
19
{
20
    private $output;
21
    private $pop;
22
    private $logger;
23
24
    public function __construct(OutputInterface $output, Printer $pop, Logger $logger)
25
    {
26
        $this->output = $output;
27
        $this->pop = $pop;
28
        $this->logger = $logger;
29
    }
30
31
    public function run(Host $host, string $command, array $config = [])
32
    {
33
        $hostname = $host->hostname();
34
        $defaults = [
35
            'timeout' => $host->get('default_timeout', 300),
36
        ];
37
38
        $config = array_merge($defaults, $config);
39
        $sshArguments = $host->getSshArguments();
40
        $become = $host->has('become') ? 'sudo -H -u ' . $host->get('become') : '';
41
42
        if ($host->sshMultiplexing()) {
43
            $sshArguments = $this->initMultiplexing($host);
44
        }
45
46
        $shellCommand = $host->shell();
47
48
        if (strtolower(substr(PHP_OS, 0, 3)) === 'win') {
49
            $ssh = "ssh $sshArguments $hostname $become \"$shellCommand; printf '[exit_code:%s]' $?;\"";
50
        } else {
51
            $ssh = "ssh $sshArguments $hostname $become '$shellCommand; printf \"[exit_code:%s]\" $?;'";
52
        }
53
54
        // -vvv for ssh command
55
        if ($this->output->isDebug()) {
56
            $this->pop->writeln(Process::OUT, $host, "$ssh");
57
        }
58
59
        $this->pop->command($host, $command);
60
        $this->logger->log("[{$host->alias()}] run $command");
61
62
        $terminalOutput = $this->pop->callback($host);
63
        $callback = function ($type, $buffer) use ($host, $terminalOutput) {
64
            $this->logger->printBuffer($host, $type, $buffer);
65
            $terminalOutput($type, $buffer);
66
        };
67
68
69
        $process = $this->createProcess($ssh);
70
        $process
71
            ->setInput($command)
72
            ->setTimeout($config['timeout']);
73
74
75
        $process->run($callback);
76
77
        $output = $this->pop->filterOutput($process->getOutput());
78
        $exitCode = $this->parseExitStatus($process);
79
80
        if ($exitCode !== 0) {
81
            $trace = debug_backtrace();
82
            throw new RunException(
83
                basename($trace[1]['file']),
84
                $trace[1]['line'],
85
                $hostname,
86
                $command,
87
                $exitCode,
88
                $output,
89
                $process->getErrorOutput()
90
            );
91
        }
92
93
        return $output;
94
    }
95
96
    private function parseExitStatus(Process $process)
97
    {
98
        $output = $process->getOutput();
99
        preg_match('/\[exit_code:(.*?)\]/', $output, $match);
100
101
        if (!isset($match[1])) {
102
            return -1;
103
        }
104
105
        $exitCode = (int)$match[1];
106
        return $exitCode;
107
    }
108
109
    public function connect(Host $host)
110
    {
111
        if ($host->sshMultiplexing()) {
112
            $this->initMultiplexing($host);
113
        }
114
    }
115
116
    private function initMultiplexing(Host $host)
117
    {
118
        $sshArguments = $host->getSshArguments()->withMultiplexing($host);
119
120
        if (!$this->isMultiplexingInitialized($host, $sshArguments)) {
121
            $hostname = $host->hostname();
122
123
            if ($this->output->isDebug()) {
124
                $this->pop->writeln(Process::OUT, $host, '<info>ssh multiplexing initialization</info>');
125
                $this->pop->writeln(Process::OUT, $host, "ssh -N $sshArguments $hostname");
126
            }
127
128
            $output = $this->exec("ssh -N $sshArguments $hostname");
129
130
            if ($this->output->isDebug()) {
131
                $this->pop->printBuffer(Process::OUT, $host, $output);
132
            }
133
        }
134
135
        return $sshArguments;
136
    }
137
138
    private function isMultiplexingInitialized(Host $host, Arguments $sshArguments)
139
    {
140
        $process = $this->createProcess("ssh -O check $sshArguments {$host->alias()} 2>&1");
141
        $process->run();
142
        return (bool)preg_match('/Master running/', $process->getOutput());
143
    }
144
145
    private function exec($command, &$exitCode = null)
146
    {
147
        $descriptors = [
148
            ['pipe', 'r'],
149
            ['pipe', 'w'],
150
            ['pipe', 'w'],
151
        ];
152
153
        // Don't read from stderr, there is a bug in OpenSSH_7.2p2 (stderr doesn't closed with ControlMaster)
154
155
        $process = proc_open($command, $descriptors, $pipes);
156
        if (is_resource($process)) {
157
            fclose($pipes[0]);
158
            $output = stream_get_contents($pipes[1]);
159
            fclose($pipes[1]);
160
            fclose($pipes[2]);
161
            $exitCode = proc_close($process);
162
        } else {
163
            $output = 'proc_open failure';
164
            $exitCode = 1;
165
        }
166
        return $output;
167
    }
168
169
    private function createProcess($command)
170
    {
171
        if (method_exists('Symfony\Component\Process\Process', 'fromShellCommandline')) {
172
            return Process::fromShellCommandline($command);
173
        } else {
174
            return new Process($command);
175
        }
176
    }
177
}
178