diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index 84c31dfd0cac6..bc2786cc3b485 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -53,6 +53,7 @@ External storage can be configured using the GUI or at the command line. This se OCA\Files_External\Command\Verify OCA\Files_External\Command\Notify OCA\Files_External\Command\Scan + OCA\Files_External\Command\Dependencies diff --git a/apps/files_external/composer/composer/autoload_classmap.php b/apps/files_external/composer/composer/autoload_classmap.php index 156847d56200b..589b70a078b05 100644 --- a/apps/files_external/composer/composer/autoload_classmap.php +++ b/apps/files_external/composer/composer/autoload_classmap.php @@ -14,6 +14,7 @@ 'OCA\\Files_External\\Command\\Config' => $baseDir . '/../lib/Command/Config.php', 'OCA\\Files_External\\Command\\Create' => $baseDir . '/../lib/Command/Create.php', 'OCA\\Files_External\\Command\\Delete' => $baseDir . '/../lib/Command/Delete.php', + 'OCA\\Files_External\\Command\\Dependencies' => $baseDir . '/../lib/Command/Dependencies.php', 'OCA\\Files_External\\Command\\Export' => $baseDir . '/../lib/Command/Export.php', 'OCA\\Files_External\\Command\\Import' => $baseDir . '/../lib/Command/Import.php', 'OCA\\Files_External\\Command\\ListCommand' => $baseDir . '/../lib/Command/ListCommand.php', diff --git a/apps/files_external/composer/composer/autoload_static.php b/apps/files_external/composer/composer/autoload_static.php index 186f85bc5bc55..0399f47685c8a 100644 --- a/apps/files_external/composer/composer/autoload_static.php +++ b/apps/files_external/composer/composer/autoload_static.php @@ -29,6 +29,7 @@ class ComposerStaticInitFiles_External 'OCA\\Files_External\\Command\\Config' => __DIR__ . '/..' . '/../lib/Command/Config.php', 'OCA\\Files_External\\Command\\Create' => __DIR__ . '/..' . '/../lib/Command/Create.php', 'OCA\\Files_External\\Command\\Delete' => __DIR__ . '/..' . '/../lib/Command/Delete.php', + 'OCA\\Files_External\\Command\\Dependencies' => __DIR__ . '/..' . '/../lib/Command/Dependencies.php', 'OCA\\Files_External\\Command\\Export' => __DIR__ . '/..' . '/../lib/Command/Export.php', 'OCA\\Files_External\\Command\\Import' => __DIR__ . '/..' . '/../lib/Command/Import.php', 'OCA\\Files_External\\Command\\ListCommand' => __DIR__ . '/..' . '/../lib/Command/ListCommand.php', diff --git a/apps/files_external/lib/Command/Dependencies.php b/apps/files_external/lib/Command/Dependencies.php new file mode 100644 index 0000000000000..1bb5777812912 --- /dev/null +++ b/apps/files_external/lib/Command/Dependencies.php @@ -0,0 +1,56 @@ +setName('files_external:dependencies') + ->setDescription('Show information about the backend dependencies'); + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $storageBackends = $this->backendService->getBackends(); + + $anyMissing = false; + + foreach ($storageBackends as $backend) { + if ($backend->getDeprecateTo() !== null) { + continue; + } + $missingDependencies = $backend->checkDependencies(); + if ($missingDependencies) { + $anyMissing = true; + $output->writeln($backend->getText() . ':'); + foreach ($missingDependencies as $missingDependency) { + if ($missingDependency->getMessage()) { + $output->writeln(" - {$missingDependency->getDependency()}: {$missingDependency->getMessage()}"); + } else { + $output->writeln(" - {$missingDependency->getDependency()}"); + } + } + } + } + + if (!$anyMissing) { + $output->writeln('All dependencies are met'); + } + + return self::SUCCESS; + } +} diff --git a/apps/files_external/lib/Lib/Backend/SMB.php b/apps/files_external/lib/Lib/Backend/SMB.php index b246b0638f007..3549f69cbe314 100644 --- a/apps/files_external/lib/Lib/Backend/SMB.php +++ b/apps/files_external/lib/Lib/Backend/SMB.php @@ -10,19 +10,20 @@ use Icewind\SMB\BasicAuth; use Icewind\SMB\KerberosApacheAuth; use Icewind\SMB\KerberosAuth; +use Icewind\SMB\Native\NativeServer; +use Icewind\SMB\Wrapped\Server; use OCA\Files_External\Lib\Auth\AuthMechanism; use OCA\Files_External\Lib\Auth\Password\Password; use OCA\Files_External\Lib\Auth\SMB\KerberosApacheAuth as KerberosApacheAuthMechanism; use OCA\Files_External\Lib\DefinitionParameter; use OCA\Files_External\Lib\InsufficientDataForMeaningfulAnswerException; -use OCA\Files_External\Lib\LegacyDependencyCheckPolyfill; +use OCA\Files_External\Lib\MissingDependency; +use OCA\Files_External\Lib\Storage\SystemBridge; use OCA\Files_External\Lib\StorageConfig; use OCP\IL10N; use OCP\IUser; class SMB extends Backend { - use LegacyDependencyCheckPolyfill; - public function __construct(IL10N $l, Password $legacyAuth) { $this ->setIdentifier('smb') @@ -122,4 +123,20 @@ public function manipulateStorageConfig(StorageConfig &$storage, ?IUser $user = $storage->setBackendOption('auth', $smbAuth); } + + public function checkDependencies() { + $system = \OCP\Server::get(SystemBridge::class); + if (NativeServer::available($system)) { + return []; + } elseif (Server::available($system)) { + $missing = new MissingDependency('php-smbclient'); + $missing->setOptional(true); + $missing->setMessage('The php-smbclient library provides improved compatibility and performance for SMB storages.'); + return [$missing]; + } else { + $missing = new MissingDependency('php-smbclient'); + $missing->setMessage('Either the php-smbclient library (preferred) or the smbclient binary is required for SMB storages.'); + return [$missing, new MissingDependency('smbclient')]; + } + } } diff --git a/apps/files_external/lib/Lib/MissingDependency.php b/apps/files_external/lib/Lib/MissingDependency.php index 5c2c6880f23d2..da4cbb1de4610 100644 --- a/apps/files_external/lib/Lib/MissingDependency.php +++ b/apps/files_external/lib/Lib/MissingDependency.php @@ -12,13 +12,14 @@ class MissingDependency { /** @var string|null Custom message */ - private $message = null; + private ?string $message = null; + private bool $optional = false; /** * @param string $dependency */ public function __construct( - private $dependency, + private readonly string $dependency, ) { } @@ -38,4 +39,12 @@ public function setMessage($message) { $this->message = $message; return $this; } + + public function isOptional(): bool { + return $this->optional; + } + + public function setOptional(bool $optional): void { + $this->optional = $optional; + } } diff --git a/apps/files_external/lib/Service/BackendService.php b/apps/files_external/lib/Service/BackendService.php index e37a0ab464965..c0c7118648d4f 100644 --- a/apps/files_external/lib/Service/BackendService.php +++ b/apps/files_external/lib/Service/BackendService.php @@ -12,6 +12,7 @@ use OCA\Files_External\Lib\Backend\Backend; use OCA\Files_External\Lib\Config\IAuthMechanismProvider; use OCA\Files_External\Lib\Config\IBackendProvider; +use OCA\Files_External\Lib\MissingDependency; use OCP\EventDispatcher\GenericEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; @@ -193,7 +194,8 @@ public function getBackends() { */ public function getAvailableBackends() { return array_filter($this->getBackends(), function ($backend) { - return !$backend->checkDependencies(); + $missing = array_filter($backend->checkDependencies(), fn (MissingDependency $dependency) => !$dependency->isOptional()); + return count($missing) === 0; }); }