Completed
Push — test ( d8d9f2...ee908a )
by Tom
14:20 queued 28s
created

RunnerOptions::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 6
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 11
ccs 7
cts 7
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
            null,
103 5
            null,
104 5
            ConfigOptions::bind($this->args)->run()
105
        );
106
107 5
        $this->parse($this->args, $runOpts);
108
109 2
        return $runOpts;
110
    }
111
112
    /**
113
     * Parse keep arguments
114
     *
115
     * @param Args $args
116
     * @param RunOpts $runOpts
117
     *
118
     * @throws ArgsException
119
     * @throws StatusException
120
     *
121
     * @return void
122
     */
123 5
    public function parse(Args $args, RunOpts $runOpts)
124
    {
125
        // FIXME(tk): \Ktomk\Pipelines\Value\Prefix::verify
126 5
        $runOpts->setPrefix($this->parsePrefix($args));
127
128 4
        $runOpts->setBinaryPackage($this->parseDockerClient($args));
129
130 3
        $this->parseDockerClientListPackages($args);
131
132 2
        $runOpts->setSteps($args->getOptionArgument(array('step', 'steps')));
133
134 2
        $runOpts->setNoManual($args->hasOption('no-manual'));
135
136 2
        $runOpts->setUser($this->parseUser($args));
137
138 2
        $runOpts->setSsh($args->hasOption('ssh-auth-sock') ?: null);
139 2
    }
140
141
    /**
142
     * @param Args $args
143
     *
144
     * @throws ArgsException
145
     *
146
     * @return null|string
147
     */
148 2
    private function parseUser(Args $args)
149
    {
150 2
        $result = $args->getOptionOptionalArgument('user', true);
151 2
        if (true !== $result) {
152 1
            return $result;
153
        }
154
155 1
        $exec = $this->exec ?: new Exec();
156 1
        $status = $exec->capture('printf "%d:%d" "$(id -u)" "$(id -g)"', array(), $out, $err);
157 1
        if (0 !== $status || '' !== $err) {
158 1
            throw new ArgsException(
159 1
                sprintf(
160 1
                    '--user internal error to resolve id -u / id -g: %d%s',
161
                    $status,
162 1
                    $err ? " : ${err}" : ''
163
                )
164
            );
165
        }
166
        $result = $out;
167
168
        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...
169
    }
170
171
    /**
172
     * @param Args $args
173
     *
174
     * @throws ArgsException
175
     *
176
     * @return string
177
     */
178
    private function parseDockerClient(Args $args)
179
    {
180 4
        $default = Repository::PKG_INTEGRATE;
181 4
        $binaryClient = $args->getStringOptionArgument('docker-client', $default);
182 4
        if ($binaryClient !== $default) {
183 2
            $repository = self::createRepository();
184
185
            try {
186 2
                $repository->resolve($binaryClient);
187 1
            } catch (\InvalidArgumentException $ex) {
188 1
                $message = "--docker-client needs a valid package name, file or docker client binary path; '${binaryClient}' given";
189 1
                $message .= "\n  docker client binary packages shipping w/ pipelines:";
190 1
                $message .= "\n    - " . implode("\n    - ", $repository->listPackages());
191
192 1
                throw new ArgsException($message);
193
            }
194
        }
195
196 3
        return $binaryClient;
197
    }
198
199
    /**
200
     * @param Args $args
201
     *
202
     * @throws StatusException
203
     *
204
     * @return void
205
     */
206
    private function parseDockerClientListPackages(Args $args)
207
    {
208 3
        if (!$args->hasOption('docker-client-pkgs')) {
209 2
            return;
210
        }
211
212 1
        self::listPackages($this->streams);
213
214 1
        throw new StatusException('', 0);
215
    }
216
217
    /**
218
     * @param Args $args
219
     *
220
     * @throws ArgsException
221
     *
222
     * @return string
223
     */
224
    private function parsePrefix(Args $args)
225
    {
226 5
        $prefix = $args->getStringOptionArgument('prefix', App::UTILITY_NAME);
227 5
        if (!preg_match('~^[a-z]{3,}$~', $prefix)) {
228 1
            throw new ArgsException(sprintf("invalid prefix: '%s'", $prefix));
229
        }
230
231 4
        return $prefix;
232
    }
233
}
234