Refresh master with initial release/0.24 snapshot (#332)

* Initial port of release/0.24 source code

* Fix additional headers

* Fix a typo in launch.json
This commit is contained in:
Karl Burtram
2017-12-15 15:38:57 -08:00
committed by GitHub
parent 271b3a0b82
commit 6ad0df0e3e
7118 changed files with 107999 additions and 56466 deletions

View File

@@ -7,10 +7,9 @@
import * as path from 'path';
import * as crypto from 'crypto';
import * as platform from 'vs/base/common/platform';
import pfs = require('vs/base/node/pfs');
import Uri from 'vs/base/common/uri';
import { Queue } from 'vs/base/common/async';
import { ResourceQueue } from 'vs/base/common/async';
import { IBackupFileService, BACKUP_FILE_UPDATE_OPTIONS } from 'vs/workbench/services/backup/common/backup';
import { IFileService } from 'vs/platform/files/common/files';
import { TPromise } from 'vs/base/common/winjs.base';
@@ -88,24 +87,29 @@ export class BackupFilesModel implements IBackupFilesModel {
export class BackupFileService implements IBackupFileService {
private static readonly META_MARKER = '\n';
public _serviceBrand: any;
private static readonly META_MARKER = '\n';
private backupWorkspacePath: string;
private isShuttingDown: boolean;
private ready: TPromise<IBackupFilesModel>;
/**
* Ensure IO operations on individual files are performed in order, this could otherwise lead
* to unexpected behavior when backups are persisted and discarded in the wrong order.
*/
private ioOperationQueues: { [path: string]: Queue<void> };
private ioOperationQueues: ResourceQueue<void>; // queue IO operations to ensure write order
constructor(
private backupWorkspacePath: string,
backupWorkspacePath: string,
@IFileService private fileService: IFileService
) {
this.isShuttingDown = false;
this.ioOperationQueues = {};
this.ioOperationQueues = new ResourceQueue<void>();
this.initialize(backupWorkspacePath);
}
public initialize(backupWorkspacePath: string): void {
this.backupWorkspacePath = backupWorkspacePath;
this.ready = this.init();
}
@@ -141,16 +145,6 @@ export class BackupFileService implements IBackupFileService {
return backupResource;
}
// Otherwise: on Windows and Mac pre v1.11 we used to store backups in lowercase format
// Therefor we also want to check if we have backups of this old format hanging around
// TODO@Ben migration
if (platform.isWindows || platform.isMacintosh) {
const legacyBackupResource = this.getBackupResource(resource, true /* legacyMacWindowsFormat */);
if (model.has(legacyBackupResource)) {
return legacyBackupResource;
}
}
return void 0;
});
}
@@ -173,7 +167,7 @@ export class BackupFileService implements IBackupFileService {
// Add metadata to top of file
content = `${resource.toString()}${BackupFileService.META_MARKER}${content}`;
return this.getResourceIOQueue(backupResource).queue(() => {
return this.ioOperationQueues.queueFor(backupResource).queue(() => {
return this.fileService.updateContent(backupResource, content, BACKUP_FILE_UPDATE_OPTIONS).then(() => model.add(backupResource, versionId));
});
});
@@ -186,40 +180,12 @@ export class BackupFileService implements IBackupFileService {
return void 0;
}
return this.getResourceIOQueue(backupResource).queue(() => {
return this.ioOperationQueues.queueFor(backupResource).queue(() => {
return pfs.del(backupResource.fsPath).then(() => model.remove(backupResource));
}).then(() => {
// On Windows and Mac pre v1.11 we used to store backups in lowercase format
// Therefor we also want to check if we have backups of this old format laying around
// TODO@Ben migration
if (platform.isWindows || platform.isMacintosh) {
const legacyBackupResource = this.getBackupResource(resource, true /* legacyMacWindowsFormat */);
if (model.has(legacyBackupResource)) {
return this.getResourceIOQueue(legacyBackupResource).queue(() => {
return pfs.del(legacyBackupResource.fsPath).then(() => model.remove(legacyBackupResource));
});
}
}
return TPromise.as(void 0);
});
});
}
private getResourceIOQueue(resource: Uri) {
const key = resource.toString();
if (!this.ioOperationQueues[key]) {
const queue = new Queue<void>();
queue.onFinished(() => {
queue.dispose();
delete this.ioOperationQueues[key];
});
this.ioOperationQueues[key] = queue;
}
return this.ioOperationQueues[key];
}
public discardAllWorkspaceBackups(): TPromise<void> {
this.isShuttingDown = true;
@@ -252,17 +218,15 @@ export class BackupFileService implements IBackupFileService {
return textSource.lines.slice(1).join(textSource.EOL); // The first line of a backup text file is the file name
}
protected getBackupResource(resource: Uri, legacyMacWindowsFormat?: boolean): Uri {
protected getBackupResource(resource: Uri): Uri {
if (!this.backupEnabled) {
return null;
}
return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, this.hashPath(resource, legacyMacWindowsFormat)));
return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, this.hashPath(resource)));
}
private hashPath(resource: Uri, legacyMacWindowsFormat?: boolean): string {
const caseAwarePath = legacyMacWindowsFormat ? resource.fsPath.toLowerCase() : resource.fsPath;
return crypto.createHash('md5').update(caseAwarePath).digest('hex');
private hashPath(resource: Uri): string {
return crypto.createHash('md5').update(resource.fsPath).digest('hex');
}
}

View File

@@ -19,8 +19,8 @@ import { FileService } from 'vs/workbench/services/files/node/fileService';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
import { RawTextSource } from 'vs/editor/common/model/textSource';
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath } from 'vs/workbench/test/workbenchTestServices';
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
class TestEnvironmentService extends EnvironmentService {
@@ -34,7 +34,7 @@ class TestEnvironmentService extends EnvironmentService {
get backupWorkspacesPath(): string { return this._backupWorkspacesPath; }
}
const parentDir = path.join(os.tmpdir(), 'vsctests', 'service');
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
const backupHome = path.join(parentDir, 'Backups');
const workspacesJsonPath = path.join(backupHome, 'workspaces.json');
@@ -44,19 +44,18 @@ const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo');
const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
const untitledFile = Uri.from({ scheme: 'untitled', path: 'Untitled-1' });
const fooBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath).digest('hex'));
const fooBackupPathLegacy = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath.toLowerCase()).digest('hex'));
const barBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(barFile.fsPath).digest('hex'));
const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', crypto.createHash('md5').update(untitledFile.fsPath).digest('hex'));
class TestBackupFileService extends BackupFileService {
constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, [workspace])), new TestConfigurationService(), { disableWatcher: true });
const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true });
super(workspaceBackupPath, fileService);
}
public getBackupResource(resource: Uri, legacyMacWindowsFormat?: boolean): Uri {
return super.getBackupResource(resource, legacyMacWindowsFormat);
public getBackupResource(resource: Uri): Uri {
return super.getBackupResource(resource);
}
}
@@ -115,47 +114,6 @@ suite('BackupFileService', () => {
});
});
});
test('should return whether a backup resource exists - legacy support (read old lowercase format as fallback)', done => {
if (platform.isLinux) {
done();
return; // only on mac and windows
}
pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
fs.writeFileSync(fooBackupPathLegacy, 'foo');
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service.loadBackupResource(fooFile).then(resource => {
assert.ok(resource);
assert.equal(path.basename(resource.fsPath), path.basename(fooBackupPathLegacy));
return service.hasBackups().then(hasBackups => {
assert.ok(hasBackups);
done();
});
});
});
});
test('should return whether a backup resource exists - legacy support #2 (both cases present, return case sensitive backup)', done => {
if (platform.isLinux) {
done();
return; // only on mac and windows
}
pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
fs.writeFileSync(fooBackupPath, 'foo');
fs.writeFileSync(fooBackupPathLegacy, 'foo');
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service.loadBackupResource(fooFile).then(resource => {
assert.ok(resource);
assert.equal(path.basename(resource.fsPath), path.basename(fooBackupPath));
return service.hasBackups().then(hasBackups => {
assert.ok(hasBackups);
done();
});
});
});
});
});
suite('backupResource', () => {
@@ -200,27 +158,6 @@ suite('BackupFileService', () => {
});
});
});
test('text file - legacy support (dicard lowercase backup file if present)', done => {
if (platform.isLinux) {
done();
return; // only on mac and windows
}
pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
fs.writeFileSync(fooBackupPathLegacy, 'foo');
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service.backupResource(fooFile, 'test').then(() => {
assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2);
service.discardResourceBackup(fooFile).then(() => {
assert.equal(fs.existsSync(fooBackupPath), false);
assert.equal(fs.existsSync(fooBackupPathLegacy), false);
assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0);
done();
});
});
});
});
});
suite('discardAllWorkspaceBackups', () => {