PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/private/App/DependencyAnalyzer.php

https://gitlab.com/wuhang2003/core
PHP | 319 lines | 196 code | 27 blank | 96 comment | 37 complexity | 433c8b8692246d5b7996ac2d9dd2348d MD5 | raw file
  1. <?php
  2. /**
  3. * @author Bernhard Posselt <dev@bernhard-posselt.com>
  4. * @author Joas Schilling <nickvergessen@owncloud.com>
  5. * @author Lukas Reschke <lukas@owncloud.com>
  6. * @author Morris Jobke <hey@morrisjobke.de>
  7. * @author Thomas Müller <thomas.mueller@tmit.eu>
  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. namespace OC\App;
  26. use OCP\IL10N;
  27. class DependencyAnalyzer {
  28. /** @var Platform */
  29. private $platform;
  30. /** @var \OCP\IL10N */
  31. private $l;
  32. /** @var array */
  33. private $appInfo;
  34. /**
  35. * @param Platform $platform
  36. * @param \OCP\IL10N $l
  37. */
  38. function __construct(Platform $platform, IL10N $l) {
  39. $this->platform = $platform;
  40. $this->l = $l;
  41. }
  42. /**
  43. * @param array $app
  44. * @returns array of missing dependencies
  45. */
  46. public function analyze(array $app) {
  47. $this->appInfo = $app;
  48. if (isset($app['dependencies'])) {
  49. $dependencies = $app['dependencies'];
  50. } else {
  51. $dependencies = [];
  52. }
  53. return array_merge(
  54. $this->analyzePhpVersion($dependencies),
  55. $this->analyzeDatabases($dependencies),
  56. $this->analyzeCommands($dependencies),
  57. $this->analyzeLibraries($dependencies),
  58. $this->analyzeOS($dependencies),
  59. $this->analyzeOC($dependencies, $app)
  60. );
  61. }
  62. /**
  63. * Truncates both versions to the lowest common version, e.g.
  64. * 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1,
  65. * 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1
  66. * @param string $first
  67. * @param string $second
  68. * @return string[] first element is the first version, second element is the
  69. * second version
  70. */
  71. private function normalizeVersions($first, $second) {
  72. $first = explode('.', $first);
  73. $second = explode('.', $second);
  74. // get both arrays to the same minimum size
  75. $length = min(count($second), count($first));
  76. $first = array_slice($first, 0, $length);
  77. $second = array_slice($second, 0, $length);
  78. return [implode('.', $first), implode('.', $second)];
  79. }
  80. /**
  81. * Parameters will be normalized and then passed into version_compare
  82. * in the same order they are specified in the method header
  83. * @param string $first
  84. * @param string $second
  85. * @param string $operator
  86. * @return bool result similar to version_compare
  87. */
  88. private function compare($first, $second, $operator) {
  89. // we can't normalize versions if one of the given parameters is not a
  90. // version string but null. In case one parameter is null normalization
  91. // will therefore be skipped
  92. if ($first !== null && $second !== null) {
  93. list($first, $second) = $this->normalizeVersions($first, $second);
  94. }
  95. return version_compare($first, $second, $operator);
  96. }
  97. /**
  98. * Checks if a version is bigger than another version
  99. * @param string $first
  100. * @param string $second
  101. * @return bool true if the first version is bigger than the second
  102. */
  103. private function compareBigger($first, $second) {
  104. return $this->compare($first, $second, '>');
  105. }
  106. /**
  107. * Checks if a version is smaller than another version
  108. * @param string $first
  109. * @param string $second
  110. * @return bool true if the first version is smaller than the second
  111. */
  112. private function compareSmaller($first, $second) {
  113. return $this->compare($first, $second, '<');
  114. }
  115. /**
  116. * @param array $dependencies
  117. * @return array
  118. */
  119. private function analyzePhpVersion(array $dependencies) {
  120. $missing = [];
  121. if (isset($dependencies['php']['@attributes']['min-version'])) {
  122. $minVersion = $dependencies['php']['@attributes']['min-version'];
  123. if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) {
  124. $missing[] = (string)$this->l->t('PHP %s or higher is required.', $minVersion);
  125. }
  126. }
  127. if (isset($dependencies['php']['@attributes']['max-version'])) {
  128. $maxVersion = $dependencies['php']['@attributes']['max-version'];
  129. if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) {
  130. $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', $maxVersion);
  131. }
  132. }
  133. return $missing;
  134. }
  135. /**
  136. * @param array $dependencies
  137. * @return array
  138. */
  139. private function analyzeDatabases(array $dependencies) {
  140. $missing = [];
  141. if (!isset($dependencies['database'])) {
  142. return $missing;
  143. }
  144. $supportedDatabases = $dependencies['database'];
  145. if (empty($supportedDatabases)) {
  146. return $missing;
  147. }
  148. if (!is_array($supportedDatabases)) {
  149. $supportedDatabases = array($supportedDatabases);
  150. }
  151. $supportedDatabases = array_map(function ($db) {
  152. return $this->getValue($db);
  153. }, $supportedDatabases);
  154. $currentDatabase = $this->platform->getDatabase();
  155. if (!in_array($currentDatabase, $supportedDatabases)) {
  156. $missing[] = (string)$this->l->t('Following databases are supported: %s', join(', ', $supportedDatabases));
  157. }
  158. return $missing;
  159. }
  160. /**
  161. * @param array $dependencies
  162. * @return array
  163. */
  164. private function analyzeCommands(array $dependencies) {
  165. $missing = [];
  166. if (!isset($dependencies['command'])) {
  167. return $missing;
  168. }
  169. $commands = $dependencies['command'];
  170. if (!is_array($commands)) {
  171. $commands = array($commands);
  172. }
  173. $os = $this->platform->getOS();
  174. foreach ($commands as $command) {
  175. if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) {
  176. continue;
  177. }
  178. $commandName = $this->getValue($command);
  179. if (!$this->platform->isCommandKnown($commandName)) {
  180. $missing[] = (string)$this->l->t('The command line tool %s could not be found', $commandName);
  181. }
  182. }
  183. return $missing;
  184. }
  185. /**
  186. * @param array $dependencies
  187. * @return array
  188. */
  189. private function analyzeLibraries(array $dependencies) {
  190. $missing = [];
  191. if (!isset($dependencies['lib'])) {
  192. return $missing;
  193. }
  194. $libs = $dependencies['lib'];
  195. if (!is_array($libs)) {
  196. $libs = array($libs);
  197. }
  198. foreach ($libs as $lib) {
  199. $libName = $this->getValue($lib);
  200. $libVersion = $this->platform->getLibraryVersion($libName);
  201. if (is_null($libVersion)) {
  202. $missing[] = (string)$this->l->t('The library %s is not available.', $libName);
  203. continue;
  204. }
  205. if (is_array($lib)) {
  206. if (isset($lib['@attributes']['min-version'])) {
  207. $minVersion = $lib['@attributes']['min-version'];
  208. if ($this->compareSmaller($libVersion, $minVersion)) {
  209. $missing[] = (string)$this->l->t('Library %s with a version higher than %s is required - available version %s.',
  210. array($libName, $minVersion, $libVersion));
  211. }
  212. }
  213. if (isset($lib['@attributes']['max-version'])) {
  214. $maxVersion = $lib['@attributes']['max-version'];
  215. if ($this->compareBigger($libVersion, $maxVersion)) {
  216. $missing[] = (string)$this->l->t('Library %s with a version lower than %s is required - available version %s.',
  217. array($libName, $maxVersion, $libVersion));
  218. }
  219. }
  220. }
  221. }
  222. return $missing;
  223. }
  224. /**
  225. * @param array $dependencies
  226. * @return array
  227. */
  228. private function analyzeOS(array $dependencies) {
  229. $missing = [];
  230. if (!isset($dependencies['os'])) {
  231. return $missing;
  232. }
  233. $oss = $dependencies['os'];
  234. if (empty($oss)) {
  235. return $missing;
  236. }
  237. if (is_array($oss)) {
  238. $oss = array_map(function ($os) {
  239. return $this->getValue($os);
  240. }, $oss);
  241. } else {
  242. $oss = array($oss);
  243. }
  244. $currentOS = $this->platform->getOS();
  245. if (!in_array($currentOS, $oss)) {
  246. $missing[] = (string)$this->l->t('Following platforms are supported: %s', join(', ', $oss));
  247. }
  248. return $missing;
  249. }
  250. /**
  251. * @param array $dependencies
  252. * @param array $appInfo
  253. * @return array
  254. */
  255. private function analyzeOC(array $dependencies, array $appInfo) {
  256. $missing = [];
  257. $minVersion = null;
  258. if (isset($dependencies['owncloud']['@attributes']['min-version'])) {
  259. $minVersion = $dependencies['owncloud']['@attributes']['min-version'];
  260. } elseif (isset($appInfo['requiremin'])) {
  261. $minVersion = $appInfo['requiremin'];
  262. } elseif (isset($appInfo['require'])) {
  263. $minVersion = $appInfo['require'];
  264. }
  265. $maxVersion = null;
  266. if (isset($dependencies['owncloud']['@attributes']['max-version'])) {
  267. $maxVersion = $dependencies['owncloud']['@attributes']['max-version'];
  268. } elseif (isset($appInfo['requiremax'])) {
  269. $maxVersion = $appInfo['requiremax'];
  270. }
  271. if (!is_null($minVersion)) {
  272. if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) {
  273. $missing[] = (string)$this->l->t('ownCloud %s or higher is required.', $minVersion);
  274. }
  275. }
  276. if (!is_null($maxVersion)) {
  277. if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) {
  278. $missing[] = (string)$this->l->t('ownCloud %s or lower is required.', $maxVersion);
  279. }
  280. }
  281. return $missing;
  282. }
  283. /**
  284. * @param $element
  285. * @return mixed
  286. */
  287. private function getValue($element) {
  288. if (isset($element['@value']))
  289. return $element['@value'];
  290. return (string)$element;
  291. }
  292. }