mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd * fix issues with merges * bump node version in azpipe * replace license headers * remove duplicate launch task * fix build errors * fix build errors * fix tslint issues * working through package and linux build issues * more work * wip * fix packaged builds * working through linux build errors * wip * wip * wip * fix mac and linux file limits * iterate linux pipeline * disable editor typing * revert series to parallel * remove optimize vscode from linux * fix linting issues * revert testing change * add work round for new node * readd packaging for extensions * fix issue with angular not resolving decorator dependencies
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as crypto from 'crypto';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { URI as Uri } from 'vs/base/common/uri';
|
||||
@@ -14,6 +14,9 @@ import { readToMatchingString } from 'vs/base/node/stream';
|
||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel';
|
||||
import { keys } from 'vs/base/common/map';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
|
||||
export interface IBackupFilesModel {
|
||||
resolve(backupRoot: string): Promise<IBackupFilesModel>;
|
||||
@@ -106,6 +109,63 @@ export class BackupFilesModel implements IBackupFilesModel {
|
||||
|
||||
export class BackupFileService implements IBackupFileService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
private impl: IBackupFileService;
|
||||
|
||||
constructor(
|
||||
@IWindowService windowService: IWindowService,
|
||||
@IFileService fileService: IFileService
|
||||
) {
|
||||
const backupWorkspacePath = windowService.getConfiguration().backupPath;
|
||||
if (backupWorkspacePath) {
|
||||
this.impl = new BackupFileServiceImpl(backupWorkspacePath, fileService);
|
||||
} else {
|
||||
this.impl = new InMemoryBackupFileService();
|
||||
}
|
||||
}
|
||||
|
||||
initialize(backupWorkspacePath: string): void {
|
||||
if (this.impl instanceof BackupFileServiceImpl) {
|
||||
this.impl.initialize(backupWorkspacePath);
|
||||
}
|
||||
}
|
||||
|
||||
hasBackups(): Promise<boolean> {
|
||||
return this.impl.hasBackups();
|
||||
}
|
||||
|
||||
loadBackupResource(resource: Uri): Promise<Uri | undefined> {
|
||||
return this.impl.loadBackupResource(resource);
|
||||
}
|
||||
|
||||
backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise<void> {
|
||||
return this.impl.backupResource(resource, content, versionId);
|
||||
}
|
||||
|
||||
discardResourceBackup(resource: Uri): Promise<void> {
|
||||
return this.impl.discardResourceBackup(resource);
|
||||
}
|
||||
|
||||
discardAllWorkspaceBackups(): Promise<void> {
|
||||
return this.impl.discardAllWorkspaceBackups();
|
||||
}
|
||||
|
||||
getWorkspaceFileBackups(): Promise<Uri[]> {
|
||||
return this.impl.getWorkspaceFileBackups();
|
||||
}
|
||||
|
||||
resolveBackupContent(backup: Uri): Promise<ITextBufferFactory | undefined> {
|
||||
return this.impl.resolveBackupContent(backup);
|
||||
}
|
||||
|
||||
toBackupResource(resource: Uri): Uri {
|
||||
return this.impl.toBackupResource(resource);
|
||||
}
|
||||
}
|
||||
|
||||
class BackupFileServiceImpl implements IBackupFileService {
|
||||
|
||||
private static readonly META_MARKER = '\n';
|
||||
|
||||
_serviceBrand: any;
|
||||
@@ -169,7 +229,7 @@ export class BackupFileService implements IBackupFileService {
|
||||
}
|
||||
|
||||
return this.ioOperationQueues.queueFor(backupResource).queue(() => {
|
||||
const preamble = `${resource.toString()}${BackupFileService.META_MARKER}`;
|
||||
const preamble = `${resource.toString()}${BackupFileServiceImpl.META_MARKER}`;
|
||||
|
||||
// Update content with value
|
||||
return this.fileService.updateContent(backupResource, new BackupSnapshot(content, preamble), BACKUP_FILE_UPDATE_OPTIONS).then(() => model.add(backupResource, versionId));
|
||||
@@ -201,7 +261,7 @@ export class BackupFileService implements IBackupFileService {
|
||||
|
||||
model.get().forEach(fileBackup => {
|
||||
readPromises.push(
|
||||
readToMatchingString(fileBackup.fsPath, BackupFileService.META_MARKER, 2000, 10000).then(Uri.parse)
|
||||
readToMatchingString(fileBackup.fsPath, BackupFileServiceImpl.META_MARKER, 2000, 10000).then(Uri.parse)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -216,7 +276,7 @@ export class BackupFileService implements IBackupFileService {
|
||||
let metaFound = false;
|
||||
const metaPreambleFilter = (chunk: string) => {
|
||||
if (!metaFound && chunk) {
|
||||
const metaIndex = chunk.indexOf(BackupFileService.META_MARKER);
|
||||
const metaIndex = chunk.indexOf(BackupFileServiceImpl.META_MARKER);
|
||||
if (metaIndex === -1) {
|
||||
return ''; // meta not yet found, return empty string
|
||||
}
|
||||
@@ -233,11 +293,7 @@ export class BackupFileService implements IBackupFileService {
|
||||
}
|
||||
|
||||
toBackupResource(resource: Uri): Uri {
|
||||
return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, this.hashPath(resource)));
|
||||
}
|
||||
|
||||
private hashPath(resource: Uri): string {
|
||||
return crypto.createHash('md5').update(resource.fsPath).digest('hex');
|
||||
return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, hashPath(resource)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +313,7 @@ export class InMemoryBackupFileService implements IBackupFileService {
|
||||
return Promise.resolve(backupResource);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise<void> {
|
||||
@@ -273,7 +329,7 @@ export class InMemoryBackupFileService implements IBackupFileService {
|
||||
return Promise.resolve(createTextBufferFactoryFromSnapshot(snapshot));
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getWorkspaceFileBackups(): Promise<Uri[]> {
|
||||
@@ -293,10 +349,16 @@ export class InMemoryBackupFileService implements IBackupFileService {
|
||||
}
|
||||
|
||||
toBackupResource(resource: Uri): Uri {
|
||||
return Uri.file(path.join(resource.scheme, this.hashPath(resource)));
|
||||
return Uri.file(path.join(resource.scheme, hashPath(resource)));
|
||||
}
|
||||
}
|
||||
|
||||
private hashPath(resource: Uri): string {
|
||||
return crypto.createHash('md5').update(resource.fsPath).digest('hex');
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Exported only for testing
|
||||
*/
|
||||
export function hashPath(resource: Uri): string {
|
||||
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
|
||||
return crypto.createHash('md5').update(str).digest('hex');
|
||||
}
|
||||
|
||||
registerSingleton(IBackupFileService, BackupFileService);
|
||||
@@ -8,38 +8,57 @@ import * as platform from 'vs/base/common/platform';
|
||||
import * as crypto from 'crypto';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { URI as Uri } from 'vs/base/common/uri';
|
||||
import { BackupFileService, BackupFilesModel } from 'vs/workbench/services/backup/node/backupFileService';
|
||||
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
|
||||
import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService';
|
||||
import { FileService } from 'vs/workbench/services/files/node/fileService';
|
||||
import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestEnvironmentService, TestStorageService, TestWindowService } from 'vs/workbench/test/workbenchTestServices';
|
||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { DefaultEndOfLine } from 'vs/editor/common/model';
|
||||
import { snapshotToString } from 'vs/platform/files/common/files';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
|
||||
|
||||
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
|
||||
const backupHome = path.join(parentDir, 'Backups');
|
||||
const workspacesJsonPath = path.join(backupHome, 'workspaces.json');
|
||||
|
||||
const workspaceResource = Uri.file(platform.isWindows ? 'c:\\workspace' : '/workspace');
|
||||
const workspaceBackupPath = path.join(backupHome, crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'));
|
||||
const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource));
|
||||
const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo');
|
||||
const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
|
||||
const untitledFile = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' });
|
||||
const fooBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath).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'));
|
||||
const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile));
|
||||
const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile));
|
||||
const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile));
|
||||
|
||||
class TestBackupWindowService extends TestWindowService {
|
||||
|
||||
private config: IWindowConfiguration;
|
||||
|
||||
constructor(workspaceBackupPath: string) {
|
||||
super();
|
||||
|
||||
this.config = Object.create(null);
|
||||
this.config.backupPath = workspaceBackupPath;
|
||||
}
|
||||
|
||||
getConfiguration(): IWindowConfiguration {
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
|
||||
class TestBackupFileService extends BackupFileService {
|
||||
constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
|
||||
const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), TestEnvironmentService, new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
|
||||
const windowService = new TestBackupWindowService(workspaceBackupPath);
|
||||
|
||||
super(workspaceBackupPath, fileService);
|
||||
super(windowService, fileService);
|
||||
}
|
||||
|
||||
public toBackupResource(resource: Uri): Uri {
|
||||
@@ -65,12 +84,37 @@ suite('BackupFileService', () => {
|
||||
return pfs.del(backupHome, os.tmpdir());
|
||||
});
|
||||
|
||||
suite('hashPath', () => {
|
||||
test('should correctly hash the path for untitled scheme URIs', () => {
|
||||
const uri = Uri.from({
|
||||
scheme: 'untitled',
|
||||
path: 'Untitled-1'
|
||||
});
|
||||
const actual = hashPath(uri);
|
||||
// If these hashes change people will lose their backed up files!
|
||||
assert.equal(actual, '13264068d108c6901b3592ea654fcd57');
|
||||
assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex'));
|
||||
});
|
||||
|
||||
test('should correctly hash the path for file scheme URIs', () => {
|
||||
const uri = Uri.file('/foo');
|
||||
const actual = hashPath(uri);
|
||||
// If these hashes change people will lose their backed up files!
|
||||
if (platform.isWindows) {
|
||||
assert.equal(actual, 'dec1a583f52468a020bd120c3f01d812');
|
||||
} else {
|
||||
assert.equal(actual, '1effb2475fcfba4f9e8b8a1dbc8f3caf');
|
||||
}
|
||||
assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex'));
|
||||
});
|
||||
});
|
||||
|
||||
suite('getBackupResource', () => {
|
||||
test('should get the correct backup path for text files', () => {
|
||||
// Format should be: <backupHome>/<workspaceHash>/<scheme>/<filePathHash>
|
||||
const backupResource = fooFile;
|
||||
const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex');
|
||||
const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex');
|
||||
const workspaceHash = hashPath(workspaceResource);
|
||||
const filePathHash = hashPath(backupResource);
|
||||
const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath;
|
||||
assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath);
|
||||
});
|
||||
@@ -78,8 +122,8 @@ suite('BackupFileService', () => {
|
||||
test('should get the correct backup path for untitled files', () => {
|
||||
// Format should be: <backupHome>/<workspaceHash>/<scheme>/<filePath>
|
||||
const backupResource = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' });
|
||||
const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex');
|
||||
const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex');
|
||||
const workspaceHash = hashPath(workspaceResource);
|
||||
const filePathHash = hashPath(backupResource);
|
||||
const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath;
|
||||
assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath);
|
||||
});
|
||||
@@ -257,7 +301,7 @@ suite('BackupFileService', () => {
|
||||
const contents = 'test\nand more stuff';
|
||||
service.backupResource(untitledFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
|
||||
service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => {
|
||||
assert.equal(contents, snapshotToString(factory.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
|
||||
assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -272,7 +316,7 @@ suite('BackupFileService', () => {
|
||||
|
||||
service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
|
||||
service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => {
|
||||
assert.equal(contents, snapshotToString(factory.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
|
||||
assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user