Skip to content

Commit aa43b1e

Browse files
authored
Add configurability of bazel executable and args (#5)
1 parent edc5197 commit aa43b1e

File tree

5 files changed

+229
-113
lines changed

5 files changed

+229
-113
lines changed

src/compilationDatabase.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import path = require('path');
2+
import * as tmp from 'tmp';
3+
import * as vscode from 'vscode';
4+
import { Container } from './container';
5+
6+
export class CompilationDatabase implements vscode.Disposable {
7+
disposables: vscode.Disposable[] = [];
8+
9+
constructor() {
10+
this.disposables.push(
11+
vscode.commands.registerCommand('bsv.cc.compdb.generate', this.generate, this),
12+
);
13+
}
14+
15+
async generate(): Promise<vscode.TaskExecution | void> {
16+
const compdbConfig = vscode.workspace.getConfiguration('bsv.cc.compdb');
17+
const targets = compdbConfig.get<string[] | undefined>('targets', undefined);
18+
if (!targets || targets.length === 0) {
19+
vscode.window.showErrorMessage(
20+
'The list of bazel targets to index for the compilation database is not configured. ' +
21+
'Please configure the "bsv.cc.compdb.targets" workspace setting to include a list of cc_library, cc_binary labels');
22+
return;
23+
}
24+
25+
const bazelConfig = vscode.workspace.getConfiguration('bsv.bazel');
26+
const bazelExecutable = bazelConfig.get<string>('executable', 'bazel');
27+
const bazelBuildArgs = bazelConfig.get<string[]>('buildArgs', []);
28+
29+
vscode.window.showInformationMessage('Building clang compilation database for ' + JSON.stringify(targets));
30+
31+
return vscode.tasks.executeTask(this.createGenerateTask(targets, bazelExecutable, bazelBuildArgs));
32+
}
33+
34+
createGenerateTask(targets: string[], bazelExecutable: string, buildArgs: string[]): vscode.Task {
35+
const name = 'bazel-compdb';
36+
const repositoryPath = Container.file("compdb/");
37+
const cwd = Container.workspaceFolderFsPath || ".";
38+
const buildEventsJsonTempFile = tmp.fileSync().name; // cleaned up on process exit
39+
const args = createBazelBuildAspectCommand(
40+
repositoryPath.fsPath,
41+
buildEventsJsonTempFile,
42+
buildArgs,
43+
targets,
44+
);
45+
const env = {};
46+
47+
const task = new vscode.Task(
48+
{ type: name },
49+
vscode.TaskScope.Workspace,
50+
name,
51+
name,
52+
new vscode.ShellExecution(bazelExecutable, args, {
53+
env: env,
54+
cwd: cwd,
55+
}),
56+
);
57+
task.presentationOptions = {
58+
clear: true,
59+
echo: true,
60+
showReuseMessage: false,
61+
panel: vscode.TaskPanelKind.Shared,
62+
};
63+
64+
return task;
65+
}
66+
67+
dispose() {
68+
this.disposables.forEach(d => d.dispose());
69+
}
70+
}
71+
72+
export function createBazelBuildAspectCommand(
73+
repositoryPath: string,
74+
tmpFile: string,
75+
buildArgs: string[],
76+
targets: string[],
77+
): string[] {
78+
return [
79+
"build",
80+
"--override_repository=bazel_vscode_compdb=" + repositoryPath,
81+
"--aspects=@bazel_vscode_compdb//:aspects.bzl%compilation_database_aspect",
82+
"--color=no",
83+
"--noshow_progress",
84+
"--noshow_loading_progress",
85+
"--output_groups=compdb_files,header_files",
86+
"--build_event_json_file=" + tmpFile,
87+
...buildArgs,
88+
...targets,
89+
"&&",
90+
path.join(repositoryPath, "postprocess.py"),
91+
"-b", tmpFile,
92+
"&&",
93+
"rm", tmpFile,
94+
];
95+
}

src/compilation_database.ts

Lines changed: 0 additions & 111 deletions
This file was deleted.

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { registerProblemMatchers } from 'bazel-stack-vscode-api';
22
import * as vscode from 'vscode';
3-
import { CompilationDatabase } from './compilation_database';
3+
import { CompilationDatabase } from './compilationDatabase';
44
import { Container } from './container';
55

66
export function activate(context: vscode.ExtensionContext) {
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { createBazelBuildAspectCommand } from '../../compilationDatabase';
2+
import * as assert from 'assert';
3+
import * as fs from 'fs';
4+
import * as tmp from 'tmp';
5+
import path = require('path');
6+
import { ExecException, execFile } from 'child_process';
7+
import { assertType } from 'vscode-common/out/types';
8+
9+
suite('Compilation Database', () => {
10+
11+
test('createBazelBuildAspectCommand', () => {
12+
const repoPath = '/path/to/this/extension/compdb';
13+
const tmpFile = '/tmp/build-events.json';
14+
const buildArgs: string[] = ["--config=foo"];
15+
const targets: string[] = ['//app/a', '//app/b'];
16+
17+
const cmd = createBazelBuildAspectCommand(
18+
repoPath,
19+
tmpFile,
20+
buildArgs,
21+
targets,
22+
);
23+
24+
assert.deepStrictEqual([
25+
'build',
26+
'--override_repository=bazel_vscode_compdb=/path/to/this/extension/compdb',
27+
'--aspects=@bazel_vscode_compdb//:aspects.bzl%compilation_database_aspect',
28+
'--color=no',
29+
'--noshow_progress',
30+
'--noshow_loading_progress',
31+
'--output_groups=compdb_files,header_files',
32+
'--build_event_json_file=/tmp/build-events.json',
33+
'--config=foo',
34+
'//app/a',
35+
'//app/b',
36+
'&&',
37+
process.platform === 'win32' ? '\\path\\to\\this\\extension\\compdb\\postprocess.py' : '/path/to/this/extension/compdb/postprocess.py',
38+
'-b',
39+
'/tmp/build-events.json',
40+
'&&',
41+
'rm',
42+
'/tmp/build-events.json',
43+
], cmd);
44+
});
45+
46+
// test not working in CI yet.
47+
test.skip('postprocess.py exists', (done) => {
48+
const extensionDevelopmentPath = path.resolve(__dirname, '../../..');
49+
const postprocessPy = path.join(extensionDevelopmentPath, 'compdb/postprocess.py');
50+
assert.ok(fs.existsSync(postprocessPy));
51+
52+
// prep temp files
53+
const tmpDir = tmp.dirSync().name;
54+
const buildEventsJsonTempFile = path.join(tmpDir, 'build-events.json');
55+
const fooCommandsFile = path.join(tmpDir, 'foo.compile_commands.json');
56+
const barCommandsFile = path.join(tmpDir, 'bar.compile_commands.json');
57+
const compileCommandsFile = path.join(tmpDir, 'compile_commands.json');
58+
59+
fs.writeFileSync(fooCommandsFile, JSON.stringify([
60+
{
61+
command: "external/local_config_cc/cc_wrapper.sh -iquote . app/a/foo.cpp",
62+
directory: "__EXEC_ROOT__",
63+
file: "app/a/foo.cpp",
64+
},
65+
]));
66+
fs.writeFileSync(barCommandsFile, JSON.stringify([
67+
{
68+
command: "external/local_config_cc/cc_wrapper.sh -iquote . app/a/bar.cpp",
69+
directory: "__EXEC_ROOT__",
70+
file: "app/a/bar.cpp",
71+
},
72+
]));
73+
74+
// write fake build events as a file where every line is a JSON object
75+
const events = [
76+
JSON.stringify({
77+
started: {
78+
workspaceDirectory: tmpDir,
79+
},
80+
}),
81+
JSON.stringify({
82+
workspaceInfo: {
83+
localExecRoot: tmpDir,
84+
},
85+
}),
86+
JSON.stringify({
87+
progress: {
88+
stderr: [
89+
' ' + fooCommandsFile,
90+
' ' + barCommandsFile,
91+
].join('\n'),
92+
},
93+
}),
94+
];
95+
96+
fs.writeFileSync(buildEventsJsonTempFile, events.join('\n'));
97+
const postprocessArgs = ['--build_events_json_file', buildEventsJsonTempFile];
98+
99+
execFile(postprocessPy, postprocessArgs, {}, (err: ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => {
100+
if (err) {
101+
done(err);
102+
return;
103+
}
104+
console.log('OUT', stdout);
105+
console.log('ERR', stderr);
106+
assert.ok(fs.existsSync(compileCommandsFile));
107+
108+
const jsonContent = fs.readFileSync(compileCommandsFile).toString()
109+
.split(tmpDir).join('__TMPDIR__');
110+
const compileCommands = JSON.parse(jsonContent);
111+
112+
assert.deepStrictEqual(compileCommands,
113+
[
114+
{
115+
command: 'external/local_config_cc/cc_wrapper.sh -I . app/a/foo.cpp',
116+
directory: '__TMPDIR__',
117+
file: 'app/a/foo.cpp'
118+
},
119+
{
120+
command: 'external/local_config_cc/cc_wrapper.sh -I . app/a/bar.cpp',
121+
directory: '__TMPDIR__',
122+
file: 'app/a/bar.cpp'
123+
}
124+
]
125+
);
126+
127+
done();
128+
});
129+
130+
});
131+
132+
});

src/test/suite/extension.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ suite('Problem Matchers', () => {
3131
cases.forEach((tc) => {
3232
test(tc.d || tc.name, async () => runner.test(tc));
3333
});
34-
34+
3535
});

0 commit comments

Comments
 (0)