From 595e78077dfb0681f85cffe0254138a37b89ddbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 28 Nov 2023 17:10:19 +0100 Subject: [PATCH 1/4] Update Psalm to 5.9 to sync with server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- composer.json | 2 +- composer.lock | 14 +++++++------- psalm.xml | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 52196b1f1..95a20c470 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "sabre/dav": "^4.1", "sabre/xml": "^2.2", "symfony/event-dispatcher": "^5.3.11", - "psalm/phar": "^4.10", + "psalm/phar": "^5.9", "nextcloud/coding-standard": "^1.0", "nextcloud/ocp": "dev-master" }, diff --git a/composer.lock b/composer.lock index 40e5b786c..27ab0815e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "616c61f244d35253185f76d157a16652", + "content-hash": "b941b1d343cd286749cbd1f0f901ba5e", "packages": [ { "name": "php-parallel-lint/php-parallel-lint", @@ -923,16 +923,16 @@ }, { "name": "psalm/phar", - "version": "4.18.1", + "version": "5.16.0", "source": { "type": "git", "url": "https://github.com/psalm/phar.git", - "reference": "2c5140c62d897982d7f623d8dbb25ab802557c5f" + "reference": "be4f93e50edf473d60a6e6f9c1d78546a3a32b90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/phar/zipball/2c5140c62d897982d7f623d8dbb25ab802557c5f", - "reference": "2c5140c62d897982d7f623d8dbb25ab802557c5f", + "url": "https://api.github.com/repos/psalm/phar/zipball/be4f93e50edf473d60a6e6f9c1d78546a3a32b90", + "reference": "be4f93e50edf473d60a6e6f9c1d78546a3a32b90", "shasum": "" }, "require": { @@ -952,9 +952,9 @@ "description": "Composer-based Psalm Phar", "support": { "issues": "https://github.com/psalm/phar/issues", - "source": "https://github.com/psalm/phar/tree/4.18.1" + "source": "https://github.com/psalm/phar/tree/5.16.0" }, - "time": "2022-01-08T21:49:33+00:00" + "time": "2023-11-22T22:05:24+00:00" }, { "name": "psr/clock", diff --git a/psalm.xml b/psalm.xml index 0f14f1e62..7a2937cc4 100644 --- a/psalm.xml +++ b/psalm.xml @@ -6,6 +6,8 @@ xmlns="https://getpsalm.org/schema/config" xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" errorBaseline="tests/psalm-baseline.xml" + findUnusedBaselineEntry="true" + findUnusedCode="false" > From caae08c8b62e0a3253be83f7f5f309fdacead0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 28 Nov 2023 18:10:06 +0100 Subject: [PATCH 2/4] Fix stubs and fix psalm spotted issues throughout the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- composer.lock | 33 +- lib/Command/ListCommand.php | 3 +- lib/Controller/FolderController.php | 4 +- lib/Folder/FolderManager.php | 2 +- .../CircleDestroyedEventListener.php | 3 + .../LoadAdditionalScriptsListener.php | 5 + lib/Versions/VersionsBackend.php | 28 +- tests/psalm-baseline.xml | 46 +- tests/stub.phpstub | 1049 ++++++++++++----- 9 files changed, 834 insertions(+), 339 deletions(-) diff --git a/composer.lock b/composer.lock index 27ab0815e..880826484 100644 --- a/composer.lock +++ b/composer.lock @@ -241,26 +241,26 @@ "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "5c5b6d8600ddaf9f466736e34103b2921cc9b0e3" + "reference": "5047d4e94814933e913a562a410d87cf27b2c284" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/5c5b6d8600ddaf9f466736e34103b2921cc9b0e3", - "reference": "5c5b6d8600ddaf9f466736e34103b2921cc9b0e3", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/5047d4e94814933e913a562a410d87cf27b2c284", + "reference": "5047d4e94814933e913a562a410d87cf27b2c284", "shasum": "" }, "require": { - "php": "^7.4 || ~8.0 || ~8.1", + "php": "~8.0 || ~8.1 || ~8.2 || ~8.3", "psr/clock": "^1.0", - "psr/container": "^1.1.1", + "psr/container": "^2.0.2", "psr/event-dispatcher": "^1.0", - "psr/log": "^1.1" + "psr/log": "^1.1.4" }, "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "26.0.0-dev" + "dev-master": "29.0.0-dev" } }, "notification-url": "https://packagist.org/downloads/", @@ -278,7 +278,7 @@ "issues": "https://github.com/nextcloud-deps/ocp/issues", "source": "https://github.com/nextcloud-deps/ocp/tree/master" }, - "time": "2023-02-09T00:37:24+00:00" + "time": "2023-11-28T09:57:05+00:00" }, { "name": "nikic/php-parser", @@ -1006,22 +1006,27 @@ }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -1048,9 +1053,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "psr/event-dispatcher", diff --git a/lib/Command/ListCommand.php b/lib/Command/ListCommand.php index 8ff0cac3f..f8bd8bd84 100644 --- a/lib/Command/ListCommand.php +++ b/lib/Command/ListCommand.php @@ -35,6 +35,7 @@ use Symfony\Component\Console\Output\OutputInterface; class ListCommand extends Base { + /** @var array */ public const PERMISSION_NAMES = [ Constants::PERMISSION_READ => 'read', Constants::PERMISSION_UPDATE => 'write', @@ -132,7 +133,7 @@ private function permissionsToString(int $permissions): string { if ($permissions === 0) { return 'none'; } - return implode(', ', array_filter(self::PERMISSION_NAMES, function ($possiblePermission) use ($permissions) { + return implode(', ', array_filter(self::PERMISSION_NAMES, function (int $possiblePermission) use ($permissions) { return $possiblePermission & $permissions; }, ARRAY_FILTER_USE_KEY)); } diff --git a/lib/Controller/FolderController.php b/lib/Controller/FolderController.php index f17a849bf..56e7989d1 100644 --- a/lib/Controller/FolderController.php +++ b/lib/Controller/FolderController.php @@ -88,8 +88,8 @@ private function filterNonAdminFolder(array $folder): ?array { } /** - * @param array{id: mixed, mount_point: mixed, groups: array, quota: int, size: int, acl: bool} $folder - * @return array{id: mixed, mount_point: mixed, groups:array, group_details: array|mixed, quota: int, size: int, acl: bool} + * @param array{acl: bool, groups: array, id: int, manage: array, mount_point: mixed, quota: int, size: int} $folder + * @return array{acl: bool, group_details: array, groups: array, id: int, manage: array, mount_point: mixed, quota: int, size: int} */ private function formatFolder(array $folder): array { // keep compatibility with the old 'groups' field diff --git a/lib/Folder/FolderManager.php b/lib/Folder/FolderManager.php index 91c394a40..1bdd5778d 100644 --- a/lib/Folder/FolderManager.php +++ b/lib/Folder/FolderManager.php @@ -359,7 +359,7 @@ private function getAllApplicable(): array { * @param CirclesQueryHelper|null $queryHelper * @param string|null $entityId the type of the entity * - * @return array{displayname?: string, id?: string, type?: "group"|"user"|"circle"} + * @return array{displayName: string, permissions: int, type: 'circle'|'group'} */ private function generateApplicableMapEntry( array $row, diff --git a/lib/Listeners/CircleDestroyedEventListener.php b/lib/Listeners/CircleDestroyedEventListener.php index 9b1757392..c0b67fe3f 100644 --- a/lib/Listeners/CircleDestroyedEventListener.php +++ b/lib/Listeners/CircleDestroyedEventListener.php @@ -31,6 +31,9 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +/** + * @template-implements IEventListener + */ class CircleDestroyedEventListener implements IEventListener { public function __construct( private FolderManager $folderManager, diff --git a/lib/Listeners/LoadAdditionalScriptsListener.php b/lib/Listeners/LoadAdditionalScriptsListener.php index b36033979..85c91137a 100644 --- a/lib/Listeners/LoadAdditionalScriptsListener.php +++ b/lib/Listeners/LoadAdditionalScriptsListener.php @@ -27,7 +27,12 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCA\Files\Event\LoadAdditionalScriptsEvent; +use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; +/** + * @template-implements IEventListener + */ class LoadAdditionalScriptsListener implements IEventListener { public function handle(Event $event): void { \OCP\Util::addScript('groupfolders', 'groupfolders-files'); diff --git a/lib/Versions/VersionsBackend.php b/lib/Versions/VersionsBackend.php index c79fe1631..1de84094e 100644 --- a/lib/Versions/VersionsBackend.php +++ b/lib/Versions/VersionsBackend.php @@ -59,8 +59,8 @@ public function useBackendForStorage(IStorage $storage): bool { return true; } - public function getVersionsForFile(IUser $user, FileInfo $fileInfo): array { - $mount = $fileInfo->getMountPoint(); + public function getVersionsForFile(IUser $user, FileInfo $file): array { + $mount = $file->getMountPoint(); if (!($mount instanceof GroupMountPoint)) { return []; } @@ -68,13 +68,13 @@ public function getVersionsForFile(IUser $user, FileInfo $fileInfo): array { try { $folderId = $mount->getFolderId(); /** @var Folder $versionsFolder */ - $versionsFolder = $this->getVersionsFolder($mount->getFolderId())->get((string)$fileInfo->getId()); + $versionsFolder = $this->getVersionsFolder($mount->getFolderId())->get((string)$file->getId()); $userFolder = $this->rootFolder->getUserFolder($user->getUID()); - $nodes = $userFolder->getById($fileInfo->getId()); - $file = array_pop($nodes); + $nodes = $userFolder->getById($file->getId()); + $node = array_pop($nodes); - $versions = $this->getVersionsForFileFromDB($fileInfo, $user, $folderId); + $versions = $this->getVersionsForFileFromDB($file, $user, $folderId); // Early exit if we find any version in the database. // Else we continue to populate the DB from what's on disk. @@ -84,10 +84,10 @@ public function getVersionsForFile(IUser $user, FileInfo $fileInfo): array { // Insert the entry in the DB for the current version. $versionEntity = new GroupVersionEntity(); - $versionEntity->setFileId($file->getId()); - $versionEntity->setTimestamp($file->getMTime()); - $versionEntity->setSize($file->getSize()); - $versionEntity->setMimetype($this->mimeTypeLoader->getId($file->getMimetype())); + $versionEntity->setFileId($node->getId()); + $versionEntity->setTimestamp($node->getMTime()); + $versionEntity->setSize($node->getSize()); + $versionEntity->setMimetype($this->mimeTypeLoader->getId($node->getMimetype())); $versionEntity->setDecodedMetadata([]); $this->groupVersionsMapper->insert($versionEntity); @@ -99,12 +99,12 @@ public function getVersionsForFile(IUser $user, FileInfo $fileInfo): array { } $versionEntity = new GroupVersionEntity(); - $versionEntity->setFileId($file->getId()); + $versionEntity->setFileId($node->getId()); // HACK: before this commit, versions were created with the current timestamp instead of the version's mtime. // This means that the name of some versions is the exact mtime of the next version. This behavior is now fixed. // To prevent occasional conflicts between the last version and the current one, we decrement the last version mtime. $mtime = (int)$version->getName(); - if ($mtime === $file->getMTime()) { + if ($mtime === $node->getMTime()) { $versionEntity->setTimestamp($mtime - 1); $version->move($version->getParent()->getPath() . '/' . ($mtime - 1)); } else { @@ -112,12 +112,12 @@ public function getVersionsForFile(IUser $user, FileInfo $fileInfo): array { } $versionEntity->setSize($version->getSize()); // Use the main file mimetype for this initialization as the original mimetype is unknown. - $versionEntity->setMimetype($this->mimeTypeLoader->getId($file->getMimetype())); + $versionEntity->setMimetype($this->mimeTypeLoader->getId($node->getMimetype())); $versionEntity->setDecodedMetadata([]); $this->groupVersionsMapper->insert($versionEntity); } - return $this->getVersionsForFileFromDB($file, $user, $folderId); + return $this->getVersionsForFileFromDB($node, $user, $folderId); } catch (NotFoundException $e) { return []; } diff --git a/tests/psalm-baseline.xml b/tests/psalm-baseline.xml index dd0f8599f..63b8ea0a4 100644 --- a/tests/psalm-baseline.xml +++ b/tests/psalm-baseline.xml @@ -1,52 +1,18 @@ - + - + filemtime hash - + IteratorDirectory - - getDirectoryContent - - - parent::getMetaData($path) - parent::writeStream($path, $stream, $size) - - - - - BeforeTemplateRenderedEvent - CircleDestroyedEvent - - - - - array{id: mixed, mount_point: mixed, groups: array<empty, empty>|mixed, quota: int, size: int|mixed, acl: bool}|false - - - - - $this->__call(__FUNCTION__, func_get_args()) - $this->__call(__FUNCTION__, func_get_args()) - - - - - parent::getMetaData($path) - - - - - parent::__construct($backend, $originalLocation, $deletedTime, $trashPath, $fileInfo, $user) - - - self::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter'] === -1 - self::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter'] === -1 + + + diff --git a/tests/stub.phpstub b/tests/stub.phpstub index 6fa7f7b27..53ee63855 100644 --- a/tests/stub.phpstub +++ b/tests/stub.phpstub @@ -75,135 +75,188 @@ namespace OCA\Files_Trashbin\Trash { public function getTitle(): string; } - class TrashItem implements ITrashItem { - public function getTrashBackend(): ITrashBackend { - throw new \Exception('stub'); + class TrashItem implements \OCA\Files_Trashbin\Trash\ITrashItem + { + /** @var ITrashBackend */ + private $backend; + /** @var string */ + private $orignalLocation; + /** @var int */ + private $deletedTime; + /** @var string */ + private $trashPath; + /** @var FileInfo */ + private $fileInfo; + /** @var IUser */ + private $user; + public function __construct(\OCA\Files_Trashbin\Trash\ITrashBackend $backend, string $originalLocation, int $deletedTime, string $trashPath, \OCP\Files\FileInfo $fileInfo, \OCP\IUser $user) + { } - - public function getOriginalLocation(): string { - throw new \Exception('stub'); + public function getTrashBackend() : \OCA\Files_Trashbin\Trash\ITrashBackend + { } - - public function getDeletedTime(): int { - throw new \Exception('stub'); + public function getOriginalLocation() : string + { } - - public function getTrashPath(): string { - throw new \Exception('stub'); + public function getDeletedTime() : int + { } - - public function isRootItem(): bool { - throw new \Exception('stub'); + public function getTrashPath() : string + { } - - public function getUser(): IUser { - throw new \Exception('stub'); + public function isRootItem() : bool + { } - - public function getEtag() { + public function getUser() : \OCP\IUser + { } - - public function getId() { + public function getEtag() + { } - - public function getSize($includeMounts = true) { - throw new \Exception('stub'); + public function getSize($includeMounts = true) + { } - - public function getMtime() { - throw new \Exception('stub'); + public function getMtime() + { } - - public function getName() { - throw new \Exception('stub'); + public function getName() + { } - - public function getInternalPath() { - throw new \Exception('stub'); + public function getInternalPath() + { } - - public function getPath() { - throw new \Exception('stub'); + public function getPath() + { } - - public function getMimetype() { - throw new \Exception('stub'); + public function getMimetype() + { } - - public function getMimePart() { - throw new \Exception('stub'); + public function getMimePart() + { } - - public function getStorage() { - throw new \Exception('stub'); + public function getStorage() + { } - - public function isEncrypted() { - throw new \Exception('stub'); + public function getId() + { } - - public function getPermissions() { - throw new \Exception('stub'); + public function isEncrypted() + { } - - public function getType() { - throw new \Exception('stub'); + public function getPermissions() + { } - - public function isReadable() { - throw new \Exception('stub'); + public function getType() + { } - - public function isUpdateable() { - throw new \Exception('stub'); + public function isReadable() + { } - - public function isCreatable() { - throw new \Exception('stub'); + public function isUpdateable() + { } - - public function isDeletable() { - throw new \Exception('stub'); + public function isCreatable() + { } - - public function isShareable() { - throw new \Exception('stub'); + public function isDeletable() + { } - - public function isShared() { - throw new \Exception('stub'); + public function isShareable() + { } - - public function isMounted() { - throw new \Exception('stub'); + public function isShared() + { } - - public function getMountPoint() { - throw new \Exception('stub'); + public function isMounted() + { } - - public function getOwner() { - throw new \Exception('stub'); + public function getMountPoint() + { } - - public function getChecksum() { - throw new \Exception('stub'); + public function getOwner() + { } - - public function getExtension(): string { - throw new \Exception('stub'); + public function getChecksum() + { } - - public function getTitle(): string { - throw new \Exception('stub'); + public function getExtension() : string + { + } + public function getTitle() : string + { } + public function getCreationTime() : int + { + } + public function getUploadTime() : int + { + } + public function getParentId() : int + { + } + /** + * @inheritDoc + * @return array + */ + public function getMetadata() : array + { + } + } +} - public function getCreationTime(): int { - throw new \Exception('stub'); +namespace OCA\Files\Event { + /** + * This event is triggered when the files app is rendered. + * It can be used to add additional scripts to the files app. + * + * @since 17.0.0 + */ + class LoadAdditionalScriptsEvent extends \OCP\EventDispatcher\Event + { + private $hiddenFields = []; + public function addHiddenField(string $name, string $value) : void + { + } + public function getHiddenFields() : array + { } + } +} - public function getUploadTime(): int { - throw new \Exception('stub'); +namespace OCA\Files_Sharing\Event { + /** + * Emitted before the rendering step of the public share page happens. The event + * holds a flag that specifies if it is the authentication page of a public share. + * + * @since 20.0.0 + */ + class BeforeTemplateRenderedEvent extends \OCP\EventDispatcher\Event + { + /** + * @since 20.0.0 + */ + public const SCOPE_PUBLIC_SHARE_AUTH = 'publicShareAuth'; + /** @var IShare */ + private $share; + /** @var string|null */ + private $scope; + /** + * @since 20.0.0 + */ + public function __construct(\OCP\Share\IShare $share, ?string $scope = null) + { + } + /** + * @since 20.0.0 + */ + public function getShare() : \OCP\Share\IShare + { + } + /** + * @since 20.0.0 + */ + public function getScope() : ?string + { } } } @@ -236,28 +289,66 @@ namespace OCA\Files_Versions\Versions { use OCP\Files\Storage\IStorage; use OCP\IUser; - interface IVersionBackend { - public function useBackendForStorage(IStorage $storage): bool; - + /** + * @since 15.0.0 + */ + interface IVersionBackend + { /** - * @return IVersion[] - */ - public function getVersionsForFile(IUser $user, FileInfo $file): array; - - public function createVersion(IUser $user, FileInfo $file); - - public function rollback(IVersion $version); - + * Whether or not this version backend should be used for a storage + * + * If false is returned then the next applicable backend will be used + * + * @param IStorage $storage + * @return bool + * @since 17.0.0 + */ + public function useBackendForStorage(\OCP\Files\Storage\IStorage $storage) : bool; /** - * @return resource|false - * @throws NotFoundException - */ - public function read(IVersion $version); - + * Get all versions for a file + * + * @param IUser $user + * @param FileInfo $file + * @return IVersion[] + * @since 15.0.0 + */ + public function getVersionsForFile(\OCP\IUser $user, \OCP\Files\FileInfo $file) : array; /** - * @param int|string $revision - */ - public function getVersionFile(IUser $user, FileInfo $sourceFile, $revision): ?File; + * Create a new version for a file + * + * @param IUser $user + * @param FileInfo $file + * @since 15.0.0 + */ + public function createVersion(\OCP\IUser $user, \OCP\Files\FileInfo $file); + /** + * Restore this version + * + * @param IVersion $version + * @since 15.0.0 + */ + public function rollback(\OCA\Files_Versions\Versions\IVersion $version); + /** + * Open the file for reading + * + * @param IVersion $version + * @return resource|false + * @throws NotFoundException + * @since 15.0.0 + */ + public function read(\OCA\Files_Versions\Versions\IVersion $version); + /** + * Get the preview for a specific version of a file + * + * @param IUser $user + * @param FileInfo $sourceFile + * @param int|string $revision + * + * @return File + * + * @since 15.0.0 + */ + public function getVersionFile(\OCP\IUser $user, \OCP\Files\FileInfo $sourceFile, $revision) : \OCP\Files\File; } interface INameableVersionBackend { @@ -783,203 +874,631 @@ namespace OC\Files\Storage { use OCP\Files\Storage\IStorage; use OCP\Files\Cache\IScanner; - class Storage implements IStorage { - /** @var ?IScanner */ - public $scanner; + interface Storage extends \OCP\Files\Storage { + /** + * get a cache instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage|null (optional) the storage to pass to the cache + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = '', $storage = null); - public function __construct(array $parameters) { - } + /** + * get a scanner instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path = '', $storage = null); - public function getId() {} - public function mkdir($path) {} + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path); - public function rmdir($path) {} + /** + * get a watcher instance for the cache + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = '', $storage = null); - public function opendir($path) { - throw new \Exception('stub'); - } + /** + * get a propagator instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Propagator + */ + public function getPropagator($storage = null); - public function is_dir($path) { - throw new \Exception('stub'); - } + /** + * get a updater instance for the cache + * + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Updater + */ + public function getUpdater($storage = null); - public function is_file($path) { - throw new \Exception('stub'); - } + /** + * @return \OC\Files\Cache\Storage + */ + public function getStorageCache(); - public function stat($path) { - throw new \Exception('stub'); - } + /** + * @param string $path + * @return array|null + */ + public function getMetaData($path); - public function filetype($path) { - throw new \Exception('stub'); - } + /** + * @param string $path The path of the file to acquire the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + */ + public function acquireLock($path, $type, ILockingProvider $provider); - public function filesize($path) { - throw new \Exception('stub'); - } + /** + * @param string $path The path of the file to release the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + */ + public function releaseLock($path, $type, ILockingProvider $provider); - public function isCreatable($path) { - throw new \Exception('stub'); - } + /** + * @param string $path The path of the file to change the lock for + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + */ + public function changeLock($path, $type, ILockingProvider $provider); - public function isReadable($path) { - throw new \Exception('stub'); - } + /** + * Get the contents of a directory with metadata + * + * @param string $directory + * @return \Traversable an iterator, containing file metadata + * + * The metadata array will contain the following fields + * + * - name + * - mimetype + * - mtime + * - size + * - etag + * - storage_mtime + * - permissions + */ + public function getDirectoryContent($directory): \Traversable; + } +} - public function isUpdatable($path) { - throw new \Exception('stub'); - } +namespace OC\Files\Storage\Wrapper{ - public function isDeletable($path) { - throw new \Exception('stub'); - } + use OCP\Files\Cache\ICache; + use OCP\Files\Cache\ICacheEntry; + use OCP\Files\Search\ISearchQuery; + use OC\Files\Storage\Storage; + use OCP\Files\Storage\IStorage; + use OCP\Files\Cache\IScanner; - public function isSharable($path) { - throw new \Exception('stub'); + class Wrapper implements \OC\Files\Storage\Storage, \OCP\Files\Storage\ILockingStorage, \OCP\Files\Storage\IWriteStreamStorage + { + /** + * @var \OC\Files\Storage\Storage $storage + */ + protected $storage; + public $cache; + public $scanner; + public $watcher; + public $propagator; + public $updater; + /** + * @param array $parameters + */ + public function __construct($parameters) + { } - - public function getPermissions($path) { - throw new \Exception('stub'); + /** + * @return \OC\Files\Storage\Storage + */ + public function getWrapperStorage() + { } - - public function file_exists($path) { - throw new \Exception('stub'); + /** + * Get the identifier for the storage, + * the returned id should be the same for every storage object that is created with the same parameters + * and two storage objects with the same id should refer to two storages that display the same files. + * + * @return string + */ + public function getId() + { } - - public function filemtime($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.mkdir.php + * + * @param string $path + * @return bool + */ + public function mkdir($path) + { } - - public function file_get_contents($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.rmdir.php + * + * @param string $path + * @return bool + */ + public function rmdir($path) + { } - - public function file_put_contents($path, $data) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.opendir.php + * + * @param string $path + * @return resource|false + */ + public function opendir($path) + { } - - public function unlink($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.is_dir.php + * + * @param string $path + * @return bool + */ + public function is_dir($path) + { } - - public function rename($path1, $path2) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.is_file.php + * + * @param string $path + * @return bool + */ + public function is_file($path) + { } - - public function copy($path1, $path2) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.stat.php + * only the following keys are required in the result: size and mtime + * + * @param string $path + * @return array|bool + */ + public function stat($path) + { } - - public function fopen($path, $mode) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.filetype.php + * + * @param string $path + * @return string|bool + */ + public function filetype($path) + { } - - public function getMimeType($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.filesize.php + * The result for filesize when called on a folder is required to be 0 + */ + public function filesize($path) : false|int|float + { } - - public function hash($type, $path, $raw = false) { - throw new \Exception('stub'); + /** + * check if a file can be created in $path + * + * @param string $path + * @return bool + */ + public function isCreatable($path) + { } - - public function free_space($path) { - throw new \Exception('stub'); + /** + * check if a file can be read + * + * @param string $path + * @return bool + */ + public function isReadable($path) + { } - - public function touch($path, $mtime = null) { - throw new \Exception('stub'); + /** + * check if a file can be written to + * + * @param string $path + * @return bool + */ + public function isUpdatable($path) + { } - - public function getLocalFile($path) { - throw new \Exception('stub'); + /** + * check if a file can be deleted + * + * @param string $path + * @return bool + */ + public function isDeletable($path) + { } - - public function hasUpdated($path, $time) { - throw new \Exception('stub'); + /** + * check if a file can be shared + * + * @param string $path + * @return bool + */ + public function isSharable($path) + { } - - public function getETag($path) { - throw new \Exception('stub'); + /** + * get the full permissions of a path. + * Should return a combination of the PERMISSION_ constants defined in lib/public/constants.php + * + * @param string $path + * @return int + */ + public function getPermissions($path) + { } - - public function isLocal() { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.file_exists.php + * + * @param string $path + * @return bool + */ + public function file_exists($path) + { } - - public function instanceOfStorage($class) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.filemtime.php + * + * @param string $path + * @return int|bool + */ + public function filemtime($path) + { } - - public function getDirectDownload($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.file_get_contents.php + * + * @param string $path + * @return string|false + */ + public function file_get_contents($path) + { } - - public function verifyPath($path, $fileName) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.file_put_contents.php + * + * @param string $path + * @param mixed $data + * @return int|float|false + */ + public function file_put_contents($path, $data) + { } - - public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.unlink.php + * + * @param string $path + * @return bool + */ + public function unlink($path) + { } - - public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.rename.php + * + * @param string $source + * @param string $target + * @return bool + */ + public function rename($source, $target) + { } - - public function test() { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.copy.php + * + * @param string $source + * @param string $target + * @return bool + */ + public function copy($source, $target) + { } - - public function getAvailability() { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.fopen.php + * + * @param string $path + * @param string $mode + * @return resource|bool + */ + public function fopen($path, $mode) + { } - - public function setAvailability($isAvailable) { - throw new \Exception('stub'); + /** + * get the mimetype for a file or folder + * The mimetype for a folder is required to be "httpd/unix-directory" + * + * @param string $path + * @return string|bool + */ + public function getMimeType($path) + { } - - public function getOwner($path) { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.hash.php + * + * @param string $type + * @param string $path + * @param bool $raw + * @return string|bool + */ + public function hash($type, $path, $raw = false) + { } - - public function getCache() { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.free_space.php + * + * @param string $path + * @return int|float|bool + */ + public function free_space($path) + { } - - public function getPropagator() { - throw new \Exception('stub'); + /** + * search for occurrences of $query in file names + * + * @param string $query + * @return array|bool + */ + public function search($query) + { } - - public function getScanner() { - throw new \Exception('stub'); + /** + * see https://www.php.net/manual/en/function.touch.php + * If the backend does not support the operation, false should be returned + * + * @param string $path + * @param int $mtime + * @return bool + */ + public function touch($path, $mtime = null) + { } - - public function getUpdater() { - throw new \Exception('stub'); + /** + * get the path to a local version of the file. + * The local version of the file can be temporary and doesn't have to be persistent across requests + * + * @param string $path + * @return string|false + */ + public function getLocalFile($path) + { } - - public function getWatcher() { - throw new \Exception('stub'); + /** + * check if a file or folder has been updated since $time + * + * @param string $path + * @param int $time + * @return bool + * + * hasUpdated for folders should return at least true if a file inside the folder is add, removed or renamed. + * returning true for other changes in the folder is optional + */ + public function hasUpdated($path, $time) + { } - } -} - -namespace OC\Files\Storage\Wrapper{ - - use OCP\Files\Cache\ICache; - use OCP\Files\Cache\ICacheEntry; - use OCP\Files\Search\ISearchQuery; - use OC\Files\Storage\Storage; - use OCP\Files\Storage\IStorage; - use OCP\Files\Cache\IScanner; + /** + * get a cache instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage|null (optional) the storage to pass to the cache + * @return \OC\Files\Cache\Cache + */ + public function getCache($path = '', $storage = null) + { + } + /** + * get a scanner instance for the storage + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the scanner + * @return \OC\Files\Cache\Scanner + */ + public function getScanner($path = '', $storage = null) + { + } + /** + * get the user id of the owner of a file or folder + * + * @param string $path + * @return string + */ + public function getOwner($path) + { + } + /** + * get a watcher instance for the cache + * + * @param string $path + * @param \OC\Files\Storage\Storage (optional) the storage to pass to the watcher + * @return \OC\Files\Cache\Watcher + */ + public function getWatcher($path = '', $storage = null) + { + } + public function getPropagator($storage = null) + { + } + public function getUpdater($storage = null) + { + } + /** + * @return \OC\Files\Cache\Storage + */ + public function getStorageCache() + { + } + /** + * get the ETag for a file or folder + * + * @param string $path + * @return string|false + */ + public function getETag($path) + { + } + /** + * Returns true + * + * @return true + */ + public function test() + { + } + /** + * Returns the wrapped storage's value for isLocal() + * + * @return bool wrapped storage's isLocal() value + */ + public function isLocal() + { + } + /** + * Check if the storage is an instance of $class or is a wrapper for a storage that is an instance of $class + * + * @param class-string $class + * @return bool + */ + public function instanceOfStorage($class) + { + } + /** + * @psalm-template T of IStorage + * @psalm-param class-string $class + * @psalm-return T|null + */ + public function getInstanceOfStorage(string $class) + { + } + /** + * Pass any methods custom to specific storage implementations to the wrapped storage + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, $args) + { + } + /** + * A custom storage implementation can return an url for direct download of a give file. + * + * For now the returned array can hold the parameter url - in future more attributes might follow. + * + * @param string $path + * @return array|bool + */ + public function getDirectDownload($path) + { + } + /** + * Get availability of the storage + * + * @return array [ available, last_checked ] + */ + public function getAvailability() + { + } + /** + * Set availability of the storage + * + * @param bool $isAvailable + */ + public function setAvailability($isAvailable) + { + } + /** + * @param string $path the path of the target folder + * @param string $fileName the name of the file itself + * @return void + * @throws InvalidPathException + */ + public function verifyPath($path, $fileName) + { + } + /** + * @param IStorage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function copyFromStorage(\OCP\Files\Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) + { + } + /** + * @param IStorage $sourceStorage + * @param string $sourceInternalPath + * @param string $targetInternalPath + * @return bool + */ + public function moveFromStorage(\OCP\Files\Storage\IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) + { + } + public function getMetaData($path) + { + } + /** + * @param string $path + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + * @throws \OCP\Lock\LockedException + */ + public function acquireLock($path, $type, \OCP\Lock\ILockingProvider $provider) + { + } + /** + * @param string $path + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + */ + public function releaseLock($path, $type, \OCP\Lock\ILockingProvider $provider) + { + } + /** + * @param string $path + * @param int $type \OCP\Lock\ILockingProvider::LOCK_SHARED or \OCP\Lock\ILockingProvider::LOCK_EXCLUSIVE + * @param \OCP\Lock\ILockingProvider $provider + */ + public function changeLock($path, $type, \OCP\Lock\ILockingProvider $provider) + { + } + /** + * @return bool + */ + public function needsPartFile() + { + } + public function writeStream(string $path, $stream, int $size = null) : int + { + } + public function getDirectoryContent($directory) : \Traversable + { + } + } - class Wrapper extends Storage { - protected Storage $storage; - public function getWrapperStorage(): ?IStorage {} - } class Jail extends Wrapper { public function getUnjailedPath(string $path): string {} @@ -994,10 +1513,6 @@ namespace OC\Files\Storage\Wrapper{ } } -namespace OCP\Files\Mount { - interface ISystemMountPoint {} -} - namespace OC\Files\ObjectStore { use OC\Files\Storage\Wrapper\Wrapper; class ObjectStoreStorage extends Wrapper {} @@ -1063,7 +1578,7 @@ namespace OCA\Circles\Model\Probes { namespace OCA\Circles\Events { use OCA\Circles\Model\Circle; - class CircleDestroyedEvent { + class CircleDestroyedEvent extends \OCP\EventDispatcher\Event { public function getCircle(): Circle {} } } From 241512f1b8e03f049efd52503acd4f3d71985d86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 30 Nov 2023 12:13:45 +0100 Subject: [PATCH 3/4] Fix or suppress remaining psalm issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/Mount/GroupFolderStorage.php | 5 ++++- lib/Versions/ExpireManager.php | 1 + lib/Versions/GroupVersionsExpireManager.php | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Mount/GroupFolderStorage.php b/lib/Mount/GroupFolderStorage.php index add33243a..8236d7c76 100644 --- a/lib/Mount/GroupFolderStorage.php +++ b/lib/Mount/GroupFolderStorage.php @@ -49,6 +49,9 @@ public function getFolderId(): int { return $this->folderId; } + /** + * @psalm-suppress FalsableReturnStatement Return type of getOwner is not clear even in server + */ public function getOwner($path) { $user = $this->userSession->getUser(); if ($user !== null) { @@ -70,7 +73,7 @@ public function getCache($path = '', $storage = null) { } public function getScanner($path = '', $storage = null) { - /** @var \OC\Files\Storage\Storage $storage */ + /** @var \OC\Files\Storage\Wrapper\Wrapper $storage */ if (!$storage) { $storage = $this; } diff --git a/lib/Versions/ExpireManager.php b/lib/Versions/ExpireManager.php index a4d8cf642..e4dec1ce9 100644 --- a/lib/Versions/ExpireManager.php +++ b/lib/Versions/ExpireManager.php @@ -97,6 +97,7 @@ protected function getAutoExpireList(int $time, array $versions): array { $newInterval = false; // version checked so we can move to the next one } else { // time to move on to the next interval $interval++; + /** @psalm-suppress InvalidArrayOffset We know that $interval is <= 6 thanks to the -1 intervalEndsAfter in the last step */ $step = self::MAX_VERSIONS_PER_INTERVAL[$interval]['step']; $nextVersion = $prevTimestamp - $step; if (self::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter'] === -1) { diff --git a/lib/Versions/GroupVersionsExpireManager.php b/lib/Versions/GroupVersionsExpireManager.php index 1b7a4ad5c..377e20938 100644 --- a/lib/Versions/GroupVersionsExpireManager.php +++ b/lib/Versions/GroupVersionsExpireManager.php @@ -61,7 +61,7 @@ public function expireAll(): void { } /** - * @param array{id: int, mount_point: string, groups: array|array, quota: int, size: int, acl: bool} $folder + * @param array{acl: bool, groups: array>, id: int, mount_point: mixed, quota: int, size: 0} $folder */ public function expireFolder(array $folder): void { $view = new View('/__groupfolders/versions/' . $folder['id']); From 512f551dc75116eb883a1ece2d5e4dfc7074517d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 30 Nov 2023 12:14:10 +0100 Subject: [PATCH 4/4] Run cs:fix with new coding standard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- lib/Listeners/LoadAdditionalScriptsListener.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Listeners/LoadAdditionalScriptsListener.php b/lib/Listeners/LoadAdditionalScriptsListener.php index 85c91137a..a5b1f8e36 100644 --- a/lib/Listeners/LoadAdditionalScriptsListener.php +++ b/lib/Listeners/LoadAdditionalScriptsListener.php @@ -25,10 +25,10 @@ namespace OCA\GroupFolders\Listeners; -use OCP\EventDispatcher\Event; -use OCP\EventDispatcher\IEventListener; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files_Sharing\Event\BeforeTemplateRenderedEvent; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; /** * @template-implements IEventListener