mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421 (#7404)
* Merge from vscode e0762af258c0b20320ed03f3871a41967acc4421 * readd svgs
This commit is contained in:
@@ -5,18 +5,18 @@
|
||||
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IFileService, FileSystemProviderErrorCode, FileSystemProviderError, IFileContent } from 'vs/platform/files/common/files';
|
||||
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { IUserData, UserDataSyncStoreError, UserDataSyncStoreErrorCode, ISynchroniser, SyncStatus, ISettingsMergeService, IUserDataSyncStoreService, DEFAULT_IGNORED_SETTINGS, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { parse, ParseError } from 'vs/base/common/json';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { CancelablePromise, createCancelablePromise, ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { IStringDictionary } from 'vs/base/common/collections';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface ISyncPreviewResult {
|
||||
readonly fileContent: IFileContent | null;
|
||||
@@ -48,7 +48,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IUserDataSyncStoreService private readonly userDataSyncStoreService: IUserDataSyncStoreService,
|
||||
@ISettingsMergeService private readonly settingsMergeService: ISettingsMergeService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IUserDataSyncLogService private readonly logService: IUserDataSyncLogService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
) {
|
||||
super();
|
||||
@@ -80,20 +80,28 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
}
|
||||
|
||||
async sync(_continue?: boolean): Promise<boolean> {
|
||||
if (!this.configurationService.getValue<boolean>('configurationSync.enableSettings')) {
|
||||
this.logService.trace('Settings: Skipping synchronising settings as it is disabled.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_continue) {
|
||||
this.logService.info('Settings: Resumed synchronising settings');
|
||||
return this.continueSync();
|
||||
}
|
||||
|
||||
if (this.status !== SyncStatus.Idle) {
|
||||
this.logService.trace('Settings: Skipping synchronising settings as it is running already.');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.logService.trace('Settings: Started synchronising settings...');
|
||||
this.setStatus(SyncStatus.Syncing);
|
||||
|
||||
try {
|
||||
const result = await this.getPreview();
|
||||
if (result.hasConflicts) {
|
||||
this.logService.info('Settings: Detected conflicts while synchronising settings.');
|
||||
this.setStatus(SyncStatus.HasConflicts);
|
||||
return false;
|
||||
}
|
||||
@@ -104,18 +112,28 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
this.setStatus(SyncStatus.Idle);
|
||||
if (e instanceof UserDataSyncStoreError && e.code === UserDataSyncStoreErrorCode.Rejected) {
|
||||
// Rejected as there is a new remote version. Syncing again,
|
||||
this.logService.info('Failed to Synchronise settings as there is a new remote version available. Synchronising again...');
|
||||
this.logService.info('Settings: Failed to synchronise settings as there is a new remote version available. Synchronising again...');
|
||||
return this.sync();
|
||||
}
|
||||
if (e instanceof FileSystemProviderError && e.code === FileSystemProviderErrorCode.FileExists) {
|
||||
// Rejected as there is a new local version. Syncing again.
|
||||
this.logService.info('Failed to Synchronise settings as there is a new local version available. Synchronising again...');
|
||||
this.logService.info('Settings: Failed to synchronise settings as there is a new local version available. Synchronising again...');
|
||||
return this.sync();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.syncPreviewResultPromise) {
|
||||
this.syncPreviewResultPromise.cancel();
|
||||
this.syncPreviewResultPromise = null;
|
||||
this.logService.info('Settings: Stopped synchronising settings.');
|
||||
}
|
||||
this.fileService.del(this.environmentService.settingsSyncPreviewResource);
|
||||
this.setStatus(SyncStatus.Idle);
|
||||
}
|
||||
|
||||
private async continueSync(): Promise<boolean> {
|
||||
if (this.status !== SyncStatus.HasConflicts) {
|
||||
return false;
|
||||
@@ -133,19 +151,27 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
const settingsPreivew = await this.fileService.readFile(this.environmentService.settingsSyncPreviewResource);
|
||||
const content = settingsPreivew.value.toString();
|
||||
if (this.hasErrors(content)) {
|
||||
return Promise.reject(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again."));
|
||||
const error = new Error(localize('errorInvalidSettings', "Unable to sync settings. Please resolve conflicts without any errors/warnings and try again."));
|
||||
this.logService.error(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
let { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged } = await this.syncPreviewResultPromise;
|
||||
if (!hasLocalChanged && !hasRemoteChanged) {
|
||||
this.logService.trace('Settings: No changes found during synchronising settings.');
|
||||
}
|
||||
if (hasLocalChanged) {
|
||||
this.logService.info('Settings: Updating local settings');
|
||||
await this.writeToLocal(content, fileContent);
|
||||
}
|
||||
if (hasRemoteChanged) {
|
||||
const remoteContent = remoteUserData.content ? await this.settingsMergeService.computeRemoteContent(content, remoteUserData.content, this.getIgnoredSettings()) : content;
|
||||
const remoteContent = remoteUserData.content ? await this.settingsMergeService.computeRemoteContent(content, remoteUserData.content, this.getIgnoredSettings(content)) : content;
|
||||
this.logService.info('Settings: Updating remote settings');
|
||||
const ref = await this.writeToRemote(remoteContent, remoteUserData.ref);
|
||||
remoteUserData = { ref, content };
|
||||
}
|
||||
if (hasLocalChanged) {
|
||||
await this.writeToLocal(content, fileContent);
|
||||
}
|
||||
if (remoteUserData.content) {
|
||||
this.logService.info('Settings: Updating last synchronised sttings');
|
||||
await this.updateLastSyncValue(remoteUserData);
|
||||
}
|
||||
|
||||
@@ -153,6 +179,7 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
await this.fileService.del(this.environmentService.settingsSyncPreviewResource);
|
||||
}
|
||||
|
||||
this.logService.trace('Settings: Finised synchronising settings.');
|
||||
this.syncPreviewResultPromise = null;
|
||||
this.setStatus(SyncStatus.Idle);
|
||||
}
|
||||
@@ -165,12 +192,12 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
|
||||
private getPreview(): Promise<ISyncPreviewResult> {
|
||||
if (!this.syncPreviewResultPromise) {
|
||||
this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview());
|
||||
this.syncPreviewResultPromise = createCancelablePromise(token => this.generatePreview(token));
|
||||
}
|
||||
return this.syncPreviewResultPromise;
|
||||
}
|
||||
|
||||
private async generatePreview(): Promise<ISyncPreviewResult> {
|
||||
private async generatePreview(token: CancellationToken): Promise<ISyncPreviewResult> {
|
||||
const lastSyncData = await this.getLastSyncUserData();
|
||||
const remoteUserData = await this.userDataSyncStoreService.read(SettingsSynchroniser.EXTERNAL_USER_DATA_SETTINGS_KEY, lastSyncData);
|
||||
const remoteContent: string | null = remoteUserData.content;
|
||||
@@ -179,39 +206,56 @@ export class SettingsSynchroniser extends Disposable implements ISynchroniser {
|
||||
let hasLocalChanged: boolean = false;
|
||||
let hasRemoteChanged: boolean = false;
|
||||
let hasConflicts: boolean = false;
|
||||
let previewContent = null;
|
||||
|
||||
if (remoteContent) {
|
||||
const localContent: string = fileContent ? fileContent.value.toString() : '{}';
|
||||
if (this.hasErrors(localContent)) {
|
||||
this.logService.error('Settings: Unable to sync settings as there are errors/warning in settings file.');
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
|
||||
}
|
||||
|
||||
if (!lastSyncData // First time sync
|
||||
|| lastSyncData.content !== localContent // Local has moved forwarded
|
||||
|| lastSyncData.content !== remoteContent // Remote has moved forwarded
|
||||
) {
|
||||
this.logService.trace('Settings Sync: Merging remote contents with settings file.');
|
||||
this.logService.trace('Settings: Merging remote settings with local settings...');
|
||||
const result = await this.settingsMergeService.merge(localContent, remoteContent, lastSyncData ? lastSyncData.content : null, this.getIgnoredSettings());
|
||||
// Sync only if there are changes
|
||||
if (result.hasChanges) {
|
||||
hasLocalChanged = result.mergeContent !== localContent;
|
||||
hasRemoteChanged = result.mergeContent !== remoteContent;
|
||||
hasConflicts = result.hasConflicts;
|
||||
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(result.mergeContent));
|
||||
previewContent = result.mergeContent;
|
||||
}
|
||||
}
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
|
||||
}
|
||||
|
||||
// First time sync to remote
|
||||
if (fileContent) {
|
||||
this.logService.trace('Settings Sync: Remote contents does not exist. So sync with settings file.');
|
||||
// First time syncing to remote
|
||||
else if (fileContent) {
|
||||
this.logService.info('Settings: Remote settings does not exist. Synchronising settings for the first time.');
|
||||
hasRemoteChanged = true;
|
||||
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(fileContent.value.toString()));
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
|
||||
previewContent = fileContent.value.toString();
|
||||
}
|
||||
|
||||
if (previewContent && !token.isCancellationRequested) {
|
||||
await this.fileService.writeFile(this.environmentService.settingsSyncPreviewResource, VSBuffer.fromString(previewContent));
|
||||
}
|
||||
|
||||
return { fileContent, remoteUserData, hasLocalChanged, hasRemoteChanged, hasConflicts };
|
||||
}
|
||||
|
||||
private getIgnoredSettings(): IStringDictionary<boolean> {
|
||||
return this.configurationService.getValue<IStringDictionary<boolean>>('userConfiguration.ignoreSettings');
|
||||
private getIgnoredSettings(settingsContent?: string): string[] {
|
||||
const value: string[] = (settingsContent ? parse(settingsContent)['configurationSync.settingsToIgnore'] : this.configurationService.getValue<string[]>('configurationSync.settingsToIgnore')) || [];
|
||||
const added: string[] = [], removed: string[] = [];
|
||||
for (const key of value) {
|
||||
if (startsWith(key, '-')) {
|
||||
removed.push(key.substring(1));
|
||||
} else {
|
||||
added.push(key);
|
||||
}
|
||||
}
|
||||
return [...DEFAULT_IGNORED_SETTINGS, ...added].filter(setting => removed.indexOf(setting) === -1);
|
||||
}
|
||||
|
||||
private async getLastSyncUserData(): Promise<IUserData | null> {
|
||||
|
||||
Reference in New Issue
Block a user