2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import { Queue } from '../../../base/common/async.js';
7
>
import { VSBuffer } from '../../../base/common/buffer.js';
8
>
import { Disposable } from '../../../base/common/lifecycle.js';
9
>
import { Emitter, Event } from '../../../base/common/event.js';
10
>
import { ResourceMap } from '../../../base/common/map.js';
11
>
import { URI, UriComponents } from '../../../base/common/uri.js';
12
>
import { Metadata, isIExtensionIdentifier } from './extensionManagement.js';
13
>
import { areSameExtensions } from './extensionManagementUtil.js';
14
>
import { IExtension, IExtensionIdentifier } from '../../extensions/common/extensions.js';
15
>
import { FileOperationResult, IFileService, toFileOperationResult } from '../../files/common/files.js';
16
>
import { createDecorator } from '../../instantiation/common/instantiation.js';
17
>
import { ILogService } from '../../log/common/log.js';
18
>
import { IUserDataProfilesService } from '../../userDataProfile/common/userDataProfile.js';
19
>
import { IUriIdentityService } from '../../uriIdentity/common/uriIdentity.js';
20
>
import { Mutable, isObject, isString, isUndefined } from '../../../base/common/types.js';
21
>
import { getErrorMessage } from '../../../base/common/errors.js';
22
>
23
>
interface IStoredProfileExtension {
24
>
identifier: IExtensionIdentifier;
25
>
location: UriComponents | string;
26
>
relativeLocation: string | undefined;
27
>
version: string;
28
>
metadata?: Metadata;
29
>
}
30
>
31
>
export const enum ExtensionsProfileScanningErrorCode {
32
>
33
>
/**
34
>
* Error when trying to scan extensions from a profile that does not exist.
35
>
*/
36
>
ERROR_PROFILE_NOT_FOUND = 'ERROR_PROFILE_NOT_FOUND',
37
>
38
>
/**
39
>
* Error when profile file is invalid.
40
>
*/
41
>
ERROR_INVALID_CONTENT = 'ERROR_INVALID_CONTENT',
42
>
43
>
}
44
>
45
>
export class ExtensionsProfileScanningError extends Error {
46
>
constructor(message: string, public code: ExtensionsProfileScanningErrorCode) {
47
super(message);
48
}
50
>
51
>
export interface IScannedProfileExtension {
52
>
readonly identifier: IExtensionIdentifier;
53
>
readonly version: string;
54
>
readonly location: URI;
55
>
readonly metadata?: Metadata;
56
>
}
57
>
58
>
export interface ProfileExtensionsEvent {
59
>
readonly extensions: readonly IScannedProfileExtension[];
60
>
readonly profileLocation: URI;
61
>
}
62
>
63
>
export interface DidAddProfileExtensionsEvent extends ProfileExtensionsEvent {
64
>
readonly error?: Error;
65
>
}
66
>
67
>
export interface DidRemoveProfileExtensionsEvent extends ProfileExtensionsEvent {
68
>
readonly error?: Error;
69
>
}
70
>
71
>
export interface IProfileExtensionsScanOptions {
72
>
readonly bailOutWhenFileNotFound?: boolean;
73
>
}
74
>
75
>
export const IExtensionsProfileScannerService = createDecorator<IExtensionsProfileScannerService>('IExtensionsProfileScannerService');
76
>
export interface IExtensionsProfileScannerService {
77
>
readonly _serviceBrand: undefined;
78
>
79
>
readonly onAddExtensions: Event<ProfileExtensionsEvent>;
80
>
readonly onDidAddExtensions: Event<DidAddProfileExtensionsEvent>;
81
>
readonly onRemoveExtensions: Event<ProfileExtensionsEvent>;
82
>
readonly onDidRemoveExtensions: Event<DidRemoveProfileExtensionsEvent>;
83
>
84
>
scanProfileExtensions(profileLocation: URI, options?: IProfileExtensionsScanOptions): Promise<IScannedProfileExtension[]>;
85
>
addExtensionsToProfile(extensions: [IExtension, Metadata | undefined][], profileLocation: URI, keepExistingVersions?: boolean): Promise<IScannedProfileExtension[]>;
86
>
updateMetadata(extensions: [IExtension, Metadata | undefined][], profileLocation: URI): Promise<IScannedProfileExtension[]>;
87
>
removeExtensionsFromProfile(extensions: IExtensionIdentifier[], profileLocation: URI): Promise<void>;
88
>
}
89
>
90
>
export abstract class AbstractExtensionsProfileScannerService extends Disposable implements IExtensionsProfileScannerService {
91
>
readonly _serviceBrand: undefined;
92
>
93
>
private readonly _onAddExtensions = this._register(new Emitter<ProfileExtensionsEvent>());
94
>
readonly onAddExtensions = this._onAddExtensions.event;
95
>
96
>
private readonly _onDidAddExtensions = this._register(new Emitter<DidAddProfileExtensionsEvent>());
97
>
readonly onDidAddExtensions = this._onDidAddExtensions.event;
98
>
99
>
private readonly _onRemoveExtensions = this._register(new Emitter<ProfileExtensionsEvent>());
100
>
readonly onRemoveExtensions = this._onRemoveExtensions.event;
101
>
102
>
private readonly _onDidRemoveExtensions = this._register(new Emitter<DidRemoveProfileExtensionsEvent>());
103
>
readonly onDidRemoveExtensions = this._onDidRemoveExtensions.event;
104
>
105
>
private readonly resourcesAccessQueueMap = new ResourceMap<Queue<IScannedProfileExtension[]>>();
106
>
107
>
constructor(
108
private readonly extensionsLocation: URI,
109
@IFileService private readonly fileService: IFileService,