提交 37c72e77 编写于 作者: S Sandeep Somavarapu

Add ability to not to sync an extension while installing using cli

上级 9de43268
...@@ -86,7 +86,7 @@ export class Main { ...@@ -86,7 +86,7 @@ export class Main {
} else if (argv['list-extensions']) { } else if (argv['list-extensions']) {
await this.listExtensions(!!argv['show-versions'], argv['category']); await this.listExtensions(!!argv['show-versions'], argv['category']);
} else if (argv['install-extension']) { } else if (argv['install-extension']) {
await this.installExtensions(argv['install-extension'], !!argv['force'], !!argv['default']); await this.installExtensions(argv['install-extension'], !!argv['force'], !!argv['donot-sync']);
} else if (argv['uninstall-extension']) { } else if (argv['uninstall-extension']) {
await this.uninstallExtension(argv['uninstall-extension']); await this.uninstallExtension(argv['uninstall-extension']);
} else if (argv['locate-extension']) { } else if (argv['locate-extension']) {
...@@ -126,7 +126,7 @@ export class Main { ...@@ -126,7 +126,7 @@ export class Main {
extensions.forEach(e => console.log(getId(e.manifest, showVersions))); extensions.forEach(e => console.log(getId(e.manifest, showVersions)));
} }
private async installExtensions(extensions: string[], force: boolean, isDefault: boolean): Promise<void> { private async installExtensions(extensions: string[], force: boolean, donotSync: boolean): Promise<void> {
const failed: string[] = []; const failed: string[] = [];
const installedExtensionsManifests: IExtensionManifest[] = []; const installedExtensionsManifests: IExtensionManifest[] = [];
if (extensions.length) { if (extensions.length) {
...@@ -135,7 +135,7 @@ export class Main { ...@@ -135,7 +135,7 @@ export class Main {
for (const extension of extensions) { for (const extension of extensions) {
try { try {
const manifest = await this.installExtension(extension, force, isDefault); const manifest = await this.installExtension(extension, force, donotSync);
if (manifest) { if (manifest) {
installedExtensionsManifests.push(manifest); installedExtensionsManifests.push(manifest);
} }
...@@ -150,7 +150,7 @@ export class Main { ...@@ -150,7 +150,7 @@ export class Main {
return failed.length ? Promise.reject(localize('installation failed', "Failed Installing Extensions: {0}", failed.join(', '))) : Promise.resolve(); return failed.length ? Promise.reject(localize('installation failed', "Failed Installing Extensions: {0}", failed.join(', '))) : Promise.resolve();
} }
private async installExtension(extension: string, force: boolean, isDefault: boolean): Promise<IExtensionManifest | null> { private async installExtension(extension: string, force: boolean, donotSync: boolean): Promise<IExtensionManifest | null> {
if (/\.vsix$/i.test(extension)) { if (/\.vsix$/i.test(extension)) {
extension = path.isAbsolute(extension) ? extension : path.join(process.cwd(), extension); extension = path.isAbsolute(extension) ? extension : path.join(process.cwd(), extension);
...@@ -158,7 +158,7 @@ export class Main { ...@@ -158,7 +158,7 @@ export class Main {
const valid = await this.validate(manifest, force); const valid = await this.validate(manifest, force);
if (valid) { if (valid) {
return this.extensionManagementService.install(URI.file(extension)).then(id => { return this.extensionManagementService.install(URI.file(extension), donotSync).then(id => {
console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(extension))); console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(extension)));
return manifest; return manifest;
}, error => { }, error => {
...@@ -205,7 +205,7 @@ export class Main { ...@@ -205,7 +205,7 @@ export class Main {
} }
console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, extension.version)); console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, extension.version));
} }
await this.installFromGallery(id, extension, isDefault); await this.installFromGallery(id, extension, donotSync);
return manifest; return manifest;
})); }));
} }
...@@ -227,11 +227,11 @@ export class Main { ...@@ -227,11 +227,11 @@ export class Main {
return true; return true;
} }
private async installFromGallery(id: string, extension: IGalleryExtension, isDefault: boolean): Promise<void> { private async installFromGallery(id: string, extension: IGalleryExtension, donotSync: boolean): Promise<void> {
console.log(localize('installing', "Installing extension '{0}' v{1}...", id, extension.version)); console.log(localize('installing', "Installing extension '{0}' v{1}...", id, extension.version));
try { try {
await this.extensionManagementService.installFromGallery(extension, isDefault); await this.extensionManagementService.installFromGallery(extension, donotSync);
console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, extension.version)); console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, extension.version));
} catch (error) { } catch (error) {
if (isPromiseCanceledError(error)) { if (isPromiseCanceledError(error)) {
......
...@@ -72,7 +72,7 @@ export interface ParsedArgs { ...@@ -72,7 +72,7 @@ export interface ParsedArgs {
remote?: string; remote?: string;
'disable-user-env-probe'?: boolean; 'disable-user-env-probe'?: boolean;
'force'?: boolean; 'force'?: boolean;
'default'?: boolean; 'donot-sync'?: boolean;
'force-user-env'?: boolean; 'force-user-env'?: boolean;
'sync'?: 'on' | 'off'; 'sync'?: 'on' | 'off';
...@@ -188,7 +188,7 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = { ...@@ -188,7 +188,7 @@ export const OPTIONS: OptionDescriptions<Required<ParsedArgs>> = {
'file-chmod': { type: 'boolean' }, 'file-chmod': { type: 'boolean' },
'driver-verbose': { type: 'boolean' }, 'driver-verbose': { type: 'boolean' },
'force': { type: 'boolean' }, 'force': { type: 'boolean' },
'default': { type: 'boolean' }, 'donot-sync': { type: 'boolean' },
'trace': { type: 'boolean' }, 'trace': { type: 'boolean' },
'trace-category-filter': { type: 'string' }, 'trace-category-filter': { type: 'string' },
'trace-options': { type: 'string' }, 'trace-options': { type: 'string' },
......
...@@ -92,7 +92,7 @@ export interface IGalleryMetadata { ...@@ -92,7 +92,7 @@ export interface IGalleryMetadata {
export interface ILocalExtension extends IExtension { export interface ILocalExtension extends IExtension {
readonly manifest: IExtensionManifest; readonly manifest: IExtensionManifest;
isDefault: boolean | undefined; isMachineScoped: boolean;
publisherId: string | null; publisherId: string | null;
publisherDisplayName: string | null; publisherDisplayName: string | null;
readmeUrl: URI | null; readmeUrl: URI | null;
...@@ -206,8 +206,8 @@ export interface IExtensionManagementService { ...@@ -206,8 +206,8 @@ export interface IExtensionManagementService {
zip(extension: ILocalExtension): Promise<URI>; zip(extension: ILocalExtension): Promise<URI>;
unzip(zipLocation: URI): Promise<IExtensionIdentifier>; unzip(zipLocation: URI): Promise<IExtensionIdentifier>;
getManifest(vsix: URI): Promise<IExtensionManifest>; getManifest(vsix: URI): Promise<IExtensionManifest>;
install(vsix: URI, isDefault?: boolean): Promise<ILocalExtension>; install(vsix: URI, isMachineScoped?: boolean): Promise<ILocalExtension>;
installFromGallery(extension: IGalleryExtension, isDefault?: boolean): Promise<ILocalExtension>; installFromGallery(extension: IGalleryExtension, isMachineScoped?: boolean): Promise<ILocalExtension>;
uninstall(extension: ILocalExtension, force?: boolean): Promise<void>; uninstall(extension: ILocalExtension, force?: boolean): Promise<void>;
reinstallFromGallery(extension: ILocalExtension): Promise<void>; reinstallFromGallery(extension: ILocalExtension): Promise<void>;
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]>; getInstalled(type?: ExtensionType): Promise<ILocalExtension[]>;
......
...@@ -152,7 +152,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -152,7 +152,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
} }
install(vsix: URI, isDefault?: boolean): Promise<ILocalExtension> { install(vsix: URI, isMachineScoped?: boolean): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#install', vsix.toString()); this.logService.trace('ExtensionManagementService#install', vsix.toString());
return createCancelablePromise(token => { return createCancelablePromise(token => {
return this.downloadVsix(vsix).then(downloadLocation => { return this.downloadVsix(vsix).then(downloadLocation => {
...@@ -170,6 +170,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -170,6 +170,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
.then(installedExtensions => { .then(installedExtensions => {
const existing = installedExtensions.filter(i => areSameExtensions(identifier, i.identifier))[0]; const existing = installedExtensions.filter(i => areSameExtensions(identifier, i.identifier))[0];
if (existing) { if (existing) {
isMachineScoped = isMachineScoped || existing.isMachineScoped;
operation = InstallOperation.Update; operation = InstallOperation.Update;
if (identifierWithVersion.equals(new ExtensionIdentifierWithVersion(existing.identifier, existing.manifest.version))) { if (identifierWithVersion.equals(new ExtensionIdentifierWithVersion(existing.identifier, existing.manifest.version))) {
return this.extensionsScanner.removeExtension(existing, 'existing').then(null, e => Promise.reject(new Error(nls.localize('restartCode', "Please restart VS Code before reinstalling {0}.", manifest.displayName || manifest.name)))); return this.extensionsScanner.removeExtension(existing, 'existing').then(null, e => Promise.reject(new Error(nls.localize('restartCode', "Please restart VS Code before reinstalling {0}.", manifest.displayName || manifest.name))));
...@@ -194,8 +195,8 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -194,8 +195,8 @@ export class ExtensionManagementService extends Disposable implements IExtension
this._onInstallExtension.fire({ identifier, zipPath }); this._onInstallExtension.fire({ identifier, zipPath });
return this.getGalleryMetadata(getGalleryExtensionId(manifest.publisher, manifest.name)) return this.getGalleryMetadata(getGalleryExtensionId(manifest.publisher, manifest.name))
.then( .then(
metadata => this.installFromZipPath(identifierWithVersion, zipPath, { ...metadata, isDefault }, operation, token), metadata => this.installFromZipPath(identifierWithVersion, zipPath, { ...metadata, isMachineScoped }, operation, token),
() => this.installFromZipPath(identifierWithVersion, zipPath, isDefault ? { isDefault } : undefined, operation, token)) () => this.installFromZipPath(identifierWithVersion, zipPath, isMachineScoped ? { isMachineScoped } : undefined, operation, token))
.then( .then(
local => { this.logService.info('Successfully installed the extension:', identifier.id); return local; }, local => { this.logService.info('Successfully installed the extension:', identifier.id); return local; },
e => { e => {
...@@ -239,7 +240,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -239,7 +240,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
)); ));
} }
async installFromGallery(extension: IGalleryExtension, isDefault?: boolean): Promise<ILocalExtension> { async installFromGallery(extension: IGalleryExtension, isMachineScoped?: boolean): Promise<ILocalExtension> {
if (!this.galleryService.isEnabled()) { if (!this.galleryService.isEnabled()) {
return Promise.reject(new Error(nls.localize('MarketPlaceDisabled', "Marketplace is not enabled"))); return Promise.reject(new Error(nls.localize('MarketPlaceDisabled', "Marketplace is not enabled")));
} }
...@@ -288,7 +289,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -288,7 +289,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
this.downloadInstallableExtension(extension, operation) this.downloadInstallableExtension(extension, operation)
.then(installableExtension => { .then(installableExtension => {
installableExtension.metadata.isDefault = isDefault !== undefined ? isDefault : existingExtension?.isDefault; installableExtension.metadata.isMachineScoped = isMachineScoped || existingExtension?.isMachineScoped;
return this.installExtension(installableExtension, cancellationToken) return this.installExtension(installableExtension, cancellationToken)
.then(local => this.extensionsDownloader.delete(URI.file(installableExtension.zipPath)).finally(() => { }).then(() => local)); .then(local => this.extensionsDownloader.delete(URI.file(installableExtension.zipPath)).finally(() => { }).then(() => local));
}) })
...@@ -483,7 +484,7 @@ export class ExtensionManagementService extends Disposable implements IExtension ...@@ -483,7 +484,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> { async updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> {
this.logService.trace('ExtensionManagementService#updateMetadata', local.identifier.id); this.logService.trace('ExtensionManagementService#updateMetadata', local.identifier.id);
local = await this.extensionsScanner.saveMetadataForLocalExtension(local, { ...metadata, isDefault: local.isDefault }); local = await this.extensionsScanner.saveMetadataForLocalExtension(local, { ...metadata, isMachineScoped: local.isMachineScoped });
this.manifestCache.invalidate(); this.manifestCache.invalidate();
return local; return local;
} }
......
...@@ -32,7 +32,7 @@ const INSTALL_ERROR_EXTRACTING = 'extracting'; ...@@ -32,7 +32,7 @@ const INSTALL_ERROR_EXTRACTING = 'extracting';
const INSTALL_ERROR_DELETING = 'deleting'; const INSTALL_ERROR_DELETING = 'deleting';
const INSTALL_ERROR_RENAMING = 'renaming'; const INSTALL_ERROR_RENAMING = 'renaming';
export type IMetadata = Partial<IGalleryMetadata & { isDefault: boolean; }>; export type IMetadata = Partial<IGalleryMetadata & { isMachineScoped: boolean; }>;
export class ExtensionsScanner extends Disposable { export class ExtensionsScanner extends Disposable {
...@@ -131,6 +131,9 @@ export class ExtensionsScanner extends Disposable { ...@@ -131,6 +131,9 @@ export class ExtensionsScanner extends Disposable {
async saveMetadataForLocalExtension(local: ILocalExtension, metadata: IMetadata): Promise<ILocalExtension> { async saveMetadataForLocalExtension(local: ILocalExtension, metadata: IMetadata): Promise<ILocalExtension> {
this.setMetadata(local, metadata); this.setMetadata(local, metadata);
// unset if false
metadata.isMachineScoped = metadata.isMachineScoped || undefined;
const manifestPath = path.join(local.location.fsPath, 'package.json'); const manifestPath = path.join(local.location.fsPath, 'package.json');
const raw = await pfs.readFile(manifestPath, 'utf8'); const raw = await pfs.readFile(manifestPath, 'utf8');
const { manifest } = await this.parseManifest(raw); const { manifest } = await this.parseManifest(raw);
...@@ -229,7 +232,7 @@ export class ExtensionsScanner extends Disposable { ...@@ -229,7 +232,7 @@ export class ExtensionsScanner extends Disposable {
const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0]; const changelog = children.filter(child => /^changelog(\.txt|\.md|)$/i.test(child))[0];
const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)) : null; const changelogUrl = changelog ? URI.file(path.join(extensionPath, changelog)) : null;
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
const local = <ILocalExtension>{ type, identifier, manifest, location: URI.file(extensionPath), readmeUrl, changelogUrl, publisherDisplayName: null, publisherId: null, isDefault: undefined }; const local = <ILocalExtension>{ type, identifier, manifest, location: URI.file(extensionPath), readmeUrl, changelogUrl, publisherDisplayName: null, publisherId: null, isMachineScoped: false };
if (metadata) { if (metadata) {
this.setMetadata(local, metadata); this.setMetadata(local, metadata);
} }
...@@ -261,7 +264,7 @@ export class ExtensionsScanner extends Disposable { ...@@ -261,7 +264,7 @@ export class ExtensionsScanner extends Disposable {
local.publisherDisplayName = metadata.publisherDisplayName || null; local.publisherDisplayName = metadata.publisherDisplayName || null;
local.publisherId = metadata.publisherId || null; local.publisherId = metadata.publisherId || null;
local.identifier.uuid = metadata.id; local.identifier.uuid = metadata.id;
local.isDefault = metadata.isDefault; local.isMachineScoped = !!metadata.isMachineScoped;
} }
private async removeUninstalledExtensions(): Promise<void> { private async removeUninstalledExtensions(): Promise<void> {
......
...@@ -8,6 +8,9 @@ import { ISyncExtension } from 'vs/platform/userDataSync/common/userDataSync'; ...@@ -8,6 +8,9 @@ import { ISyncExtension } from 'vs/platform/userDataSync/common/userDataSync';
import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { startsWith } from 'vs/base/common/strings'; import { startsWith } from 'vs/base/common/strings';
import { deepClone } from 'vs/base/common/objects'; import { deepClone } from 'vs/base/common/objects';
import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { distinct } from 'vs/base/common/arrays';
export interface IMergeResult { export interface IMergeResult {
added: ISyncExtension[]; added: ISyncExtension[];
...@@ -201,3 +204,19 @@ function massageOutgoingExtension(extension: ISyncExtension, key: string): ISync ...@@ -201,3 +204,19 @@ function massageOutgoingExtension(extension: ISyncExtension, key: string): ISync
} }
return massagedExtension; return massagedExtension;
} }
export function getIgnoredExtensions(installed: ILocalExtension[], configurationService: IConfigurationService): string[] {
const defaultIgnoredExtensions = installed.filter(i => i.isMachineScoped).map(i => i.identifier.id.toLowerCase());
const value = (configurationService.getValue<string[]>('sync.ignoredExtensions') || []).map(id => id.toLowerCase());
const added: string[] = [], removed: string[] = [];
if (Array.isArray(value)) {
for (const key of value) {
if (startsWith(key, '-')) {
removed.push(key.substring(1));
} else {
added.push(key);
}
}
}
return distinct([...defaultIgnoredExtensions, ...added,].filter(setting => removed.indexOf(setting) === -1));
}
...@@ -6,12 +6,12 @@ ...@@ -6,12 +6,12 @@
import { SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncResource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService, ISyncResourceHandle, ISyncPreviewResult, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync'; import { SyncStatus, IUserDataSyncStoreService, ISyncExtension, IUserDataSyncLogService, IUserDataSynchroniser, SyncResource, IUserDataSyncEnablementService, IUserDataSyncBackupStoreService, ISyncResourceHandle, ISyncPreviewResult, USER_DATA_SYNC_SCHEME } from 'vs/platform/userDataSync/common/userDataSync';
import { Event } from 'vs/base/common/event'; import { Event } from 'vs/base/common/event';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService, IGlobalExtensionEnablementService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionType, IExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IFileService } from 'vs/platform/files/common/files'; import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { merge } from 'vs/platform/userDataSync/common/extensionsMerge'; import { merge, getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
import { isNonEmptyArray } from 'vs/base/common/arrays'; import { isNonEmptyArray } from 'vs/base/common/arrays';
import { AbstractSynchroniser, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer'; import { AbstractSynchroniser, IRemoteUserData, ISyncData } from 'vs/platform/userDataSync/common/abstractSynchronizer';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
...@@ -87,9 +87,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -87,9 +87,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
if (remoteUserData.syncData !== null) { if (remoteUserData.syncData !== null) {
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const localExtensions = this.getLocalExtensions(installedExtensions);
const remoteExtensions = await this.parseAndMigrateExtensions(remoteUserData.syncData); const remoteExtensions = await this.parseAndMigrateExtensions(remoteUserData.syncData);
const { added, updated, remote, removed } = merge(localExtensions, remoteExtensions, localExtensions, [], this.getIgnoredExtensions()); const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
const { added, updated, remote, removed } = merge(localExtensions, remoteExtensions, localExtensions, [], ignoredExtensions);
await this.apply({ await this.apply({
added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData, added, removed, updated, remote, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0, hasLocalChanged: added.length > 0 || removed.length > 0 || updated.length > 0,
...@@ -120,8 +122,10 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -120,8 +122,10 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
this.logService.info(`${this.syncResourceLogLabel}: Started pushing extensions...`); this.logService.info(`${this.syncResourceLogLabel}: Started pushing extensions...`);
this.setStatus(SyncStatus.Syncing); this.setStatus(SyncStatus.Syncing);
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], this.getIgnoredExtensions()); const localExtensions = this.getLocalExtensions(installedExtensions);
const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
const { added, removed, updated, remote } = merge(localExtensions, null, null, [], ignoredExtensions);
const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>(); const lastSyncUserData = await this.getLastSyncUserData<ILastSyncUserData>();
const remoteUserData = await this.getRemoteUserData(lastSyncUserData); const remoteUserData = await this.getRemoteUserData(lastSyncUserData);
await this.apply({ await this.apply({
...@@ -145,7 +149,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -145,7 +149,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
async resolveContent(uri: URI): Promise<string | null> { async resolveContent(uri: URI): Promise<string | null> {
if (isEqual(uri, ExtensionsSynchroniser.EXTENSIONS_DATA_URI)) { if (isEqual(uri, ExtensionsSynchroniser.EXTENSIONS_DATA_URI)) {
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const localExtensions = this.getLocalExtensions(installedExtensions);
return this.format(localExtensions); return this.format(localExtensions);
} }
...@@ -189,7 +194,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -189,7 +194,8 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
async hasLocalData(): Promise<boolean> { async hasLocalData(): Promise<boolean> {
try { try {
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const localExtensions = this.getLocalExtensions(installedExtensions);
if (isNonEmptyArray(localExtensions)) { if (isNonEmptyArray(localExtensions)) {
return true; return true;
} }
...@@ -206,9 +212,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -206,9 +212,11 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
} }
protected async performReplace(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<void> { protected async performReplace(syncData: ISyncData, remoteUserData: IRemoteUserData, lastSyncUserData: ILastSyncUserData | null): Promise<void> {
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const localExtensions = this.getLocalExtensions(installedExtensions);
const syncExtensions = await this.parseAndMigrateExtensions(syncData); const syncExtensions = await this.parseAndMigrateExtensions(syncData);
const { added, updated, removed } = merge(localExtensions, syncExtensions, localExtensions, [], this.getIgnoredExtensions()); const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
const { added, updated, removed } = merge(localExtensions, syncExtensions, localExtensions, [], ignoredExtensions);
await this.apply({ await this.apply({
added, removed, updated, remote: syncExtensions, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData, added, removed, updated, remote: syncExtensions, remoteUserData, localExtensions, skippedExtensions: [], lastSyncUserData,
...@@ -222,7 +230,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -222,7 +230,9 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? await this.parseAndMigrateExtensions(lastSyncUserData.syncData!) : null; const lastSyncExtensions: ISyncExtension[] | null = lastSyncUserData ? await this.parseAndMigrateExtensions(lastSyncUserData.syncData!) : null;
const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : []; const skippedExtensions: ISyncExtension[] = lastSyncUserData ? lastSyncUserData.skippedExtensions || [] : [];
const localExtensions = await this.getLocalExtensions(); const installedExtensions = await this.extensionManagementService.getInstalled();
const localExtensions = this.getLocalExtensions(installedExtensions);
const ignoredExtensions = getIgnoredExtensions(installedExtensions, this.configurationService);
if (remoteExtensions) { if (remoteExtensions) {
this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`); this.logService.trace(`${this.syncResourceLogLabel}: Merging remote extensions with local extensions...`);
...@@ -230,7 +240,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -230,7 +240,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`); this.logService.trace(`${this.syncResourceLogLabel}: Remote extensions does not exist. Synchronizing extensions for the first time.`);
} }
const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, this.getIgnoredExtensions()); const { added, removed, updated, remote } = merge(localExtensions, remoteExtensions, lastSyncExtensions, skippedExtensions, ignoredExtensions);
return { return {
added, added,
...@@ -246,10 +256,6 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -246,10 +256,6 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
}; };
} }
private getIgnoredExtensions() {
return this.configurationService.getValue<string[]>('sync.ignoredExtensions') || [];
}
private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData, localExtensions, hasLocalChanged, hasRemoteChanged }: IExtensionsSyncPreviewResult, forcePush?: boolean): Promise<void> { private async apply({ added, removed, updated, remote, remoteUserData, skippedExtensions, lastSyncUserData, localExtensions, hasLocalChanged, hasRemoteChanged }: IExtensionsSyncPreviewResult, forcePush?: boolean): Promise<void> {
if (!hasLocalChanged && !hasRemoteChanged) { if (!hasLocalChanged && !hasRemoteChanged) {
...@@ -388,8 +394,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse ...@@ -388,8 +394,7 @@ export class ExtensionsSynchroniser extends AbstractSynchroniser implements IUse
return JSON.parse(syncData.content); return JSON.parse(syncData.content);
} }
private async getLocalExtensions(): Promise<ISyncExtension[]> { private getLocalExtensions(installedExtensions: ILocalExtension[]): ISyncExtension[] {
const installedExtensions = await this.extensionManagementService.getInstalled();
const disabledExtensions = this.extensionEnablementService.getDisabledExtensions(); const disabledExtensions = this.extensionEnablementService.getDisabledExtensions();
return installedExtensions return installedExtensions
.map(({ identifier, type }) => { .map(({ identifier, type }) => {
......
...@@ -45,7 +45,6 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService ...@@ -45,7 +45,6 @@ import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess'; import { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';
import { InstallExtensionQuickAccessProvider, ManageExtensionsQuickAccessProvider } from 'vs/workbench/contrib/extensions/browser/extensionsQuickAccess'; import { InstallExtensionQuickAccessProvider, ManageExtensionsQuickAccessProvider } from 'vs/workbench/contrib/extensions/browser/extensionsQuickAccess';
import { ExtensionRecommendationsService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService'; import { ExtensionRecommendationsService } from 'vs/workbench/contrib/extensions/browser/extensionRecommendationsService';
...@@ -450,15 +449,11 @@ registerAction2(class extends Action2 { ...@@ -450,15 +449,11 @@ registerAction2(class extends Action2 {
} }
async run(accessor: ServicesAccessor, id: string) { async run(accessor: ServicesAccessor, id: string) {
const configurationService = accessor.get(IConfigurationService); const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);
const ignoredExtensions = [...configurationService.getValue<string[]>('sync.ignoredExtensions')]; const extension = extensionsWorkbenchService.local.find(e => areSameExtensions({ id }, e.identifier));
const index = ignoredExtensions.findIndex(ignoredExtension => areSameExtensions({ id: ignoredExtension }, { id })); if (extension) {
if (index !== -1) { return extensionsWorkbenchService.toggleExtensionIgnoredToSync(extension);
ignoredExtensions.splice(index, 1);
} else {
ignoredExtensions.push(id);
} }
return configurationService.updateValue('sync.ignoredExtensions', ignoredExtensions.length ? ignoredExtensions : undefined, ConfigurationTarget.USER);
} }
}); });
......
...@@ -808,7 +808,7 @@ export class MenuItemExtensionAction extends ExtensionAction { ...@@ -808,7 +808,7 @@ export class MenuItemExtensionAction extends ExtensionAction {
constructor( constructor(
private readonly action: IAction, private readonly action: IAction,
@IConfigurationService private readonly configurationService: IConfigurationService @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
) { ) {
super(action.id, action.label); super(action.id, action.label);
} }
...@@ -818,7 +818,7 @@ export class MenuItemExtensionAction extends ExtensionAction { ...@@ -818,7 +818,7 @@ export class MenuItemExtensionAction extends ExtensionAction {
return; return;
} }
if (this.action.id === TOGGLE_IGNORE_EXTENSION_ACTION_ID) { if (this.action.id === TOGGLE_IGNORE_EXTENSION_ACTION_ID) {
this.checked = !this.configurationService.getValue<string[]>('sync.ignoredExtensions').some(id => areSameExtensions({ id }, this.extension!.identifier)); this.checked = !this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension);
} }
} }
...@@ -2660,7 +2660,8 @@ export class SyncIgnoredIconAction extends ExtensionAction { ...@@ -2660,7 +2660,8 @@ export class SyncIgnoredIconAction extends ExtensionAction {
private static readonly DISABLE_CLASS = `${SyncIgnoredIconAction.ENABLE_CLASS} hide`; private static readonly DISABLE_CLASS = `${SyncIgnoredIconAction.ENABLE_CLASS} hide`;
constructor( constructor(
@IConfigurationService private readonly configurationService: IConfigurationService @IConfigurationService private readonly configurationService: IConfigurationService,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
) { ) {
super('extensions.syncignore', '', SyncIgnoredIconAction.DISABLE_CLASS, false); super('extensions.syncignore', '', SyncIgnoredIconAction.DISABLE_CLASS, false);
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectedKeys.includes('sync.ignoredExtensions'))(() => this.update())); this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectedKeys.includes('sync.ignoredExtensions'))(() => this.update()));
...@@ -2670,11 +2671,8 @@ export class SyncIgnoredIconAction extends ExtensionAction { ...@@ -2670,11 +2671,8 @@ export class SyncIgnoredIconAction extends ExtensionAction {
update(): void { update(): void {
this.class = SyncIgnoredIconAction.DISABLE_CLASS; this.class = SyncIgnoredIconAction.DISABLE_CLASS;
if (this.extension) { if (this.extension && this.extensionsWorkbenchService.isExtensionIgnoredToSync(this.extension)) {
const ignoredExtensions = this.configurationService.getValue<string[]>('sync.ignoredExtensions') || []; this.class = SyncIgnoredIconAction.ENABLE_CLASS;
if (ignoredExtensions.some(id => areSameExtensions({ id }, this.extension!.identifier))) {
this.class = SyncIgnoredIconAction.ENABLE_CLASS;
}
} }
} }
......
...@@ -19,7 +19,7 @@ import { ...@@ -19,7 +19,7 @@ import {
import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { IWorkbenchExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IHostService } from 'vs/workbench/services/host/browser/host';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { IExtension, ExtensionState, IExtensionsWorkbenchService, AutoUpdateConfigurationKey, AutoCheckUpdatesConfigurationKey } from 'vs/workbench/contrib/extensions/common/extensions';
...@@ -37,6 +37,7 @@ import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, is ...@@ -37,6 +37,7 @@ import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, is
import { IModeService } from 'vs/editor/common/services/modeService'; import { IModeService } from 'vs/editor/common/services/modeService';
import { IProductService } from 'vs/platform/product/common/productService'; import { IProductService } from 'vs/platform/product/common/productService';
import { asDomUri } from 'vs/base/browser/dom'; import { asDomUri } from 'vs/base/browser/dom';
import { getIgnoredExtensions } from 'vs/platform/userDataSync/common/extensionsMerge';
interface IExtensionStateProvider<T> { interface IExtensionStateProvider<T> {
(extension: Extension): T; (extension: Extension): T;
...@@ -863,6 +864,39 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension ...@@ -863,6 +864,39 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
}, () => this.extensionService.reinstallFromGallery(toReinstall).then(() => this.local.filter(local => areSameExtensions(local.identifier, extension.identifier))[0])); }, () => this.extensionService.reinstallFromGallery(toReinstall).then(() => this.local.filter(local => areSameExtensions(local.identifier, extension.identifier))[0]));
} }
isExtensionIgnoredToSync(extension: IExtension): boolean {
const localExtensions = (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer
? this.local.filter(i => i.server === this.extensionManagementServerService.localExtensionManagementServer)
: this.local)
.filter(l => !!l.local)
.map(l => l.local!);
const ignoredExtensions = getIgnoredExtensions(localExtensions, this.configurationService);
return ignoredExtensions.includes(extension.identifier.id.toLowerCase());
}
toggleExtensionIgnoredToSync(extension: IExtension): Promise<void> {
const isIgnored = this.isExtensionIgnoredToSync(extension);
const isDefaultIgnored = extension.local?.isMachineScoped;
const id = extension.identifier.id.toLowerCase();
// first remove the extension completely from ignored extensions
let currentValue = [...this.configurationService.getValue<string[]>('sync.ignoredExtensions')].map(id => id.toLowerCase());
currentValue = currentValue.filter(v => v !== id && v !== `-${id}`);
// If ignored, then add only if it is ignored by default
if (isIgnored && isDefaultIgnored) {
currentValue.push(`-${id}`);
}
// If asked not to sync, then add only if it is not ignored by default
if (!isIgnored && !isDefaultIgnored) {
currentValue.push(id);
}
return this.configurationService.updateValue('sync.ignoredExtensions', currentValue.length ? currentValue : undefined, ConfigurationTarget.USER);
}
private installWithProgress<T>(installTask: () => Promise<T>, extensionName?: string): Promise<T> { private installWithProgress<T>(installTask: () => Promise<T>, extensionName?: string): Promise<T> {
const title = extensionName ? nls.localize('installing named extension', "Installing '{0}' extension....", extensionName) : nls.localize('installing extension', 'Installing extension....'); const title = extensionName ? nls.localize('installing named extension', "Installing '{0}' extension....", extensionName) : nls.localize('installing extension', 'Installing extension....');
return this.progressService.withProgress({ return this.progressService.withProgress({
......
...@@ -88,6 +88,10 @@ export interface IExtensionsWorkbenchService { ...@@ -88,6 +88,10 @@ export interface IExtensionsWorkbenchService {
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>; setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>;
open(extension: IExtension, options?: { sideByside?: boolean, preserveFocus?: boolean, pinned?: boolean }): Promise<any>; open(extension: IExtension, options?: { sideByside?: boolean, preserveFocus?: boolean, pinned?: boolean }): Promise<any>;
checkForUpdates(): Promise<void>; checkForUpdates(): Promise<void>;
// Sync APIs
isExtensionIgnoredToSync(extension: IExtension): boolean;
toggleExtensionIgnoredToSync(extension: IExtension): Promise<void>;
} }
export const ConfigurationKey = 'extensions'; export const ConfigurationKey = 'extensions';
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册