Skip to content

Commit fca2faf

Browse files
authored
Add extension and storage paths to App container (#1756)
1 parent 3fd9fd4 commit fca2faf

File tree

9 files changed

+118
-14
lines changed

9 files changed

+118
-14
lines changed

extensions/ql-vscode/src/common/app.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ import { AppEventEmitter } from './events';
22

33
export interface App {
44
createEventEmitter<T>(): AppEventEmitter<T>;
5+
extensionPath: string;
6+
globalStoragePath: string;
7+
workspaceStoragePath?: string;
58
}

extensions/ql-vscode/src/common/vscode/vscode-app.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1+
import * as vscode from 'vscode';
12
import { App } from '../app';
23
import { AppEventEmitter } from '../events';
34
import { VSCodeAppEventEmitter } from './events';
45

56
export class ExtensionApp implements App {
7+
public constructor(
8+
public readonly extensionContext: vscode.ExtensionContext
9+
) {
10+
}
11+
12+
public get extensionPath(): string {
13+
return this.extensionContext.extensionPath;
14+
}
15+
16+
public get globalStoragePath(): string {
17+
return this.extensionContext.globalStorageUri.fsPath;
18+
}
19+
20+
public get workspaceStoragePath(): string | undefined {
21+
return this.extensionContext.storageUri?.fsPath;
22+
}
23+
624
public createEventEmitter<T>(): AppEventEmitter<T> {
725
return new VSCodeAppEventEmitter<T>();
826
}

extensions/ql-vscode/src/databases/db-config-store.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as chokidar from 'chokidar';
55
import { DisposableObject } from '../pure/disposable-object';
66
import { DbConfigValidator } from './db-config-validator';
77
import { ValueResult } from '../common/value-result';
8+
import { App } from '../common/app';
89

910
export class DbConfigStore extends DisposableObject {
1011
private readonly configPath: string;
@@ -14,17 +15,16 @@ export class DbConfigStore extends DisposableObject {
1415
private configErrors: string[];
1516
private configWatcher: chokidar.FSWatcher | undefined;
1617

17-
public constructor(
18-
workspaceStoragePath: string,
19-
extensionPath: string) {
18+
public constructor(app: App) {
2019
super();
2120

22-
this.configPath = path.join(workspaceStoragePath, 'workspace-databases.json');
21+
const storagePath = app.workspaceStoragePath || app.globalStoragePath;
22+
this.configPath = path.join(storagePath, 'workspace-databases.json');
2323

2424
this.config = this.createEmptyConfig();
2525
this.configErrors = [];
2626
this.configWatcher = undefined;
27-
this.configValidator = new DbConfigValidator(extensionPath);
27+
this.configValidator = new DbConfigValidator(app.extensionPath);
2828
}
2929

3030
public async initialize(): Promise<void> {

extensions/ql-vscode/src/databases/db-module.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from 'vscode';
2+
import { ExtensionApp } from '../common/vscode/vscode-app';
23
import { isCanary, isNewQueryRunExperienceEnabled } from '../config';
34
import { logger } from '../logging';
45
import { DisposableObject } from '../pure/disposable-object';
@@ -21,9 +22,9 @@ export class DbModule extends DisposableObject {
2122

2223
void logger.log('Initializing database module');
2324

24-
const storagePath = extensionContext.storageUri?.fsPath || extensionContext.globalStorageUri.fsPath;
25-
const extensionPath = extensionContext.extensionPath;
26-
const dbConfigStore = new DbConfigStore(storagePath, extensionPath);
25+
const app = new ExtensionApp(extensionContext);
26+
27+
const dbConfigStore = new DbConfigStore(app);
2728
await dbConfigStore.initialize();
2829

2930
const dbManager = new DbManager(dbConfigStore);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as vscode from 'vscode';
2+
3+
/**
4+
* Creates a partially implemented mock of vscode.ExtensionContext.
5+
*/
6+
export function createMockExtensionContext({
7+
extensionPath = '/mock/extension/path',
8+
workspaceStoragePath = '/mock/workspace/storage/path',
9+
globalStoragePath = '/mock/global/storage/path',
10+
}: {
11+
extensionPath?: string,
12+
workspaceStoragePath?: string,
13+
globalStoragePath?: string,
14+
}): vscode.ExtensionContext {
15+
16+
return {
17+
extensionPath: extensionPath,
18+
globalStorageUri: vscode.Uri.file(globalStoragePath),
19+
storageUri: vscode.Uri.file(workspaceStoragePath),
20+
} as any as vscode.ExtensionContext;
21+
}

extensions/ql-vscode/src/vscode-tests/minimal-workspace/databases/db-panel.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import { DbTreeDataProvider } from '../../../databases/ui/db-tree-data-provider'
1010
import { DbPanel } from '../../../databases/ui/db-panel';
1111
import { DbItemKind } from '../../../databases/db-item';
1212
import { DbTreeViewItem } from '../../../databases/ui/db-tree-view-item';
13+
import { ExtensionApp } from '../../../common/vscode/vscode-app';
14+
import { createMockExtensionContext } from '../../factories/extension-context';
1315

1416
const proxyquire = pq.noPreserveCache();
1517

1618
describe('db panel', async () => {
17-
const workspaceStoragePath = path.join(__dirname, 'test-workspace');
19+
const workspaceStoragePath = path.join(__dirname, 'test-workspace-storage');
20+
const globalStoragePath = path.join(__dirname, 'test-global-storage');
1821
const extensionPath = path.join(__dirname, '../../../../');
1922
const dbConfigFilePath = path.join(workspaceStoragePath, 'workspace-databases.json');
2023
let dbTreeDataProvider: DbTreeDataProvider;
@@ -23,7 +26,14 @@ describe('db panel', async () => {
2326
let dbPanel: DbPanel;
2427

2528
before(async () => {
26-
dbConfigStore = new DbConfigStore(workspaceStoragePath, extensionPath);
29+
const extensionContext = createMockExtensionContext({
30+
extensionPath,
31+
globalStoragePath,
32+
workspaceStoragePath
33+
});
34+
const app = new ExtensionApp(extensionContext);
35+
36+
dbConfigStore = new DbConfigStore(app);
2737
dbManager = new DbManager(dbConfigStore);
2838

2939
// Create a modified version of the DbPanel module that allows
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { App } from '../../src/common/app';
2+
import { AppEvent, AppEventEmitter } from '../../src/common/events';
3+
import { Disposable } from '../../src/pure/disposable-object';
4+
5+
export function createMockApp({
6+
extensionPath = '/mock/extension/path',
7+
workspaceStoragePath = '/mock/workspace/storage/path',
8+
globalStoragePath = '/mock/global/storage/path',
9+
createEventEmitter = <T>() => new MockAppEventEmitter<T>()
10+
}: {
11+
extensionPath?: string,
12+
workspaceStoragePath?: string,
13+
globalStoragePath?: string,
14+
createEventEmitter?: <T>() => AppEventEmitter<T>
15+
}): App {
16+
return {
17+
createEventEmitter,
18+
extensionPath,
19+
workspaceStoragePath,
20+
globalStoragePath
21+
};
22+
}
23+
24+
export class MockAppEventEmitter<T> implements AppEventEmitter<T> {
25+
public event: AppEvent<T>;
26+
27+
constructor() {
28+
this.event = () => {
29+
return {} as Disposable;
30+
};
31+
}
32+
33+
public fire(): void {
34+
// no-op
35+
}
36+
}

extensions/ql-vscode/test/pure-tests/databases/db-config-store.test.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as fs from 'fs-extra';
22
import * as path from 'path';
33
import { DbConfigStore } from '../../../src/databases/db-config-store';
44
import { expect } from 'chai';
5+
import { createMockApp } from '../../__mocks__/appMock';
56

67
describe('db config store', async () => {
78
const extensionPath = path.join(__dirname, '../../..');
@@ -17,9 +18,14 @@ describe('db config store', async () => {
1718
});
1819

1920
it('should create a new config if one does not exist', async () => {
21+
const app = createMockApp({
22+
extensionPath,
23+
workspaceStoragePath: tempWorkspaceStoragePath
24+
});
25+
2026
const configPath = path.join(tempWorkspaceStoragePath, 'workspace-databases.json');
2127

22-
const configStore = new DbConfigStore(tempWorkspaceStoragePath, extensionPath);
28+
const configStore = new DbConfigStore(app);
2329
await configStore.initialize();
2430

2531
expect(await fs.pathExists(configPath)).to.be.true;
@@ -32,7 +38,11 @@ describe('db config store', async () => {
3238
});
3339

3440
it('should load an existing config', async () => {
35-
const configStore = new DbConfigStore(testDataStoragePath, extensionPath);
41+
const app = createMockApp({
42+
extensionPath,
43+
workspaceStoragePath: testDataStoragePath
44+
});
45+
const configStore = new DbConfigStore(app);
3646
await configStore.initialize();
3747

3848
const config = configStore.getConfig().value;
@@ -70,7 +80,11 @@ describe('db config store', async () => {
7080
});
7181

7282
it('should not allow modification of the config', async () => {
73-
const configStore = new DbConfigStore(testDataStoragePath, extensionPath);
83+
const app = createMockApp({
84+
extensionPath,
85+
workspaceStoragePath: testDataStoragePath
86+
});
87+
const configStore = new DbConfigStore(app);
7488
await configStore.initialize();
7589

7690
const config = configStore.getConfig().value;

extensions/ql-vscode/test/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"exclude": [],
55
"compilerOptions": {
66
"noEmit": true,
7-
"resolveJsonModule": true
7+
"resolveJsonModule": true,
8+
"rootDirs": [".", "../src"]
89
}
910
}

0 commit comments

Comments
 (0)