Skip to content

Commit af77dff

Browse files
committed
Adds a ConfigManager to persist configuration
Signed-off-by: Tyler Smalley <[email protected]>
1 parent 9a88a32 commit af77dff

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

src/config-manager.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as vscode from 'vscode';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
import { test, expect, beforeEach } from 'vitest';
5+
import { ConfigManager } from './config-manager';
6+
7+
const extensionContext = {
8+
globalStoragePath: '/tmp/vscode-tailscale',
9+
} as vscode.ExtensionContext;
10+
11+
const configPath = path.join(extensionContext.globalStoragePath, 'config.json');
12+
13+
beforeEach(() => {
14+
if (fs.existsSync(configPath)) {
15+
fs.unlinkSync(configPath);
16+
}
17+
});
18+
19+
test('withContext will create directory if it does not exist', () => {
20+
fs.rmSync(extensionContext.globalStoragePath, { recursive: true, force: true });
21+
expect(fs.existsSync(extensionContext.globalStoragePath)).toBe(false);
22+
23+
ConfigManager.withContext(extensionContext);
24+
expect(fs.existsSync(extensionContext.globalStoragePath)).toBe(true);
25+
});
26+
27+
test('withContext returns an initialized ConfigManager', () => {
28+
const cm = ConfigManager.withContext(extensionContext);
29+
expect(cm.configPath).toBe(configPath);
30+
});
31+
32+
test('set persists config to disk', () => {
33+
const cm = new ConfigManager(configPath);
34+
const hosts = {
35+
'host-1': {
36+
user: 'foo',
37+
rootDir: '/',
38+
},
39+
};
40+
41+
cm.set('hosts', hosts);
42+
expect(cm.get('hosts')).toEqual(hosts);
43+
44+
const f = fs.readFileSync(configPath, 'utf8');
45+
expect(JSON.parse(f)).toEqual({ hosts });
46+
});

src/config-manager.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as vscode from 'vscode';
2+
import * as fs from 'fs';
3+
import * as path from 'path';
4+
5+
interface Host {
6+
user: string;
7+
rootDir: string;
8+
}
9+
10+
interface Config {
11+
defaultHost?: Host;
12+
hosts?: Record<string, Host>;
13+
}
14+
15+
export class ConfigManager {
16+
private config: Config;
17+
18+
constructor(public readonly configPath: string) {
19+
if (fs.existsSync(this.configPath)) {
20+
const rawData = fs.readFileSync(this.configPath, 'utf8');
21+
this.config = JSON.parse(rawData);
22+
} else {
23+
this.config = {};
24+
}
25+
}
26+
27+
static withContext(context: vscode.ExtensionContext) {
28+
const globalStoragePath = context.globalStoragePath;
29+
30+
if (!fs.existsSync(globalStoragePath)) {
31+
fs.mkdirSync(globalStoragePath);
32+
}
33+
34+
return new ConfigManager(path.join(globalStoragePath, 'config.json'));
35+
}
36+
37+
get<K extends keyof Config>(key: K): Config[K] {
38+
return this.config[key];
39+
}
40+
41+
set<K extends keyof Config>(key: K, value: Config[K]) {
42+
this.config[key] = value;
43+
this.saveConfig();
44+
}
45+
46+
private saveConfig() {
47+
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf8');
48+
}
49+
}

src/extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as vscode from 'vscode';
2-
32
import { ServePanelProvider } from './serve-panel-provider';
43
import { ADMIN_CONSOLE } from './utils/url';
54
import { Tailscale } from './tailscale';
@@ -13,6 +12,7 @@ import {
1312
} from './node-explorer-provider';
1413

1514
import { TSFileSystemProvider } from './ts-file-system-provider';
15+
import { ConfigManager } from './config-manager';
1616

1717
let tailscaleInstance: Tailscale;
1818

0 commit comments

Comments
 (0)