forked from github/vscode-codeql
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconfig.ts
237 lines (192 loc) · 8.26 KB
/
config.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
import { DisposableObject } from './vscode-utils/disposable-object';
import { workspace, Event, EventEmitter, ConfigurationChangeEvent, ConfigurationTarget } from 'vscode';
import { DistributionManager } from './distribution';
import { logger } from './logging';
/** Helper class to look up a labelled (and possibly nested) setting. */
class Setting {
name: string;
parent?: Setting;
constructor(name: string, parent?: Setting) {
this.name = name;
this.parent = parent;
}
get qualifiedName(): string {
if (this.parent === undefined) {
return this.name;
} else {
return `${this.parent.qualifiedName}.${this.name}`;
}
}
getValue<T>(): T {
if (this.parent === undefined) {
throw new Error('Cannot get the value of a root setting.');
}
return workspace.getConfiguration(this.parent.qualifiedName).get<T>(this.name)!;
}
updateValue<T>(value: T, target: ConfigurationTarget): Thenable<void> {
if (this.parent === undefined) {
throw new Error('Cannot update the value of a root setting.');
}
return workspace.getConfiguration(this.parent.qualifiedName).update(this.name, value, target);
}
}
const ROOT_SETTING = new Setting('codeQL');
// Distribution configuration
const DISTRIBUTION_SETTING = new Setting('cli', ROOT_SETTING);
const CUSTOM_CODEQL_PATH_SETTING = new Setting('executablePath', DISTRIBUTION_SETTING);
const INCLUDE_PRERELEASE_SETTING = new Setting('includePrerelease', DISTRIBUTION_SETTING);
const PERSONAL_ACCESS_TOKEN_SETTING = new Setting('personalAccessToken', DISTRIBUTION_SETTING);
const QUERY_HISTORY_SETTING = new Setting('queryHistory', ROOT_SETTING);
const QUERY_HISTORY_FORMAT_SETTING = new Setting('format', QUERY_HISTORY_SETTING);
/** When these settings change, the distribution should be updated. */
const DISTRIBUTION_CHANGE_SETTINGS = [CUSTOM_CODEQL_PATH_SETTING, INCLUDE_PRERELEASE_SETTING, PERSONAL_ACCESS_TOKEN_SETTING];
export interface DistributionConfig {
customCodeQlPath?: string;
includePrerelease: boolean;
personalAccessToken?: string;
ownerName?: string;
repositoryName?: string;
onDidChangeConfiguration?: Event<void>;
}
// Query server configuration
const RUNNING_QUERIES_SETTING = new Setting('runningQueries', ROOT_SETTING);
const NUMBER_OF_THREADS_SETTING = new Setting('numberOfThreads', RUNNING_QUERIES_SETTING);
const TIMEOUT_SETTING = new Setting('timeout', RUNNING_QUERIES_SETTING);
const MEMORY_SETTING = new Setting('memory', RUNNING_QUERIES_SETTING);
const DEBUG_SETTING = new Setting('debug', RUNNING_QUERIES_SETTING);
const RUNNING_TESTS_SETTING = new Setting('runningTests', ROOT_SETTING);
const RESULTS_DISPLAY_SETTING = new Setting('resultsDisplay', ROOT_SETTING);
export const NUMBER_OF_TEST_THREADS_SETTING = new Setting('numberOfThreads', RUNNING_TESTS_SETTING);
export const MAX_QUERIES = new Setting('maxQueries', RUNNING_QUERIES_SETTING);
export const AUTOSAVE_SETTING = new Setting('autoSave', RUNNING_QUERIES_SETTING);
export const PAGE_SIZE = new Setting('pageSize', RESULTS_DISPLAY_SETTING);
/** When these settings change, the running query server should be restarted. */
const QUERY_SERVER_RESTARTING_SETTINGS = [NUMBER_OF_THREADS_SETTING, MEMORY_SETTING, DEBUG_SETTING];
export interface QueryServerConfig {
codeQlPath: string;
debug: boolean;
numThreads: number;
queryMemoryMb?: number;
timeoutSecs: number;
onDidChangeConfiguration?: Event<void>;
}
/** When these settings change, the query history should be refreshed. */
const QUERY_HISTORY_SETTINGS = [QUERY_HISTORY_FORMAT_SETTING];
export interface QueryHistoryConfig {
format: string;
onDidChangeConfiguration: Event<void>;
}
const CLI_SETTINGS = [NUMBER_OF_TEST_THREADS_SETTING];
export interface CliConfig {
numberTestThreads: number;
onDidChangeConfiguration?: Event<void>;
}
abstract class ConfigListener extends DisposableObject {
protected readonly _onDidChangeConfiguration = this.push(new EventEmitter<void>());
constructor() {
super();
this.updateConfiguration();
this.push(workspace.onDidChangeConfiguration(this.handleDidChangeConfiguration, this));
}
/**
* Calls `updateConfiguration` if any of the `relevantSettings` have changed.
*/
protected handleDidChangeConfigurationForRelevantSettings(relevantSettings: Setting[], e: ConfigurationChangeEvent): void {
// Check whether any options that affect query running were changed.
for (const option of relevantSettings) {
// TODO: compare old and new values, only update if there was actually a change?
if (e.affectsConfiguration(option.qualifiedName)) {
this.updateConfiguration();
break; // only need to do this once, if any of the settings have changed
}
}
}
protected abstract handleDidChangeConfiguration(e: ConfigurationChangeEvent): void;
private updateConfiguration(): void {
this._onDidChangeConfiguration.fire();
}
public get onDidChangeConfiguration(): Event<void> {
return this._onDidChangeConfiguration.event;
}
}
export class DistributionConfigListener extends ConfigListener implements DistributionConfig {
public get customCodeQlPath(): string | undefined {
return CUSTOM_CODEQL_PATH_SETTING.getValue() || undefined;
}
public get includePrerelease(): boolean {
return INCLUDE_PRERELEASE_SETTING.getValue();
}
public get personalAccessToken(): string | undefined {
return PERSONAL_ACCESS_TOKEN_SETTING.getValue() || undefined;
}
protected handleDidChangeConfiguration(e: ConfigurationChangeEvent): void {
this.handleDidChangeConfigurationForRelevantSettings(DISTRIBUTION_CHANGE_SETTINGS, e);
}
}
export class QueryServerConfigListener extends ConfigListener implements QueryServerConfig {
public constructor(private _codeQlPath = '') {
super();
}
public static async createQueryServerConfigListener(distributionManager: DistributionManager): Promise<QueryServerConfigListener> {
const codeQlPath = await distributionManager.getCodeQlPathWithoutVersionCheck();
const config = new QueryServerConfigListener(codeQlPath!);
if (distributionManager.onDidChangeDistribution) {
config.push(distributionManager.onDidChangeDistribution(async () => {
const codeQlPath = await distributionManager.getCodeQlPathWithoutVersionCheck();
config._codeQlPath = codeQlPath!;
config._onDidChangeConfiguration.fire();
}));
}
return config;
}
public get codeQlPath(): string {
return this._codeQlPath;
}
public get numThreads(): number {
return NUMBER_OF_THREADS_SETTING.getValue<number>();
}
/** Gets the configured query timeout, in seconds. This looks up the setting at the time of access. */
public get timeoutSecs(): number {
return TIMEOUT_SETTING.getValue<number | null>() || 0;
}
public get queryMemoryMb(): number | undefined {
const memory = MEMORY_SETTING.getValue<number | null>();
if (memory === null) {
return undefined;
}
if (memory == 0 || typeof (memory) !== 'number') {
logger.log(`Ignoring value '${memory}' for setting ${MEMORY_SETTING.qualifiedName}`);
return undefined;
}
return memory;
}
public get debug(): boolean {
return DEBUG_SETTING.getValue<boolean>();
}
protected handleDidChangeConfiguration(e: ConfigurationChangeEvent): void {
this.handleDidChangeConfigurationForRelevantSettings(QUERY_SERVER_RESTARTING_SETTINGS, e);
}
}
export class QueryHistoryConfigListener extends ConfigListener implements QueryHistoryConfig {
protected handleDidChangeConfiguration(e: ConfigurationChangeEvent): void {
this.handleDidChangeConfigurationForRelevantSettings(QUERY_HISTORY_SETTINGS, e);
}
public get format(): string {
return QUERY_HISTORY_FORMAT_SETTING.getValue<string>();
}
}
export class CliConfigListener extends ConfigListener implements CliConfig {
public get numberTestThreads(): number {
return NUMBER_OF_TEST_THREADS_SETTING.getValue();
}
protected handleDidChangeConfiguration(e: ConfigurationChangeEvent): void {
this.handleDidChangeConfigurationForRelevantSettings(CLI_SETTINGS, e);
}
}
// Enable experimental features
/**
* Any settings below are deliberately not in package.json so that
* they do not appear in the settings ui in vscode itself. If users
* want to enable experimental features, they can add them directly in
* their vscode settings json file.
*/