Passed
Push — test ( 7d3b45...f494b8 )
by Tom
03:36
created

EnvResolver::addLines()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Runner;
6
7
use InvalidArgumentException;
8
use Ktomk\Pipelines\Cli\Args\Args;
9
use Ktomk\Pipelines\Cli\Args\OptionFilterIterator;
10
use Ktomk\Pipelines\LibFs;
11
use Ktomk\Pipelines\Value\Env\EnvFile;
12
use Ktomk\Pipelines\Value\Env\EnvVar;
13
use UnexpectedValueException;
14
15
/**
16
 * resolve environment variables against docker --env & --env-file arguments
17
 *
18
 * some string values in the bitbucket-pipelines.yml file might need resolution
19
 * against a part of the current host environment but only if set for the
20
 * container as well (--env-file, -e, --env)
21
 *
22
 * @package Ktomk\Pipelines\Runner\Runner
23
 */
24
class EnvResolver
25
{
26
    /**
27
     * @var array host environment (that exports)
28
     */
29
    private $environment;
30
31
    /**
32
     * @var array container environment (partial w/o bitbucket environment)
33
     */
34
    private $variables;
35
36
    /**
37
     * EnvResolver constructor.
38
     *
39
     * @param array|string[] $environment host environment variables (name => string)
40
     */
41 11
    public function __construct(array $environment)
42
    {
43 11
        $this->environment = array_filter($environment, 'is_string');
44
    }
45
46
    /**
47
     * resolve a string or an array of strings
48
     *
49
     * @param string|string[] $stringOrArray
50
     *
51
     * @throws UnexpectedValueException
52
     *
53
     * @return string|string[]
54
     *
55
     * @see resolveString
56
     */
57 1
    public function __invoke($stringOrArray)
58
    {
59
        // TODO(tk): provide full environment (string) on NULL parameter
60 1
        if (is_array($stringOrArray)) {
61 1
            return array_map(array($this, 'resolveString'), $stringOrArray);
62
        }
63
64 1
        return $this->resolveString($stringOrArray);
65
    }
66
67
    /**
68
     * @param Args $args
69
     *
70
     * @throws InvalidArgumentException
71
     *
72
     * @return void
73
     */
74 1
    public function addArguments(Args $args)
75
    {
76 1
        $files = new OptionFilterIterator($args, 'env-file');
77 1
        foreach ($files->getArguments() as $file) {
78 1
            $this->addFile($file);
79
        }
80
81 1
        $definitions = new OptionFilterIterator($args, array('e', 'env'));
82 1
        foreach ($definitions->getArguments() as $definition) {
83 1
            $this->addDefinition($definition);
84
        }
85
    }
86
87
    /**
88
     * add a file (--env-file option)
89
     *
90
     * @param string $path path to file
91
     *
92
     * @throws InvalidArgumentException
93
     *
94
     * @return void
95
     */
96 4
    public function addFile($path)
97
    {
98 4
        foreach (new EnvFile($path) as $var) {
99 3
            $this->addVar($var);
100
        }
101
    }
102
103
    /**
104
     * add a file but only if it exists (similar to --env-file option)
105
     *
106
     * @param string $file path to (potentially existing) file
107
     *
108
     * @throws InvalidArgumentException
109
     *
110
     * @return bool file was added
111
     */
112 2
    public function addFileIfExists($file)
113
    {
114 2
        if (!LibFs::isReadableFile($file)) {
115 1
            return false;
116
        }
117
118 1
        $this->addFile($file);
119
120 1
        return true;
121
    }
122
123
    /**
124
     * add a variable definition (-e, --env <definition>)
125
     *
126
     * @param string $definition variable definition, either name only or w/ equal sign
127
     *
128
     * @throws InvalidArgumentException
129
     *
130
     * @return void
131
     */
132 5
    public function addDefinition($definition)
133
    {
134 5
        $this->addVar(new EnvVar($definition));
135
    }
136
137
    /**
138
     * @param EnvVar $var
139
     *
140
     * @return void
141
     */
142 6
    public function addVar(EnvVar $var)
143
    {
144 6
        list($name, $value) = $var->getPair();
145
146 6
        if (null === $value && isset($this->environment[$name])) {
147 5
            $value = $this->environment[$name];
148
        }
149
150 6
        $this->variables[$name] = $value;
151
    }
152
153
    /**
154
     * get value of variable
155
     *
156
     * @param string $name of variable to obtain value from
157
     *
158
     * @return null|string value, null if unset
159
     */
160 8
    public function getValue($name)
161
    {
162 8
        return isset($this->variables[$name])
163 5
            ? $this->variables[$name]
164 8
            : null;
165
    }
166
167
    /**
168
     * @return array
169
     */
170 1
    public function getVariables()
171
    {
172 1
        return $this->variables;
173
    }
174
175
    /**
176
     * replace variable with its content if it is a portable, Shell and
177
     * Utilities variable name (see POSIX).
178
     *
179
     * zero-length string if the variable is undefined in the resolver
180
     * context.
181
     *
182
     * @param string $string
183
     *
184
     * @throws UnexpectedValueException
185
     *
186
     * @return string
187
     */
188 2
    public function resolveString($string)
189
    {
190 2
        $pattern = '~^\$([A-Z_]+[0-9A-Z_]*)$~';
191 2
        $result = preg_match($pattern, $string, $matches);
192 2
        if (false === $result) {
193
            throw new UnexpectedValueException('regex pattern error'); // @codeCoverageIgnore
194
        }
195
196 2
        if (0 === $result) {
197 2
            return $string;
198
        }
199
200 2
        list(, $name) = $matches;
201 2
        $value = $this->getValue($name);
202
203 2
        return (string)$value;
204
    }
205
}
206