Skip to content

Commit 7888d21

Browse files
committed
Move DatabaseResolver to separate file
1 parent 67983c6 commit 7888d21

3 files changed

Lines changed: 150 additions & 146 deletions

File tree

extensions/ql-vscode/src/databases/local-databases.ts

Lines changed: 4 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
import { pathExists, remove } from "fs-extra";
2-
import { glob } from "glob";
3-
import { join, basename, resolve, dirname, extname } from "path";
1+
import { remove } from "fs-extra";
2+
import { join, dirname, extname } from "path";
43
import * as vscode from "vscode";
54
import * as cli from "../codeql-cli/cli";
65
import { ExtensionContext } from "vscode";
76
import {
8-
showAndLogWarningMessage,
9-
showAndLogInformationMessage,
107
showAndLogExceptionWithTelemetry,
118
isFolderAlreadyInWorkspace,
129
getFirstWorkspaceFolder,
1310
showNeverAskAgainDialog,
1411
} from "../helpers";
1512
import { ProgressCallback, withProgress } from "../common/vscode/progress";
16-
import { encodeArchiveBasePath } from "../common/vscode/archive-filesystem-provider";
1713
import { DisposableObject } from "../pure/disposable-object";
1814
import { Logger, extLogger } from "../common";
1915
import { asError, getErrorMessage } from "../pure/helpers-pure";
@@ -35,14 +31,11 @@ import {
3531
PersistedDatabaseItem,
3632
} from "./local-databases/database-item";
3733
import { DatabaseItemImpl } from "./local-databases/database-item-impl";
38-
import {
39-
DatabaseContents,
40-
DatabaseContentsWithDbScheme,
41-
DatabaseKind,
42-
} from "./local-databases/database-contents";
34+
import { DatabaseResolver } from "./local-databases/database-resolver";
4335

4436
export { DatabaseContentsWithDbScheme } from "./local-databases/database-contents";
4537
export { DatabaseItem } from "./local-databases/database-item";
38+
export { DatabaseResolver } from "./local-databases/database-resolver";
4639

4740
/**
4841
* databases.ts
@@ -66,136 +59,6 @@ const CURRENT_DB = "currentDatabase";
6659
*/
6760
const DB_LIST = "databaseList";
6861

69-
/**
70-
* An error thrown when we cannot find a valid database in a putative
71-
* database directory.
72-
*/
73-
class InvalidDatabaseError extends Error {}
74-
75-
async function findDataset(parentDirectory: string): Promise<vscode.Uri> {
76-
/*
77-
* Look directly in the root
78-
*/
79-
let dbRelativePaths = await glob("db-*/", {
80-
cwd: parentDirectory,
81-
});
82-
83-
if (dbRelativePaths.length === 0) {
84-
/*
85-
* Check If they are in the old location
86-
*/
87-
dbRelativePaths = await glob("working/db-*/", {
88-
cwd: parentDirectory,
89-
});
90-
}
91-
if (dbRelativePaths.length === 0) {
92-
throw new InvalidDatabaseError(
93-
`'${parentDirectory}' does not contain a dataset directory.`,
94-
);
95-
}
96-
97-
const dbAbsolutePath = join(parentDirectory, dbRelativePaths[0]);
98-
if (dbRelativePaths.length > 1) {
99-
void showAndLogWarningMessage(
100-
`Found multiple dataset directories in database, using '${dbAbsolutePath}'.`,
101-
);
102-
}
103-
104-
return vscode.Uri.file(dbAbsolutePath);
105-
}
106-
107-
// exported for testing
108-
export async function findSourceArchive(
109-
databasePath: string,
110-
): Promise<vscode.Uri | undefined> {
111-
const relativePaths = ["src", "output/src_archive"];
112-
113-
for (const relativePath of relativePaths) {
114-
const basePath = join(databasePath, relativePath);
115-
const zipPath = `${basePath}.zip`;
116-
117-
// Prefer using a zip archive over a directory.
118-
if (await pathExists(zipPath)) {
119-
return encodeArchiveBasePath(zipPath);
120-
} else if (await pathExists(basePath)) {
121-
return vscode.Uri.file(basePath);
122-
}
123-
}
124-
125-
void showAndLogInformationMessage(
126-
`Could not find source archive for database '${databasePath}'. Assuming paths are absolute.`,
127-
);
128-
return undefined;
129-
}
130-
131-
/** Gets the relative paths of all `.dbscheme` files in the given directory. */
132-
async function getDbSchemeFiles(dbDirectory: string): Promise<string[]> {
133-
return await glob("*.dbscheme", { cwd: dbDirectory });
134-
}
135-
136-
export class DatabaseResolver {
137-
public static async resolveDatabaseContents(
138-
uri: vscode.Uri,
139-
): Promise<DatabaseContentsWithDbScheme> {
140-
if (uri.scheme !== "file") {
141-
throw new Error(
142-
`Database URI scheme '${uri.scheme}' not supported; only 'file' URIs are supported.`,
143-
);
144-
}
145-
const databasePath = uri.fsPath;
146-
if (!(await pathExists(databasePath))) {
147-
throw new InvalidDatabaseError(
148-
`Database '${databasePath}' does not exist.`,
149-
);
150-
}
151-
152-
const contents = await this.resolveDatabase(databasePath);
153-
154-
if (contents === undefined) {
155-
throw new InvalidDatabaseError(
156-
`'${databasePath}' is not a valid database.`,
157-
);
158-
}
159-
160-
// Look for a single dbscheme file within the database.
161-
// This should be found in the dataset directory, regardless of the form of database.
162-
const dbPath = contents.datasetUri.fsPath;
163-
const dbSchemeFiles = await getDbSchemeFiles(dbPath);
164-
if (dbSchemeFiles.length === 0) {
165-
throw new InvalidDatabaseError(
166-
`Database '${databasePath}' does not contain a CodeQL dbscheme under '${dbPath}'.`,
167-
);
168-
} else if (dbSchemeFiles.length > 1) {
169-
throw new InvalidDatabaseError(
170-
`Database '${databasePath}' contains multiple CodeQL dbschemes under '${dbPath}'.`,
171-
);
172-
} else {
173-
const dbSchemeUri = vscode.Uri.file(resolve(dbPath, dbSchemeFiles[0]));
174-
return {
175-
...contents,
176-
dbSchemeUri,
177-
};
178-
}
179-
}
180-
181-
public static async resolveDatabase(
182-
databasePath: string,
183-
): Promise<DatabaseContents> {
184-
const name = basename(databasePath);
185-
186-
// Look for dataset and source archive.
187-
const datasetUri = await findDataset(databasePath);
188-
const sourceArchiveUri = await findSourceArchive(databasePath);
189-
190-
return {
191-
kind: DatabaseKind.Database,
192-
name,
193-
datasetUri,
194-
sourceArchiveUri,
195-
};
196-
}
197-
}
198-
19962
export enum DatabaseEventKind {
20063
Add = "Add",
20164
Remove = "Remove",

extensions/ql-vscode/src/databases/local-databases/database-item-impl.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,9 @@ import { DatabaseItem, PersistedDatabaseItem } from "./database-item";
1414
import { isLikelyDatabaseRoot } from "../../helpers";
1515
import { stat } from "fs-extra";
1616
import { pathsEqual } from "../../pure/files";
17-
import {
18-
DatabaseChangedEvent,
19-
DatabaseEventKind,
20-
DatabaseResolver,
21-
} from "../local-databases";
17+
import { DatabaseChangedEvent, DatabaseEventKind } from "../local-databases";
2218
import { DatabaseContents } from "./database-contents";
19+
import { DatabaseResolver } from "./database-resolver";
2320

2421
export class DatabaseItemImpl implements DatabaseItem {
2522
private _error: Error | undefined = undefined;
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import vscode from "vscode";
2+
import { pathExists } from "fs-extra";
3+
import { basename, join, resolve } from "path";
4+
import {
5+
DatabaseContents,
6+
DatabaseContentsWithDbScheme,
7+
DatabaseKind,
8+
} from "./database-contents";
9+
import { glob } from "glob";
10+
import {
11+
showAndLogInformationMessage,
12+
showAndLogWarningMessage,
13+
} from "../../helpers";
14+
import { encodeArchiveBasePath } from "../../common/vscode/archive-filesystem-provider";
15+
16+
export class DatabaseResolver {
17+
public static async resolveDatabaseContents(
18+
uri: vscode.Uri,
19+
): Promise<DatabaseContentsWithDbScheme> {
20+
if (uri.scheme !== "file") {
21+
throw new Error(
22+
`Database URI scheme '${uri.scheme}' not supported; only 'file' URIs are supported.`,
23+
);
24+
}
25+
const databasePath = uri.fsPath;
26+
if (!(await pathExists(databasePath))) {
27+
throw new InvalidDatabaseError(
28+
`Database '${databasePath}' does not exist.`,
29+
);
30+
}
31+
32+
const contents = await this.resolveDatabase(databasePath);
33+
34+
if (contents === undefined) {
35+
throw new InvalidDatabaseError(
36+
`'${databasePath}' is not a valid database.`,
37+
);
38+
}
39+
40+
// Look for a single dbscheme file within the database.
41+
// This should be found in the dataset directory, regardless of the form of database.
42+
const dbPath = contents.datasetUri.fsPath;
43+
const dbSchemeFiles = await getDbSchemeFiles(dbPath);
44+
if (dbSchemeFiles.length === 0) {
45+
throw new InvalidDatabaseError(
46+
`Database '${databasePath}' does not contain a CodeQL dbscheme under '${dbPath}'.`,
47+
);
48+
} else if (dbSchemeFiles.length > 1) {
49+
throw new InvalidDatabaseError(
50+
`Database '${databasePath}' contains multiple CodeQL dbschemes under '${dbPath}'.`,
51+
);
52+
} else {
53+
const dbSchemeUri = vscode.Uri.file(resolve(dbPath, dbSchemeFiles[0]));
54+
return {
55+
...contents,
56+
dbSchemeUri,
57+
};
58+
}
59+
}
60+
61+
public static async resolveDatabase(
62+
databasePath: string,
63+
): Promise<DatabaseContents> {
64+
const name = basename(databasePath);
65+
66+
// Look for dataset and source archive.
67+
const datasetUri = await findDataset(databasePath);
68+
const sourceArchiveUri = await findSourceArchive(databasePath);
69+
70+
return {
71+
kind: DatabaseKind.Database,
72+
name,
73+
datasetUri,
74+
sourceArchiveUri,
75+
};
76+
}
77+
}
78+
79+
/**
80+
* An error thrown when we cannot find a valid database in a putative
81+
* database directory.
82+
*/
83+
class InvalidDatabaseError extends Error {}
84+
85+
async function findDataset(parentDirectory: string): Promise<vscode.Uri> {
86+
/*
87+
* Look directly in the root
88+
*/
89+
let dbRelativePaths = await glob("db-*/", {
90+
cwd: parentDirectory,
91+
});
92+
93+
if (dbRelativePaths.length === 0) {
94+
/*
95+
* Check If they are in the old location
96+
*/
97+
dbRelativePaths = await glob("working/db-*/", {
98+
cwd: parentDirectory,
99+
});
100+
}
101+
if (dbRelativePaths.length === 0) {
102+
throw new InvalidDatabaseError(
103+
`'${parentDirectory}' does not contain a dataset directory.`,
104+
);
105+
}
106+
107+
const dbAbsolutePath = join(parentDirectory, dbRelativePaths[0]);
108+
if (dbRelativePaths.length > 1) {
109+
void showAndLogWarningMessage(
110+
`Found multiple dataset directories in database, using '${dbAbsolutePath}'.`,
111+
);
112+
}
113+
114+
return vscode.Uri.file(dbAbsolutePath);
115+
}
116+
117+
/** Gets the relative paths of all `.dbscheme` files in the given directory. */
118+
async function getDbSchemeFiles(dbDirectory: string): Promise<string[]> {
119+
return await glob("*.dbscheme", { cwd: dbDirectory });
120+
}
121+
122+
// exported for testing
123+
export async function findSourceArchive(
124+
databasePath: string,
125+
): Promise<vscode.Uri | undefined> {
126+
const relativePaths = ["src", "output/src_archive"];
127+
128+
for (const relativePath of relativePaths) {
129+
const basePath = join(databasePath, relativePath);
130+
const zipPath = `${basePath}.zip`;
131+
132+
// Prefer using a zip archive over a directory.
133+
if (await pathExists(zipPath)) {
134+
return encodeArchiveBasePath(zipPath);
135+
} else if (await pathExists(basePath)) {
136+
return vscode.Uri.file(basePath);
137+
}
138+
}
139+
140+
void showAndLogInformationMessage(
141+
`Could not find source archive for database '${databasePath}'. Assuming paths are absolute.`,
142+
);
143+
return undefined;
144+
}

0 commit comments

Comments
 (0)