-
Notifications
You must be signed in to change notification settings - Fork 98
Expand file tree
/
Copy pathAbstractProcessor.php
More file actions
227 lines (187 loc) · 7.16 KB
/
AbstractProcessor.php
File metadata and controls
227 lines (187 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<?php
namespace Incenteev\ParameterHandler\Processor;
use Composer\IO\IOInterface;
use Incenteev\ParameterHandler\Parser\ParseException;
use Incenteev\ParameterHandler\Parser\ParserInterface;
use Symfony\Component\Yaml\Inline;
abstract class AbstractProcessor
{
/**
* IO Interface of composer used for displaying messages and requesting input from user.
*
* @var IOInterface
*/
protected $io;
/**
* Parser.
*
* @var ParserInterface
*/
protected $parser;
/**
* Constructor.
*
* @param IOInterface $io Composer IO
* @param ParserInterface $parser Instance of parser for type YAML or JSON
*/
public function __construct(IOInterface $io, ParserInterface $parser)
{
$this->parser = $parser;
$this->io = $io;
}
/**
* Processes single operations for a passed parameter file configuration.
*
* @throws ParseException|\InvalidArgumentException|\RuntimeException
*/
public function processFile(array $config)
{
$config = $this->processConfig($config);
$realFile = $config['file'];
$parameterKey = $config['parameter-key'];
$exists = is_file($realFile);
$action = $exists ? 'Updating' : 'Creating';
$this->io->write(sprintf('<info>%s the "%s" file</info>', $action, $realFile));
// Find the expected params
$expectedValues = $this->parser->parse(file_get_contents($config['dist-file']));
if (!isset($expectedValues[$parameterKey])) {
throw new \InvalidArgumentException(sprintf('The top-level key %s is missing.', $parameterKey));
}
$expectedParams = (array) $expectedValues[$parameterKey];
// find the actual params
$actualValues = array_merge(
// Preserve other top-level keys than `$parameterKey` in the file
$expectedValues,
array($parameterKey => array())
);
if ($exists) {
$existingValues = $this->parser->parse(file_get_contents($realFile));
if ($existingValues === null) {
$existingValues = array();
}
if (!is_array($existingValues)) {
throw new \InvalidArgumentException(sprintf('The existing "%s" file does not contain an array', $realFile));
}
$actualValues = array_merge($actualValues, $existingValues);
}
$actualValues[$parameterKey] = $this->processParams($config, $expectedParams, (array) $actualValues[$parameterKey]);
if (!is_dir($dir = dirname($realFile)) && (!@mkdir($dir, 0755, true) && !is_dir($dir))) {
throw new \RuntimeException(
sprintf('Error while creating directory "%s". Check path and permissions.', $dir)
);
}
$this->writeFile($realFile, $actualValues);
}
/**
* @param array $config
*
* @return array
*
* @throws \InvalidArgumentException
*/
protected function processConfig(array $config)
{
if (empty($config['dist-file'])) {
$config['dist-file'] = $config['file'].'.dist';
}
if (!is_file($config['dist-file'])) {
throw new \InvalidArgumentException(sprintf('The dist file "%s" does not exist. Check your dist-file config or create it.', $config['dist-file']));
}
if (empty($config['parameter-key'])) {
$config['parameter-key'] = 'parameters';
}
return $config;
}
protected function processParams(array $config, array $expectedParams, array $actualParams)
{
// Grab values for parameters that were renamed
$renameMap = empty($config['rename-map']) ? array() : (array) $config['rename-map'];
$actualParams = array_replace($actualParams, $this->processRenamedValues($renameMap, $actualParams));
$keepOutdatedParams = false;
if (isset($config['keep-outdated'])) {
$keepOutdatedParams = (boolean) $config['keep-outdated'];
}
if (!$keepOutdatedParams) {
$actualParams = array_intersect_key($actualParams, $expectedParams);
}
$envMap = empty($config['env-map']) ? array() : (array) $config['env-map'];
// Add the params coming from the environment values
$actualParams = array_replace($actualParams, $this->getEnvValues($envMap));
return $this->getParams($expectedParams, $actualParams);
}
/**
* Parses environments variables by map and resolves correct types.
* As environment variables can only be strings, they are also parsed to allow specifying null, false,
* true or numbers easily.
*
* @param array $envMap Map used to map data from environment variable name to parameter name.
*
* @return array
*/
protected function getEnvValues(array $envMap)
{
$params = array();
foreach ($envMap as $param => $env) {
$value = getenv($env);
if ($value) {
$params[$param] = Inline::parse($value);
}
}
return $params;
}
private function processRenamedValues(array $renameMap, array $actualParams)
{
foreach ($renameMap as $param => $oldParam) {
if (array_key_exists($param, $actualParams)) {
continue;
}
if (!array_key_exists($oldParam, $actualParams)) {
continue;
}
$actualParams[$param] = $actualParams[$oldParam];
}
return $actualParams;
}
/**
* Returns the current set of parameters.
* If IO mode non interactive it simply sets the expected values, otherwise it asks user for defining missing
* parameters.
*
* @param array $expectedParams Parameters required
* @param array $actualParams Parameters defined already
*
* @return array Updated set of parameters
*
* @throws \RuntimeException
*/
private function getParams(array $expectedParams, array $actualParams)
{
// Simply use the expectedParams value as default for the missing params.
if (!$this->io->isInteractive()) {
return array_replace($expectedParams, $actualParams);
}
$isStarted = false;
foreach ($expectedParams as $key => $value) {
if (array_key_exists($key, $actualParams)) {
continue;
}
if (!$isStarted) {
$isStarted = true;
$this->io->write('<comment>Some parameters are missing. Please provide them.</comment>');
}
$default = Inline::dump($value);
$value = $this->io->ask(sprintf('<question>%s</question> (<comment>%s</comment>): ', $key, $default), $default);
$actualParams[$key] = Inline::parse($value);
}
return $actualParams;
}
/**
* Persists configuration.
*
* @param string $file Filename to persist configuration to.
* @param array $configuration Configuration to persist.
*
* @return bool TRUE after successful persisting the file, otherwise FALSE
*/
abstract protected function writeFile($file, array $configuration);
}