Skip to content

Commit 2c35a97

Browse files
committed
Make database storage paths more unique
1 parent dbd5078 commit 2c35a97

1 file changed

Lines changed: 46 additions & 11 deletions

File tree

extensions/ql-vscode/src/databases/database-fetcher.ts

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from "fs-extra";
1616
import { basename, join } from "path";
1717
import type { Octokit } from "@octokit/rest";
18+
import { nanoid } from "nanoid";
1819

1920
import type { DatabaseManager, DatabaseItem } from "./local-databases";
2021
import { tmpDir } from "../tmp-dir";
@@ -365,7 +366,11 @@ async function databaseArchiveFetcher(
365366
throw new Error("No storage path specified.");
366367
}
367368
await ensureDir(storagePath);
368-
const unzipPath = await getStorageFolder(storagePath, databaseUrl);
369+
const unzipPath = await getStorageFolder(
370+
storagePath,
371+
databaseUrl,
372+
nameOverride,
373+
);
369374

370375
if (isFile(databaseUrl)) {
371376
await readAndUnzip(databaseUrl, unzipPath, cli, progress);
@@ -408,16 +413,41 @@ async function databaseArchiveFetcher(
408413
}
409414
}
410415

411-
async function getStorageFolder(storagePath: string, urlStr: string) {
412-
// we need to generate a folder name for the unzipped archive,
413-
// this needs to be human readable since we may use this name as the initial
414-
// name for the database
415-
const url = Uri.parse(urlStr);
416-
// MacOS has a max filename length of 255
417-
// and remove a few extra chars in case we need to add a counter at the end.
418-
let lastName = basename(url.path).substring(0, 250);
419-
if (lastName.endsWith(".zip")) {
420-
lastName = lastName.substring(0, lastName.length - 4);
416+
async function getStorageFolder(
417+
storagePath: string,
418+
urlStr: string,
419+
nameOverrride?: string,
420+
) {
421+
let lastName: string;
422+
423+
if (nameOverrride) {
424+
// Lowercase everything
425+
let name = nameOverrride.toLowerCase();
426+
427+
// Replace all spaces, dots, underscores, and forward slashes with hyphens
428+
name = name.replaceAll(/[\s._/]+/g, "-");
429+
430+
// Replace all characters which are not allowed by empty strings
431+
name = name.replaceAll(/[^a-z0-9-]/g, "");
432+
433+
// Remove any leading or trailing hyphens
434+
name = name.replaceAll(/^-|-$/g, "");
435+
436+
// Remove any duplicate hyphens
437+
name = name.replaceAll(/-{2,}/g, "-");
438+
439+
lastName = name;
440+
} else {
441+
// we need to generate a folder name for the unzipped archive,
442+
// this needs to be human readable since we may use this name as the initial
443+
// name for the database
444+
const url = Uri.parse(urlStr);
445+
// MacOS has a max filename length of 255
446+
// and remove a few extra chars in case we need to add a counter at the end.
447+
lastName = basename(url.path).substring(0, 250);
448+
if (lastName.endsWith(".zip")) {
449+
lastName = lastName.substring(0, lastName.length - 4);
450+
}
421451
}
422452

423453
const realpath = await fs_realpath(storagePath);
@@ -429,6 +459,11 @@ async function getStorageFolder(storagePath: string, urlStr: string) {
429459
counter++;
430460
folderName = join(realpath, `${lastName}-${counter}`);
431461
if (counter > 100) {
462+
// If there are more than 100 similarly named databases,
463+
// give up on using a counter and use a random string instead.
464+
folderName = join(realpath, `${lastName}-${nanoid()}`);
465+
}
466+
if (counter > 200) {
432467
throw new Error("Could not find a unique name for downloaded database.");
433468
}
434469
}

0 commit comments

Comments
 (0)