提交 fd455c37 编写于 作者: S Sandeep Somavarapu

Fix #102001

上级 cf0094f9
......@@ -311,7 +311,7 @@ export abstract class AbstractSynchroniser extends Disposable {
if (remoteUserData.syncData && remoteUserData.syncData.version > this.version) {
// current version is not compatible with cloud version
this.telemetryService.publicLog2<{ source: string }, SyncSourceClassification>('sync/incompatible', { source: this.resource });
throw new UserDataSyncError(localize({ key: 'incompatible', comment: ['This is an error while syncing a resource that its local version is not compatible with its remote version.'] }, "Cannot sync {0} as its local version {1} is not compatible with its remote version {2}", this.resource, this.version, remoteUserData.syncData.version), UserDataSyncErrorCode.Incompatible, this.resource);
throw new UserDataSyncError(localize({ key: 'incompatible', comment: ['This is an error while syncing a resource that its local version is not compatible with its remote version.'] }, "Cannot sync {0} as its local version {1} is not compatible with its remote version {2}", this.resource, this.version, remoteUserData.syncData.version), UserDataSyncErrorCode.IncompatibleLocalContent, this.resource);
}
try {
......@@ -626,7 +626,7 @@ export abstract class AbstractSynchroniser extends Disposable {
} catch (error) {
this.logService.error(error);
}
throw new UserDataSyncError(localize('incompatible sync data', "Cannot parse sync data as it is not compatible with current version."), UserDataSyncErrorCode.Incompatible, this.resource);
throw new UserDataSyncError(localize('incompatible sync data', "Cannot parse sync data as it is not compatible with current version."), UserDataSyncErrorCode.IncompatibleRemoteContent, this.resource);
}
private async getUserData(refOrLastSyncData: string | IRemoteUserData | null): Promise<IUserData> {
......
......@@ -218,6 +218,26 @@ export class UserDataAutoSyncService extends UserDataAutoSyncEnablementService i
this.logService.info('Auto Sync: Turned off sync because of making too many requests to server');
}
// Upgrade Required or Gone
else if (userDataSyncError.code === UserDataSyncErrorCode.UpgradeRequired || userDataSyncError.code === UserDataSyncErrorCode.Gone) {
await this.turnOff(false, true /* force soft turnoff on error */,
true /* do not disable machine because disabling a machine makes request to server and can fail with upgrade required or gone */);
this.disableMachineEventually();
this.logService.info('Auto Sync: Turned off sync because current client is not compatible with server. Requires client upgrade.');
}
// Incompatible Local Content
else if (userDataSyncError.code === UserDataSyncErrorCode.IncompatibleLocalContent) {
await this.turnOff(false, true /* force soft turnoff on error */);
this.logService.info('Auto Sync: Turned off sync because server has {0} content with newer version than of client. Requires client upgrade.', userDataSyncError.resource);
}
// Incompatible Remote Content
else if (userDataSyncError.code === UserDataSyncErrorCode.IncompatibleRemoteContent) {
await this.turnOff(false, true /* force soft turnoff on error */);
this.logService.info('Auto Sync: Turned off sync because server has {0} content with older version than of client. Requires server reset.', userDataSyncError.resource);
}
else {
this.logService.error(userDataSyncError);
this.successiveFailures++;
......
......@@ -217,7 +217,8 @@ export enum UserDataSyncErrorCode {
LocalPreconditionFailed = 'LocalPreconditionFailed',
LocalInvalidContent = 'LocalInvalidContent',
LocalError = 'LocalError',
Incompatible = 'Incompatible',
IncompatibleLocalContent = 'IncompatibleLocalContent',
IncompatibleRemoteContent = 'IncompatibleRemoteContent',
UnresolvedConflicts = 'UnresolvedConflicts',
Unknown = 'Unknown',
......@@ -415,6 +416,7 @@ export interface IUserDataSyncService {
pull(): Promise<void>;
replace(uri: URI): Promise<void>;
reset(): Promise<void>;
resetRemote(): Promise<void>;
resetLocal(): Promise<void>;
hasLocalData(): Promise<boolean>;
......
......@@ -49,6 +49,7 @@ export class UserDataSyncChannel implements IServerChannel {
case 'pull': return this.service.pull();
case 'replace': return this.service.replace(URI.revive(args[0]));
case 'reset': return this.service.reset();
case 'resetRemote': return this.service.resetRemote();
case 'resetLocal': return this.service.resetLocal();
case 'hasPreviouslySynced': return this.service.hasPreviouslySynced();
case 'hasLocalData': return this.service.hasLocalData();
......
......@@ -313,6 +313,16 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
await this.resetLocal();
}
async resetRemote(): Promise<void> {
await this.checkEnablement();
try {
await this.userDataSyncStoreService.clear();
this.logService.info('Cleared data on server');
} catch (e) {
this.logService.error(e);
}
}
async resetLocal(): Promise<void> {
await this.checkEnablement();
this.storageService.remove(LAST_SYNC_TIME_KEY, StorageScope.GLOBAL);
......@@ -336,16 +346,6 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
return false;
}
private async resetRemote(): Promise<void> {
await this.checkEnablement();
try {
await this.userDataSyncStoreService.clear();
this.logService.info('Cleared data on server');
} catch (e) {
this.logService.error(e);
}
}
private setStatus(status: SyncStatus): void {
const oldStatus = this._status;
if (this._status !== status) {
......@@ -402,7 +402,8 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
case UserDataSyncErrorCode.LocalTooManyRequests:
case UserDataSyncErrorCode.Gone:
case UserDataSyncErrorCode.UpgradeRequired:
case UserDataSyncErrorCode.Incompatible:
case UserDataSyncErrorCode.IncompatibleRemoteContent:
case UserDataSyncErrorCode.IncompatibleLocalContent:
throw e;
}
}
......
......@@ -119,6 +119,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
@IStorageService private readonly storageService: IStorageService,
@IOpenerService private readonly openerService: IOpenerService,
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
@ICommandService private readonly commandService: ICommandService,
) {
super();
......@@ -294,10 +295,9 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
this.handleTooLargeError(error.resource, localize('too large', "Disabled syncing {0} because size of the {1} file to sync is larger than {2}. Please open the file and reduce the size and enable sync", sourceArea.toLowerCase(), sourceArea.toLowerCase(), '100kb'), error);
}
break;
case UserDataSyncErrorCode.Incompatible:
case UserDataSyncErrorCode.IncompatibleLocalContent:
case UserDataSyncErrorCode.Gone:
case UserDataSyncErrorCode.UpgradeRequired:
this.userDataSyncWorkbenchService.turnoff(false);
const message = localize('error upgrade required', "Preferences sync is disabled because the current version ({0}, {1}) is not compatible with the sync service. Please update before turning on sync.", this.productService.version, this.productService.commit);
const operationId = error.operationId ? localize('operationId', "Operation Id: {0}", error.operationId) : undefined;
this.notificationService.notify({
......@@ -305,6 +305,18 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
message: operationId ? `${message} ${operationId}` : message,
});
break;
case UserDataSyncErrorCode.IncompatibleRemoteContent:
this.notificationService.notify({
severity: Severity.Error,
message: localize('error reset required', "Preferences sync is disabled because your data in the cloud is older than that of in the client. Please reset your data in the cloud before turning on sync."),
actions: {
primary: [
new Action('reset', localize('reset', "Reset Synced Data"), undefined, true, () => this.userDataSyncWorkbenchService.resetSyncedData()),
new Action('show synced data', localize('show synced data action', "Show Synced Data"), undefined, true, () => this.commandService.executeCommand(SHOW_SYNCED_DATA_COMMAND_ID))
]
}
});
return;
}
}
......@@ -439,7 +451,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
return;
}
break;
case UserDataSyncErrorCode.Incompatible:
case UserDataSyncErrorCode.IncompatibleLocalContent:
case UserDataSyncErrorCode.Gone:
case UserDataSyncErrorCode.UpgradeRequired:
const message = localize('error upgrade required while starting sync', "Preferences sync cannot be turned on because the current version ({0}, {1}) is not compatible with the sync service. Please update before turning on sync.", this.productService.version, this.productService.commit);
......@@ -449,6 +461,18 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
message: operationId ? `${message} ${operationId}` : message,
});
return;
case UserDataSyncErrorCode.IncompatibleRemoteContent:
this.notificationService.notify({
severity: Severity.Error,
message: localize('error reset required while starting sync', "Preferences sync cannot be turned on because your data in the cloud is older than that of in the client. Please reset your data in the cloud before turning on sync."),
actions: {
primary: [
new Action('reset', localize('reset', "Reset Synced Data"), undefined, true, () => this.userDataSyncWorkbenchService.resetSyncedData()),
new Action('show synced data', localize('show synced data action', "Show Synced Data"), undefined, true, () => this.commandService.executeCommand(SHOW_SYNCED_DATA_COMMAND_ID))
]
}
});
return;
}
}
this.notificationService.error(localize('turn on failed', "Error while starting Sync: {0}", toErrorMessage(e)));
......@@ -946,7 +970,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo
that.viewsEnablementContext.set(true);
const viewDescriptorService = accessor.get(IViewDescriptorService);
const viewsService = accessor.get(IViewsService);
const viewContainer = viewDescriptorService.getViewContainerByViewId(viewContainerId);
const viewContainer = viewDescriptorService.getViewContainerById(viewContainerId);
if (viewContainer) {
const model = viewDescriptorService.getViewContainerModel(viewContainer);
if (model.activeViewDescriptors.length) {
......
......@@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ALL_SYNC_RESOURCES, SyncResource, IUserDataSyncService, ISyncResourceHandle as IResourceHandle, SyncStatus, IUserDataSyncResourceEnablementService, IUserDataAutoSyncService, Change } from 'vs/platform/userDataSync/common/userDataSync';
import { ALL_SYNC_RESOURCES, SyncResource, IUserDataSyncService, ISyncResourceHandle as IResourceHandle, SyncStatus, IUserDataSyncResourceEnablementService, IUserDataAutoSyncService, Change, UserDataSyncError, UserDataSyncErrorCode } from 'vs/platform/userDataSync/common/userDataSync';
import { registerAction2, Action2, MenuId } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr, ContextKeyEqualsExpr } from 'vs/platform/contextkey/common/contextkey';
import { URI } from 'vs/base/common/uri';
......@@ -33,7 +33,7 @@ import { IAction, Action } from 'vs/base/common/actions';
import { IUserDataSyncWorkbenchService, CONTEXT_SYNC_STATE, getSyncAreaLabel, CONTEXT_ACCOUNT_STATE, AccountStatus, CONTEXT_ENABLE_VIEWS, SHOW_SYNC_LOG_COMMAND_ID, CONFIGURE_SYNC_COMMAND_ID, CONTEXT_SHOW_MANUAL_SYNC_VIEW, IUserDataSyncPreview, IUserDataSyncResourceGroup } from 'vs/workbench/services/userDataSync/common/userDataSync';
import { IUserDataSyncMachinesService, IUserDataSyncMachine } from 'vs/platform/userDataSync/common/userDataSyncMachines';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { TreeView } from 'vs/workbench/contrib/views/browser/treeView';
import { flatten } from 'vs/base/common/arrays';
import { isEqual, basename } from 'vs/base/common/resources';
......@@ -42,7 +42,6 @@ export class UserDataSyncViewPaneContainer extends ViewPaneContainer {
constructor(
containerId: string,
@IDialogService private readonly dialogService: IDialogService,
@IUserDataSyncWorkbenchService private readonly userDataSyncWorkbenchService: IUserDataSyncWorkbenchService,
@ICommandService private readonly commandService: ICommandService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
......@@ -68,22 +67,10 @@ export class UserDataSyncViewPaneContainer extends ViewPaneContainer {
getSecondaryActions(): IAction[] {
return [
new Action('workbench.actions.syncData.reset', localize('workbench.actions.syncData.reset', "Reset Synced Data"), undefined, true, () => this.reset()),
new Action('workbench.actions.syncData.reset', localize('workbench.actions.syncData.reset', "Reset Synced Data"), undefined, true, () => this.userDataSyncWorkbenchService.resetSyncedData()),
];
}
private async reset(): Promise<void> {
const result = await this.dialogService.confirm({
message: localize('reset', "This will clear your synced data from the cloud and stop sync on all your devices."),
title: localize('reset title', "Reset Synced Data"),
type: 'info',
primaryButton: localize('reset button', "Reset"),
});
if (result.confirmed) {
await this.userDataSyncWorkbenchService.turnoff(true);
}
}
}
export class UserDataSyncDataViews extends Disposable {
......@@ -626,6 +613,7 @@ abstract class UserDataSyncActivityViewDataProvider implements ITreeViewDataProv
constructor(
@IUserDataSyncService protected readonly userDataSyncService: IUserDataSyncService,
@IUserDataAutoSyncService protected readonly userDataAutoSyncService: IUserDataAutoSyncService,
@IUserDataSyncWorkbenchService private readonly userDataSyncWorkbenchService: IUserDataSyncWorkbenchService,
@INotificationService private readonly notificationService: INotificationService,
) { }
......@@ -639,7 +627,22 @@ abstract class UserDataSyncActivityViewDataProvider implements ITreeViewDataProv
}
return [];
} catch (error) {
this.notificationService.error(error);
if (!(error instanceof UserDataSyncError)) {
error = UserDataSyncError.toUserDataSyncError(error);
}
if (error instanceof UserDataSyncError && error.code === UserDataSyncErrorCode.IncompatibleRemoteContent) {
this.notificationService.notify({
severity: Severity.Error,
message: error.message,
actions: {
primary: [
new Action('reset', localize('reset', "Reset Synced Data"), undefined, true, () => this.userDataSyncWorkbenchService.resetSyncedData()),
]
}
});
} else {
this.notificationService.error(error);
}
throw error;
}
}
......@@ -705,9 +708,10 @@ class RemoteUserDataSyncActivityViewDataProvider extends UserDataSyncActivityVie
@IUserDataSyncService userDataSyncService: IUserDataSyncService,
@IUserDataAutoSyncService userDataAutoSyncService: IUserDataAutoSyncService,
@IUserDataSyncMachinesService private readonly userDataSyncMachinesService: IUserDataSyncMachinesService,
@IUserDataSyncWorkbenchService userDataSyncWorkbenchService: IUserDataSyncWorkbenchService,
@INotificationService notificationService: INotificationService,
) {
super(userDataSyncService, userDataAutoSyncService, notificationService);
super(userDataSyncService, userDataAutoSyncService, userDataSyncWorkbenchService, notificationService);
}
async getChildren(element?: ITreeItem): Promise<ITreeItem[]> {
......
......@@ -357,6 +357,18 @@ export class UserDataSyncWorkbenchService extends Disposable implements IUserDat
}
}
async resetSyncedData(): Promise<void> {
const result = await this.dialogService.confirm({
message: localize('reset', "This will clear your synced data from the cloud and stop sync on all your devices."),
title: localize('reset title', "Reset Synced Data"),
type: 'info',
primaryButton: localize('reset button', "Reset"),
});
if (result.confirmed) {
await this.userDataSyncService.resetRemote();
}
}
private isSupportedAuthenticationProviderId(authenticationProviderId: string): boolean {
return this.authenticationProviders.some(({ id }) => id === authenticationProviderId);
}
......
......@@ -54,6 +54,7 @@ export interface IUserDataSyncWorkbenchService {
turnOn(): Promise<void>;
turnoff(everyWhere: boolean): Promise<void>;
signIn(): Promise<void>;
resetSyncedData(): Promise<void>;
}
export function getSyncAreaLabel(source: SyncResource): string {
......
......@@ -86,6 +86,10 @@ export class UserDataSyncService extends Disposable implements IUserDataSyncServ
return this.channel.call('reset');
}
resetRemote(): Promise<void> {
return this.channel.call('resetRemote');
}
resetLocal(): Promise<void> {
return this.channel.call('resetLocal');
}
......@@ -165,7 +169,16 @@ class ManualSyncTask implements IManualSyncTask {
readonly manifest: IUserDataManifest | null,
sharedProcessService: ISharedProcessService,
) {
this.channel = sharedProcessService.getChannel(`manualSyncTask-${id}`);
const manualSyncTaskChannel = sharedProcessService.getChannel(`manualSyncTask-${id}`);
this.channel = {
call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T> {
return manualSyncTaskChannel.call(command, arg, cancellationToken)
.then(null, error => { throw UserDataSyncError.toUserDataSyncError(error); });
},
listen<T>(event: string, arg?: any): Event<T> {
return manualSyncTaskChannel.listen(event, arg);
}
};
}
async preview(): Promise<[SyncResource, ISyncResourcePreview][]> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册