Skip to content

Commit 6d7b025

Browse files
committed
Add "pack install" and "pack download" commands
1 parent 51906cb commit 6d7b025

4 files changed

Lines changed: 181 additions & 0 deletions

File tree

extensions/ql-vscode/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,14 @@
374374
"command": "codeQL.clearCache",
375375
"title": "CodeQL: Clear Cache"
376376
},
377+
{
378+
"command": "codeQL.installPacks",
379+
"title": "CodeQL: Install Packs"
380+
},
381+
{
382+
"command": "codeQL.downloadPacks",
383+
"title": "CodeQL: Download Packs"
384+
},
377385
{
378386
"command": "codeQLDatabases.setCurrentDatabase",
379387
"title": "Set Current Database"

extensions/ql-vscode/src/cli.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,14 @@ export class CodeQLCliServer implements Disposable {
845845
);
846846
}
847847

848+
/**
849+
* Downloads a specified pack.
850+
* @param pack The `<package-scope/name[@version]>` of the pack to download.
851+
*/
852+
async packDownload(pack: string) {
853+
return this.runJsonCodeQlCliCommand(['pack', 'download'], [pack], 'Downloading packs');
854+
}
855+
848856
async packInstall(dir: string) {
849857
return this.runJsonCodeQlCliCommand(['pack', 'install'], [dir], 'Installing pack dependencies');
850858
}

extensions/ql-vscode/src/extension.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ import { RemoteQuery } from './remote-queries/remote-query';
8383
import { URLSearchParams } from 'url';
8484
import { RemoteQueriesInterfaceManager } from './remote-queries/remote-queries-interface';
8585
import { sampleRemoteQuery, sampleRemoteQueryResult } from './remote-queries/sample-data';
86+
import { handleDownloadPacks, handleInstallPacks } from './packaging';
8687

8788
/**
8889
* extension.ts
@@ -922,6 +923,26 @@ async function activateWithInstalledDistribution(
922923
}
923924
}));
924925

926+
ctx.subscriptions.push(
927+
commandRunnerWithProgress('codeQL.installPacks', async (
928+
progress: ProgressCallback
929+
) =>
930+
await handleInstallPacks(cliServer, progress),
931+
{
932+
title: 'Installing packs',
933+
}
934+
));
935+
936+
ctx.subscriptions.push(
937+
commandRunnerWithProgress('codeQL.downloadPacks', async (
938+
progress: ProgressCallback
939+
) =>
940+
await handleDownloadPacks(cliServer, progress),
941+
{
942+
title: 'Downloading packs',
943+
}
944+
));
945+
925946
commands.registerCommand('codeQL.showLogs', () => {
926947
logger.show();
927948
});
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { CodeQLCliServer } from './cli';
2+
import * as fs from 'fs-extra';
3+
import * as path from 'path';
4+
import {
5+
getOnDiskWorkspaceFolders,
6+
showAndLogErrorMessage,
7+
showAndLogInformationMessage,
8+
} from './helpers';
9+
import { window } from 'vscode';
10+
import { ProgressCallback } from './commandRunner';
11+
12+
const CORE_PACKS = [
13+
'codeql/cpp-all',
14+
'codeql/csharp-all',
15+
'codeql/go-all',
16+
'codeql/java-all',
17+
'codeql/javascript-all',
18+
'codeql/python-all',
19+
'codeql/ruby-all',
20+
];
21+
22+
/**
23+
* Lists all workspace folders that contain a qlpack.yml file.
24+
*
25+
* Note: This currently only finds packs at the root of a workspace folder.
26+
* TODO: Add support for packs in subfolders.
27+
*/
28+
function getWorkspacePacks(): string[] {
29+
const packs: string[] = [];
30+
const workspaceFolders = getOnDiskWorkspaceFolders();
31+
for (const folder of workspaceFolders) {
32+
const qlpackYml = path.join(folder, 'qlpack.yml');
33+
if (fs.pathExistsSync(qlpackYml)) {
34+
packs.push(folder);
35+
}
36+
}
37+
return packs;
38+
}
39+
40+
/**
41+
* Prompts user to choose packs to download, and downloads them.
42+
*
43+
* @param cliServer The CLI server.
44+
* @param progress A progress callback.
45+
*/
46+
export async function handleDownloadPacks(
47+
cliServer: CodeQLCliServer,
48+
progress: ProgressCallback,
49+
): Promise<void> {
50+
progress({
51+
message: 'Choose packs to download',
52+
step: 1,
53+
maxStep: 2,
54+
});
55+
let packsToDownload: string[] = [];
56+
const corePackOption = 'Download core CodeQL packs';
57+
const customPackOption = 'Download custom specified pack';
58+
const quickpick = await window.showQuickPick(
59+
[corePackOption, customPackOption],
60+
{ ignoreFocusOut: true }
61+
);
62+
if (quickpick === corePackOption) {
63+
packsToDownload = CORE_PACKS;
64+
} else if (quickpick === customPackOption) {
65+
const customPack = await window.showInputBox({
66+
prompt:
67+
'Enter the <package-scope/name[@version]> of the pack to download',
68+
ignoreFocusOut: true,
69+
});
70+
if (customPack) {
71+
packsToDownload.push(customPack);
72+
} else {
73+
void showAndLogErrorMessage('No pack specified.');
74+
}
75+
}
76+
if (packsToDownload && packsToDownload.length > 0) {
77+
progress({
78+
message: `Downloading ${packsToDownload.join(', ')}`,
79+
step: 2,
80+
maxStep: 2,
81+
});
82+
for (const pack of packsToDownload) {
83+
try {
84+
await cliServer.packDownload(pack);
85+
} catch (error) {
86+
void showAndLogErrorMessage(`Unable to download pack ${pack}. See logs for more details.`);
87+
}
88+
}
89+
void showAndLogInformationMessage('Finished downloading packs.');
90+
}
91+
}
92+
93+
/**
94+
* Prompts user to choose packs to install, and installs them.
95+
*
96+
* @param cliServer The CLI server.
97+
* @param progress A progress callback.
98+
*/
99+
export async function handleInstallPacks(
100+
cliServer: CodeQLCliServer,
101+
progress: ProgressCallback,
102+
): Promise<void> {
103+
progress({
104+
message: 'Choose packs to install',
105+
step: 1,
106+
maxStep: 2,
107+
});
108+
let packsToInstall: string[] = [];
109+
const workspacePackOption = 'Install workspace packs';
110+
const customPackOption = 'Install custom specified pack';
111+
const quickpick = await window.showQuickPick(
112+
[workspacePackOption, customPackOption],
113+
{ ignoreFocusOut: true }
114+
);
115+
if (quickpick === workspacePackOption) {
116+
packsToInstall = getWorkspacePacks();
117+
} else if (quickpick === customPackOption) {
118+
const customPack = await window.showInputBox({
119+
prompt:
120+
'Enter the root directory of the pack to install (as an absolute path)',
121+
ignoreFocusOut: true,
122+
});
123+
if (customPack) {
124+
packsToInstall.push(customPack);
125+
} else {
126+
void showAndLogErrorMessage('No pack specified.');
127+
}
128+
}
129+
if (packsToInstall && packsToInstall.length > 0) {
130+
progress({
131+
message: `Installing ${packsToInstall.join(', ')}`,
132+
step: 2,
133+
maxStep: 2,
134+
});
135+
for (const pack of packsToInstall) {
136+
try {
137+
await cliServer.packInstall(pack);
138+
} catch (error) {
139+
void showAndLogErrorMessage(`Unable to install pack ${pack}. See logs for more details.`);
140+
}
141+
}
142+
void showAndLogInformationMessage('Finished installing packs.');
143+
}
144+
}

0 commit comments

Comments
 (0)