Skip to content

Commit 7073738

Browse files
Add file watcher for .databricks/project.json (#84)
Closes #50
1 parent 6a3137b commit 7073738

File tree

5 files changed

+125
-20
lines changed

5 files changed

+125
-20
lines changed

packages/databricks-vscode/src/configuration/ConnectionManager.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,6 @@ export class ConnectionManager {
9898
let profile;
9999

100100
try {
101-
if (!vscodeWorkspace.rootPath) {
102-
throw new Error(
103-
"Can't login to Databricks: Not in a VSCode workspace"
104-
);
105-
}
106-
107101
projectConfigFile = await ProjectConfigFile.load(
108102
vscodeWorkspace.rootPath
109103
);
@@ -173,7 +167,7 @@ export class ConnectionManager {
173167
}
174168

175169
async configureProject() {
176-
let profile;
170+
let profile: string | undefined;
177171
while (true) {
178172
profile = await selectProfile(this.cli);
179173
if (!profile) {
@@ -200,7 +194,7 @@ export class ConnectionManager {
200194

201195
case "Open configuration file":
202196
await commands.executeCommand(
203-
"databricks.openDatabricksConfigFile"
197+
"databricks.connection.openDatabricksConfigFile"
204198
);
205199
return;
206200
}
@@ -216,10 +210,6 @@ export class ConnectionManager {
216210
}
217211

218212
private async writeConfigFile(profile: string) {
219-
if (!vscodeWorkspace.rootPath) {
220-
throw new Error("Not in a VSCode workspace");
221-
}
222-
223213
const projectConfigFile = new ProjectConfigFile(
224214
{},
225215
vscodeWorkspace.rootPath
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
3+
import {Disposable, Uri, workspace} from "vscode";
4+
import {CliWrapper} from "../cli/CliWrapper";
5+
import {mkdtemp, readFile} from "fs/promises";
6+
import {ProjectConfigFile} from "./ProjectConfigFile";
7+
import * as assert from "assert";
8+
import path from "path";
9+
import * as os from "os";
10+
11+
describe(__filename, () => {
12+
let tempDir: string;
13+
before(async () => {
14+
tempDir = await mkdtemp(path.join(os.tmpdir(), "ProjectConfTests-"));
15+
});
16+
17+
it("should write config file", async () => {
18+
const expected = {
19+
clusterId: "testClusterId",
20+
profile: "testProfile",
21+
workspacePath: "workspacePath",
22+
};
23+
await new ProjectConfigFile(expected, tempDir).write();
24+
25+
const rawData = await readFile(
26+
ProjectConfigFile.getProjectConfigFilePath(tempDir),
27+
{encoding: "utf-8"}
28+
);
29+
const actual = JSON.parse(rawData);
30+
assert.deepEqual(actual, expected);
31+
});
32+
33+
it("should load config file", async () => {
34+
const expected = {
35+
clusterId: "testClusterId",
36+
profile: "testProfile",
37+
workspacePath: "workspacePath",
38+
};
39+
const actual = await ProjectConfigFile.load(tempDir);
40+
assert.deepEqual(actual.config, expected);
41+
});
42+
});

packages/databricks-vscode/src/configuration/ProjectConfigFile.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,45 @@ export interface ProjectConfig {
1010
export class ConfigFileError extends Error {}
1111

1212
export class ProjectConfigFile {
13-
constructor(public config: ProjectConfig, private projectDir: string) {}
13+
constructor(public config: ProjectConfig, readonly rootPath?: string) {}
14+
15+
get profile() {
16+
return this.config.profile;
17+
}
1418

1519
set profile(profile: string | undefined) {
1620
this.config.profile = profile;
1721
}
1822

23+
get clusterId() {
24+
return this.config.clusterId;
25+
}
26+
1927
set clusterId(clusterId: string | undefined) {
2028
this.config.clusterId = clusterId;
2129
}
2230

31+
get workspacePath() {
32+
return this.config.workspacePath;
33+
}
34+
2335
set workspacePath(workspacePath: string | undefined) {
2436
this.config.workspacePath = workspacePath;
2537
}
2638

2739
async write() {
40+
try {
41+
const originalConfig = await ProjectConfigFile.load(this.rootPath);
42+
if (
43+
JSON.stringify(originalConfig.config, null, 2) ===
44+
JSON.stringify(this.config, null, 2)
45+
) {
46+
return;
47+
}
48+
} catch (e) {}
49+
2850
let fileName = ProjectConfigFile.getProjectConfigFilePath(
29-
this.projectDir
51+
this.rootPath
3052
);
3153
await fs.mkdir(path.dirname(fileName), {recursive: true});
3254

@@ -35,8 +57,8 @@ export class ProjectConfigFile {
3557
});
3658
}
3759

38-
static async load(projectDir: string): Promise<ProjectConfigFile> {
39-
const projectConfigFilePath = this.getProjectConfigFilePath(projectDir);
60+
static async load(rootPath?: string): Promise<ProjectConfigFile> {
61+
const projectConfigFilePath = this.getProjectConfigFilePath(rootPath);
4062

4163
let rawConfig;
4264
try {
@@ -60,11 +82,14 @@ export class ProjectConfigFile {
6082
throw new ConfigFileError("Error parsing project config file");
6183
}
6284

63-
return new ProjectConfigFile(config, projectDir);
85+
return new ProjectConfigFile(config, rootPath);
6486
}
6587

66-
private static getProjectConfigFilePath(projectDir: string): string {
67-
let cwd = path.normalize(projectDir);
88+
static getProjectConfigFilePath(rootPath?: string): string {
89+
if (!rootPath) {
90+
throw new Error("Not in a VSCode workspace");
91+
}
92+
let cwd = path.normalize(rootPath);
6893
return path.join(cwd, ".databricks", "project.json");
6994
}
7095
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {Disposable, workspace} from "vscode";
2+
import {ConnectionManager} from "./ConnectionManager";
3+
import {ProjectConfigFile} from "./ProjectConfigFile";
4+
5+
export class ProjectConfigFileWatcher implements Disposable {
6+
private disposables: Array<Disposable> = [];
7+
constructor(
8+
readonly connectionManager: ConnectionManager,
9+
rootPath?: string
10+
) {
11+
const fileSystemWatcher = workspace.createFileSystemWatcher(
12+
ProjectConfigFile.getProjectConfigFilePath(rootPath)
13+
);
14+
15+
this.disposables.push(
16+
fileSystemWatcher,
17+
fileSystemWatcher.onDidCreate(async (e) => {
18+
if (connectionManager.state !== "CONNECTED") {
19+
connectionManager.login();
20+
}
21+
}, this),
22+
fileSystemWatcher.onDidChange(async (e) => {
23+
const configFile = await ProjectConfigFile.load(rootPath);
24+
if (configFile.profile !== connectionManager.profile) {
25+
connectionManager.login();
26+
}
27+
}, this),
28+
fileSystemWatcher.onDidDelete((e) => {
29+
connectionManager.logout();
30+
}, this)
31+
);
32+
}
33+
dispose() {
34+
this.disposables.forEach((item) => item.dispose());
35+
}
36+
}

packages/databricks-vscode/src/extension.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import {commands, debug, ExtensionContext, tasks, window} from "vscode";
1+
import {
2+
commands,
3+
debug,
4+
ExtensionContext,
5+
tasks,
6+
window,
7+
workspace,
8+
} from "vscode";
29
import {CliWrapper} from "./cli/CliWrapper";
310
import {ConnectionCommands} from "./configuration/ConnectionCommands";
411
import {ConnectionManager} from "./configuration/ConnectionManager";
@@ -13,6 +20,7 @@ import {DatabricksWorkflowDebugAdapterFactory} from "./run/DabaricksWorkflowDebu
1320
import {SyncCommands} from "./sync/SyncCommands";
1421
import {CodeSynchronizer} from "./sync/CodeSynchronizer";
1522
import {BricksTaskProvider} from "./cli/BricksTasks";
23+
import {ProjectConfigFileWatcher} from "./configuration/ProjectConfigFileWatcher";
1624

1725
export function activate(context: ExtensionContext) {
1826
let cli = new CliWrapper(context);
@@ -176,6 +184,10 @@ export function activate(context: ExtensionContext) {
176184
cliCommands
177185
)
178186
);
187+
188+
context.subscriptions.push(
189+
new ProjectConfigFileWatcher(connectionManager, workspace.rootPath)
190+
);
179191
}
180192

181193
// this method is called when your extension is deactivated

0 commit comments

Comments
 (0)