Change:
Moving this over from After the backups are not restored if the workspace directory doesn't exist anymore. The workspace is no longer tracked but the backups are kept around in the backup directory should they be needed later.
Tricky.... I would expect an empty window to open with those files dirty. This might require some work on the area of restoring on empty workspaces. Have not thought about this longer yet.
Marking as important because this means data loss if the folder is deleted on disk.
maybe this should be done on the main side on startup similarly to If a folder no longer exists, convert it into an empty workspace backup and let it open as empty window.
On test plan:

Discussion:
public registerWindowForBackups(windowId: number, isEmptyWorkspace: boolean, backupFolder?: string, workspacePath?: string): void { // Generate a new folder if this is a new empty workspace if (isEmptyWorkspace && !backupFolder) { <del> backupFolder = Date.now().toString(); </del> <ins> backupFolder = this.getRandomEmptyWorkspaceId(); </ins> } this.mapWindowToBackupFolder[windowId] = isEmptyWorkspace ? backupFolder : this.getWorkspaceHash(workspacePath); this.pushBackupPathsSync(isEmptyWorkspace ? backupFolder : workspacePath, isEmptyWorkspace); } <del> protected pushBackupPathsSync(workspaceIdentifier: string, isEmptyWorkspace: boolean): void { </del> <ins> private getRandomEmptyWorkspaceId(): string { return (Date.now() + Math.round(Math.random() * 1000)).toString(); } protected pushBackupPathsSync(workspaceIdentifier: string, isEmptyWorkspace: boolean): string { </ins> if (!isEmptyWorkspace) { workspaceIdentifier = this.sanitizePath(workspaceIdentifier); }

array.push(workspaceIdentifier); this.saveSync(); } <ins> return workspaceIdentifier; </ins> } protected removeBackupPathSync(workspaceIdentifier: string, isEmptyWorkspace: boolean): void {

backups.folderWorkspaces.forEach(workspacePath => { const backupPath = path.join(this.backupHome, this.getWorkspaceHash(workspacePath)); <del> if (!this.hasBackupsSync(backupPath)) { </del> <ins> const hasBackups = this.hasBackupsSync(backupPath); const missingWorkspace = hasBackups && !fs.existsSync(workspacePath); // If the folder has no backups, make sure to delete it // If the folder has backups, but the target workspace is missing, convert backups to empty ones if (!hasBackups || missingWorkspace) { </ins> const backupWorkspace = this.sanitizePath(workspacePath); staleBackupWorkspaces.push({ workspaceIdentifier: Uri.file(backupWorkspace).fsPath, backupPath, isEmptyWorkspace: false }); <ins> if (missingWorkspace) { const identifier = this.pushBackupPathsSync(this.getRandomEmptyWorkspaceId(), true /* is empty workspace */); const newEmptyWorkspaceBackupPath = path.join(path.dirname(backupPath), identifier); try { fs.renameSync(backupPath, newEmptyWorkspaceBackupPath); } catch (ex) { console.error(`Backup: Could not rename backup folder for missing workspace: ${ex.toString()}`); this.removeBackupPathSync(identifier, true); } } </ins> } });

staleBackupWorkspaces.forEach(staleBackupWorkspace => { const {backupPath, workspaceIdentifier, isEmptyWorkspace} = staleBackupWorkspace; <del> extfs.delSync(backupPath); </del> <ins> try { extfs.delSync(backupPath); } catch (ex) { console.error(`Backup: Could not delete stale backup: ${ex.toString()}`); } </ins> this.removeBackupPathSync(workspaceIdentifier, isEmptyWorkspace); }); }

} fs.writeFileSync(this.workspacesJsonPath, JSON.stringify(this.backups)); } catch (ex) { <del> console.error('Could not save workspaces.json', ex); </del> <ins> console.error(`Backup: Could not save workspaces.json: ${ex.toString()}`); </ins> } }

}); test('service validates backup workspaces on startup and cleans up', done => { // 1) backup workspace path does not exist service.registerWindowForBackups(1, false, null, fooFile.fsPath); service.registerWindowForBackups(2, false, null, barFile.fsPath);

assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath))); assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath))); <ins> // 4) backup workspace path points to a workspace that no longer exists // so it should convert the backup worspace to an empty workspace backup const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), 'file'); fs.mkdirSync(service.toBackupPath(fooFile.fsPath)); fs.mkdirSync(service.toBackupPath(barFile.fsPath)); fs.mkdirSync(fileBackups); service.registerWindowForBackups(1, false, null, fooFile.fsPath); assert.equal(service.workspaceBackupPaths.length, 1); assert.equal(service.emptyWorkspaceBackupPaths.length, 0); fs.writeFileSync(path.join(fileBackups, 'backup.txt'), ''); service.loadSync(); assert.equal(service.workspaceBackupPaths.length, 0); assert.equal(service.emptyWorkspaceBackupPaths.length, 1); </ins> done(); });