Fix folder deletion (#140)
This commit is contained in:
parent
aa73a5d718
commit
1ddba47b80
9 changed files with 69 additions and 25 deletions
|
|
@ -29,8 +29,10 @@ class MockDatabase implements Partial<Database> {
|
|||
class FakeFileSystemOperations implements FileSystemOperations {
|
||||
public readonly names = new Set<string>();
|
||||
|
||||
public async listAllFiles(): Promise<RelativePath[]> {
|
||||
throw new Error("Method not implemented.");
|
||||
public async listFilesRecursively(
|
||||
_root: RelativePath | undefined
|
||||
): Promise<RelativePath[]> {
|
||||
return ["file.md"];
|
||||
}
|
||||
public async read(_path: RelativePath): Promise<Uint8Array> {
|
||||
throw new Error("Method not implemented.");
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { SafeFileSystemOperations } from "./safe-filesystem-operations";
|
|||
import type { TextWithCursors } from "reconcile-text";
|
||||
import { isBinary, reconcile } from "reconcile-text";
|
||||
import { isFileTypeMergable } from "../utils/is-file-type-mergable";
|
||||
|
||||
export class FileOperations {
|
||||
private static readonly PARENTHESES_REGEX = / \((\d+)\)$/;
|
||||
private readonly fs: SafeFileSystemOperations;
|
||||
|
|
@ -18,8 +19,22 @@ export class FileOperations {
|
|||
this.fs = new SafeFileSystemOperations(fs, logger);
|
||||
}
|
||||
|
||||
public async listAllFiles(): Promise<RelativePath[]> {
|
||||
return this.fs.listAllFiles();
|
||||
private static getParentDirAndFile(
|
||||
path: RelativePath
|
||||
): [RelativePath, RelativePath] {
|
||||
const pathParts = path.split("/");
|
||||
const fileName = pathParts.pop();
|
||||
if (fileName == "" || fileName == null) {
|
||||
throw new Error(`Path '${path}' cannot be empty`);
|
||||
}
|
||||
|
||||
return [pathParts.join("/"), fileName];
|
||||
}
|
||||
|
||||
public async listFilesRecursively(
|
||||
root: RelativePath | undefined = undefined
|
||||
): Promise<RelativePath[]> {
|
||||
return this.fs.listFilesRecursively(root);
|
||||
}
|
||||
|
||||
public async read(path: RelativePath): Promise<Uint8Array> {
|
||||
|
|
@ -120,7 +135,8 @@ export class FileOperations {
|
|||
|
||||
public async delete(path: RelativePath): Promise<void> {
|
||||
if (await this.exists(path)) {
|
||||
return this.fs.delete(path);
|
||||
await this.fs.delete(path);
|
||||
await this.deletingEmptyParentDirectoriesOfDeletedFile(path);
|
||||
} else {
|
||||
this.logger.debug(`No need to delete '${path}', it doesn't exist`);
|
||||
}
|
||||
|
|
@ -146,6 +162,31 @@ export class FileOperations {
|
|||
|
||||
this.database.move(oldPath, newPath);
|
||||
await this.fs.rename(oldPath, newPath);
|
||||
await this.deletingEmptyParentDirectoriesOfDeletedFile(oldPath);
|
||||
}
|
||||
|
||||
private async deletingEmptyParentDirectoriesOfDeletedFile(
|
||||
path: RelativePath
|
||||
): Promise<void> {
|
||||
let directory = path;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
while (true) {
|
||||
[directory] = FileOperations.getParentDirAndFile(directory);
|
||||
if (directory.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const remainingContent =
|
||||
await this.fs.listFilesRecursively(directory);
|
||||
if (remainingContent.length === 0) {
|
||||
this.logger.debug(
|
||||
`Folder (${directory}) is now empty, deleting`
|
||||
);
|
||||
await this.fs.delete(directory);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fromNativeLineEndings(content: Uint8Array): Uint8Array {
|
||||
|
|
@ -184,13 +225,9 @@ export class FileOperations {
|
|||
}
|
||||
|
||||
private async deconflictPath(path: RelativePath): Promise<RelativePath> {
|
||||
const pathParts = path.split("/");
|
||||
const fileName = pathParts.pop();
|
||||
if (fileName == "" || fileName == null) {
|
||||
throw new Error(`Path '${path}' cannot be empty`);
|
||||
}
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [directory, fileName] = FileOperations.getParentDirAndFile(path);
|
||||
|
||||
let directory = pathParts.join("/");
|
||||
if (directory) {
|
||||
directory += "/";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@ import type { RelativePath } from "../persistence/database";
|
|||
import type { TextWithCursors } from "reconcile-text";
|
||||
|
||||
export interface FileSystemOperations {
|
||||
// List all files that should be synced.
|
||||
listAllFiles: () => Promise<RelativePath[]>;
|
||||
// List all files under root that should be synced. If root is undefined, return every file.
|
||||
listFilesRecursively: (
|
||||
root: RelativePath | undefined
|
||||
) => Promise<RelativePath[]>;
|
||||
|
||||
// Read the content of a file.
|
||||
read: (path: RelativePath) => Promise<Uint8Array>;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@ export class SafeFileSystemOperations implements FileSystemOperations {
|
|||
this.locks = new Locks(logger);
|
||||
}
|
||||
|
||||
public async listAllFiles(): Promise<RelativePath[]> {
|
||||
public async listFilesRecursively(
|
||||
root: RelativePath | undefined
|
||||
): Promise<RelativePath[]> {
|
||||
this.logger.debug("Listing all files");
|
||||
const result = await this.fs.listAllFiles();
|
||||
const result = await this.fs.listFilesRecursively(root);
|
||||
this.logger.debug(`Listed ${result.length} files`);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ export class Syncer {
|
|||
private async internalScheduleSyncForOfflineChanges(): Promise<void> {
|
||||
await this.createFakeDocumentsFromRemoteState();
|
||||
|
||||
const allLocalFiles = await this.operations.listAllFiles();
|
||||
const allLocalFiles = await this.operations.listFilesRecursively();
|
||||
|
||||
let locallyPossiblyDeletedFiles: DocumentRecord[] = [];
|
||||
|
||||
|
|
@ -431,7 +431,7 @@ export class Syncer {
|
|||
}
|
||||
|
||||
const [allLocalFiles, remote] = await Promise.all([
|
||||
this.operations.listAllFiles(),
|
||||
this.operations.listFilesRecursively(),
|
||||
this.syncQueue.add(async () => this.syncService.getAll())
|
||||
]);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue