Skip to content

Commit f97495b

Browse files
committed
feat: add command to check files_external dependencies
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 2f1c74d commit f97495b

File tree

7 files changed

+93
-6
lines changed

7 files changed

+93
-6
lines changed

apps/files_external/appinfo/info.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ External storage can be configured using the GUI or at the command line. This se
5353
<command>OCA\Files_External\Command\Verify</command>
5454
<command>OCA\Files_External\Command\Notify</command>
5555
<command>OCA\Files_External\Command\Scan</command>
56+
<command>OCA\Files_External\Command\Dependencies</command>
5657
</commands>
5758

5859
<settings>

apps/files_external/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
'OCA\\Files_External\\Command\\Config' => $baseDir . '/../lib/Command/Config.php',
1515
'OCA\\Files_External\\Command\\Create' => $baseDir . '/../lib/Command/Create.php',
1616
'OCA\\Files_External\\Command\\Delete' => $baseDir . '/../lib/Command/Delete.php',
17+
'OCA\\Files_External\\Command\\Dependencies' => $baseDir . '/../lib/Command/Dependencies.php',
1718
'OCA\\Files_External\\Command\\Export' => $baseDir . '/../lib/Command/Export.php',
1819
'OCA\\Files_External\\Command\\Import' => $baseDir . '/../lib/Command/Import.php',
1920
'OCA\\Files_External\\Command\\ListCommand' => $baseDir . '/../lib/Command/ListCommand.php',

apps/files_external/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ComposerStaticInitFiles_External
2929
'OCA\\Files_External\\Command\\Config' => __DIR__ . '/..' . '/../lib/Command/Config.php',
3030
'OCA\\Files_External\\Command\\Create' => __DIR__ . '/..' . '/../lib/Command/Create.php',
3131
'OCA\\Files_External\\Command\\Delete' => __DIR__ . '/..' . '/../lib/Command/Delete.php',
32+
'OCA\\Files_External\\Command\\Dependencies' => __DIR__ . '/..' . '/../lib/Command/Dependencies.php',
3233
'OCA\\Files_External\\Command\\Export' => __DIR__ . '/..' . '/../lib/Command/Export.php',
3334
'OCA\\Files_External\\Command\\Import' => __DIR__ . '/..' . '/../lib/Command/Import.php',
3435
'OCA\\Files_External\\Command\\ListCommand' => __DIR__ . '/..' . '/../lib/Command/ListCommand.php',
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
/**
3+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
*/
6+
namespace OCA\Files_External\Command;
7+
8+
use OC\Core\Command\Base;
9+
use OCA\Files_External\Service\BackendService;
10+
use Symfony\Component\Console\Input\InputInterface;
11+
use Symfony\Component\Console\Output\OutputInterface;
12+
13+
class Dependencies extends Base {
14+
public function __construct(
15+
private readonly BackendService $backendService,
16+
) {
17+
parent::__construct();
18+
}
19+
20+
protected function configure(): void {
21+
$this
22+
->setName('files_external:dependencies')
23+
->setDescription('Show information about the backend dependencies');
24+
parent::configure();
25+
}
26+
27+
protected function execute(InputInterface $input, OutputInterface $output): int {
28+
$storageBackends = $this->backendService->getBackends();
29+
30+
$anyMissing = false;
31+
32+
foreach ($storageBackends as $backend) {
33+
if ($backend->getDeprecateTo() !== null) {
34+
continue;
35+
}
36+
$missingDependencies = $backend->checkDependencies();
37+
if ($missingDependencies) {
38+
$anyMissing = true;
39+
$output->writeln($backend->getText() . ':');
40+
foreach ($missingDependencies as $missingDependency) {
41+
if ($missingDependency->getMessage()) {
42+
$output->writeln(" - <comment>{$missingDependency->getDependency()}</comment>: {$missingDependency->getMessage()}");
43+
} else {
44+
$output->writeln(" - <comment>{$missingDependency->getDependency()}</comment>");
45+
}
46+
}
47+
}
48+
}
49+
50+
if (!$anyMissing) {
51+
$output->writeln('<info>All dependencies are met</info>');
52+
}
53+
54+
return self::SUCCESS;
55+
}
56+
}

apps/files_external/lib/Lib/Backend/SMB.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,20 @@
1010
use Icewind\SMB\BasicAuth;
1111
use Icewind\SMB\KerberosApacheAuth;
1212
use Icewind\SMB\KerberosAuth;
13+
use Icewind\SMB\Native\NativeServer;
14+
use Icewind\SMB\Wrapped\Server;
1315
use OCA\Files_External\Lib\Auth\AuthMechanism;
1416
use OCA\Files_External\Lib\Auth\Password\Password;
1517
use OCA\Files_External\Lib\Auth\SMB\KerberosApacheAuth as KerberosApacheAuthMechanism;
1618
use OCA\Files_External\Lib\DefinitionParameter;
1719
use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException;
18-
use OCA\Files_External\Lib\LegacyDependencyCheckPolyfill;
20+
use OCA\Files_External\Lib\MissingDependency;
21+
use OCA\Files_External\Lib\Storage\SystemBridge;
1922
use OCA\Files_External\Lib\StorageConfig;
2023
use OCP\IL10N;
2124
use OCP\IUser;
2225

2326
class SMB extends Backend {
24-
use LegacyDependencyCheckPolyfill;
25-
2627
public function __construct(IL10N $l, Password $legacyAuth) {
2728
$this
2829
->setIdentifier('smb')
@@ -122,4 +123,20 @@ public function manipulateStorageConfig(StorageConfig &$storage, ?IUser $user =
122123

123124
$storage->setBackendOption('auth', $smbAuth);
124125
}
126+
127+
public function checkDependencies() {
128+
$system = \OCP\Server::get(SystemBridge::class);
129+
if (NativeServer::available($system)) {
130+
return [];
131+
} elseif (Server::available($system)) {
132+
$missing = new MissingDependency('php-smbclient');
133+
$missing->setOptional(true);
134+
$missing->setMessage('The php-smbclient library provides improved compatibility and performance for SMB storages.');
135+
return [$missing];
136+
} else {
137+
$missing = new MissingDependency('php-smbclient');
138+
$missing->setMessage('Either the php-smbclient library (preferred) or the smbclient binary is required for SMB storages.');
139+
return [$missing, new MissingDependency('smbclient')];
140+
}
141+
}
125142
}

apps/files_external/lib/Lib/MissingDependency.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
class MissingDependency {
1313

1414
/** @var string|null Custom message */
15-
private $message = null;
15+
private ?string $message = null;
16+
private bool $optional = false;
1617

1718
/**
1819
* @param string $dependency
1920
*/
2021
public function __construct(
21-
private $dependency,
22+
private readonly string $dependency,
2223
) {
2324
}
2425

@@ -38,4 +39,12 @@ public function setMessage($message) {
3839
$this->message = $message;
3940
return $this;
4041
}
42+
43+
public function isOptional(): bool {
44+
return $this->optional;
45+
}
46+
47+
public function setOptional(bool $optional): void {
48+
$this->optional = $optional;
49+
}
4150
}

apps/files_external/lib/Service/BackendService.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use OCA\Files_External\Lib\Backend\Backend;
1313
use OCA\Files_External\Lib\Config\IAuthMechanismProvider;
1414
use OCA\Files_External\Lib\Config\IBackendProvider;
15+
use OCA\Files_External\Lib\MissingDependency;
1516
use OCP\EventDispatcher\GenericEvent;
1617
use OCP\EventDispatcher\IEventDispatcher;
1718
use OCP\IAppConfig;
@@ -187,7 +188,8 @@ public function getBackends() {
187188
*/
188189
public function getAvailableBackends() {
189190
return array_filter($this->getBackends(), function ($backend) {
190-
return !$backend->checkDependencies();
191+
$missing = array_filter($backend->checkDependencies(), fn (MissingDependency $dependency) => !$dependency->isOptional());
192+
return count($missing) === 0;
191193
});
192194
}
193195

0 commit comments

Comments
 (0)