Skip to content

Commit

Permalink
Adds a ConfigManager to persist configuration (#115)
Browse files Browse the repository at this point in the history
Stacked on #116

Signed-off-by: Tyler Smalley <tyler@tailscale.com>
  • Loading branch information
tylersmalley committed Jul 20, 2023
1 parent 82e0890 commit 5f93acc
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@
"package": "vsce package --allow-star-activation",
"precommit": "lint-staged",
"prepare": "husky install",
"test": "vitest --passWithNoTests",
"test": "vitest",
"vscode:prepublish": "(yarn run bundle-js & pid1=$!; yarn run bundle-go & pid2=$!; wait $pid1 || exit 1; wait $pid2 || exit 1)",
"watch": "webpack serve"
},
Expand Down
46 changes: 46 additions & 0 deletions src/config-manager.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { test, expect, beforeEach } from 'vitest';
import { ConfigManager } from './config-manager';

const extensionContext = {
globalStoragePath: '/tmp/vscode-tailscale',
} as vscode.ExtensionContext;

const configPath = path.join(extensionContext.globalStoragePath, 'config.json');

beforeEach(() => {
if (fs.existsSync(configPath)) {
fs.unlinkSync(configPath);
}
});

test('withContext will create directory if it does not exist', () => {
fs.rmSync(extensionContext.globalStoragePath, { recursive: true, force: true });
expect(fs.existsSync(extensionContext.globalStoragePath)).toBe(false);

ConfigManager.withContext(extensionContext);
expect(fs.existsSync(extensionContext.globalStoragePath)).toBe(true);
});

test('withContext returns an initialized ConfigManager', () => {
const cm = ConfigManager.withContext(extensionContext);
expect(cm.configPath).toBe(configPath);
});

test('set persists config to disk', () => {
const cm = new ConfigManager(configPath);
const hosts = {
'host-1': {
user: 'foo',
rootDir: '/',
},
};

cm.set('hosts', hosts);
expect(cm.get('hosts')).toEqual(hosts);

const f = fs.readFileSync(configPath, 'utf8');
expect(JSON.parse(f)).toEqual({ hosts });
});
49 changes: 49 additions & 0 deletions src/config-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';

interface Host {
user: string;
rootDir: string;
}

interface Config {
defaultHost?: Host;
hosts?: Record<string, Host>;
}

export class ConfigManager {
private config: Config;

constructor(public readonly configPath: string) {
if (fs.existsSync(this.configPath)) {
const rawData = fs.readFileSync(this.configPath, 'utf8');
this.config = JSON.parse(rawData);
} else {
this.config = {};
}
}

static withContext(context: vscode.ExtensionContext) {
const globalStoragePath = context.globalStoragePath;

if (!fs.existsSync(globalStoragePath)) {
fs.mkdirSync(globalStoragePath);
}

return new ConfigManager(path.join(globalStoragePath, 'config.json'));
}

get<K extends keyof Config>(key: K): Config[K] {
return this.config[key];
}

set<K extends keyof Config>(key: K, value: Config[K]) {
this.config[key] = value;
this.saveConfig();
}

private saveConfig() {
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf8');
}
}

0 comments on commit 5f93acc

Please sign in to comment.