Skip to content

Commit 6db5148

Browse files
authored
Merge branch 'master' into jcreed/jump-to-def-release
2 parents a98e3bc + 0e4c3be commit 6db5148

File tree

7 files changed

+201
-42
lines changed

7 files changed

+201
-42
lines changed

extensions/ql-vscode/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- Enable 'Go to Definition' and 'Go to References' on source archive
66
files in CodeQL databases. This is handled by a CodeQL query.
77

8-
## 1.1.5
8+
## 1.1.5 - 15 May 2020
99

1010
- Links in results are no longer underlined and monospaced.
1111
- Add the ability to choose a database either from an archive, a folder, or from the internet.

extensions/ql-vscode/README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,11 @@ While you can use the [CodeQL CLI to create your own databases](https://help.sem
6666
1. Find a project you're interested in and display the **Integrations** tab (for example, [Apache Kafka](https://lgtm.com/projects/g/apache/kafka/ci/)).
6767
1. Scroll to the **CodeQL databases for local analysis** section at the bottom of the page.
6868
1. Download databases for the languages that you want to explore.
69-
1. Unzip the databases.
7069
1. For each database that you want to import:
71-
1. In the VS Code sidebar, go to **CodeQL** > **Databases** and click **+**.
72-
1. Browse to the unzipped database folder (the parent folder that contains `db-<language>` and `src`) and select **Choose database** to add it.
70+
1. Go to the CodeQL Databases view in the sidebar. Hover over the Databases title bar and click the icon to **Choose Database from Archive**.
71+
1. Browse to the zipped database that you downloaded from LGTM.
7372

74-
When the import is complete, each CodeQL database is displayed in the CodeQL sidebar under **Databases**.
73+
Once you've added a CodeQL database, it is displayed in the Databases view.
7574

7675
### Running a query
7776

extensions/ql-vscode/package.json

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"description": "CodeQL for Visual Studio Code",
55
"author": "GitHub",
66
"private": true,
7-
"version": "1.1.5",
7+
"version": "1.1.6",
88
"publisher": "GitHub",
99
"license": "MIT",
1010
"icon": "media/VS-marketplace-CodeQL-icon.png",
@@ -27,11 +27,13 @@
2727
"onView:codeQLQueryHistory",
2828
"onView:test-explorer",
2929
"onCommand:codeQL.checkForUpdatesToCLI",
30+
"onCommand:codeQLDatabases.chooseDatabaseFolder",
31+
"onCommand:codeQLDatabases.chooseDatabaseArchive",
32+
"onCommand:codeQLDatabases.chooseDatabaseInternet",
33+
"onCommand:codeQL.setCurrentDatabase",
3034
"onCommand:codeQL.chooseDatabaseFolder",
3135
"onCommand:codeQL.chooseDatabaseArchive",
3236
"onCommand:codeQL.chooseDatabaseInternet",
33-
"onCommand:codeQL.setCurrentDatabase",
34-
"onCommand:codeQL.downloadDatabase",
3537
"onCommand:codeQLDatabases.chooseDatabase",
3638
"onCommand:codeQLDatabases.setCurrentDatabase",
3739
"onCommand:codeQL.quickQuery",
@@ -175,24 +177,24 @@
175177
"title": "CodeQL: Quick Query"
176178
},
177179
{
178-
"command": "codeQL.chooseDatabaseFolder",
180+
"command": "codeQLDatabases.chooseDatabaseFolder",
179181
"title": "Choose Database from Folder",
180182
"icon": {
181183
"light": "media/light/folder-opened-plus.svg",
182184
"dark": "media/dark/folder-opened-plus.svg"
183185
}
184186
},
185187
{
186-
"command": "codeQL.chooseDatabaseArchive",
188+
"command": "codeQLDatabases.chooseDatabaseArchive",
187189
"title": "Choose Database from Archive",
188190
"icon": {
189191
"light": "media/light/archive-plus.svg",
190192
"dark": "media/dark/archive-plus.svg"
191193
}
192194
},
193195
{
194-
"command": "codeQL.chooseDatabaseInternet",
195-
"title": "Download database",
196+
"command": "codeQLDatabases.chooseDatabaseInternet",
197+
"title": "Download Database",
196198
"icon": {
197199
"light": "media/light/cloud-download.svg",
198200
"dark": "media/dark/cloud-download.svg"
@@ -231,8 +233,16 @@
231233
"title": "Show Database Directory"
232234
},
233235
{
234-
"command": "codeQL.downloadDatabase",
235-
"title": "CodeQL: Download database"
236+
"command": "codeQL.chooseDatabaseFolder",
237+
"title": "CodeQL: Choose Database from Folder"
238+
},
239+
{
240+
"command": "codeQL.chooseDatabaseArchive",
241+
"title": "CodeQL: Choose Database from Archive"
242+
},
243+
{
244+
"command": "codeQL.chooseDatabaseInternet",
245+
"title": "CodeQL: Download Database"
236246
},
237247
{
238248
"command": "codeQLDatabases.sortByName",
@@ -312,17 +322,17 @@
312322
"group": "navigation"
313323
},
314324
{
315-
"command": "codeQL.chooseDatabaseFolder",
325+
"command": "codeQLDatabases.chooseDatabaseFolder",
316326
"when": "view == codeQLDatabases",
317327
"group": "navigation"
318328
},
319329
{
320-
"command": "codeQL.chooseDatabaseArchive",
330+
"command": "codeQLDatabases.chooseDatabaseArchive",
321331
"when": "view == codeQLDatabases",
322332
"group": "navigation"
323333
},
324334
{
325-
"command": "codeQL.chooseDatabaseInternet",
335+
"command": "codeQLDatabases.chooseDatabaseInternet",
326336
"when": "view == codeQLDatabases",
327337
"group": "navigation"
328338
}
@@ -406,10 +416,6 @@
406416
"command": "codeQL.runQuery",
407417
"when": "resourceLangId == ql && resourceExtname == .ql"
408418
},
409-
{
410-
"command": "codeQL.downloadDatabase",
411-
"when": "true"
412-
},
413419
{
414420
"command": "codeQL.quickEval",
415421
"when": "editorLangId == ql"
@@ -442,6 +448,22 @@
442448
"command": "codeQLDatabases.removeDatabase",
443449
"when": "false"
444450
},
451+
{
452+
"command": "codeQLDatabases.chooseDatabaseFolder",
453+
"when": "false"
454+
},
455+
{
456+
"command": "codeQLDatabases.chooseDatabaseArchive",
457+
"when": "false"
458+
},
459+
{
460+
"command": "codeQLDatabases.chooseDatabaseInternet",
461+
"when": "false"
462+
},
463+
{
464+
"command": "codeQLDatabases.upgradeDatabase",
465+
"when": "false"
466+
},
445467
{
446468
"command": "codeQLQueryHistory.openQuery",
447469
"when": "false"

extensions/ql-vscode/src/databaseFetcher.ts

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ import { Uri, ProgressOptions, ProgressLocation, commands, window } from "vscode
44
import * as fs from "fs-extra";
55
import * as path from "path";
66
import { DatabaseManager, DatabaseItem } from "./databases";
7-
import { ProgressCallback, showAndLogErrorMessage, withProgress } from "./helpers";
7+
import { ProgressCallback, showAndLogErrorMessage, withProgress, showAndLogInformationMessage } from "./helpers";
88

99
/**
1010
* Prompts a user to fetch a database from a remote location. Database is assumed to be an archive file.
1111
*
1212
* @param databasesManager the DatabaseManager
1313
* @param storagePath where to store the unzipped database.
1414
*/
15-
export default async function promptFetchDatabase(databasesManager: DatabaseManager, storagePath: string): Promise<DatabaseItem | undefined> {
15+
export async function promptImportInternetDatabase(databasesManager: DatabaseManager, storagePath: string): Promise<DatabaseItem | undefined> {
1616
let item: DatabaseItem | undefined = undefined;
1717

1818
try {
1919
const databaseUrl = await window.showInputBox({
2020
prompt: 'Enter URL of zipfile of database to download'
2121
});
2222
if (databaseUrl) {
23-
validateUrl(databaseUrl);
23+
validateHttpsUrl(databaseUrl);
2424

2525
const progressOptions: ProgressOptions = {
2626
location: ProgressLocation.Notification,
@@ -30,13 +30,41 @@ export default async function promptFetchDatabase(databasesManager: DatabaseMana
3030
await withProgress(progressOptions, async progress => (item = await databaseArchiveFetcher(databaseUrl, databasesManager, storagePath, progress)));
3131
commands.executeCommand('codeQLDatabases.focus');
3232
}
33+
showAndLogInformationMessage('Database downloaded and imported successfully.');
3334
} catch (e) {
3435
showAndLogErrorMessage(e.message);
3536
}
3637

3738
return item;
3839
}
3940

41+
42+
/**
43+
* Imports a database from a local archive.
44+
*
45+
* @param databaseUrl the file url of the archive to import
46+
* @param databasesManager the DatabaseManager
47+
* @param storagePath where to store the unzipped database.
48+
*/
49+
export async function importArchiveDatabase(databaseUrl: string, databasesManager: DatabaseManager, storagePath: string): Promise<DatabaseItem | undefined> {
50+
let item: DatabaseItem | undefined = undefined;
51+
try {
52+
const progressOptions: ProgressOptions = {
53+
location: ProgressLocation.Notification,
54+
title: 'Importing database from archive',
55+
cancellable: false,
56+
};
57+
await withProgress(progressOptions, async progress => (item = await databaseArchiveFetcher(databaseUrl, databasesManager, storagePath, progress)));
58+
commands.executeCommand('codeQLDatabases.focus');
59+
60+
showAndLogInformationMessage('Database unzipped and imported successfully.');
61+
} catch (e) {
62+
showAndLogErrorMessage(e.message);
63+
}
64+
return item;
65+
}
66+
67+
4068
/**
4169
* Fetches an archive database. The database might be on the internet
4270
* or in the local filesystem.
@@ -46,15 +74,15 @@ export default async function promptFetchDatabase(databasesManager: DatabaseMana
4674
* @param storagePath where to store the unzipped database.
4775
* @param progressCallback optional callback to send progress messages to
4876
*/
49-
export async function databaseArchiveFetcher(
77+
async function databaseArchiveFetcher(
5078
databaseUrl: string,
5179
databasesManager: DatabaseManager,
5280
storagePath: string,
5381
progressCallback?: ProgressCallback
5482
): Promise<DatabaseItem> {
5583
progressCallback?.({
5684
maxStep: 3,
57-
message: 'Downloading database',
85+
message: 'Getting database',
5886
step: 1
5987
});
6088
if (!storagePath) {
@@ -75,9 +103,10 @@ export async function databaseArchiveFetcher(
75103
step: 3
76104
});
77105

106+
// find the path to the database. The actual database might be in a sub-folder
78107
const dbPath = await findDirWithFile(unzipPath, '.dbinfo', 'codeql-database.yml');
79108
if (dbPath) {
80-
const item = await databasesManager.openDatabase(Uri.parse(dbPath));
109+
const item = await databasesManager.openDatabase(Uri.parse(`file:${dbPath}`));
81110
databasesManager.setCurrentDatabaseItem(item);
82111
return item;
83112
} else {
@@ -86,14 +115,21 @@ export async function databaseArchiveFetcher(
86115
}
87116

88117
async function getStorageFolder(storagePath: string, urlStr: string) {
118+
// we need to generate a folder name for the unzipped archive,
119+
// this needs to be human readable since we may use this name as the initial
120+
// name for the database
89121
const url = Uri.parse(urlStr);
90-
let lastName = path.basename(url.path).substring(0, 255);
122+
// MacOS has a max filename length of 255
123+
// and remove a few extra chars in case we need to add a counter at the end.
124+
let lastName = path.basename(url.path).substring(0, 250);
91125
if (lastName.endsWith(".zip")) {
92126
lastName = lastName.substring(0, lastName.length - 4);
93127
}
94128

95129
const realpath = await fs.realpath(storagePath);
96130
let folderName = path.join(realpath, lastName);
131+
132+
// avoid overwriting existing folders
97133
let counter = 0;
98134
while (await fs.pathExists(folderName)) {
99135
counter++;
@@ -106,7 +142,7 @@ async function getStorageFolder(storagePath: string, urlStr: string) {
106142
}
107143

108144

109-
function validateUrl(databaseUrl: string) {
145+
function validateHttpsUrl(databaseUrl: string) {
110146
let uri;
111147
try {
112148
uri = Uri.parse(databaseUrl, true);
@@ -126,7 +162,7 @@ async function readAndUnzip(databaseUrl: string, unzipPath: string) {
126162

127163
await new Promise((resolve, reject) => {
128164
// we already know this is a file scheme
129-
const databaseFile = Uri.parse(databaseUrl).path;
165+
const databaseFile = Uri.parse(databaseUrl).fsPath;
130166
const stream = fs.createReadStream(databaseFile);
131167
stream.on('error', reject);
132168
unzipStream.on('error', reject);

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { logger } from './logging';
88
import { clearCacheInDatabase, UserCancellationException } from './run-queries';
99
import * as qsClient from './queryserver-client';
1010
import { upgradeDatabase } from './upgrades';
11-
import promptFetchDatabase, { databaseArchiveFetcher } from './databaseFetcher';
11+
import { importArchiveDatabase, promptImportInternetDatabase } from './databaseFetcher';
1212

1313
type ThemableIconPath = { light: string; dark: string } | string;
1414

@@ -174,9 +174,9 @@ export class DatabaseUI extends DisposableObject {
174174
this.treeDataProvider = this.push(new DatabaseTreeDataProvider(ctx, databaseManager));
175175
this.push(window.createTreeView('codeQLDatabases', { treeDataProvider: this.treeDataProvider }));
176176

177-
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseFolder', this.handleChooseDatabaseFolder));
178-
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseArchive', this.handleChooseDatabaseArchive));
179-
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseInternet', this.handleChooseDatabaseInternet));
177+
ctx.subscriptions.push(commands.registerCommand('codeQLDatabases.chooseDatabaseFolder', this.handleChooseDatabaseFolder));
178+
ctx.subscriptions.push(commands.registerCommand('codeQLDatabases.chooseDatabaseArchive', this.handleChooseDatabaseArchive));
179+
ctx.subscriptions.push(commands.registerCommand('codeQLDatabases.chooseDatabaseInternet', this.handleChooseDatabaseInternet));
180180
ctx.subscriptions.push(commands.registerCommand('codeQL.setCurrentDatabase', this.handleSetCurrentDatabase));
181181
ctx.subscriptions.push(commands.registerCommand('codeQL.upgradeCurrentDatabase', this.handleUpgradeCurrentDatabase));
182182
ctx.subscriptions.push(commands.registerCommand('codeQL.clearCache', this.handleClearCache));
@@ -193,7 +193,7 @@ export class DatabaseUI extends DisposableObject {
193193
await this.databaseManager.setCurrentDatabaseItem(databaseItem);
194194
}
195195

196-
private handleChooseDatabaseFolder = async (): Promise<DatabaseItem | undefined> => {
196+
handleChooseDatabaseFolder = async (): Promise<DatabaseItem | undefined> => {
197197
try {
198198
return await this.chooseAndSetDatabase(true);
199199
} catch (e) {
@@ -202,7 +202,7 @@ export class DatabaseUI extends DisposableObject {
202202
}
203203
}
204204

205-
private handleChooseDatabaseArchive = async (): Promise<DatabaseItem | undefined> => {
205+
handleChooseDatabaseArchive = async (): Promise<DatabaseItem | undefined> => {
206206
try {
207207
return await this.chooseAndSetDatabase(false);
208208
} catch (e) {
@@ -211,8 +211,8 @@ export class DatabaseUI extends DisposableObject {
211211
}
212212
}
213213

214-
private handleChooseDatabaseInternet = async (): Promise<DatabaseItem | undefined> => {
215-
return await promptFetchDatabase(this.databaseManager, this.storagePath);
214+
handleChooseDatabaseInternet = async (): Promise<DatabaseItem | undefined> => {
215+
return await promptImportInternetDatabase(this.databaseManager, this.storagePath);
216216
}
217217

218218
private handleSortByName = async () => {
@@ -292,7 +292,7 @@ export class DatabaseUI extends DisposableObject {
292292
private handleSetCurrentDatabase = async (uri: Uri): Promise<DatabaseItem | undefined> => {
293293
// Assume user has selected an archive if the file has a .zip extension
294294
if (uri.path.endsWith('.zip')) {
295-
return await databaseArchiveFetcher(uri.toString(), this.databaseManager, this.storagePath);
295+
return await importArchiveDatabase(uri.toString(true), this.databaseManager, this.storagePath);
296296
}
297297

298298
return await this.setCurrentDatabase(uri);
@@ -366,7 +366,7 @@ export class DatabaseUI extends DisposableObject {
366366
else {
367367
// we are selecting a database archive. Must unzip into a workspace-controlled area
368368
// before importing.
369-
return await databaseArchiveFetcher(uri.toString(), this.databaseManager, this.storagePath);
369+
return await importArchiveDatabase(uri.toString(true), this.databaseManager, this.storagePath);
370370
}
371371
}
372372
}

extensions/ql-vscode/src/extension.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { displayQuickQuery } from './quick-query';
2020
import { compileAndRunQueryAgainstDatabase, tmpDirDisposal, UserCancellationException } from './run-queries';
2121
import { QLTestAdapterFactory } from './test-adapter';
2222
import { TestUIService } from './test-ui';
23-
import promptFetchDatabase from './databaseFetcher';
2423

2524
/**
2625
* extension.ts
@@ -335,7 +334,9 @@ async function activateWithInstalledDistribution(ctx: ExtensionContext, distribu
335334
await qs.restartQueryServer();
336335
helpers.showAndLogInformationMessage('CodeQL Query Server restarted.', { outputLogger: queryServerLogger });
337336
}));
338-
ctx.subscriptions.push(commands.registerCommand('codeQL.downloadDatabase', () => promptFetchDatabase(dbm, getContextStoragePath(ctx))));
337+
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseFolder', () => databaseUI.handleChooseDatabaseFolder()));
338+
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseArchive', () => databaseUI.handleChooseDatabaseArchive()));
339+
ctx.subscriptions.push(commands.registerCommand('codeQL.chooseDatabaseInternet', () => databaseUI.handleChooseDatabaseInternet()));
339340

340341
ctx.subscriptions.push(client.start());
341342

0 commit comments

Comments
 (0)