Passed
Push — steps ( 2bf0cd...c7b5f4 )
by Tom
04:13
created

Env::getVarDefinitions()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 0
dl 0
loc 11
ccs 6
cts 6
cp 1
crap 3
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Env::getResolver() 0 7 2
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Runner;
6
7
use Ktomk\Pipelines\Cli\Args\Args;
8
use Ktomk\Pipelines\Cli\Args\Collector;
9
use Ktomk\Pipelines\Lib;
10
11
/**
12
 * Pipeline environment collaborator
13
 */
14
class Env
15
{
16
    /**
17
     * @var array pipelines (bitbucket) environment variables
18
     */
19
    private $vars = array();
20
21
    /**
22
     * collected arguments
23
     *
24
     * @var array
25
     */
26
    private $collected = array();
27
28
    /**
29
     * environment variables to inherit from
30
     *
31
     * @var array
32
     */
33
    private $inherit = array();
34
35
    /**
36
     * @var null|EnvResolver
37
     */
38
    private $resolver;
39
40
    /**
41
     * @param null|array $inherit
42
     *
43
     * @return Env
44
     */
45 17
    public static function create(array $inherit = array())
46
    {
47 17
        $env = new self();
48 17
        $env->initDefaultVars($inherit);
49
50 17
        return $env;
51
    }
52
53
    /**
54
     * @param array $vars
55
     * @return array w/ a string variable definition (name=value) per value
56
     */
57 12
    public static function createVarDefinitions(array $vars)
58
    {
59 12
        $array = array();
60
61 12
        foreach ($vars as $name => $value) {
62 11
            if (isset($value)) {
63 11
                $array[] = sprintf('%s=%s', $name, $value);
64
            }
65
        }
66
67 12
        return $array;
68
    }
69
70
    /**
71
     * @param string $option "-e" typically for Docker binary
72
     * @param array $vars variables as hashmap
73
     *
74
     * @return array of options (from $option) and values, ['-e', 'val1', '-e', 'val2', ...]
75
     */
76 12
    public static function createArgVarDefinitions($option, array $vars)
77
    {
78 12
        $args = array();
79
80 12
        foreach (self::createVarDefinitions($vars) as $definition) {
81 11
            $args[] = $option;
82 11
            $args[] = $definition;
83
        }
84
85 12
        return $args;
86
    }
87
88
    /**
89
     * Initialize default environment used in a Bitbucket Pipeline
90
     *
91
     * As the runner mimics some values, defaults are available
92
     *
93
     * @param array $inherit Environment variables to inherit from
94
     */
95 20
    public function initDefaultVars(array $inherit)
96
    {
97 20
        $this->inherit = array_filter($inherit, 'is_string');
98
99
        $inheritable = array(
100 20
            'BITBUCKET_BOOKMARK' => null,
101
            'BITBUCKET_BRANCH' => null,
102 20
            'BITBUCKET_BUILD_NUMBER' => '0',
103 20
            'BITBUCKET_COMMIT' => '0000000000000000000000000000000000000000',
104 20
            'BITBUCKET_REPO_OWNER' => '' . Lib::r($inherit['USER'], 'nobody'),
105 20
            'BITBUCKET_REPO_SLUG' => 'local-has-no-slug',
106
            'BITBUCKET_TAG' => null,
107 20
            'CI' => 'true',
108
            'PIPELINES_CONTAINER_NAME' => null,
109
            'PIPELINES_IDS' => null,
110
            'PIPELINES_PARENT_CONTAINER_NAME' => null,
111
            'PIPELINES_PIP_CONTAINER_NAME' => null,
112
            'PIPELINES_PROJECT_PATH' => null,
113
        );
114
115
        $invariant = array(
116 20
            'PIPELINES_ID' => null,
117
        );
118
119 20
        foreach ($inheritable as $name => $value) {
120 20
            isset($inherit[$name]) ? $inheritable[$name] = $inherit[$name] : null;
121
        }
122
123 20
        $var = $invariant + $inheritable;
124 20
        ksort($var);
125
126 20
        $this->vars = $var;
127 20
    }
128
129
    /**
130
     * Map reference to environment variable setting
131
     *
132
     * Only add the BITBUCKET_BOOKMARK/_BRANCH/_TAG variable
133
     * if not yet set.
134
     *
135
     * @param Reference $ref
136
     */
137 4
    public function addReference(Reference $ref)
138
    {
139 4
        if (null === $type = $ref->getType()) {
140 2
            return;
141
        }
142
143
        $map = array(
144 4
            'bookmark' => 'BITBUCKET_BOOKMARK',
145
            'branch' => 'BITBUCKET_BRANCH',
146
            'tag' => 'BITBUCKET_TAG',
147
            'pr' => 'BITBUCKET_BRANCH',
148
        );
149
150 4
        if (!isset($map[$type])) {
151 1
            throw new \UnexpectedValueException(sprintf('Unknown reference type: "%s"', $type));
152
        }
153 3
        $var = $map[$type];
154
155 3
        if (!isset($this->vars[$var])) {
156 2
            $this->vars[$var] = $ref->getName();
157
        }
158 3
    }
159
160
    /**
161
     * @param string $name of container
162
     */
163 2
    public function setContainerName($name)
164
    {
165 2
        if (isset($this->vars['PIPELINES_CONTAINER_NAME'])) {
166 2
            $this->vars['PIPELINES_PARENT_CONTAINER_NAME']
167 2
                = $this->vars['PIPELINES_CONTAINER_NAME'];
168
        }
169
170 2
        $this->vars['PIPELINES_CONTAINER_NAME'] = $name;
171 2
        $this->setFirstPipelineVariable('PIPELINES_PIP_CONTAINER_NAME', $name);
172 2
    }
173
174
    /**
175
     * set the pipelines environment's running pipeline id
176
     *
177
     * @param string $id of pipeline, e.g. "default" or "branch/feature/*"
178
     *
179
     * @return bool whether was used before (endless pipelines in pipelines loop)
180
     */
181 2
    public function setPipelinesId($id)
182
    {
183 2
        $list = (string)$this->getValue('PIPELINES_IDS');
184 2
        $hashes = preg_split('~\s+~', $list, -1, PREG_SPLIT_NO_EMPTY);
185 2
        $hashes = array_map('strtolower', /** @scrutinizer ignore-type */ $hashes);
186
187 2
        $idHash = md5($id);
188 2
        $hasId = in_array($idHash, $hashes, true);
189 2
        $hashes[] = $idHash;
190
191 2
        $this->vars['PIPELINES_ID'] = $id;
192 2
        $this->vars['PIPELINES_IDS'] = implode(' ', $hashes);
193
194 2
        return $hasId;
195
    }
196
197
    /**
198
     * set PIPELINES_PROJECT_PATH
199
     *
200
     * can never be overwritten, must be set by pipelines itself for the
201
     * initial pipeline. will be taken over into each sub-pipeline.
202
     *
203
     * @param string $path absolute path to the project directory (deploy source path)
204
     */
205 1
    public function setPipelinesProjectPath($path)
206
    {
207
        // TODO $path must be absolute
208 1
        $this->setFirstPipelineVariable('PIPELINES_PROJECT_PATH', $path);
209 1
    }
210
211
    /**
212
     * @param string $option "-e" typically for Docker binary
213
     *
214
     * @return array of options (from $option) and values, ['-e', 'val1', '-e', 'val2', ...]
215
     */
216 12
    public function getArgs($option)
217
    {
218 12
        $args = Lib::merge(
219 12
            $this->collected,
220 12
            self::createArgVarDefinitions($option, $this->vars)
221
        );
222
223 12
        return $args;
224
    }
225
226
    /**
227
     * get a variables' value from the inherited
228
     * environment or null if not set
229
     *
230
     * @param $name
231
     *
232
     * @return null|string
233
     */
234 1
    public function getInheritValue($name)
235
    {
236 1
        return isset($this->inherit[$name])
237 1
            ? $this->inherit[$name]
238 1
            : null;
239
    }
240
241
    /**
242
     * get a variables value or null if not set
243
     *
244
     * @param string $name
245
     *
246
     * @return null|string
247
     */
248 6
    public function getValue($name)
249
    {
250 6
        return isset($this->vars[$name])
251 5
            ? $this->vars[$name]
252 6
            : null;
253
    }
254
255
    /**
256
     * collect option arguments
257
     *
258
     * those options to be passed to docker client, normally -e,
259
     * --env and --env-file.
260
     *
261
     * @param Args $args
262
     * @param string|string[] $option
263
     *
264
     * @throws \InvalidArgumentException
265
     * @throws \Ktomk\Pipelines\Cli\ArgsException
266
     */
267 1
    public function collect(Args $args, $option)
268
    {
269 1
        $collector = new Collector($args);
270 1
        $collector->collect($option);
271 1
        $this->collected = array_merge($this->collected, $collector->getArgs());
272
273 1
        $this->getResolver()->addArguments($collector);
274 1
    }
275
276
    /**
277
     * @param array $paths
278
     *
279
     * @throws \InvalidArgumentException
280
     */
281 2
    public function collectFiles(array $paths)
282
    {
283 2
        $resolver = $this->getResolver();
284 2
        foreach ($paths as $path) {
285 2
            if ($resolver->addFileIfExists($path)) {
286 2
                $this->collected[] = '--env-file';
287 2
                $this->collected[] = $path;
288
            }
289
        }
290 2
    }
291
292
    /**
293
     * @return EnvResolver
294
     */
295 4
    public function getResolver()
296
    {
297 4
        if (null === $this->resolver) {
298 4
            $this->resolver = new EnvResolver($this->inherit);
299
        }
300
301 4
        return $this->resolver;
302
    }
303
304
    /**
305
     * set am environment variable only if not yet set and in the first
306
     * pipeline.
307
     *
308
     * @param string $name
309
     * @param string $value
310
     */
311 3
    private function setFirstPipelineVariable($name, $value)
312
    {
313 3
        if (isset($this->vars[$name])
314 3
            || !isset($this->vars['PIPELINES_ID'], $this->vars['PIPELINES_IDS'])
315 1
            || $this->vars['PIPELINES_IDS'] !== md5($this->vars['PIPELINES_ID'])
316
        ) {
317 3
            return;
318
        }
319
320 1
        $this->vars[$name] = $value;
321 1
    }
322
}
323