Passed
Push — master ( 1f6f72...a5203b )
by Tom
02:42
created

StepContainer   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 56
dl 0
loc 244
ccs 67
cts 67
cp 1
rs 10
c 1
b 0
f 0
wmc 26

13 Methods

Rating   Name   Duplication   Size   Complexity  
A createName() 0 3 1
A create() 0 7 2
A run() 0 6 1
A keepOrKill() 0 16 3
A getId() 0 3 1
A execShutdownContainer() 0 14 4
A killAndRemove() 0 5 1
A getName() 0 3 1
A __construct() 0 4 1
A getDisplayId() 0 3 2
A execRun() 0 10 3
A execKillAndRemove() 0 8 3
A generateName() 0 20 3
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Runner;
6
7
use Ktomk\Pipelines\Cli\Docker;
8
use Ktomk\Pipelines\Cli\Exec;
9
use Ktomk\Pipelines\Cli\Streams;
10
use Ktomk\Pipelines\File\Pipeline\Step;
11
use Ktomk\Pipelines\Lib;
12
13
/**
14
 * Class StepContainer
15
 *
16
 * @package Ktomk\Pipelines\Runner
17
 */
18
class StepContainer
19
{
20
    /**
21
     * @var null|string id of the (running) container
22
     */
23
    private $id;
24
25
    /**
26
     * @var null|string name of the container
27
     */
28
    private $name;
29
30
    /**
31
     * @var Step
32
     */
33
    private $step;
34
35
    /**
36
     * @var Exec
37
     */
38
    private $exec;
39
40
    /**
41
     * @param Step $step
42
     * @param null|Exec $exec
43
     *
44
     * @return StepContainer
45
     */
46 6
    public static function create(Step $step, Exec $exec = null)
47
    {
48 6
        if (null === $exec) {
49 2
            $exec = new Exec();
50
        }
51
52 6
        return new self($step, $exec);
53
    }
54
55
    /**
56
     * @param Step $step
57
     * @param string $prefix
58
     * @param string $project name
59
     *
60
     * @return string
61
     */
62 1
    public static function createName(Step $step, $prefix, $project)
63
    {
64 1
        return self::create($step)->generateName($prefix, $project);
65
    }
66
67
    /**
68
     * kill and remove static implementation
69
     *
70
     * @param Exec $exec
71
     * @param string|string[] $idOrIds container id(s) or name(s)
72
     * @param bool $kill
73
     * @param bool $remove
74
     *
75
     * @return void
76
     */
77 4
    public static function execKillAndRemove(Exec $exec, $idOrIds, $kill, $remove)
78
    {
79 4
        if ($kill) {
80 2
            Docker::create($exec)->getProcessManager()->kill($idOrIds);
81
        }
82
83 4
        if ($remove) {
84 3
            Docker::create($exec)->getProcessManager()->remove($idOrIds);
85
        }
86 4
    }
87
88
    /**
89
     * @param Exec $exec
90
     * @param array $args
91
     *
92
     * @return array array(int $status, string $out, string $err, string|null $id)
93
     */
94 4
    public static function execRun(Exec $exec, array $args)
95
    {
96 4
        $status = $exec->capture('docker', Lib::merge('run', $args), $out, $err);
97
98 4
        $id = null;
99 4
        if (0 === $status) {
100 4
            $id = rtrim($out) ?: null;
101
        }
102
103 4
        return array($status, $out, $err, $id);
104
    }
105
106
    /**
107
     * @param Exec $exec
108
     * @param Streams $streams
109
     * @param string|string[] $idOrIds
110
     * @param int $status
111
     * @param Flags $flags
112
     * @param string $message
113
     * @param string $id
114
     *
115
     * @return void
116
     *
117
     * @see StepRunner::shutdownStepContainer
118
     */
119 4
    public static function execShutdownContainer(Exec $exec, Streams $streams, $idOrIds, $status, Flags $flags, $message)
120
    {
121
        # keep container on error
122 4
        if (0 !== $status && $flags->keepOnError()) {
123 2
            $streams->err(sprintf("error, %s\n", $message));
124
125 2
            return;
126
        }
127
128
        # keep or kill/remove container
129 2
        self::execKillAndRemove($exec, $idOrIds, $flags->killContainer(), $flags->removeContainer());
130
131 2
        if ($flags->keep()) {
132 1
            $streams->out(sprintf("%s\n", $message));
133
        }
134 2
    }
135
136
    /**
137
     * StepContainer constructor.
138
     *
139
     * @param Step $step
140
     * @param Exec $exec
141
     */
142 14
    public function __construct(Step $step, Exec $exec)
143
    {
144 14
        $this->step = $step;
145 14
        $this->exec = $exec;
146 14
    }
147
148
    /**
149
     * generate step container name
150
     *
151
     * example: pipelines-1.pipeline-features-and-introspection.default.app
152
     *              ^    `^`                  ^                `    ^  ` ^
153
     *              |     |                   |                     |    |
154
     *              | step number        step name           pipeline id |
155
     *           prefix                                                project
156
     *
157
     * @param string $prefix for the name (normally "pipelines")
158
     * @param string $project name
159
     *
160
     * @return string
161
     */
162 9
    public function generateName($prefix, $project)
163
    {
164 9
        $step = $this->step;
165
166 9
        $idContainerSlug = preg_replace('([^a-zA-Z0-9_.-]+)', '-', $step->getPipeline()->getId());
167 9
        if ('' === $idContainerSlug) {
168 9
            $idContainerSlug = 'null';
169
        }
170 9
        $nameSlug = preg_replace(array('( )', '([^a-zA-Z0-9_.-]+)'), array('-', ''), $step->getName());
171 9
        if ('' === $nameSlug) {
172 9
            $nameSlug = 'no-name';
173
        }
174
175 9
        return $this->name = $prefix . '-' . implode(
176 9
            '.',
177
            array(
178 9
                    $step->getIndex() + 1,
179 9
                    $nameSlug,
180 9
                    trim($idContainerSlug, '-'),
181 9
                    $project,
182
                )
183
        );
184
    }
185
186
    /**
187
     * the display id
188
     *
189
     *   side-effect: if id is null, this signals a dry-run which is made
190
     * visible by the string "*dry-run*"
191
     *
192
     * @return string
193
     */
194 8
    public function getDisplayId()
195
    {
196 8
        return isset($this->id) ? $this->id : '*dry-run*';
197
    }
198
199
    /**
200
     * @return null|string ID of (once) running container or null if not yet running
201
     */
202 3
    public function getId()
203
    {
204 3
        return $this->id;
205
    }
206
207
    /**
208
     * @return null|string name of the container, NULL if no name generated yet
209
     */
210 3
    public function getName()
211
    {
212 3
        return $this->name;
213
    }
214
215
    /**
216
     * @param bool $keep a container on true, kill on false (if it exists)
217
     *
218
     * @return null|string
219
     */
220 7
    public function keepOrKill($keep)
221
    {
222 7
        $name = $this->name;
223 7
        if (null === $name) {
224 1
            throw new \BadMethodCallException('Container has no name yet');
225
        }
226
227 6
        $processManager = Docker::create($this->exec)->getProcessManager();
228
229 6
        if (false === $keep) {
230 2
            $processManager->zapContainersByName($name);
231
232 2
            return $this->id = null;
233
        }
234
235 5
        return $this->id = $processManager->findContainerIdByName($name);
236
    }
237
238
    /**
239
     * @param bool $kill
240
     * @param bool $remove
241
     *
242
     * @return void
243
     */
244 2
    public function killAndRemove($kill, $remove)
245
    {
246 2
        $id = $this->getDisplayId();
247
248 2
        self::execKillAndRemove($this->exec, $id, $kill, $remove);
249 2
    }
250
251
    /**
252
     * @param array $args
253
     *
254
     * @return array array(int $status, string $out, string $err)
255
     */
256 4
    public function run(array $args)
257
    {
258 4
        $execRun = self::execRun($this->exec, $args);
259 4
        $this->id = array_pop($execRun);
260
261 4
        return $execRun;
262
    }
263
}
264