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 ( 971843...0fc630 )
by Anton
05:02
created

Client   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 154
ccs 0
cts 101
cp 0
rs 10
c 0
b 0
f 0
wmc 16
lcom 1
cbo 7

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B run() 0 59 6
A parseExitStatus() 0 12 2
A initMultiplexing() 0 18 4
A isMultiplexingInitialized() 0 6 1
A exec() 0 23 2
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\Ssh;
9
10
use Deployer\Deployer;
11
use Deployer\Exception\RuntimeException;
12
use Deployer\Host\Host;
13
use Deployer\Utility\ProcessOutputPrinter;
14
use Symfony\Component\Console\Output\OutputInterface;
15
use Symfony\Component\Process\Process;
16
17
class Client
18
{
19
    /**
20
     * @var OutputInterface
21
     */
22
    private $output;
23
24
    /**
25
     * @var ProcessOutputPrinter
26
     */
27
    private $pop;
28
29
    /**
30
     * @var bool
31
     */
32
    private $multiplexing;
33
34
    public function __construct(OutputInterface $output, ProcessOutputPrinter $pop, bool $multiplexing)
35
    {
36
        $this->output = $output;
37
        $this->pop = $pop;
38
        $this->multiplexing = $multiplexing;
39
    }
40
41
    /**
42
     * @param Host $host
43
     * @param string $command
44
     * @param array $config
45
     * @return string
46
     * @throws RuntimeException
47
     */
48
    public function run(Host $host, string $command, array $config = [])
49
    {
50
        $hostname = $host->getHostname();
51
        $defaults = [
52
            'timeout' => Deployer::getDefault('default_timeout', 300),
53
            'tty' => false,
54
        ];
55
        $config = array_merge($defaults, $config);
56
57
        $this->pop->command($hostname, $command);
58
59
        $sshArguments = $host->getSshArguments();
60
        $become = $host->has('become') ? 'sudo -u ' . $host->get('become') : '';
61
62
        // When tty need to be allocated, don't use multiplexing,
63
        // and pass command without bash allocation on remote host.
64
        if ($config['tty']) {
65
            $this->output->write(''); // Notify OutputWatcher
66
            $sshArguments = $sshArguments->withFlag('-tt');
67
            $command = escapeshellarg($command);
68
69
            $ssh = "ssh $sshArguments $host $command";
70
            $process = new Process($ssh);
71
            $process
72
                ->setTimeout($config['timeout'])
73
                ->setTty(true)
74
                ->mustRun();
75
76
            return $process->getOutput();
77
        }
78
79
        if ($host->isMultiplexing() === null ? $this->multiplexing : $host->isMultiplexing()) {
80
            $sshArguments = $this->initMultiplexing($host);
81
        }
82
83
        $ssh = "ssh $sshArguments $host $become 'bash -s; printf \"[exit_code:%s]\" $?;'";
84
85
        $process = new Process($ssh);
86
        $process
87
            ->setInput($command)
88
            ->setTimeout($config['timeout']);
89
90
        $process->run($this->pop->callback($hostname));
91
92
        $output = $this->pop->filterOutput($process->getOutput());
93
        $exitCode = $this->parseExitStatus($process);
94
95
        if ($exitCode !== 0) {
96
            throw new RuntimeException(
97
                $hostname,
98
                $command,
99
                $exitCode,
100
                $output,
101
                $process->getErrorOutput()
102
            );
103
        }
104
105
        return $output;
106
    }
107
108
    private function parseExitStatus(Process $process)
109
    {
110
        $output = $process->getOutput();
111
        preg_match('/\[exit_code:(.*?)\]/', $output, $match);
112
113
        if (!isset($match[1])) {
114
            return -1;
115
        }
116
117
        $exitCode = (int)$match[1];
118
        return $exitCode;
119
    }
120
121
    private function initMultiplexing(Host $host)
122
    {
123
        $sshArguments = $host->getSshArguments()->withMultiplexing($host);
124
125
        if (!$this->isMultiplexingInitialized($host, $sshArguments)) {
126
            if ($this->output->isVeryVerbose()) {
127
                $this->pop->writeln(Process::OUT, $host->getHostname(), 'ssh multiplexing initialization');
128
            }
129
130
            $output = $this->exec("ssh -N $sshArguments $host");
131
132
            if ($this->output->isVeryVerbose()) {
133
                $this->pop->writeln(Process::OUT, $host->getHostname(), $output);
134
            }
135
        }
136
137
        return $sshArguments;
138
    }
139
140
    private function isMultiplexingInitialized(Host $host, Arguments $sshArguments)
141
    {
142
        $process = new Process("ssh -O check $sshArguments $host 2>&1");
143
        $process->run();
144
        return (bool)preg_match('/Master running/', $process->getOutput());
145
    }
146
147
    private function exec($command, &$exitCode = null)
148
    {
149
        $descriptors = [
150
            ['pipe', 'r'],
151
            ['pipe', 'w'],
152
            ['pipe', 'w'],
153
        ];
154
155
        // Don't read from stderr, there is a bug in OpenSSH_7.2p2 (stderr doesn't closed with ControlMaster)
156
157
        $process = proc_open($command, $descriptors, $pipes);
158
        if (is_resource($process)) {
159
            fclose($pipes[0]);
160
            $output = stream_get_contents($pipes[1]);
161
            fclose($pipes[1]);
162
            fclose($pipes[2]);
163
            $exitCode = proc_close($process);
164
        } else {
165
            $output = 'proc_open failure';
166
            $exitCode = 1;
167
        }
168
        return $output;
169
    }
170
}
171