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
Pull Request — master (#2037)
by Elan
02:09
created

Arguments   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 177
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 89.33%

Importance

Changes 0
Metric Value
dl 0
loc 177
ccs 67
cts 75
cp 0.8933
rs 10
c 0
b 0
f 0
wmc 21
lcom 1
cbo 3

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getCliArguments() 0 17 1
A getOption() 0 4 1
A getFlag() 0 8 2
A withFlags() 0 7 1
A withOptions() 0 7 1
A withFlag() 0 7 1
A withOption() 0 7 1
A withDefaults() 0 8 1
A withMultiplexing() 0 12 1
B generateControlPath() 0 38 6
A buildFlagsFromArray() 0 20 4
A __toString() 0 4 1
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\Exception\Exception;
11
use Deployer\Host\Host;
12
use Deployer\Support\Unix;
13
14
class Arguments
15
{
16
    /**
17
     * @var array
18
     */
19
    private $flags = [];
20
21
    /**
22
     * @var array
23
     */
24
    private $options = [];
25
26 9
    public function getCliArguments()
27
    {
28 9
        $boolFlags = array_keys(array_filter($this->flags, 'is_null'));
29
30 9
        $valueFlags = array_filter($this->flags);
31
        $valueFlags = array_map(function ($key, $value) {
32 4
            return "$key $value";
33 9
        }, array_keys($valueFlags), $valueFlags);
34
35
        $options = array_map(function ($key, $value) {
36 7
            return "-o $key=$value";
37 9
        }, array_keys($this->options), $this->options);
38
39 9
        $args = sprintf('%s %s %s', implode(' ', $boolFlags), implode(' ', $valueFlags), implode(' ', $options));
40
41 9
        return trim(preg_replace('!\s+!', ' ', $args));
42
    }
43
44 3
    public function getOption(string $option)
45
    {
46 3
        return $this->options[$option] ?? '';
47
    }
48
49 1
    public function getFlag(string $flag)
50
    {
51 1
        if (!array_key_exists($flag, $this->flags)) {
52
            return false;
53
        }
54
55 1
        return $this->flags[$flag] ?? true;
56
    }
57
58 8
    public function withFlags(array $flags)
59
    {
60 8
        $clone = clone $this;
61 8
        $clone->flags = $this->buildFlagsFromArray($flags);
62
63 8
        return $clone;
64
    }
65
66 9
    public function withOptions(array $options)
67
    {
68 9
        $clone = clone $this;
69 9
        $clone->options = $options;
70
71 9
        return $clone;
72
    }
73
74 4
    public function withFlag(string $flag, string $value = null)
75
    {
76 4
        $clone = clone $this;
77 4
        $clone->flags = array_merge($this->flags, [$flag => $value]);
78
79 4
        return $clone;
80
    }
81
82 3
    public function withOption(string $option, string $value)
83
    {
84 3
        $clone = clone $this;
85 3
        $clone->options = array_merge($this->options, [$option => $value]);
86
87 3
        return $clone;
88
    }
89
90 4
    public function withDefaults(Arguments $defaultOptions)
91
    {
92 4
        $clone = clone $this;
93 4
        $clone->options = array_merge($defaultOptions->options, $this->options);
94 4
        $clone->flags = array_merge($defaultOptions->flags, $this->flags);
95
96 4
        return $clone;
97
    }
98
99 2
    public function withMultiplexing(Host $host)
100
    {
101 2
        $controlPath = $this->generateControlPath($host);
102
103 2
        $multiplexDefaults = (new Arguments)->withOptions([
104 2
            'ControlMaster' => 'auto',
105 2
            'ControlPersist' => $host->get('ssh_control_persist', 60),
106 2
            'ControlPath' => $controlPath,
107
        ]);
108
109 2
        return $this->withDefaults($multiplexDefaults);
110
    }
111
112
    /**
113
     * Return SSH multiplexing control path
114
     *
115
     * When ControlPath is longer than 104 chars we can get:
116
     *
117
     *     SSH Error: unix_listener: too long for Unix domain socket
118
     *
119
     * So try to get as descriptive path as possible.
120
     * %C is for creating hash out of connection attributes.
121
     *
122
     * @param Host $host
123
     * @return string ControlPath
124
     * @throws Exception
125
     */
126 2
    private function generateControlPath(Host $host)
127
    {
128 2
        $connectionHashLength = 16; // Length of connection hash that OpenSSH appends to controlpath
129 2
        $unixMaxPath = 104; // Theoretical max limit for path length
130 2
        $homeDir = Unix::parseHomeDir('~');
131 2
        $port = empty($host->getPort()) ? '' : ':' . $host->getPort();
132
133
        // TODO: Reuse connection to same host.
134
        // If a few host point to same hostname, we get with a few connections.
135
        //
136
        //    host('a')->hostname('deployer.org');
137
        //    host('b')->hostname('deployer.org');
138
        //    host('c')->hostname('deployer.org');
139
        //
140
        // If simple change $connectionData to "{$host->getHostname()}$port" then
141
        // only first host be able to perform runs.
142 2
        $connectionData = "{$host->getAlias()}$port";
143
144 2
        $tryLongestPossible = 0;
145 2
        $controlPath = '';
146
        do {
147
            switch ($tryLongestPossible) {
148 2
                case 1:
149
                    $controlPath = "$homeDir/.ssh/deployer_%C";
150
                    break;
151 2
                case 2:
152
                    $controlPath = "$homeDir/.ssh/mux_%C";
153
                    break;
154 2
                case 3:
155
                    throw new Exception("The multiplexing control path is too long. Control path is: $controlPath");
156
                default:
157 2
                    $controlPath = "$homeDir/.ssh/deployer_$connectionData";
158
            }
159 2
            $tryLongestPossible++;
160 2
        } while (strlen($controlPath) + $connectionHashLength > $unixMaxPath); // Unix socket max length
161
162 2
        return $controlPath;
163
    }
164
165 8
    private function buildFlagsFromArray($flags)
166
    {
167
        $boolFlags = array_filter(array_map(function ($key, $value) {
168 8
            if (is_int($key)) {
169 7
                return $value;
170
            }
171
172 3
            if (null === $value) {
173 2
                return $key;
174
            }
175
176 3
            return false;
177 8
        }, array_keys($flags), $flags));
178
179
        $valueFlags = array_filter($flags, function ($key, $value) {
180 8
            return is_string($key) && is_string($value);
181 8
        }, ARRAY_FILTER_USE_BOTH);
182
183 8
        return array_merge(array_fill_keys($boolFlags, null), $valueFlags);
184
    }
185
186
    public function __toString()
187
    {
188
        return $this->getCliArguments();
189
    }
190
}
191