Passed
Push — test ( 63bffd...9ffc6c )
by Tom
03:04
created

RunnerOptions::parseUser()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 3
nop 1
dl 0
loc 21
ccs 11
cts 11
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
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 2
    }
133
134
    /**
135
     * @param Args $args
136
     *
137
     * @throws ArgsException
138
     *
139
     * @return null|string
140
     */
141 2
    private function parseUser(Args $args)
142
    {
143 2
        $result = $args->getOptionOptionalArgument('user', true);
144 2
        if (true !== $result) {
145 1
            return $result;
146
        }
147
148 1
        $exec = $this->exec ?: new Exec();
149 1
        $status = $exec->capture('printf "%d:%d" "$(id -u)" "$(id -g)"', array(), $out, $err);
150 1
        if (0 !== $status || '' !== $err) {
151 1
            throw new ArgsException(
152 1
                sprintf(
153 1
                    '--user internal error to resolve id -u / id -g: %d%s',
154
                    $status,
155 1
                    $err ? " : ${err}" : ''
156
                )
157
            );
158
        }
159
        $result = $out;
160
161
        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...
162
    }
163
164
    /**
165
     * @param Args $args
166
     *
167
     * @throws ArgsException
168
     *
169
     * @return string
170
     */
171
    private function parseDockerClient(Args $args)
172
    {
173 4
        $default = Repository::PKG_INTEGRATE;
174 4
        $binaryClient = $args->getStringOptionArgument('docker-client', $default);
175 4
        if ($binaryClient !== $default) {
176 2
            $repository = self::createRepository();
177
178
            try {
179 2
                $repository->resolve($binaryClient);
180 1
            } catch (\InvalidArgumentException $ex) {
181 1
                $message = "--docker-client needs a valid package name, file or docker client binary path; '${binaryClient}' given";
182 1
                $message .= "\n  docker client binary packages shipping w/ pipelines:";
183 1
                $message .= "\n    - " . implode("\n    - ", $repository->listPackages());
184
185 1
                throw new ArgsException($message);
186
            }
187
        }
188
189 3
        return $binaryClient;
190
    }
191
192
    /**
193
     * @param Args $args
194
     *
195
     * @throws StatusException
196
     *
197
     * @return void
198
     */
199
    private function parseDockerClientListPackages(Args $args)
200
    {
201 3
        if (!$args->hasOption('docker-client-pkgs')) {
202 2
            return;
203
        }
204
205 1
        self::listPackages($this->streams);
206
207 1
        throw new StatusException('', 0);
208
    }
209
210
    /**
211
     * @param Args $args
212
     *
213
     * @throws ArgsException
214
     *
215
     * @return string
216
     */
217
    private function parsePrefix(Args $args)
218
    {
219 5
        $prefix = $args->getStringOptionArgument('prefix', App::UTILITY_NAME);
220 5
        if (!preg_match('~^[a-z]{3,}$~', $prefix)) {
221 1
            throw new ArgsException(sprintf("invalid prefix: '%s'", $prefix));
222
        }
223
224 4
        return $prefix;
225
    }
226
}
227