Skip to content

Commit e3b1f01

Browse files
committed
feat(MountManager): Emit events when mounts are added, removed and moved
Signed-off-by: provokateurin <kate@provokateurin.de>
1 parent 9c717aa commit e3b1f01

File tree

7 files changed

+172
-32
lines changed

7 files changed

+172
-32
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,9 @@
431431
'OCP\\Files\\Lock\\LockContext' => $baseDir . '/lib/public/Files/Lock/LockContext.php',
432432
'OCP\\Files\\Lock\\NoLockProviderException' => $baseDir . '/lib/public/Files/Lock/NoLockProviderException.php',
433433
'OCP\\Files\\Lock\\OwnerLockedException' => $baseDir . '/lib/public/Files/Lock/OwnerLockedException.php',
434+
'OCP\\Files\\Mount\\Event\\MountAddedEvent' => $baseDir . '/lib/public/Files/Mount/Event/MountAddedEvent.php',
435+
'OCP\\Files\\Mount\\Event\\MountMovedEvent' => $baseDir . '/lib/public/Files/Mount/Event/MountMovedEvent.php',
436+
'OCP\\Files\\Mount\\Event\\MountRemovedEvent' => $baseDir . '/lib/public/Files/Mount/Event/MountRemovedEvent.php',
434437
'OCP\\Files\\Mount\\IMountManager' => $baseDir . '/lib/public/Files/Mount/IMountManager.php',
435438
'OCP\\Files\\Mount\\IMountPoint' => $baseDir . '/lib/public/Files/Mount/IMountPoint.php',
436439
'OCP\\Files\\Mount\\IMovableMount' => $baseDir . '/lib/public/Files/Mount/IMovableMount.php',

lib/composer/composer/autoload_static.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
472472
'OCP\\Files\\Lock\\LockContext' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/LockContext.php',
473473
'OCP\\Files\\Lock\\NoLockProviderException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/NoLockProviderException.php',
474474
'OCP\\Files\\Lock\\OwnerLockedException' => __DIR__ . '/../../..' . '/lib/public/Files/Lock/OwnerLockedException.php',
475+
'OCP\\Files\\Mount\\Event\\MountAddedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/Event/MountAddedEvent.php',
476+
'OCP\\Files\\Mount\\Event\\MountMovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/Event/MountMovedEvent.php',
477+
'OCP\\Files\\Mount\\Event\\MountRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/Event/MountRemovedEvent.php',
475478
'OCP\\Files\\Mount\\IMountManager' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountManager.php',
476479
'OCP\\Files\\Mount\\IMountPoint' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMountPoint.php',
477480
'OCP\\Files\\Mount\\IMovableMount' => __DIR__ . '/../../..' . '/lib/public/Files/Mount/IMovableMount.php',

lib/private/Files/Mount/Manager.php

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
use OC\Files\SetupManager;
1313
use OC\Files\SetupManagerFactory;
1414
use OCP\Cache\CappedMemoryCache;
15+
use OCP\EventDispatcher\IEventDispatcher;
1516
use OCP\Files\Config\ICachedMountInfo;
17+
use OCP\Files\Mount\Event\MountAddedEvent;
18+
use OCP\Files\Mount\Event\MountMovedEvent;
19+
use OCP\Files\Mount\Event\MountRemovedEvent;
1620
use OCP\Files\Mount\IMountManager;
1721
use OCP\Files\Mount\IMountPoint;
1822
use OCP\Files\NotFoundException;
@@ -26,43 +30,49 @@ class Manager implements IMountManager {
2630
private CappedMemoryCache $inPathCache;
2731
private SetupManager $setupManager;
2832

29-
public function __construct(SetupManagerFactory $setupManagerFactory) {
33+
public function __construct(
34+
SetupManagerFactory $setupManagerFactory,
35+
private IEventDispatcher $eventDispatcher,
36+
) {
3037
$this->pathCache = new CappedMemoryCache();
3138
$this->inPathCache = new CappedMemoryCache();
3239
$this->setupManager = $setupManagerFactory->create($this);
3340
}
3441

35-
/**
36-
* @param IMountPoint $mount
37-
*/
38-
public function addMount(IMountPoint $mount) {
42+
public function addMount(IMountPoint $mount): void {
3943
$this->mounts[$mount->getMountPoint()] = $mount;
4044
$this->pathCache->clear();
4145
$this->inPathCache->clear();
46+
47+
$this->eventDispatcher->dispatchTyped(new MountAddedEvent($mount));
4248
}
4349

44-
/**
45-
* @param string $mountPoint
46-
*/
47-
public function removeMount(string $mountPoint) {
50+
public function removeMount(string $mountPoint): void {
4851
$mountPoint = Filesystem::normalizePath($mountPoint);
4952
if (\strlen($mountPoint) > 1) {
5053
$mountPoint .= '/';
5154
}
52-
unset($this->mounts[$mountPoint]);
53-
$this->pathCache->clear();
54-
$this->inPathCache->clear();
55+
56+
$mount = $this->mounts[$mountPoint] ?? null;
57+
if ($mount !== null) {
58+
unset($this->mounts[$mountPoint]);
59+
$this->pathCache->clear();
60+
$this->inPathCache->clear();
61+
62+
$this->eventDispatcher->dispatchTyped(new MountRemovedEvent($mount));
63+
}
5564
}
5665

57-
/**
58-
* @param string $mountPoint
59-
* @param string $target
60-
*/
61-
public function moveMount(string $mountPoint, string $target) {
62-
$this->mounts[$target] = $this->mounts[$mountPoint];
63-
unset($this->mounts[$mountPoint]);
64-
$this->pathCache->clear();
65-
$this->inPathCache->clear();
66+
public function moveMount(string $mountPoint, string $target): void {
67+
$mount = $this->mounts[$mountPoint] ?? null;
68+
if ($mount !== null) {
69+
$this->mounts[$target] = $mount;
70+
unset($this->mounts[$mountPoint]);
71+
$this->pathCache->clear();
72+
$this->inPathCache->clear();
73+
74+
$this->eventDispatcher->dispatchTyped(new MountMovedEvent($mount, $mountPoint, $target));
75+
}
6676
}
6777

6878
/**
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Mount\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Mount\IMountPoint;
14+
15+
/**
16+
* Event emitted when a mount was added.
17+
*
18+
* @since 31.0.0
19+
*/
20+
class MountAddedEvent extends Event {
21+
public function __construct(
22+
public readonly IMountPoint $mountPoint,
23+
) {
24+
parent::__construct();
25+
}
26+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Mount\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Mount\IMountPoint;
14+
15+
/**
16+
* Event emitted when a mount was moved.
17+
*
18+
* @since 31.0.0
19+
*/
20+
class MountMovedEvent extends Event {
21+
public function __construct(
22+
public readonly IMountPoint $mountPoint,
23+
public readonly string $oldPath,
24+
public readonly string $newPath,
25+
) {
26+
parent::__construct();
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Mount\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Mount\IMountPoint;
14+
15+
/**
16+
* Event emitted when a mount was removed.
17+
*
18+
* @since 31.0.0
19+
*/
20+
class MountRemovedEvent extends Event {
21+
public function __construct(
22+
public readonly IMountPoint $mountPoint,
23+
) {
24+
parent::__construct();
25+
}
26+
}

tests/lib/Files/Mount/ManagerTest.php

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,65 @@
77

88
namespace Test\Files\Mount;
99

10+
use OC\Files\Mount\Manager;
11+
use OC\Files\Mount\MountPoint;
1012
use OC\Files\SetupManagerFactory;
1113
use OC\Files\Storage\Temporary;
14+
use OCP\EventDispatcher\IEventDispatcher;
15+
use OCP\Files\Mount\Event\MountAddedEvent;
16+
use OCP\Files\Mount\Event\MountMovedEvent;
17+
use OCP\Files\Mount\Event\MountRemovedEvent;
18+
use Test\TestCase;
1219

1320
class LongId extends Temporary {
1421
public function getId(): string {
1522
return 'long:' . str_repeat('foo', 50) . parent::getId();
1623
}
1724
}
1825

19-
class ManagerTest extends \Test\TestCase {
20-
/**
21-
* @var \OC\Files\Mount\Manager
22-
*/
23-
private $manager;
26+
class ManagerTest extends TestCase {
27+
private IEventDispatcher $eventDispatcher;
28+
private Manager $manager;
2429

2530
protected function setUp(): void {
2631
parent::setUp();
27-
$this->manager = new \OC\Files\Mount\Manager($this->createMock(SetupManagerFactory::class));
32+
33+
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
34+
35+
$this->manager = new Manager(
36+
$this->createMock(SetupManagerFactory::class),
37+
$this->eventDispatcher,
38+
);
2839
}
2940

3041
public function testFind(): void {
31-
$rootMount = new \OC\Files\Mount\MountPoint(new Temporary([]), '/');
42+
$rootMount = new MountPoint(new Temporary([]), '/');
3243
$this->manager->addMount($rootMount);
3344
$this->assertEquals($rootMount, $this->manager->find('/'));
3445
$this->assertEquals($rootMount, $this->manager->find('/foo/bar'));
3546

3647
$storage = new Temporary([]);
37-
$mount1 = new \OC\Files\Mount\MountPoint($storage, '/foo');
48+
$mount1 = new MountPoint($storage, '/foo');
3849
$this->manager->addMount($mount1);
3950
$this->assertEquals($rootMount, $this->manager->find('/'));
4051
$this->assertEquals($mount1, $this->manager->find('/foo/bar'));
4152

4253
$this->assertEquals(1, count($this->manager->findIn('/')));
43-
$mount2 = new \OC\Files\Mount\MountPoint(new Temporary([]), '/bar');
54+
$mount2 = new MountPoint(new Temporary([]), '/bar');
4455
$this->manager->addMount($mount2);
4556
$this->assertEquals(2, count($this->manager->findIn('/')));
4657

4758
$id = $mount1->getStorageId();
4859
$this->assertEquals([$mount1], $this->manager->findByStorageId($id));
4960

50-
$mount3 = new \OC\Files\Mount\MountPoint($storage, '/foo/bar');
61+
$mount3 = new MountPoint($storage, '/foo/bar');
5162
$this->manager->addMount($mount3);
5263
$this->assertEquals([$mount1, $mount3], $this->manager->findByStorageId($id));
5364
}
5465

5566
public function testLong(): void {
5667
$storage = new LongId([]);
57-
$mount = new \OC\Files\Mount\MountPoint($storage, '/foo');
68+
$mount = new MountPoint($storage, '/foo');
5869
$this->manager->addMount($mount);
5970

6071
$id = $mount->getStorageId();
@@ -63,4 +74,37 @@ public function testLong(): void {
6374
$this->assertEquals([$mount], $this->manager->findByStorageId($storageId));
6475
$this->assertEquals([$mount], $this->manager->findByStorageId(md5($storageId)));
6576
}
77+
78+
public function testAddMountEvent(): void {
79+
$this->eventDispatcher
80+
->expects($this->once())
81+
->method('dispatchTyped')
82+
->with($this->callback(fn (MountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/foo/'));
83+
84+
$this->manager->addMount(new MountPoint(new Temporary([]), '/foo'));
85+
}
86+
87+
public function testRemoveMountEvent(): void {
88+
$this->eventDispatcher
89+
->expects($this->exactly(2))
90+
->method('dispatchTyped')
91+
->with($this->callback(fn (MountAddedEvent|MountRemovedEvent $event) => $event->mountPoint->getMountPoint() === '/foo/'));
92+
93+
$this->manager->addMount(new MountPoint(new Temporary([]), '/foo'));
94+
$this->manager->removeMount('/foo');
95+
}
96+
97+
public function testMoveMountEvent(): void {
98+
$this->eventDispatcher
99+
->expects($this->exactly(2))
100+
->method('dispatchTyped')
101+
->with($this->callback(fn (MountAddedEvent|MountMovedEvent $event) =>
102+
($event instanceof MountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/')
103+
// The getMountPoint() still returns the old path in this test because it is updated outside the MountManager before calling moveMount().
104+
|| ($event instanceof MountMovedEvent && $event->mountPoint->getMountPoint() === '/foo/' && $event->oldPath === '/foo/' && $event->newPath === '/bar/'))
105+
);
106+
107+
$this->manager->addMount(new MountPoint(new Temporary([]), '/foo'));
108+
$this->manager->moveMount('/foo/', '/bar/');
109+
}
66110
}

0 commit comments

Comments
 (0)