fix(restore): files with brackets in name (#981)

This commit is contained in:
Nico
2026-06-14 15:22:51 +02:00
committed by GitHub
parent ab781837f4
commit 3c37360bca
2 changed files with 29 additions and 2 deletions

View File

@@ -143,6 +143,31 @@ describe("restore command", () => {
expect(getOptionValues("--include")).toEqual(["backup.20260301-233001.7z"]);
});
test("escapes selected file brackets when restoring from a non-root target", async () => {
const { getRestoreArg, getOptionValues } = setup();
await runRestore(
config,
"snapshot-bracket-file",
"/tmp/restore-target",
{
organizationId: "org-1",
include: [
"/media/A Very English Scandal (2018) [tmdbid-79299]/Season 01/A Very English Scandal (2018) - S01E01 - Folge 1 [1080p H264 UND AAC] chapters.xml",
],
selectedItemKind: "file",
},
mockDeps,
);
expect(getRestoreArg()).toBe(
"snapshot-bracket-file:/media/A Very English Scandal (2018) [tmdbid-79299]/Season 01",
);
expect(getOptionValues("--include")).toEqual([
"A Very English Scandal (2018) - S01E01 - Folge 1 \\[1080p H264 UND AAC\\] chapters.xml",
]);
});
test("treats flag-like snapshot IDs as positional restore args", async () => {
const { getArgs, getRestoreArg } = setup();

View File

@@ -22,6 +22,8 @@ class ResticRestoreCommandError extends Data.TaggedError("ResticRestoreCommandEr
message: string;
}> {}
const escapeResticIncludePattern = (pattern: string) => pattern.replace(/[\\*?[\]]/g, "\\$&");
export const restore = (
config: RepositoryConfig,
snapshotId: string,
@@ -64,7 +66,7 @@ export const restore = (
if (options.include?.length) {
if (target === "/") {
for (const pattern of options.include) {
args.push("--include", pattern);
args.push("--include", escapeResticIncludePattern(pattern));
}
} else {
const strippedIncludes = options.include.map((pattern) =>
@@ -76,7 +78,7 @@ export const restore = (
if (!includesCoverRestoreRoot) {
for (const pattern of strippedIncludes) {
args.push("--include", pattern);
args.push("--include", escapeResticIncludePattern(pattern));
}
}
}