Passed
Push — test ( d48a8e...8face6 )
by Tom
02:59
created

StepContainer::generateName()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 14
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 20
ccs 14
cts 14
cp 1
crap 3
rs 9.7998
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\File\Step;
10
use Ktomk\Pipelines\Lib;
11
12
/**
13
 * Class StepContainer
14
 *
15
 * @package Ktomk\Pipelines\Runner
16
 */
17
class StepContainer
18
{
19
    /**
20
     * @var null|string id of the (running) container
21
     */
22
    private $id;
23
24
    /**
25
     * @var null|string name of the container
26
     */
27
    private $name;
28
29
    /**
30
     * @var Step
31
     */
32
    private $step;
33
34
    /**
35
     * @var Exec
36
     */
37
    private $exec;
38
39
    /**
40
     * @param Step $step
41
     *
42
     * @return StepContainer
43
     */
44 2
    public static function create(Step $step, Exec $exec = null)
45
    {
46 2
        if (null === $exec) {
47 2
            $exec = new Exec();
48
        }
49
50 2
        return new self($step, $exec);
51
    }
52
53
    /**
54
     * @param Step $step
55
     * @param string $prefix
56
     * @param string $project name
57
     *
58
     * @return string
59
     */
60 1
    public static function createName(Step $step, $prefix, $project)
61
    {
62 1
        return self::create($step)->generateName($prefix, $project);
63
    }
64
65
    /**
66
     * StepContainer constructor.
67
     *
68
     * @param Step $step
69
     * @param Exec $exec
70
     */
71 10
    public function __construct(Step $step, Exec $exec)
72
    {
73 10
        $this->step = $step;
74 10
        $this->exec = $exec;
75 10
    }
76
77
    /**
78
     * generate step container name
79
     *
80
     * example: pipelines-1.pipeline-features-and-introspection.default.app
81
     *              ^    `^`                  ^                `    ^  ` ^
82
     *              |     |                   |                     |    |
83
     *              | step number        step name           pipeline id |
84
     *           prefix                                                project
85
     *
86
     * @param string $prefix for the name (normally "pipelines")
87
     * @param string $project name
88
     *
89
     * @return string
90
     */
91 5
    public function generateName($prefix, $project)
92
    {
93 5
        $step = $this->step;
94
95 5
        $idContainerSlug = preg_replace('([^a-zA-Z0-9_.-]+)', '-', $step->getPipeline()->getId());
96 5
        if ('' === $idContainerSlug) {
97 5
            $idContainerSlug = 'null';
98
        }
99 5
        $nameSlug = preg_replace(array('( )', '([^a-zA-Z0-9_.-]+)'), array('-', ''), $step->getName());
100 5
        if ('' === $nameSlug) {
101 5
            $nameSlug = 'no-name';
102
        }
103
104 5
        return $this->name = $prefix . '-' . implode(
105 5
            '.',
106
            array(
107 5
                $step->getIndex() + 1,
108 5
                $nameSlug,
109 5
                trim($idContainerSlug, '-'),
110 5
                $project,
111
            )
112
        );
113
    }
114
115
    /**
116
     * the display id
117
     *
118
     *   side-effect: if id is null, this signals a dry-run which is made
119
     * visible by the string "*dry-run*"
120
     *
121
     * @return string
122
     */
123 2
    public function getDisplayId()
124
    {
125 2
        return isset($this->id) ? $this->id : '*dry-run*';
126
    }
127
128
    /**
129
     * @return null|string ID of (once) running container or null if not yet running
130
     */
131 3
    public function getId()
132
    {
133 3
        return $this->id;
134
    }
135
136
    /**
137
     * @return null|string name of the container, NULL if no name generated yet
138
     */
139 1
    public function getName()
140
    {
141 1
        return $this->name;
142
    }
143
144
    /**
145
     * @param bool $keep a container on true, kill on false (if it exists)
146
     *
147
     * @return null|string
148
     */
149 3
    public function keepOrKill($keep)
150
    {
151 3
        $name = $this->name;
152 3
        if (null === $name) {
153 1
            throw new \BadMethodCallException('Container has no name yet');
154
        }
155
156 2
        $processManager = Docker::create($this->exec)->getProcessManager();
157
158 2
        if (false === $keep) {
159 1
            $processManager->zapContainersByName($name);
160
161 1
            return $this->id = null;
162
        }
163
164 2
        return $this->id = $processManager->findContainerIdByName($name);
165
    }
166
167
    /**
168
     * @param bool $kill
169
     * @param bool $remove
170
     */
171 2
    public function killAndRemove($kill, $remove)
172
    {
173 2
        if (null === $this->id) { # nothing to kill or remove, job already done
174 1
            return;
175
        }
176
177 1
        if ($kill) {
178 1
            Docker::create($this->exec)->getProcessManager()->kill($this->id);
179
        }
180
181 1
        if ($remove) {
182 1
            Docker::create($this->exec)->getProcessManager()->remove($this->id);
183
        }
184 1
    }
185
186
    /**
187
     * @param array $args
188
     *
189
     * @return array array(int $status, string $out, string $err)
190
     */
191 2
    public function run(array $args)
192
    {
193 2
        $status = $this->exec->capture('docker', Lib::merge('run', $args), $out, $err);
194
195 2
        if (0 === $status) {
196 2
            $this->id = rtrim($out) ?: null;
197
        }
198
199 2
        return array($status, $out, $err);
200
    }
201
}
202