Skip to content

Commit bdf610d

Browse files
Fix windows support for sync destination (#458)
Fixes #443 --------- Co-authored-by: Fabian Jakobs <[email protected]>
1 parent 80a105f commit bdf610d

17 files changed

+279
-321
lines changed

packages/databricks-vscode/src/cli/BricksTasks.test.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ import {Uri} from "vscode";
55
import {ProfileAuthProvider} from "../configuration/auth/AuthProvider";
66
import type {ConnectionManager} from "../configuration/ConnectionManager";
77
import {DatabricksWorkspace} from "../configuration/DatabricksWorkspace";
8-
import {SyncDestination} from "../configuration/SyncDestination";
8+
import {
9+
LocalUri,
10+
SyncDestinationMapper,
11+
} from "../configuration/SyncDestination";
912
import {PackageMetaData} from "../utils/packageJsonUtils";
1013
import {LazyCustomSyncTerminal, SyncTask} from "./BricksTasks";
1114
import type {CliWrapper} from "./CliWrapper";
@@ -65,16 +68,16 @@ describe(__filename, () => {
6568
)
6669
);
6770

68-
const mockSyncDestination = mock(SyncDestination);
69-
when(mockSyncDestination.vscodeWorkspacePath).thenReturn(
70-
Uri.file("/path/to/local/workspace")
71+
const mockSyncDestination = mock(SyncDestinationMapper);
72+
when(mockSyncDestination.localUri).thenReturn(
73+
new LocalUri(Uri.file("/path/to/local/workspace"))
7174
);
7275

7376
when(connection.databricksWorkspace).thenReturn(
7477
instance(mockDbWorkspace)
7578
);
7679

77-
when(connection.syncDestination).thenReturn(
80+
when(connection.syncDestinationMapper).thenReturn(
7881
instance(mockSyncDestination)
7982
);
8083

packages/databricks-vscode/src/cli/BricksTasks.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ export class LazyCustomSyncTerminal extends CustomSyncTerminal {
220220
@withLogContext(Loggers.Extension)
221221
getProcessOptions(@context ctx?: Context): SpawnOptions {
222222
const workspacePath =
223-
this.connection.syncDestination?.vscodeWorkspacePath.fsPath;
223+
this.connection.syncDestinationMapper?.localUri.path;
224224
if (!workspacePath) {
225225
throw this.showErrorAndKillThis(
226226
"Can't start sync: No workspace opened!",
@@ -273,7 +273,7 @@ export class LazyCustomSyncTerminal extends CustomSyncTerminal {
273273
if (this.command) {
274274
return this.command;
275275
}
276-
const syncDestination = this.connection.syncDestination;
276+
const syncDestination = this.connection.syncDestinationMapper;
277277

278278
if (!syncDestination) {
279279
throw this.showErrorAndKillThis(

packages/databricks-vscode/src/cli/CliWrapper.test.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import * as assert from "assert";
22
import {Uri} from "vscode";
3-
import {SyncDestination} from "../configuration/SyncDestination";
3+
import {
4+
LocalUri,
5+
RemoteUri,
6+
SyncDestinationMapper,
7+
} from "../configuration/SyncDestination";
48
import {promisify} from "node:util";
59
import {execFile as execFileCb} from "node:child_process";
610
import {withFile} from "tmp-promise";
711
import {writeFile} from "node:fs/promises";
812

913
import {CliWrapper} from "./CliWrapper";
10-
import {instance, mock} from "ts-mockito";
11-
import {WorkspaceFsRepo} from "@databricks/databricks-sdk";
1214
import path from "node:path";
1315

1416
const execFile = promisify(execFileCb);
@@ -26,13 +28,16 @@ describe(__filename, () => {
2628
return path;
2729
},
2830
} as any);
29-
const mapper = new SyncDestination(
30-
instance(mock(WorkspaceFsRepo)),
31-
Uri.from({
32-
scheme: "wsfs",
33-
path: "/Workspace/Repos/[email protected]/notebook-best-practices",
34-
}),
35-
Uri.file("/Users/fabian.jakobs/Desktop/notebook-best-practices")
31+
const mapper = new SyncDestinationMapper(
32+
new LocalUri(
33+
Uri.file("/Users/fabian.jakobs/Desktop/notebook-best-practices")
34+
),
35+
new RemoteUri(
36+
Uri.from({
37+
scheme: "wsfs",
38+
path: "/Repos/[email protected]/notebook-best-practices",
39+
})
40+
)
3641
);
3742

3843
let {command, args} = cli.getSyncCommand(mapper, "incremental");

packages/databricks-vscode/src/cli/CliWrapper.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {execFile as execFileCb, spawn} from "child_process";
22
import {ExtensionContext} from "vscode";
3-
import {SyncDestination} from "../configuration/SyncDestination";
3+
import {SyncDestinationMapper} from "../configuration/SyncDestination";
44
import {workspaceConfigs} from "../vscode-objs/WorkspaceConfigs";
55
import {promisify} from "node:util";
66

@@ -41,14 +41,14 @@ export class CliWrapper {
4141
* Constructs the bricks sync command
4242
*/
4343
getSyncCommand(
44-
syncDestination: SyncDestination,
44+
syncDestination: SyncDestinationMapper,
4545
syncType: SyncType
4646
): Command {
4747
const command = this.context.asAbsolutePath("./bin/bricks");
4848
const args = [
4949
"sync",
5050
"--remote-path",
51-
syncDestination.relativeWsfsDirPath,
51+
syncDestination.remoteUri.path,
5252
"--watch",
5353
];
5454
if (syncType === "full") {

packages/databricks-vscode/src/configuration/ConfigurationDataProvider.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import {ConfigurationDataProvider} from "./ConfigurationDataProvider";
77
import {ApiClient, Cluster} from "@databricks/databricks-sdk";
88
import {ConnectionManager} from "./ConnectionManager";
99
import {resolveProviderResult} from "../test/utils";
10-
import {SyncDestination} from "./SyncDestination";
10+
import {SyncDestinationMapper} from "./SyncDestination";
1111
import {CodeSynchronizer} from "../sync/CodeSynchronizer";
1212

1313
describe(__filename, () => {
1414
let connectionManagerMock: ConnectionManager;
1515
let disposables: Array<Disposable>;
1616
let onChangeClusterListener: (e: Cluster) => void;
17-
let onChangeSyncDestinationListener: (e: SyncDestination) => void;
17+
let onChangeSyncDestinationListener: (e: SyncDestinationMapper) => void;
1818
let sync: CodeSynchronizer;
1919

2020
beforeEach(() => {
@@ -87,7 +87,7 @@ describe(__filename, () => {
8787
);
8888

8989
assert(!called);
90-
onChangeSyncDestinationListener(instance(mock(SyncDestination)));
90+
onChangeSyncDestinationListener(instance(mock(SyncDestinationMapper)));
9191
assert(called);
9292
});
9393

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export class ConfigurationDataProvider
7676
}
7777

7878
const cluster = this.connectionManager.cluster;
79-
const syncDestination = this.connectionManager.syncDestination;
79+
const syncDestination = this.connectionManager.syncDestinationMapper;
8080

8181
if (!element) {
8282
const children: Array<ConfigurationTreeItem> = [];
@@ -131,16 +131,20 @@ export class ConfigurationDataProvider
131131
contextValue: "clusterDetached",
132132
});
133133
}
134-
135134
if (syncDestination) {
135+
const url = this.connectionManager.workspaceClient
136+
? await syncDestination.remoteUri.getUrl(
137+
this.connectionManager.workspaceClient
138+
)
139+
: undefined;
136140
// TODO: Add another icon over here for in_progress state
137141
// DECO-220
138142
children.push({
139143
label: `Sync Destination`,
140144
iconPath: new ThemeIcon("file-directory"),
141145
id: "SYNC-DESTINATION",
142146
collapsibleState: TreeItemCollapsibleState.Expanded,
143-
url: await syncDestination.wsfsDir.url,
147+
url: url,
144148
contextValue:
145149
this.sync.state === "WATCHING_FOR_CHANGES" ||
146150
this.sync.state === "IN_PROGRESS"
@@ -257,7 +261,7 @@ export class ConfigurationDataProvider
257261
const children: Array<TreeItem> = [
258262
{
259263
label: `Name`,
260-
description: syncDestination.name,
264+
description: syncDestination.remoteUri.name,
261265
iconPath:
262266
this.sync.state === "WATCHING_FOR_CHANGES" ||
263267
this.sync.state === "IN_PROGRESS"
@@ -268,7 +272,7 @@ export class ConfigurationDataProvider
268272
];
269273

270274
if (
271-
syncDestination.name !== syncDestination.vscodeWorkspacePathName
275+
syncDestination.remoteUri.name !== syncDestination.localUri.name
272276
) {
273277
children.push({
274278
label: "The remote sync destination name does not match the current vscode workspace name",
@@ -288,7 +292,7 @@ export class ConfigurationDataProvider
288292
},
289293
{
290294
label: `Path`,
291-
description: syncDestination.path.path,
295+
description: syncDestination.remoteUri.path,
292296
collapsibleState: TreeItemCollapsibleState.None,
293297
}
294298
);

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {ConnectionManager} from "./ConnectionManager";
1616
import {UrlUtils} from "../utils";
1717
import {workspaceConfigs} from "../vscode-objs/WorkspaceConfigs";
1818
import {WorkspaceFsCommands} from "../workspace-fs";
19-
import {REPO_NAME_SUFFIX} from "./SyncDestination";
19+
import {RemoteUri, REPO_NAME_SUFFIX} from "./SyncDestination";
2020

2121
function formatQuickPickClusterSize(sizeInMB: number): string {
2222
if (sizeInMB > 1024) {
@@ -300,9 +300,12 @@ export class ConnectionCommands implements Disposable {
300300
const fn = async () => {
301301
const selection = input
302302
.selectedItems[0] as WorkspaceFsQuickPickItem;
303-
if (selection.label !== "Create New Sync Destination") {
303+
if (
304+
selection.label !== "Create New Sync Destination" &&
305+
selection.path
306+
) {
304307
this.connectionManager.attachSyncDestination(
305-
Uri.from({scheme: "wsfs", path: selection.path})
308+
new RemoteUri(selection.path)
306309
);
307310
return;
308311
}
@@ -316,10 +319,7 @@ export class ConnectionCommands implements Disposable {
316319
return;
317320
}
318321
this.connectionManager.attachSyncDestination(
319-
Uri.from({
320-
scheme: "wsfs",
321-
path: created.path,
322-
})
322+
new RemoteUri(created.path)
323323
);
324324
};
325325
try {

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

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
workspace as vscodeWorkspace,
88
} from "vscode";
99
import {CliWrapper} from "../cli/CliWrapper";
10-
import {SyncDestination} from "./SyncDestination";
10+
import {SyncDestinationMapper, RemoteUri, LocalUri} from "./SyncDestination";
1111
import {
1212
ConfigFileError,
1313
ProjectConfig,
@@ -31,7 +31,7 @@ export type ConnectionState = "CONNECTED" | "CONNECTING" | "DISCONNECTED";
3131
export class ConnectionManager {
3232
private _state: ConnectionState = "DISCONNECTED";
3333
private _workspaceClient?: WorkspaceClient;
34-
private _syncDestination?: SyncDestination;
34+
private _syncDestinationMapper?: SyncDestinationMapper;
3535
private _projectConfigFile?: ProjectConfigFile;
3636
private _clusterManager?: ClusterManager;
3737
private _databricksWorkspace?: DatabricksWorkspace;
@@ -42,7 +42,7 @@ export class ConnectionManager {
4242
Cluster | undefined
4343
> = new EventEmitter();
4444
private readonly onDidChangeSyncDestinationEmitter: EventEmitter<
45-
SyncDestination | undefined
45+
SyncDestinationMapper | undefined
4646
> = new EventEmitter();
4747

4848
public readonly onDidChangeState = this.onDidChangeStateEmitter.event;
@@ -64,8 +64,8 @@ export class ConnectionManager {
6464
return this._clusterManager?.cluster;
6565
}
6666

67-
get syncDestination(): SyncDestination | undefined {
68-
return this._syncDestination;
67+
get syncDestinationMapper(): SyncDestinationMapper | undefined {
68+
return this._syncDestinationMapper;
6969
}
7070

7171
get databricksWorkspace(): DatabricksWorkspace | undefined {
@@ -184,9 +184,7 @@ export class ConnectionManager {
184184

185185
if (projectConfigFile.workspacePath) {
186186
await this.attachSyncDestination(
187-
SyncDestination.normalizeWorkspacePath(
188-
projectConfigFile.workspacePath
189-
),
187+
new RemoteUri(projectConfigFile.workspacePath),
190188
true
191189
);
192190
} else {
@@ -361,7 +359,7 @@ export class ConnectionManager {
361359
}
362360

363361
async attachSyncDestination(
364-
workspacePath: Uri,
362+
remoteWorkspace: RemoteUri,
365363
skipWrite = false
366364
): Promise<void> {
367365
try {
@@ -380,39 +378,35 @@ export class ConnectionManager {
380378
"Can't attach a Sync Destination when profile is not connected"
381379
);
382380
}
383-
if (!(await SyncDestination.validateRemote(this, workspacePath))) {
381+
if (!(await remoteWorkspace.validate(this))) {
384382
await this.detachSyncDestination();
385383
return;
386384
}
387385

388386
if (!skipWrite) {
389-
this._projectConfigFile!.workspacePath = workspacePath;
387+
this._projectConfigFile!.workspacePath = remoteWorkspace.uri;
390388
await this._projectConfigFile!.write();
391389
}
392390

393391
const wsUri = vscodeWorkspace.workspaceFolders[0].uri;
394392
this.updateSyncDestination(
395-
await SyncDestination.from(
396-
this.workspaceClient,
397-
workspacePath,
398-
wsUri
399-
)
393+
new SyncDestinationMapper(new LocalUri(wsUri), remoteWorkspace)
400394
);
401395
} catch (e) {
402396
NamedLogger.getOrCreate("Extension").error(
403397
"Attach Sync Destination error",
404398
e
405399
);
406400
window.showErrorMessage(
407-
`Error in attaching sync destination ${workspacePath.fsPath}`
401+
`Error in attaching sync destination ${remoteWorkspace.path}`
408402
);
409403
await this.detachSyncDestination();
410404
}
411405
}
412406

413407
async detachSyncDestination(): Promise<void> {
414408
if (
415-
!this._syncDestination &&
409+
!this._syncDestinationMapper &&
416410
this._projectConfigFile?.workspacePath === undefined
417411
) {
418412
return;
@@ -450,11 +444,13 @@ export class ConnectionManager {
450444
}
451445

452446
private updateSyncDestination(
453-
newSyncDestination: SyncDestination | undefined
447+
newSyncDestination: SyncDestinationMapper | undefined
454448
) {
455-
if (this._syncDestination !== newSyncDestination) {
456-
this._syncDestination = newSyncDestination;
457-
this.onDidChangeSyncDestinationEmitter.fire(this._syncDestination);
449+
if (this._syncDestinationMapper !== newSyncDestination) {
450+
this._syncDestinationMapper = newSyncDestination;
451+
this.onDidChangeSyncDestinationEmitter.fire(
452+
this._syncDestinationMapper
453+
);
458454
}
459455
}
460456

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Disposable, workspace} from "vscode";
22
import {ConnectionManager} from "./ConnectionManager";
33
import {ProjectConfigFile} from "./ProjectConfigFile";
4-
import {SyncDestination} from "./SyncDestination";
4+
import {RemoteUri} from "./SyncDestination";
55

66
export class ProjectConfigFileWatcher implements Disposable {
77
private disposables: Array<Disposable> = [];
@@ -41,14 +41,12 @@ export class ProjectConfigFileWatcher implements Disposable {
4141
}
4242
}
4343
if (
44-
connectionManager.syncDestination?.path.path !==
44+
connectionManager.syncDestinationMapper?.remoteUri.path !==
4545
configFile.workspacePath?.path
4646
) {
4747
if (configFile.workspacePath) {
4848
await connectionManager.attachSyncDestination(
49-
SyncDestination.normalizeWorkspacePath(
50-
configFile.workspacePath
51-
)
49+
new RemoteUri(configFile.workspacePath?.path)
5250
);
5351
} else {
5452
await connectionManager.detachSyncDestination();

0 commit comments

Comments
 (0)