chore: Cleanup DependencyAnalyzer and InfoParser

Also fix support for database dependency with attributes in the info.xml

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
This commit is contained in:
Côme Chilliet 2025-06-17 10:57:42 +02:00
parent b1e58ba1b7
commit fb4e580109
No known key found for this signature in database
GPG key ID: A3E2F658B28C760A
2 changed files with 41 additions and 102 deletions

View file

@ -1,22 +1,18 @@
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016-2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
namespace OC\App;
use OCP\IL10N;
class DependencyAnalyzer {
/** @var array */
private $appInfo;
/**
* @param Platform $platform
* @param \OCP\IL10N $l
*/
public function __construct(
private Platform $platform,
private IL10N $l,
@ -24,11 +20,9 @@ class DependencyAnalyzer {
}
/**
* @param array $app
* @returns array of missing dependencies
* @return array of missing dependencies
*/
public function analyze(array $app, bool $ignoreMax = false) {
$this->appInfo = $app;
public function analyze(array $app, bool $ignoreMax = false): array {
if (isset($app['dependencies'])) {
$dependencies = $app['dependencies'];
} else {
@ -64,12 +58,10 @@ class DependencyAnalyzer {
* Truncates both versions to the lowest common version, e.g.
* 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1,
* 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1
* @param string $first
* @param string $second
* @return string[] first element is the first version, second element is the
* second version
*/
private function normalizeVersions($first, $second) {
private function normalizeVersions(string $first, string $second): array {
$first = explode('.', $first);
$second = explode('.', $second);
@ -84,47 +76,31 @@ class DependencyAnalyzer {
/**
* Parameters will be normalized and then passed into version_compare
* in the same order they are specified in the method header
* @param string $first
* @param string $second
* @param string $operator
* @return bool result similar to version_compare
*/
private function compare($first, $second, $operator) {
// we can't normalize versions if one of the given parameters is not a
// version string but null. In case one parameter is null normalization
// will therefore be skipped
if ($first !== null && $second !== null) {
[$first, $second] = $this->normalizeVersions($first, $second);
}
private function compare(string $first, string $second, string $operator): bool {
[$first, $second] = $this->normalizeVersions($first, $second);
return version_compare($first, $second, $operator);
}
/**
* Checks if a version is bigger than another version
* @param string $first
* @param string $second
* @return bool true if the first version is bigger than the second
*/
private function compareBigger($first, $second) {
private function compareBigger(string $first, string $second): bool {
return $this->compare($first, $second, '>');
}
/**
* Checks if a version is smaller than another version
* @param string $first
* @param string $second
* @return bool true if the first version is smaller than the second
*/
private function compareSmaller($first, $second) {
private function compareSmaller(string $first, string $second): bool {
return $this->compare($first, $second, '<');
}
/**
* @param array $dependencies
* @return array
*/
private function analyzePhpVersion(array $dependencies) {
private function analyzePhpVersion(array $dependencies): array {
$missing = [];
if (isset($dependencies['php']['@attributes']['min-version'])) {
$minVersion = $dependencies['php']['@attributes']['min-version'];
@ -147,7 +123,7 @@ class DependencyAnalyzer {
return $missing;
}
private function analyzeArchitecture(array $dependencies) {
private function analyzeArchitecture(array $dependencies): array {
$missing = [];
if (!isset($dependencies['architecture'])) {
return $missing;
@ -170,11 +146,7 @@ class DependencyAnalyzer {
return $missing;
}
/**
* @param array $dependencies
* @return array
*/
private function analyzeDatabases(array $dependencies) {
private function analyzeDatabases(array $dependencies): array {
$missing = [];
if (!isset($dependencies['database'])) {
return $missing;
@ -187,6 +159,9 @@ class DependencyAnalyzer {
if (!is_array($supportedDatabases)) {
$supportedDatabases = [$supportedDatabases];
}
if (isset($supportedDatabases['@value'])) {
$supportedDatabases = [$supportedDatabases];
}
$supportedDatabases = array_map(function ($db) {
return $this->getValue($db);
}, $supportedDatabases);
@ -197,11 +172,7 @@ class DependencyAnalyzer {
return $missing;
}
/**
* @param array $dependencies
* @return array
*/
private function analyzeCommands(array $dependencies) {
private function analyzeCommands(array $dependencies): array {
$missing = [];
if (!isset($dependencies['command'])) {
return $missing;
@ -227,11 +198,7 @@ class DependencyAnalyzer {
return $missing;
}
/**
* @param array $dependencies
* @return array
*/
private function analyzeLibraries(array $dependencies) {
private function analyzeLibraries(array $dependencies): array {
$missing = [];
if (!isset($dependencies['lib'])) {
return $missing;
@ -272,11 +239,7 @@ class DependencyAnalyzer {
return $missing;
}
/**
* @param array $dependencies
* @return array
*/
private function analyzeOS(array $dependencies) {
private function analyzeOS(array $dependencies): array {
$missing = [];
if (!isset($dependencies['os'])) {
return $missing;
@ -300,12 +263,7 @@ class DependencyAnalyzer {
return $missing;
}
/**
* @param array $dependencies
* @param array $appInfo
* @return array
*/
private function analyzeOC(array $dependencies, array $appInfo, bool $ignoreMax) {
private function analyzeOC(array $dependencies, array $appInfo, bool $ignoreMax): array {
$missing = [];
$minVersion = null;
if (isset($dependencies['nextcloud']['@attributes']['min-version'])) {
@ -321,12 +279,12 @@ class DependencyAnalyzer {
if (!is_null($minVersion)) {
if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) {
$missing[] = $this->l->t('Server version %s or higher is required.', [$this->toVisibleVersion($minVersion)]);
$missing[] = $this->l->t('Server version %s or higher is required.', [$minVersion]);
}
}
if (!$ignoreMax && !is_null($maxVersion)) {
if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) {
$missing[] = $this->l->t('Server version %s or lower is required.', [$this->toVisibleVersion($maxVersion)]);
$missing[] = $this->l->t('Server version %s or lower is required.', [$maxVersion]);
}
}
return $missing;
@ -347,25 +305,7 @@ class DependencyAnalyzer {
}
/**
* Map the internal version number to the Nextcloud version
*
* @param string $version
* @return string
*/
protected function toVisibleVersion($version) {
switch ($version) {
case '9.1':
return '10';
default:
if (str_starts_with($version, '9.1.')) {
$version = '10.0.' . substr($version, 4);
}
return $version;
}
}
/**
* @param $element
* @param mixed $element
* @return mixed
*/
private function getValue($element) {

View file

@ -44,7 +44,7 @@ class InfoParser {
}
$array = $this->xmlToArray($xml);
if (is_null($array)) {
if (is_string($array)) {
return null;
}
@ -208,11 +208,7 @@ class InfoParser {
return $array;
}
/**
* @param $data
* @return bool
*/
private function isNavigationItem($data): bool {
private function isNavigationItem(array $data): bool {
// Allow settings navigation items with no route entry
$type = $data['type'] ?? 'link';
if ($type === 'settings') {
@ -221,17 +217,17 @@ class InfoParser {
return isset($data['name'], $data['route']);
}
/**
* @param \SimpleXMLElement $xml
* @return array
*/
public function xmlToArray($xml) {
if (!$xml->children()) {
public function xmlToArray(\SimpleXMLElement $xml): array|string {
$children = $xml->children();
if ($children === null) {
return (string)$xml;
}
$array = [];
foreach ($xml->children() as $element => $node) {
foreach ($children as $element => $node) {
if ($element === null) {
throw new \InvalidArgumentException('xml contains a null element');
}
$totalElement = count($xml->{$element});
if (!isset($array[$element])) {
@ -243,15 +239,18 @@ class InfoParser {
$data = [
'@attributes' => [],
];
if (!count($node->children())) {
$value = (string)$node;
if (!empty($value)) {
$data['@value'] = $value;
$converted = $this->xmlToArray($node);
if (is_string($converted)) {
if (!empty($converted)) {
$data['@value'] = $converted;
}
} else {
$data = array_merge($data, $this->xmlToArray($node));
$data = array_merge($data, $converted);
}
foreach ($attributes as $attr => $value) {
if ($attr === null) {
throw new \InvalidArgumentException('xml contains a null element');
}
$data['@attributes'][$attr] = (string)$value;
}