remove user data service

This commit is contained in:
Sandeep Somavarapu
2019-06-24 15:22:25 +02:00
parent 6e0979d57b
commit 7ce9a74bbd
27 changed files with 651 additions and 676 deletions

View File

@@ -9,10 +9,10 @@ import { Event, Emitter } from 'vs/base/common/event';
import * as errors from 'vs/base/common/errors';
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { RunOnceScheduler } from 'vs/base/common/async';
import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files';
import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files';
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels';
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES, USER_CONFIGURATION_KEY, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration';
import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService';
import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
@@ -23,27 +23,24 @@ import { Schemas } from 'vs/base/common/network';
import { IConfigurationModel } from 'vs/platform/configuration/common/configuration';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { hash } from 'vs/base/common/hash';
import { IUserDataService } from 'vs/workbench/services/userData/common/userData';
export class UserConfiguration extends Disposable {
readonly resource: URI;
private readonly parser: ConfigurationModelParser;
private readonly reloadConfigurationScheduler: RunOnceScheduler;
protected readonly _onDidChangeConfiguration: Emitter<ConfigurationModel> = this._register(new Emitter<ConfigurationModel>());
readonly onDidChangeConfiguration: Event<ConfigurationModel> = this._onDidChangeConfiguration.event;
constructor(
private readonly userSettingsResource: URI,
private readonly scopes: ConfigurationScope[] | undefined,
private readonly userDataService: IUserDataService
private readonly fileService: IFileService
) {
super();
this.resource = userDataService.toResource(USER_CONFIGURATION_KEY);
this.parser = new ConfigurationModelParser(USER_CONFIGURATION_KEY, this.scopes);
this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes);
this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50));
this._register(Event.filter(this.userDataService.onDidChange, e => e.contains(USER_CONFIGURATION_KEY))(() => this.reloadConfigurationScheduler.schedule()));
this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this.reloadConfigurationScheduler.schedule()));
}
async initialize(): Promise<ConfigurationModel> {
@@ -52,8 +49,8 @@ export class UserConfiguration extends Disposable {
async reload(): Promise<ConfigurationModel> {
try {
const content = (await this.userDataService.read(USER_CONFIGURATION_KEY)) || '{}';
this.parser.parseContent(content);
const content = await this.fileService.readFile(this.userSettingsResource);
this.parser.parseContent(content.value.toString() || '{}');
return this.parser.configurationModel;
} catch (e) {
return new ConfigurationModel();

View File

@@ -29,7 +29,7 @@ import { isEqual, dirname } from 'vs/base/common/resources';
import { mark } from 'vs/base/common/performance';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IFileService } from 'vs/platform/files/common/files';
import { IUserDataService } from 'vs/workbench/services/userData/common/userData';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService {
@@ -47,7 +47,6 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
private cachedFolderConfigs: ResourceMap<FolderConfiguration>;
private workspaceEditingQueue: Queue<void>;
readonly userSettingsResource: URI;
private readonly configurationFileService: ConfigurationFileService;
protected readonly _onDidChangeConfiguration: Emitter<IConfigurationChangeEvent> = this._register(new Emitter<IConfigurationChangeEvent>());
@@ -70,8 +69,8 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
constructor(
{ remoteAuthority, configurationCache }: { remoteAuthority?: string, configurationCache: IConfigurationCache },
environmentService: IWorkbenchEnvironmentService,
fileService: IFileService,
userDataService: IUserDataService,
remoteAgentService: IRemoteAgentService
) {
super();
@@ -82,8 +81,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic
this.configurationFileService = new ConfigurationFileService(fileService);
this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap<ConfigurationModel>(), this.workspace);
this.cachedFolderConfigs = new ResourceMap<FolderConfiguration>();
this.localUserConfiguration = this._register(new UserConfiguration(remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, userDataService));
this.userSettingsResource = this.localUserConfiguration.resource;
this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService));
this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration)));
if (remoteAuthority) {
this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, this.configurationFileService, remoteAgentService));

View File

@@ -8,7 +8,6 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { IFileService } from 'vs/platform/files/common/files';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
export const USER_CONFIGURATION_KEY = 'settings.json';
export const FOLDER_CONFIG_FOLDER_NAME = '.vscode';
export const FOLDER_SETTINGS_NAME = 'settings';
export const FOLDER_SETTINGS_PATH = `${FOLDER_CONFIG_FOLDER_NAME}/${FOLDER_SETTINGS_NAME}.json`;

View File

@@ -10,16 +10,18 @@ import * as strings from 'vs/base/common/strings';
import { setProperty } from 'vs/base/common/jsonEdit';
import { Queue } from 'vs/base/common/async';
import { Edit } from 'vs/base/common/jsonFormatter';
import { IReference } from 'vs/base/common/lifecycle';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Registry } from 'vs/platform/registry/common/platform';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IConfigurationService, IConfigurationOverrides, keyFromOverrideIdentifier } from 'vs/platform/configuration/common/configuration';
import { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY, USER_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { FOLDER_SETTINGS_PATH, WORKSPACE_STANDALONE_CONFIGURATIONS, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY } from 'vs/workbench/services/configuration/common/configuration';
import { IFileService } from 'vs/platform/files/common/files';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
import { OVERRIDE_PROPERTY_PATTERN, IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ITextModel } from 'vs/editor/common/model';
@@ -27,14 +29,6 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { withUndefinedAsNull, withNullAsUndefined } from 'vs/base/common/types';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { IUserDataService } from 'vs/workbench/services/userData/common/userData';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Emitter } from 'vs/base/common/event';
import { LanguageIdentifier } from 'vs/editor/common/modes';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Schemas } from 'vs/base/common/network';
export const enum ConfigurationEditingErrorCode {
@@ -101,6 +95,10 @@ export interface IConfigurationValue {
}
export interface IConfigurationEditingOptions {
/**
* If `true`, do not saves the configuration. Default is `false`.
*/
donotSave?: boolean;
/**
* If `true`, do not notifies the error to user by showing the message box. Default is `false`.
*/
@@ -118,127 +116,70 @@ export const enum EditableConfigurationTarget {
WORKSPACE_FOLDER
}
interface IConfigurationEditOperation extends IDisposable {
value: IConfigurationValue;
interface IConfigurationEditOperation extends IConfigurationValue {
target: EditableConfigurationTarget;
jsonPath: json.JSONPath;
resource: URI | null;
resource?: URI;
workspaceStandAloneConfigurationKey?: string;
apply(save: boolean): Promise<void>;
}
interface ConfigurationEditingOptions extends IConfigurationEditingOptions {
donotSave?: boolean;
force?: boolean;
}
function toConfigurationEditingError(error: ConfigurationEditingErrorCode, operation: IConfigurationEditOperation, contextService: IWorkspaceContextService): ConfigurationEditingError {
switch (error) {
export class ConfigurationEditingService {
// API constraints
case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return new ConfigurationEditingError(nls.localize('errorUnknownKey', "Unable to write to {0} because {1} is not a registered configuration.", stringifyTarget(operation.target), operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION: return new ConfigurationEditingError(nls.localize('errorInvalidWorkspaceConfigurationApplication', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE: return new ConfigurationEditingError(nls.localize('errorInvalidWorkspaceConfigurationMachine', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION: return new ConfigurationEditingError(nls.localize('errorInvalidFolderConfiguration', "Unable to write to Folder Settings because {0} does not support the folder resource scope.", operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET: return new ConfigurationEditingError(nls.localize('errorInvalidUserTarget', "Unable to write to User Settings because {0} does not support for global scope.", operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET: return new ConfigurationEditingError(nls.localize('errorInvalidWorkspaceTarget', "Unable to write to Workspace Settings because {0} does not support for workspace scope in a multi folder workspace.", operation.value.key), error);
case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET: return new ConfigurationEditingError(nls.localize('errorInvalidFolderTarget', "Unable to write to Folder Settings because no resource is provided."), error);
case ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED: return new ConfigurationEditingError(nls.localize('errorNoWorkspaceOpened', "Unable to write to {0} because no workspace is opened. Please open a workspace first and try again.", stringifyTarget(operation.target)), error);
public _serviceBrand: any;
// User issues
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return new ConfigurationEditingError(nls.localize('errorInvalidTaskConfiguration', "Unable to write into the tasks configuration file. Please open it to correct errors/warnings in it and try again."), error);
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return new ConfigurationEditingError(nls.localize('errorInvalidLaunchConfiguration', "Unable to write into the launch configuration file. Please open it to correct errors/warnings in it and try again."), error);
}
switch (operation.target) {
case EditableConfigurationTarget.USER_LOCAL:
return new ConfigurationEditingError(nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open the user settings to correct errors/warnings in it and try again."), error);
case EditableConfigurationTarget.USER_REMOTE:
return new ConfigurationEditingError(nls.localize('errorInvalidRemoteConfiguration', "Unable to write into remote user settings. Please open the remote user settings to correct errors/warnings in it and try again."), error);
case EditableConfigurationTarget.WORKSPACE:
return new ConfigurationEditingError(nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open the workspace settings to correct errors/warnings in the file and try again."), error);
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = contextService.getWorkspaceFolder(operation.resource);
if (folder) {
workspaceFolderName = folder.name;
}
}
return new ConfigurationEditingError(nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open the '{0}' folder settings to correct errors/warnings in it and try again.", workspaceFolderName), error);
}
return new ConfigurationEditingError('', error);
}
case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return new ConfigurationEditingError(nls.localize('errorTasksConfigurationFileDirty', "Unable to write into tasks configuration file because the file is dirty. Please save it first and then try again."), error);
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return new ConfigurationEditingError(nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch configuration file because the file is dirty. Please save it first and then try again."), error);
}
switch (operation.target) {
case EditableConfigurationTarget.USER_LOCAL:
return new ConfigurationEditingError(nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the user settings file first and then try again."), error);
case EditableConfigurationTarget.USER_REMOTE:
return new ConfigurationEditingError(nls.localize('errorRemoteConfigurationFileDirty', "Unable to write into remote user settings because the file is dirty. Please save the remote user settings file first and then try again."), error);
case EditableConfigurationTarget.WORKSPACE:
return new ConfigurationEditingError(nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the workspace settings file first and then try again."), error);
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = contextService.getWorkspaceFolder(operation.resource);
if (folder) {
workspaceFolderName = folder.name;
}
}
return new ConfigurationEditingError(nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the '{0}' folder settings file first and then try again.", workspaceFolderName), error);
}
return new ConfigurationEditingError('', error);
}
}
}
function stringifyTarget(target: EditableConfigurationTarget): string {
switch (target) {
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('userTarget', "User Settings");
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('remoteUserTarget', "Remote User Settings");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('workspaceTarget', "Workspace Settings");
case EditableConfigurationTarget.WORKSPACE_FOLDER:
return nls.localize('folderTarget', "Folder Settings");
}
return '';
}
abstract class ConfigurationEditOperation extends Disposable implements IConfigurationEditOperation {
private queue: Queue<void>;
private remoteSettingsResource: URI | null;
constructor(
readonly value: IConfigurationValue,
readonly target: EditableConfigurationTarget,
readonly jsonPath: json.JSONPath,
readonly resource: URI | null,
readonly workspaceStandAloneConfigurationKey: string | undefined,
protected readonly contextService: IWorkspaceContextService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IFileService private readonly fileService: IFileService,
@ITextModelService private readonly textModelResolverService: ITextModelService,
@ITextFileService private readonly textFileService: ITextFileService,
@INotificationService private readonly notificationService: INotificationService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IEditorService private readonly editorService: IEditorService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
super();
this.queue = new Queue<void>();
remoteAgentService.getEnvironment().then(environment => {
if (environment) {
this.remoteSettingsResource = environment.settingsPath;
}
});
}
async apply(save: boolean): Promise<void> {
this.validate();
const model = await this.resolve();
if (this.hasParseErrors(model)) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION, this, this.contextService);
}
const edit = this.getEdits(model)[0];
if (edit && this.applyEditsToBuffer(edit, model) && save) {
await this.save(model);
}
writeConfiguration(target: EditableConfigurationTarget, value: IConfigurationValue, options: IConfigurationEditingOptions = {}): Promise<void> {
const operation = this.getConfigurationEditOperation(target, value, options.scopes || {});
return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(operation, options) // queue up writes to prevent race conditions
.then(() => null,
error => {
if (!options.donotNotifyError) {
this.onError(error, operation, options.scopes);
}
return Promise.reject(error);
})));
}
private doWriteConfiguration(operation: IConfigurationEditOperation, options: ConfigurationEditingOptions): Promise<void> {
const checkDirtyConfiguration = !(options.force || options.donotSave);
const saveConfiguration = options.force || !options.donotSave;
return this.resolveAndValidate(operation.target, operation, checkDirtyConfiguration, options.scopes || {})
.then(reference => this.writeToBuffer(reference.object.textEditorModel, operation, saveConfiguration)
.then(() => reference.dispose()));
}
private async writeToBuffer(model: ITextModel, operation: IConfigurationEditOperation, save: boolean): Promise<any> {
const edit = this.getEdits(model, operation)[0];
if (edit && this.applyEditsToBuffer(edit, model) && save) {
return this.textFileService.save(operation.resource!, { skipSaveParticipants: true /* programmatic change */ });
}
}
private applyEditsToBuffer(edit: Edit, model: ITextModel): boolean {
@@ -254,239 +195,6 @@ abstract class ConfigurationEditOperation extends Disposable implements IConfigu
return false;
}
private getEdits(model: ITextModel): Edit[] {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
// Without jsonPath, the entire configuration file is being replaced, so we just use JSON.stringify
if (!this.jsonPath.length) {
const content = JSON.stringify(this.value.value, null, insertSpaces ? strings.repeat(' ', tabSize) : '\t');
return [{
content,
length: model.getValue().length,
offset: 0
}];
}
return setProperty(model.getValue(), this.jsonPath, this.value.value, { tabSize, insertSpaces, eol });
}
private hasParseErrors(model: ITextModel): boolean {
// If we write to a workspace standalone file and replace the entire contents (no key provided)
// we can return here because any parse errors can safely be ignored since all contents are replaced
if (this.workspaceStandAloneConfigurationKey && !this.value.key) {
return false;
}
const parseErrors: json.ParseError[] = [];
json.parse(model.getValue(), parseErrors);
return parseErrors.length > 0;
}
protected abstract validate(): void;
protected abstract save(model: ITextModel): Promise<void>;
protected abstract resolve(): Promise<ITextModel>;
}
class ResourceConfigurationEditOperation extends ConfigurationEditOperation {
private resolvePromise: Promise<ITextModel> | undefined = undefined;
constructor(
value: IConfigurationValue,
target: EditableConfigurationTarget,
jsonPath: json.JSONPath,
readonly resource: URI,
workspaceStandAloneConfigurationKey: string | undefined,
private readonly checkDirty: boolean,
@IFileService private readonly fileService: IFileService,
@ITextFileService private readonly textFileService: ITextFileService,
@ITextModelService private readonly textModelResolverService: ITextModelService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
super(
value,
target,
jsonPath,
resource,
workspaceStandAloneConfigurationKey,
contextService
);
}
protected async save(model: ITextModel): Promise<void> {
await this.textFileService.save(this.resource, { skipSaveParticipants: true /* programmatic change */ });
}
protected async resolve(): Promise<ITextModel> {
if (!this.resolvePromise) {
this.resolvePromise = this._resolve();
}
return this.resolvePromise;
}
protected validate(): void {
if (this.checkDirty && this.textFileService.isDirty(this.resource)) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY, this, this.contextService);
}
// Any key must be a known setting from the registry (unless this is a standalone config)
if (!this.workspaceStandAloneConfigurationKey) {
const validKeys = this.configurationService.keys().default;
if (validKeys.indexOf(this.value.key) < 0 && !OVERRIDE_PROPERTY_PATTERN.test(this.value.key)) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY, this, this.contextService);
}
}
if (this.workspaceStandAloneConfigurationKey) {
// Global tasks and launches are not supported
if (this.target === EditableConfigurationTarget.USER_LOCAL || this.target === EditableConfigurationTarget.USER_REMOTE) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, this, this.contextService);
}
// Workspace tasks are not supported
if (this.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && this.target === EditableConfigurationTarget.WORKSPACE) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, this, this.contextService);
}
}
// Target cannot be workspace or folder if no workspace opened
if ((this.target === EditableConfigurationTarget.WORKSPACE || this.target === EditableConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, this, this.contextService);
}
if (this.target === EditableConfigurationTarget.WORKSPACE) {
if (!this.workspaceStandAloneConfigurationKey) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[this.value.key].scope === ConfigurationScope.APPLICATION) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, this, this.contextService);
}
if (configurationProperties[this.value.key].scope === ConfigurationScope.MACHINE) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE, this, this.contextService);
}
}
}
if (this.target === EditableConfigurationTarget.WORKSPACE_FOLDER) {
if (!this.resource) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, this, this.contextService);
}
if (!this.workspaceStandAloneConfigurationKey) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[this.value.key].scope !== ConfigurationScope.RESOURCE) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, this, this.contextService);
}
}
}
if (!this.resource) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, this, this.contextService);
}
}
private async _resolve(): Promise<ITextModel> {
const exists = await this.fileService.exists(this.resource);
if (!exists) {
await this.textFileService.write(this.resource, '{}', { encoding: 'utf8' });
}
const reference = this._register(await this.textModelResolverService.createModelReference(this.resource));
return reference.object.textEditorModel;
}
}
class UserConfigurationEditOperation extends ConfigurationEditOperation {
private resolvePromise: Promise<ITextModel> | undefined = undefined;
constructor(
value: IConfigurationValue,
jsonPath: json.JSONPath,
@IUserDataService private readonly userDataService: IUserDataService,
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
super(
value,
EditableConfigurationTarget.USER_LOCAL,
jsonPath,
null,
undefined,
contextService
);
}
protected async save(model: ITextModel): Promise<void> {
await this.userDataService.write(USER_CONFIGURATION_KEY, model.getValue());
}
protected validate(): void {
// Any key must be a known setting from the registry
const validKeys = this.configurationService.keys().default;
if (validKeys.indexOf(this.value.key) < 0 && !OVERRIDE_PROPERTY_PATTERN.test(this.value.key)) {
throw toConfigurationEditingError(ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY, this, this.contextService);
}
}
protected resolve(): Promise<ITextModel> {
if (!this.resolvePromise) {
this.resolvePromise = this._resolve();
}
return this.resolvePromise;
}
private async _resolve(): Promise<ITextModel> {
const content = (await this.userDataService.read(USER_CONFIGURATION_KEY)) || '{}';
const languageIdentifier = this.modeService.getLanguageIdentifier('jsonc');
const model = this.modelService.createModel(content, languageIdentifier ? { languageIdentifier, onDidChange: new Emitter<LanguageIdentifier>().event, dispose: () => { } } : null, this.configurationService.userSettingsResource.with({ scheme: Schemas.vscode }));
this._register(toDisposable(() => {
model.dispose();
this.modelService.destroyModel(model.uri);
}));
return model;
}
}
export class ConfigurationEditingService {
public _serviceBrand: any;
private queue: Queue<void>;
private remoteSettingsResource: URI | null;
constructor(
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@INotificationService private readonly notificationService: INotificationService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IEditorService private readonly editorService: IEditorService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
) {
this.queue = new Queue<void>();
remoteAgentService.getEnvironment().then(environment => {
if (environment) {
this.remoteSettingsResource = environment.settingsPath;
}
});
}
writeConfiguration(target: EditableConfigurationTarget, value: IConfigurationValue, options: ConfigurationEditingOptions = {}): Promise<void> {
return this.queue.queue(async () => { // queue up writes to prevent race conditions
const operation = this.getConfigurationEditOperation(target, value, options.scopes || {}, !(options.force || options.donotSave));
try {
await operation.apply(options.force || !options.donotSave);
operation.dispose();
} catch (error) {
if (!options.donotNotifyError) {
this.onError(error, operation, options.scopes);
}
return Promise.reject(error);
}
});
}
private onError(error: ConfigurationEditingError, operation: IConfigurationEditOperation, scopes: IConfigurationOverrides | undefined): void {
switch (error.code) {
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION:
@@ -530,7 +238,7 @@ export class ConfigurationEditingService {
[{
label: nls.localize('saveAndRetry', "Save and Retry"),
run: () => {
const key = operation.value.key ? `${operation.workspaceStandAloneConfigurationKey}.${operation.value.key}` : operation.workspaceStandAloneConfigurationKey!;
const key = operation.key ? `${operation.workspaceStandAloneConfigurationKey}.${operation.key}` : operation.workspaceStandAloneConfigurationKey!;
this.writeConfiguration(operation.target, { key, value: operation.value }, <ConfigurationEditingOptions>{ force: true, scopes });
}
},
@@ -543,7 +251,7 @@ export class ConfigurationEditingService {
this.notificationService.prompt(Severity.Error, error.message,
[{
label: nls.localize('saveAndRetry', "Save and Retry"),
run: () => this.writeConfiguration(operation.target, { key: operation.value.key, value: operation.value }, <ConfigurationEditingOptions>{ force: true, scopes })
run: () => this.writeConfiguration(operation.target, { key: operation.key, value: operation.value }, <ConfigurationEditingOptions>{ force: true, scopes })
},
{
label: nls.localize('open', "Open Settings"),
@@ -579,7 +287,205 @@ export class ConfigurationEditingService {
this.editorService.openEditor({ resource });
}
private getConfigurationEditOperation(target: EditableConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides, checkDirty: boolean): IConfigurationEditOperation {
private reject<T = never>(code: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): Promise<T> {
const message = this.toErrorMessage(code, target, operation);
return Promise.reject(new ConfigurationEditingError(message, code));
}
private toErrorMessage(error: ConfigurationEditingErrorCode, target: EditableConfigurationTarget, operation: IConfigurationEditOperation): string {
switch (error) {
// API constraints
case ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY: return nls.localize('errorUnknownKey', "Unable to write to {0} because {1} is not a registered configuration.", this.stringifyTarget(target), operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION: return nls.localize('errorInvalidWorkspaceConfigurationApplication', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE: return nls.localize('errorInvalidWorkspaceConfigurationMachine', "Unable to write {0} to Workspace Settings. This setting can be written only into User settings.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION: return nls.localize('errorInvalidFolderConfiguration', "Unable to write to Folder Settings because {0} does not support the folder resource scope.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET: return nls.localize('errorInvalidUserTarget', "Unable to write to User Settings because {0} does not support for global scope.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET: return nls.localize('errorInvalidWorkspaceTarget', "Unable to write to Workspace Settings because {0} does not support for workspace scope in a multi folder workspace.", operation.key);
case ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET: return nls.localize('errorInvalidFolderTarget', "Unable to write to Folder Settings because no resource is provided.");
case ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED: return nls.localize('errorNoWorkspaceOpened', "Unable to write to {0} because no workspace is opened. Please open a workspace first and try again.", this.stringifyTarget(target));
// User issues
case ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return nls.localize('errorInvalidTaskConfiguration', "Unable to write into the tasks configuration file. Please open it to correct errors/warnings in it and try again.");
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return nls.localize('errorInvalidLaunchConfiguration', "Unable to write into the launch configuration file. Please open it to correct errors/warnings in it and try again.");
}
switch (target) {
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('errorInvalidConfiguration', "Unable to write into user settings. Please open the user settings to correct errors/warnings in it and try again.");
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('errorInvalidRemoteConfiguration', "Unable to write into remote user settings. Please open the remote user settings to correct errors/warnings in it and try again.");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('errorInvalidConfigurationWorkspace', "Unable to write into workspace settings. Please open the workspace settings to correct errors/warnings in the file and try again.");
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = this.contextService.getWorkspaceFolder(operation.resource);
if (folder) {
workspaceFolderName = folder.name;
}
}
return nls.localize('errorInvalidConfigurationFolder', "Unable to write into folder settings. Please open the '{0}' folder settings to correct errors/warnings in it and try again.", workspaceFolderName);
}
return '';
}
case ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY: {
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY) {
return nls.localize('errorTasksConfigurationFileDirty', "Unable to write into tasks configuration file because the file is dirty. Please save it first and then try again.");
}
if (operation.workspaceStandAloneConfigurationKey === LAUNCH_CONFIGURATION_KEY) {
return nls.localize('errorLaunchConfigurationFileDirty', "Unable to write into launch configuration file because the file is dirty. Please save it first and then try again.");
}
switch (target) {
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('errorConfigurationFileDirty', "Unable to write into user settings because the file is dirty. Please save the user settings file first and then try again.");
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('errorRemoteConfigurationFileDirty', "Unable to write into remote user settings because the file is dirty. Please save the remote user settings file first and then try again.");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('errorConfigurationFileDirtyWorkspace', "Unable to write into workspace settings because the file is dirty. Please save the workspace settings file first and then try again.");
case EditableConfigurationTarget.WORKSPACE_FOLDER:
let workspaceFolderName: string = '<<unknown>>';
if (operation.resource) {
const folder = this.contextService.getWorkspaceFolder(operation.resource);
if (folder) {
workspaceFolderName = folder.name;
}
}
return nls.localize('errorConfigurationFileDirtyFolder', "Unable to write into folder settings because the file is dirty. Please save the '{0}' folder settings file first and then try again.", workspaceFolderName);
}
return '';
}
}
}
private stringifyTarget(target: EditableConfigurationTarget): string {
switch (target) {
case EditableConfigurationTarget.USER_LOCAL:
return nls.localize('userTarget', "User Settings");
case EditableConfigurationTarget.USER_REMOTE:
return nls.localize('remoteUserTarget', "Remote User Settings");
case EditableConfigurationTarget.WORKSPACE:
return nls.localize('workspaceTarget', "Workspace Settings");
case EditableConfigurationTarget.WORKSPACE_FOLDER:
return nls.localize('folderTarget', "Folder Settings");
}
return '';
}
private getEdits(model: ITextModel, edit: IConfigurationEditOperation): Edit[] {
const { tabSize, insertSpaces } = model.getOptions();
const eol = model.getEOL();
const { value, jsonPath } = edit;
// Without jsonPath, the entire configuration file is being replaced, so we just use JSON.stringify
if (!jsonPath.length) {
const content = JSON.stringify(value, null, insertSpaces ? strings.repeat(' ', tabSize) : '\t');
return [{
content,
length: model.getValue().length,
offset: 0
}];
}
return setProperty(model.getValue(), jsonPath, value, { tabSize, insertSpaces, eol });
}
private async resolveModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
const exists = await this.fileService.exists(resource);
if (!exists) {
await this.textFileService.write(resource, '{}', { encoding: 'utf8' });
}
return this.textModelResolverService.createModelReference(resource);
}
private hasParseErrors(model: ITextModel, operation: IConfigurationEditOperation): boolean {
// If we write to a workspace standalone file and replace the entire contents (no key provided)
// we can return here because any parse errors can safely be ignored since all contents are replaced
if (operation.workspaceStandAloneConfigurationKey && !operation.key) {
return false;
}
const parseErrors: json.ParseError[] = [];
json.parse(model.getValue(), parseErrors);
return parseErrors.length > 0;
}
private resolveAndValidate(target: EditableConfigurationTarget, operation: IConfigurationEditOperation, checkDirty: boolean, overrides: IConfigurationOverrides): Promise<IReference<IResolvedTextEditorModel>> {
// Any key must be a known setting from the registry (unless this is a standalone config)
if (!operation.workspaceStandAloneConfigurationKey) {
const validKeys = this.configurationService.keys().default;
if (validKeys.indexOf(operation.key) < 0 && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) {
return this.reject(ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY, target, operation);
}
}
if (operation.workspaceStandAloneConfigurationKey) {
// Global tasks and launches are not supported
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_USER_TARGET, target, operation);
}
// Workspace tasks are not supported
if (operation.workspaceStandAloneConfigurationKey === TASKS_CONFIGURATION_KEY && this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE && operation.target === EditableConfigurationTarget.WORKSPACE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_TARGET, target, operation);
}
}
// Target cannot be workspace or folder if no workspace opened
if ((target === EditableConfigurationTarget.WORKSPACE || target === EditableConfigurationTarget.WORKSPACE_FOLDER) && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
return this.reject(ConfigurationEditingErrorCode.ERROR_NO_WORKSPACE_OPENED, target, operation);
}
if (target === EditableConfigurationTarget.WORKSPACE) {
if (!operation.workspaceStandAloneConfigurationKey) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[operation.key].scope === ConfigurationScope.APPLICATION) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, target, operation);
}
if (configurationProperties[operation.key].scope === ConfigurationScope.MACHINE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_MACHINE, target, operation);
}
}
}
if (target === EditableConfigurationTarget.WORKSPACE_FOLDER) {
if (!operation.resource) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation);
}
if (!operation.workspaceStandAloneConfigurationKey) {
const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties();
if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, target, operation);
}
}
}
if (!operation.resource) {
return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation);
}
return this.resolveModelReference(operation.resource)
.then(reference => {
const model = reference.object.textEditorModel;
if (this.hasParseErrors(model, operation)) {
return this.reject<typeof reference>(ConfigurationEditingErrorCode.ERROR_INVALID_CONFIGURATION, target, operation);
}
// Target cannot be dirty if not writing into buffer
if (checkDirty && this.textFileService.isDirty(operation.resource)) {
return this.reject<typeof reference>(ConfigurationEditingErrorCode.ERROR_CONFIGURATION_FILE_DIRTY, target, operation);
}
return reference;
});
}
private getConfigurationEditOperation(target: EditableConfigurationTarget, config: IConfigurationValue, overrides: IConfigurationOverrides): IConfigurationEditOperation {
// Check for standalone workspace configurations
if (config.key) {
@@ -590,32 +496,29 @@ export class ConfigurationEditingService {
// Check for prefix
if (config.key === key) {
const jsonPath = this.isWorkspaceConfigurationResource(resource) ? [key] : [];
return this.instantiationService.createInstance(ResourceConfigurationEditOperation, { key: jsonPath[jsonPath.length - 1], value: config.value }, target, jsonPath, resource, key, checkDirty);
return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource: withNullAsUndefined(resource), workspaceStandAloneConfigurationKey: key, target };
}
// Check for prefix.<setting>
const keyPrefix = `${key}.`;
if (config.key.indexOf(keyPrefix) === 0) {
const jsonPath = this.isWorkspaceConfigurationResource(resource) ? [key, config.key.substr(keyPrefix.length)] : [config.key.substr(keyPrefix.length)];
return this.instantiationService.createInstance(ResourceConfigurationEditOperation, { key: jsonPath[jsonPath.length - 1], value: config.value }, target, jsonPath, resource, key, checkDirty);
return { key: jsonPath[jsonPath.length - 1], jsonPath, value: config.value, resource: withNullAsUndefined(resource), workspaceStandAloneConfigurationKey: key, target };
}
}
}
let key = config.key;
let jsonPath = overrides.overrideIdentifier ? [keyFromOverrideIdentifier(overrides.overrideIdentifier), key] : [key];
if (target === EditableConfigurationTarget.USER_LOCAL) {
return this.instantiationService.createInstance(UserConfigurationEditOperation, { key, value: config.value }, jsonPath);
}
if (target === EditableConfigurationTarget.USER_REMOTE) {
return this.instantiationService.createInstance(ResourceConfigurationEditOperation, { key, value: config.value }, target, jsonPath, withNullAsUndefined(this.getConfigurationFileResource(target, config, '', null)), undefined, checkDirty);
if (target === EditableConfigurationTarget.USER_LOCAL || target === EditableConfigurationTarget.USER_REMOTE) {
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(this.getConfigurationFileResource(target, config, '', null)), target };
}
const resource = this.getConfigurationFileResource(target, config, FOLDER_SETTINGS_PATH, overrides.resource);
if (this.isWorkspaceConfigurationResource(resource)) {
jsonPath = ['settings', ...jsonPath];
}
return this.instantiationService.createInstance(ResourceConfigurationEditOperation, { key, value: config.value }, target, jsonPath, withNullAsUndefined(resource), undefined, checkDirty);
return { key, jsonPath, value: config.value, resource: withNullAsUndefined(resource), target };
}
private isWorkspaceConfigurationResource(resource: URI | null): boolean {
@@ -625,7 +528,7 @@ export class ConfigurationEditingService {
private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null {
if (target === EditableConfigurationTarget.USER_LOCAL) {
return null;
return this.environmentService.settingsResource;
}
if (target === EditableConfigurationTarget.USER_REMOTE) {
return this.remoteSettingsResource;

View File

@@ -7,12 +7,13 @@ import * as pfs from 'vs/base/node/pfs';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { join } from 'vs/base/common/path';
import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration';
import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService';
export class ConfigurationCache implements IConfigurationCache {
private readonly cachedConfigurations: Map<string, CachedConfiguration> = new Map<string, CachedConfiguration>();
constructor(private readonly environmentService: IEnvironmentService) {
constructor(private readonly environmentService: IWorkbenchEnvironmentService) {
}
read(key: ConfigurationKey): Promise<string> {

View File

@@ -13,7 +13,6 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { parseArgs } from 'vs/platform/environment/node/argv';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import * as uuid from 'vs/base/common/uuid';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
@@ -39,15 +38,17 @@ import { Schemas } from 'vs/base/common/network';
import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider';
import { IFileService } from 'vs/platform/files/common/files';
import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache';
import { FileUserDataService } from 'vs/workbench/services/userData/common/fileUserDataService';
import { IUserDataService } from 'vs/workbench/services/userData/common/userData';
import { dirname } from 'vs/base/common/resources';
import { KeybindingsEditingService, IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
import { UserDataFileSystemProvider } from 'vs/workbench/services/userData/common/userDataFileSystemProvider';
import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService';
import { IWindowConfiguration } from 'vs/platform/windows/common/windows';
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
class SettingsTestEnvironmentService extends EnvironmentService {
class SettingsTestEnvironmentService extends WorkbenchEnvironmentService {
constructor(args: ParsedArgs, _execPath: string, private _settingsPath: string) {
super(args, _execPath);
super(<IWindowConfiguration>args, _execPath);
}
get appSettingsHome(): URI { return dirname(URI.file(this._settingsPath)); }
@@ -111,9 +112,8 @@ suite('ConfigurationEditingService', () => {
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
instantiationService.stub(IFileService, fileService);
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
instantiationService.stub(IUserDataService, userDataService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => {
instantiationService.stub(IConfigurationService, workspaceService);

View File

@@ -11,7 +11,6 @@ import * as os from 'os';
import { URI } from 'vs/base/common/uri';
import { Registry } from 'vs/platform/registry/common/platform';
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
import * as pfs from 'vs/base/node/pfs';
import * as uuid from 'vs/base/common/uuid';
@@ -45,14 +44,16 @@ import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEn
import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration';
import { VSBuffer } from 'vs/base/common/buffer';
import { SignService } from 'vs/platform/sign/browser/signService';
import { FileUserDataService } from 'vs/workbench/services/userData/common/fileUserDataService';
import { IUserDataService } from 'vs/workbench/services/userData/common/userData';
import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider';
import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing';
import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService';
import { UserDataFileSystemProvider } from 'vs/workbench/services/userData/common/userDataFileSystemProvider';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
class SettingsTestEnvironmentService extends EnvironmentService {
class SettingsTestEnvironmentService extends WorkbenchEnvironmentService {
constructor(args: ParsedArgs, _execPath: string, private _settingsPath: string) {
super(args, _execPath);
super(<IWindowConfiguration>args, _execPath);
}
get appSettingsHome(): URI { return dirname(URI.file(this._settingsPath)); }
@@ -107,8 +108,8 @@ suite('WorkspaceContextService - Folder', () => {
const globalSettingsFile = path.join(parentDir, 'settings.json');
const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile);
const fileService = new FileService(new NullLogService());
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
workspaceContextService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, new RemoteAgentService(<IWindowConfiguration>{}, environmentService, new RemoteAuthorityResolverService(), new SignService()));
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
workspaceContextService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, new RemoteAgentService(<IWindowConfiguration>{}, environmentService, new RemoteAuthorityResolverService(), new SignService()));
return (<WorkspaceService>workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir)));
});
});
@@ -172,8 +173,8 @@ suite('WorkspaceContextService - Workspace', () => {
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
@@ -231,8 +232,8 @@ suite('WorkspaceContextService - Workspace Editing', () => {
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
@@ -491,8 +492,8 @@ suite('WorkspaceService - Initialization', () => {
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
@@ -754,9 +755,8 @@ suite('WorkspaceConfigurationService - Folder', () => {
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
instantiationService.stub(IUserDataService, userDataService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
@@ -1040,7 +1040,7 @@ suite('WorkspaceConfigurationService - Folder', () => {
suite('WorkspaceConfigurationService-Multiroot', () => {
let parentResource: string, workspaceContextService: IWorkspaceContextService, environmentService: IEnvironmentService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService, globalSettingsFile: string;
let parentResource: string, workspaceContextService: IWorkspaceContextService, environmentService: IWorkbenchEnvironmentService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService, globalSettingsFile: string;
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
suiteSetup(() => {
@@ -1084,13 +1084,12 @@ suite('WorkspaceConfigurationService-Multiroot', () => {
instantiationService.stub(IRemoteAgentService, remoteAgentService);
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService()));
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
instantiationService.stub(IUserDataService, userDataService);
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, fileService, userDataService, remoteAgentService);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, workspaceService);
instantiationService.stub(IConfigurationService, workspaceService);
instantiationService.stub(IEnvironmentService, environmentService);
instantiationService.stub(IWorkbenchEnvironmentService, environmentService);
return workspaceService.initialize(getWorkspaceIdentifier(configPath)).then(() => {
instantiationService.stub(IFileService, fileService);
@@ -1487,9 +1486,9 @@ suite('WorkspaceConfigurationService - Remote Folder', () => {
const remoteAgentService = instantiationService.stub(IRemoteAgentService, <Partial<IRemoteAgentService>>{ getEnvironment: () => remoteEnvironmentPromise });
const fileService = new FileService(new NullLogService());
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
fileService.registerProvider(Schemas.userData, new UserDataFileSystemProvider(environmentService.appSettingsHome.with({ scheme: Schemas.userData }), new FileUserDataProvider(environmentService.appSettingsHome, fileService)));
const configurationCache: IConfigurationCache = { read: () => Promise.resolve(''), write: () => Promise.resolve(), remove: () => Promise.resolve() };
const userDataService = new FileUserDataService(environmentService.appSettingsHome, fileService);
testObject = new WorkspaceService({ configurationCache, remoteAuthority }, fileService, userDataService, remoteAgentService);
testObject = new WorkspaceService({ configurationCache, remoteAuthority }, environmentService, fileService, remoteAgentService);
instantiationService.stub(IWorkspaceContextService, testObject);
instantiationService.stub(IConfigurationService, testObject);
instantiationService.stub(IEnvironmentService, environmentService);