Passed
Push — test ( 0895d9...6e4feb )
by Tom
02:26
created

RunnerOptions::listPackages()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Utility;
6
7
use Ktomk\Pipelines\Cli\Args;
8
use Ktomk\Pipelines\Cli\ArgsException;
9
use Ktomk\Pipelines\Cli\Exec;
10
use Ktomk\Pipelines\Cli\Streams;
11
use Ktomk\Pipelines\Lib;
12
use Ktomk\Pipelines\Project;
13
use Ktomk\Pipelines\Runner\Directories;
14
use Ktomk\Pipelines\Runner\Docker\Binary\Repository;
15
use Ktomk\Pipelines\Runner\RunOpts;
16
17
/**
18
 * aggregated args parser for RunOpts / runner options
19
 *
20
 * @package Ktomk\Pipelines\Utility\Args
21
 */
22
class RunnerOptions
23
{
24
    /**
25
     * @var Args
26
     */
27
    private $args;
28
29
    /**
30
     * @var Streams
31
     */
32
    private $streams;
33
34
    /**
35
     * @var Exec
36
     */
37
    private $exec;
38
39
    /**
40
     * @param Args $args
41
     * @param Streams $streams
42
     *
43
     * @return RunnerOptions
44
     */
45 4
    public static function bind(Args $args, Streams $streams)
46
    {
47 4
        return new self($args, $streams);
48
    }
49
50
    /**
51
     * the repository used for listing and validation
52
     *
53
     * @return Repository
54
     */
55 3
    public static function createRepository()
56
    {
57 3
        return Repository::create(
58 3
            new Exec(),
59 3
            new Directories(Lib::env($_SERVER), new Project('fake'))
60
        );
61
    }
62
63
    /**
64
     * list all statically available docker client package names
65
     * that ship w/ pipelines
66
     *
67
     * @param Streams $streams
68
     *
69
     * @return void
70
     */
71 1
    public static function listPackages(Streams $streams)
72
    {
73 1
        $list = self::createRepository()->listPackages();
74
75 1
        $streams->out(implode("\n", $list));
76 1
        $streams->out("\n");
77 1
    }
78
79
    /**
80
     * RunnerOptions constructor,
81
     *
82
     * @param Args $args
83
     * @param Streams $streams
84
     * @param Exec $exec
85
     */
86 5
    public function __construct(Args $args, Streams $streams, Exec $exec = null)
87
    {
88 5
        $this->args = $args;
89 5
        $this->streams = $streams;
90 5
        $this->exec = $exec;
91 5
    }
92
93
    /**
94
     * @throws ArgsException
95
     * @throws StatusException
96
     *
97
     * @return RunOpts
98
     */
99 5
    public function run()
100
    {
101 5
        $runOpts = RunOpts::create();
102 5
        $this->parse($this->args, $runOpts);
103
104 2
        return $runOpts;
105
    }
106
107
    /**
108
     * Parse keep arguments
109
     *
110
     * @param Args $args
111
     * @param RunOpts $runOpts
112
     *
113
     * @throws ArgsException
114
     * @throws StatusException
115
     *
116
     * @return void
117
     */
118 5
    public function parse(Args $args, RunOpts $runOpts)
119
    {
120
        // FIXME(tk): \Ktomk\Pipelines\Value\Prefix::verify
121 5
        $runOpts->setPrefix($this->parsePrefix($args));
122
123 4
        $runOpts->setBinaryPackage($this->parseDockerClient($args));
124
125 3
        $this->parseDockerClientListPackages($args);
126
127 2
        $runOpts->setSteps($args->getOptionArgument(array('step', 'steps')));
128
129 2
        $runOpts->setNoManual($args->hasOption('no-manual'));
130
131 2
        $runOpts->setUser($this->parseUser($args));
132
133 2
        $runOpts->setSsh($args->hasOption('ssh-auth-sock') ?: null);
134 2
    }
135
136
    /**
137
     * @param Args $args
138
     *
139
     * @throws ArgsException
140
     *
141
     * @return null|string
142
     */
143 2
    private function parseUser(Args $args)
144
    {
145 2
        $result = $args->getOptionOptionalArgument('user', true);
146 2
        if (true !== $result) {
147 1
            return $result;
148
        }
149
150 1
        $exec = $this->exec ?: new Exec();
151 1
        $status = $exec->capture('printf "%d:%d" "$(id -u)" "$(id -g)"', array(), $out, $err);
152 1
        if (0 !== $status || '' !== $err) {
153 1
            throw new ArgsException(
154 1
                sprintf(
155 1
                    '--user internal error to resolve id -u / id -g: %d%s',
156
                    $status,
157 1
                    $err ? " : ${err}" : ''
158
                )
159
            );
160
        }
161
        $result = $out;
162
163
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type true which is incompatible with the documented return type null|string.
Loading history...
164
    }
165
166
    /**
167
     * @param Args $args
168
     *
169
     * @throws ArgsException
170
     *
171
     * @return string
172
     */
173
    private function parseDockerClient(Args $args)
174
    {
175 4
        $default = Repository::PKG_INTEGRATE;
176 4
        $binaryClient = $args->getStringOptionArgument('docker-client', $default);
177 4
        if ($binaryClient !== $default) {
178 2
            $repository = self::createRepository();
179
180
            try {
181 2
                $repository->resolve($binaryClient);
182 1
            } catch (\InvalidArgumentException $ex) {
183 1
                $message = "--docker-client needs a valid package name, file or docker client binary path; '${binaryClient}' given";
184 1
                $message .= "\n  docker client binary packages shipping w/ pipelines:";
185 1
                $message .= "\n    - " . implode("\n    - ", $repository->listPackages());
186
187 1
                throw new ArgsException($message);
188
            }
189
        }
190
191 3
        return $binaryClient;
192
    }
193
194
    /**
195
     * @param Args $args
196
     *
197
     * @throws StatusException
198
     *
199
     * @return void
200
     */
201
    private function parseDockerClientListPackages(Args $args)
202
    {
203 3
        if (!$args->hasOption('docker-client-pkgs')) {
204 2
            return;
205
        }
206
207 1
        self::listPackages($this->streams);
208
209 1
        throw new StatusException('', 0);
210
    }
211
212
    /**
213
     * @param Args $args
214
     *
215
     * @throws ArgsException
216
     *
217
     * @return string
218
     */
219
    private function parsePrefix(Args $args)
220
    {
221 5
        $prefix = $args->getStringOptionArgument('prefix', App::UTILITY_NAME);
222 5
        if (!preg_match('~^[a-z]{3,}$~', $prefix)) {
223 1
            throw new ArgsException(sprintf("invalid prefix: '%s'", $prefix));
224
        }
225
226 4
        return $prefix;
227
    }
228
}
229