Completed
Push — master ( 1f63e8...5f9700 )
by Lukas
13:32
created

DependencyAnalyzer::analyzePhpVersion()   C

Complexity

Conditions 7
Paths 27

Size

Total Lines 22
Code Lines 15

Duplication

Lines 12
Ratio 54.55 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 12
loc 22
rs 6.9811
cc 7
eloc 15
nc 27
nop 1
1
<?php
2
/**
3
 * @author Bernhard Posselt <[email protected]>
4
 * @author Joas Schilling <[email protected]>
5
 * @author Lukas Reschke <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Thomas Müller <[email protected]>
8
 *
9
 * @copyright Copyright (c) 2016, ownCloud, Inc.
10
 * @license AGPL-3.0
11
 *
12
 * This code is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU Affero General Public License, version 3,
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License, version 3,
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
23
 *
24
 */
25
26
namespace OC\App;
27
28
use OCP\IL10N;
29
30
class DependencyAnalyzer {
31
32
	/** @var Platform */
33
	private $platform;
34
	/** @var \OCP\IL10N */
35
	private $l;
36
	/** @var array */
37
	private $appInfo;
38
39
	/**
40
	 * @param Platform $platform
41
	 * @param \OCP\IL10N $l
42
	 */
43
	function __construct(Platform $platform, IL10N $l) {
44
		$this->platform = $platform;
45
		$this->l = $l;
46
	}
47
48
	/**
49
	 * @param array $app
50
	 * @returns array of missing dependencies
51
	 */
52
	public function analyze(array $app) {
53
		$this->appInfo = $app;
54
		if (isset($app['dependencies'])) {
55
			$dependencies = $app['dependencies'];
56
		} else {
57
			$dependencies = [];
58
		}
59
60
		return array_merge(
61
			$this->analyzePhpVersion($dependencies),
62
			$this->analyzeDatabases($dependencies),
63
			$this->analyzeCommands($dependencies),
64
			$this->analyzeLibraries($dependencies),
65
			$this->analyzeOS($dependencies),
66
			$this->analyzeOC($dependencies, $app)
67
		);
68
	}
69
70
	/**
71
	 * Truncates both versions to the lowest common version, e.g.
72
	 * 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1,
73
	 * 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1
74
	 * @param string $first
75
	 * @param string $second
76
	 * @return string[] first element is the first version, second element is the
77
	 * second version
78
	 */
79
	private function normalizeVersions($first, $second) {
80
		$first = explode('.', $first);
81
		$second = explode('.', $second);
82
83
		// get both arrays to the same minimum size
84
		$length = min(count($second), count($first));
85
		$first = array_slice($first, 0, $length);
86
		$second = array_slice($second, 0, $length);
87
88
		return [implode('.', $first), implode('.', $second)];
89
	}
90
91
	/**
92
	 * Parameters will be normalized and then passed into version_compare
93
	 * in the same order they are specified in the method header
94
	 * @param string $first
95
	 * @param string $second
96
	 * @param string $operator
97
	 * @return bool result similar to version_compare
98
	 */
99
	private function compare($first, $second, $operator) {
100
		// we can't normalize versions if one of the given parameters is not a
101
		// version string but null. In case one parameter is null normalization
102
		// will therefore be skipped
103
		if ($first !== null && $second !== null) {
104
			list($first, $second) = $this->normalizeVersions($first, $second);
105
		}
106
107
		return version_compare($first, $second, $operator);
108
	}
109
110
	/**
111
	 * Checks if a version is bigger than another version
112
	 * @param string $first
113
	 * @param string $second
114
	 * @return bool true if the first version is bigger than the second
115
	 */
116
	private function compareBigger($first, $second) {
117
		return $this->compare($first, $second, '>');
118
	}
119
120
	/**
121
	 * Checks if a version is smaller than another version
122
	 * @param string $first
123
	 * @param string $second
124
	 * @return bool true if the first version is smaller than the second
125
	 */
126
	private function compareSmaller($first, $second) {
127
		return $this->compare($first, $second, '<');
128
	}
129
130
	/**
131
	 * @param array $dependencies
132
	 * @return array
133
	 */
134
	private function analyzePhpVersion(array $dependencies) {
135
		$missing = [];
136 View Code Duplication
		if (isset($dependencies['php']['@attributes']['min-version'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
137
			$minVersion = $dependencies['php']['@attributes']['min-version'];
138
			if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) {
139
				$missing[] = (string)$this->l->t('PHP %s or higher is required.', $minVersion);
140
			}
141
		}
142 View Code Duplication
		if (isset($dependencies['php']['@attributes']['max-version'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
143
			$maxVersion = $dependencies['php']['@attributes']['max-version'];
144
			if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) {
145
				$missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', $maxVersion);
146
			}
147
		}
148
		if (isset($dependencies['php']['@attributes']['min-int-size'])) {
149
			$intSize = $dependencies['php']['@attributes']['min-int-size'];
150
			if ($intSize > $this->platform->getIntSize()*8) {
151
				$missing[] = (string)$this->l->t('%sbit or higher PHP required.', $intSize);
152
			}
153
		}
154
		return $missing;
155
	}
156
157
	/**
158
	 * @param array $dependencies
159
	 * @return array
160
	 */
161 View Code Duplication
	private function analyzeDatabases(array $dependencies) {
162
		$missing = [];
163
		if (!isset($dependencies['database'])) {
164
			return $missing;
165
		}
166
167
		$supportedDatabases = $dependencies['database'];
168
		if (empty($supportedDatabases)) {
169
			return $missing;
170
		}
171
		if (!is_array($supportedDatabases)) {
172
			$supportedDatabases = array($supportedDatabases);
173
		}
174
		$supportedDatabases = array_map(function ($db) {
175
			return $this->getValue($db);
176
		}, $supportedDatabases);
177
		$currentDatabase = $this->platform->getDatabase();
178
		if (!in_array($currentDatabase, $supportedDatabases)) {
179
			$missing[] = (string)$this->l->t('Following databases are supported: %s', join(', ', $supportedDatabases));
180
		}
181
		return $missing;
182
	}
183
184
	/**
185
	 * @param array $dependencies
186
	 * @return array
187
	 */
188
	private function analyzeCommands(array $dependencies) {
189
		$missing = [];
190
		if (!isset($dependencies['command'])) {
191
			return $missing;
192
		}
193
194
		$commands = $dependencies['command'];
195
		if (!is_array($commands)) {
196
			$commands = array($commands);
197
		}
198
		$os = $this->platform->getOS();
199
		foreach ($commands as $command) {
200
			if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) {
201
				continue;
202
			}
203
			$commandName = $this->getValue($command);
204
			if (!$this->platform->isCommandKnown($commandName)) {
205
				$missing[] = (string)$this->l->t('The command line tool %s could not be found', $commandName);
206
			}
207
		}
208
		return $missing;
209
	}
210
211
	/**
212
	 * @param array $dependencies
213
	 * @return array
214
	 */
215
	private function analyzeLibraries(array $dependencies) {
216
		$missing = [];
217
		if (!isset($dependencies['lib'])) {
218
			return $missing;
219
		}
220
221
		$libs = $dependencies['lib'];
222
		if (!is_array($libs)) {
223
			$libs = array($libs);
224
		}
225
		foreach ($libs as $lib) {
226
			$libName = $this->getValue($lib);
227
			$libVersion = $this->platform->getLibraryVersion($libName);
228
			if (is_null($libVersion)) {
229
				$missing[] = (string)$this->l->t('The library %s is not available.', $libName);
230
				continue;
231
			}
232
233
			if (is_array($lib)) {
234 View Code Duplication
				if (isset($lib['@attributes']['min-version'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
235
					$minVersion = $lib['@attributes']['min-version'];
236
					if ($this->compareSmaller($libVersion, $minVersion)) {
237
						$missing[] = (string)$this->l->t('Library %s with a version higher than %s is required - available version %s.',
238
							array($libName, $minVersion, $libVersion));
239
					}
240
				}
241 View Code Duplication
				if (isset($lib['@attributes']['max-version'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
242
					$maxVersion = $lib['@attributes']['max-version'];
243
					if ($this->compareBigger($libVersion, $maxVersion)) {
244
						$missing[] = (string)$this->l->t('Library %s with a version lower than %s is required - available version %s.',
245
							array($libName, $maxVersion, $libVersion));
246
					}
247
				}
248
			}
249
		}
250
		return $missing;
251
	}
252
253
	/**
254
	 * @param array $dependencies
255
	 * @return array
256
	 */
257 View Code Duplication
	private function analyzeOS(array $dependencies) {
258
		$missing = [];
259
		if (!isset($dependencies['os'])) {
260
			return $missing;
261
		}
262
263
		$oss = $dependencies['os'];
264
		if (empty($oss)) {
265
			return $missing;
266
		}
267
		if (is_array($oss)) {
268
			$oss = array_map(function ($os) {
269
				return $this->getValue($os);
270
			}, $oss);
271
		} else {
272
			$oss = array($oss);
273
		}
274
		$currentOS = $this->platform->getOS();
275
		if (!in_array($currentOS, $oss)) {
276
			$missing[] = (string)$this->l->t('Following platforms are supported: %s', join(', ', $oss));
277
		}
278
		return $missing;
279
	}
280
281
	/**
282
	 * @param array $dependencies
283
	 * @param array $appInfo
284
	 * @return array
285
	 */
286
	private function analyzeOC(array $dependencies, array $appInfo) {
287
		$missing = [];
288
		$minVersion = null;
289
		if (isset($dependencies['owncloud']['@attributes']['min-version'])) {
290
			$minVersion = $dependencies['owncloud']['@attributes']['min-version'];
291
		} elseif (isset($appInfo['requiremin'])) {
292
			$minVersion = $appInfo['requiremin'];
293
		} elseif (isset($appInfo['require'])) {
294
			$minVersion = $appInfo['require'];
295
		}
296
		$maxVersion = null;
297
		if (isset($dependencies['owncloud']['@attributes']['max-version'])) {
298
			$maxVersion = $dependencies['owncloud']['@attributes']['max-version'];
299
		} elseif (isset($appInfo['requiremax'])) {
300
			$maxVersion = $appInfo['requiremax'];
301
		}
302
303
		if (!is_null($minVersion)) {
304
			if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) {
305
				$missing[] = (string)$this->l->t('ownCloud %s or higher is required.', $minVersion);
306
			}
307
		}
308
		if (!is_null($maxVersion)) {
309
			if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) {
310
				$missing[] = (string)$this->l->t('ownCloud %s or lower is required.', $maxVersion);
311
			}
312
		}
313
		return $missing;
314
	}
315
316
	/**
317
	 * @param $element
318
	 * @return mixed
319
	 */
320
	private function getValue($element) {
321
		if (isset($element['@value']))
322
			return $element['@value'];
323
		return (string)$element;
324
	}
325
}
326