Skip to content

Commit f64b324

Browse files
authored
Merge pull request microsoft#152163 from microsoft/sandy081/technological-prawn
Support profiles creation, switching and removing
2 parents a6a12cc + 917f697 commit f64b324

File tree

15 files changed

+359
-157
lines changed

15 files changed

+359
-157
lines changed

src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ import { IExtensionsScannerService } from 'vs/platform/extensionManagement/commo
102102
import { ExtensionsScannerService } from 'vs/platform/extensionManagement/node/extensionsScannerService';
103103
import { IUserDataProfilesService, UserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
104104
import { ExtensionsProfileScannerService, IExtensionsProfileScannerService } from 'vs/platform/extensionManagement/common/extensionsProfileScannerService';
105-
import { revive } from 'vs/base/common/marshalling';
106105
import { PolicyChannelClient } from 'vs/platform/policy/common/policyIpc';
107106
import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/policy';
108107
import { OneDataSystemAppender } from 'vs/platform/telemetry/node/1dsAppender';
@@ -233,7 +232,7 @@ class SharedProcessMain extends Disposable {
233232
fileService.registerProvider(Schemas.vscodeUserData, userDataFileSystemProvider);
234233

235234
// User Data Profiles
236-
const userDataProfilesService = this._register(new UserDataProfilesService(revive(this.configuration.profiles.default), revive(this.configuration.profiles.current), environmentService, fileService, logService));
235+
const userDataProfilesService = this._register(new UserDataProfilesService(this.configuration.defaultProfile, undefined, environmentService, fileService, logService));
237236
services.set(IUserDataProfilesService, userDataProfilesService);
238237

239238
// Configuration

src/vs/code/electron-main/main.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ import { IPolicyService, NullPolicyService } from 'vs/platform/policy/common/pol
6868
import { NativePolicyService } from 'vs/platform/policy/node/nativePolicyService';
6969
import { FilePolicyService } from 'vs/platform/policy/common/filePolicyService';
7070
import { DisposableStore } from 'vs/base/common/lifecycle';
71+
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
72+
import { UriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentityService';
7173

7274
/**
7375
* The main VS Code entry point.
@@ -170,6 +172,10 @@ class CodeMain {
170172
const diskFileSystemProvider = new DiskFileSystemProvider(logService);
171173
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
172174

175+
// URI Identity
176+
const uriIdentityService = new UriIdentityService(fileService);
177+
services.set(IUriIdentityService, uriIdentityService);
178+
173179
// Logger
174180
services.set(ILoggerService, new LoggerService(logService, fileService));
175181

@@ -178,7 +184,7 @@ class CodeMain {
178184
services.set(IStateMainService, stateMainService);
179185

180186
// User Data Profiles
181-
const userDataProfilesMainService = new UserDataProfilesMainService(stateMainService, environmentMainService, fileService, logService);
187+
const userDataProfilesMainService = new UserDataProfilesMainService(stateMainService, uriIdentityService, environmentMainService, fileService, logService);
182188
services.set(IUserDataProfilesService, userDataProfilesMainService);
183189

184190
// Policy
@@ -244,10 +250,7 @@ class CodeMain {
244250
].map(path => path ? FSPromises.mkdir(path, { recursive: true }) : undefined)),
245251

246252
// State service
247-
stateMainService.init(),
248-
249-
// User Data Profiles Service
250-
userDataProfilesMainService.init(),
253+
stateMainService.init().then(() => userDataProfilesMainService.init()),
251254

252255
// Configuration service
253256
configurationService.initialize()

src/vs/platform/sharedProcess/electron-main/sharedProcess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ export class SharedProcess extends Disposable implements ISharedProcess {
242242
appRoot: this.environmentMainService.appRoot,
243243
codeCachePath: this.environmentMainService.codeCachePath,
244244
backupWorkspacesPath: this.environmentMainService.backupWorkspacesPath,
245-
profiles: this.userDataProfilesService.serialize(),
245+
defaultProfile: this.userDataProfilesService.defaultProfile,
246246
userEnv: this.userEnv,
247247
args: this.environmentMainService.args,
248248
logLevel: this.logService.getLevel(),

src/vs/platform/sharedProcess/node/sharedProcess.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { IStringDictionary } from 'vs/base/common/collections';
77
import { ISandboxConfiguration } from 'vs/base/parts/sandbox/common/sandboxTypes';
88
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
99
import { LogLevel } from 'vs/platform/log/common/log';
10-
import { IUserDataProfilesDto } from 'vs/platform/userDataProfile/common/userDataProfile';
10+
import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataProfile';
1111
import { PolicyDefinition, PolicyValue } from 'vs/platform/policy/common/policy';
12+
import { UriDto } from 'vs/base/common/types';
1213

1314
export interface ISharedProcess {
1415

@@ -28,7 +29,7 @@ export interface ISharedProcessConfiguration extends ISandboxConfiguration {
2829

2930
readonly backupWorkspacesPath: string;
3031

31-
readonly profiles: IUserDataProfilesDto;
32+
readonly defaultProfile: UriDto<IUserDataProfile>;
3233

3334
readonly policiesData?: IStringDictionary<{ definition: PolicyDefinition; value: PolicyValue }>;
3435
}

src/vs/platform/storage/common/storageIpc.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
import { Emitter, Event } from 'vs/base/common/event';
77
import { Disposable } from 'vs/base/common/lifecycle';
8+
import { UriDto } from 'vs/base/common/types';
89
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
910
import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage';
10-
import { IUserDataProfileDto, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
11+
import { IUserDataProfile, IUserDataProfilesService } from 'vs/platform/userDataProfile/common/userDataProfile';
1112
import { ISerializedSingleFolderWorkspaceIdentifier, ISerializedWorkspaceIdentifier, IEmptyWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
1213

1314
export type Key = string;
@@ -21,7 +22,7 @@ export interface IBaseSerializableStorageRequest {
2122
* workspace is provided. Can be undefined to denote
2223
* application scope.
2324
*/
24-
readonly profile: IUserDataProfileDto | undefined;
25+
readonly profile: UriDto<IUserDataProfile> | undefined;
2526

2627
/**
2728
* Workspace to correlate storage. Can be undefined to
@@ -46,7 +47,7 @@ abstract class BaseStorageDatabaseClient extends Disposable implements IStorageD
4647

4748
constructor(
4849
protected channel: IChannel,
49-
protected profile: IUserDataProfileDto | undefined,
50+
protected profile: UriDto<IUserDataProfile> | undefined,
5051
protected workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | IEmptyWorkspaceIdentifier | undefined
5152
) {
5253
super();
@@ -81,7 +82,7 @@ abstract class BaseProfileAwareStorageDatabaseClient extends BaseStorageDatabase
8182
private readonly _onDidChangeItemsExternal = this._register(new Emitter<IStorageItemsChangeEvent>());
8283
readonly onDidChangeItemsExternal = this._onDidChangeItemsExternal.event;
8384

84-
constructor(channel: IChannel, profile: IUserDataProfileDto | undefined) {
85+
constructor(channel: IChannel, profile: UriDto<IUserDataProfile> | undefined) {
8586
super(channel, profile, undefined);
8687

8788
this.registerListeners();
@@ -119,7 +120,7 @@ class ApplicationStorageDatabaseClient extends BaseProfileAwareStorageDatabaseCl
119120

120121
class GlobalStorageDatabaseClient extends BaseProfileAwareStorageDatabaseClient {
121122

122-
constructor(channel: IChannel, profile: IUserDataProfileDto) {
123+
constructor(channel: IChannel, profile: UriDto<IUserDataProfile>) {
123124
super(channel, profile);
124125
}
125126

src/vs/platform/userDataProfile/common/userDataProfile.ts

Lines changed: 51 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,35 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { coalesce } from 'vs/base/common/arrays';
7-
import { Emitter, Event } from 'vs/base/common/event';
86
import { hash } from 'vs/base/common/hash';
97
import { Disposable } from 'vs/base/common/lifecycle';
108
import { joinPath } from 'vs/base/common/resources';
119
import { UriDto } from 'vs/base/common/types';
1210
import { URI } from 'vs/base/common/uri';
11+
import { localize } from 'vs/nls';
1312
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
14-
import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files';
13+
import { IFileService } from 'vs/platform/files/common/files';
1514
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1615
import { ILogService } from 'vs/platform/log/common/log';
16+
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
17+
18+
export type ProfileOptions = {
19+
settings?: boolean;
20+
keybindings?: boolean;
21+
tasks?: boolean;
22+
snippets?: boolean;
23+
extensions?: boolean;
24+
uiState?: boolean;
25+
};
26+
27+
export const DefaultOptions: ProfileOptions = {
28+
settings: true,
29+
keybindings: true,
30+
tasks: true,
31+
snippets: true,
32+
extensions: true,
33+
uiState: true
34+
};
1735

1836
export interface IUserDataProfile {
1937
readonly id: string;
@@ -28,30 +46,23 @@ export interface IUserDataProfile {
2846
readonly extensionsResource: URI | undefined;
2947
}
3048

31-
export type IUserDataProfileDto = UriDto<IUserDataProfile>;
32-
export type IUserDataProfilesDto = {
33-
readonly current: IUserDataProfileDto;
34-
readonly default: IUserDataProfileDto;
35-
};
36-
3749
export const IUserDataProfilesService = createDecorator<IUserDataProfilesService>('IUserDataProfilesService');
3850
export interface IUserDataProfilesService {
3951
readonly _serviceBrand: undefined;
4052

4153
readonly profilesHome: URI;
4254
readonly defaultProfile: IUserDataProfile;
43-
44-
readonly onDidChangeCurrentProfile: Event<IUserDataProfile>;
4555
readonly currentProfile: IUserDataProfile;
4656

47-
createProfile(name: string): IUserDataProfile;
48-
setProfile(name: string): Promise<void>;
57+
newProfile(name: string, options?: ProfileOptions): IUserDataProfile;
58+
createProfile(profile: IUserDataProfile, options: ProfileOptions, workspaceIdentifier?: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise<IUserDataProfile>;
59+
setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise<IUserDataProfile>;
60+
getProfile(workspace: URI): IUserDataProfile;
4961
getAllProfiles(): Promise<IUserDataProfile[]>;
50-
51-
serialize(): IUserDataProfilesDto;
62+
removeProfile(profile: IUserDataProfile): Promise<void>;
5263
}
5364

54-
function reviveProfile(profile: IUserDataProfile, scheme: string): IUserDataProfile {
65+
export function reviveProfile(profile: UriDto<IUserDataProfile>, scheme: string): IUserDataProfile {
5566
return {
5667
id: profile.id,
5768
isDefault: profile.isDefault,
@@ -69,74 +80,49 @@ function reviveProfile(profile: IUserDataProfile, scheme: string): IUserDataProf
6980
export class UserDataProfilesService extends Disposable implements IUserDataProfilesService {
7081
readonly _serviceBrand: undefined;
7182

72-
protected static DEFAULT_PROFILE_NAME = 'default';
83+
readonly profilesHome: URI;
7384

7485
protected _currentProfile: IUserDataProfile;
7586
get currentProfile(): IUserDataProfile { return this._currentProfile; }
7687

77-
readonly profilesHome: URI;
7888
protected _defaultProfile: IUserDataProfile;
7989
get defaultProfile(): IUserDataProfile { return this._defaultProfile; }
8090

81-
private readonly _onDidChangeCurrentProfile = this._register(new Emitter<IUserDataProfile>());
82-
readonly onDidChangeCurrentProfile = this._onDidChangeCurrentProfile.event;
83-
8491
constructor(
85-
defaultProfile: IUserDataProfile | undefined,
86-
currentProfile: IUserDataProfile | undefined,
87-
@IEnvironmentService private readonly environmentService: IEnvironmentService,
92+
defaultProfile: UriDto<IUserDataProfile> | undefined,
93+
currentProfile: UriDto<IUserDataProfile> | undefined,
94+
@IEnvironmentService protected readonly environmentService: IEnvironmentService,
8895
@IFileService protected readonly fileService: IFileService,
8996
@ILogService protected readonly logService: ILogService
9097
) {
9198
super();
9299
this.profilesHome = joinPath(this.environmentService.userRoamingDataHome, 'profiles');
93-
this._defaultProfile = defaultProfile ? reviveProfile(defaultProfile, this.profilesHome.scheme) : this.createProfile(undefined);
100+
this._defaultProfile = defaultProfile ? reviveProfile(defaultProfile, this.profilesHome.scheme) : this.toUserDataProfile(localize('defaultProfile', "Default"), environmentService.userRoamingDataHome, { ...DefaultOptions, extensions: false }, true);
94101
this._currentProfile = currentProfile ? reviveProfile(currentProfile, this.profilesHome.scheme) : this._defaultProfile;
95102
}
96103

97-
createProfile(name: string | undefined): IUserDataProfile {
98-
const isDefault = !name || name === UserDataProfilesService.DEFAULT_PROFILE_NAME;
99-
const location = name && name !== UserDataProfilesService.DEFAULT_PROFILE_NAME ? joinPath(this.profilesHome, name) : this.environmentService.userRoamingDataHome;
100-
return {
101-
id: hash(location.toString()).toString(16),
102-
isDefault,
103-
name: name ?? UserDataProfilesService.DEFAULT_PROFILE_NAME,
104-
location,
105-
globalStorageHome: joinPath(location, 'globalStorage'),
106-
settingsResource: joinPath(location, 'settings.json'),
107-
keybindingsResource: joinPath(location, 'keybindings.json'),
108-
tasksResource: joinPath(location, 'tasks.json'),
109-
snippetsHome: joinPath(location, 'snippets'),
110-
extensionsResource: name ? joinPath(location, 'extensions.json') : undefined
111-
};
112-
}
113-
114-
async getAllProfiles(): Promise<IUserDataProfile[]> {
115-
try {
116-
const stat = await this.fileService.resolve(this.profilesHome);
117-
const profiles = coalesce(stat.children?.map(stat => stat.isDirectory ? this.createProfile(stat.name) : undefined) ?? []);
118-
if (profiles.length) {
119-
profiles.unshift(this._defaultProfile);
120-
}
121-
return profiles;
122-
} catch (error) {
123-
if ((<FileOperationError>error).fileOperationResult !== FileOperationResult.FILE_NOT_FOUND) {
124-
this.logService.error('Error while getting all profiles', error);
125-
}
126-
}
127-
return [];
104+
newProfile(name: string, options: ProfileOptions = DefaultOptions): IUserDataProfile {
105+
return this.toUserDataProfile(name, joinPath(this.profilesHome, hash(name).toString(16)), options, this.defaultProfile);
128106
}
129107

130-
protected createCurrentProfile(profile: string | undefined): IUserDataProfile {
131-
return profile === UserDataProfilesService.DEFAULT_PROFILE_NAME ? this._defaultProfile : this.createProfile(profile);
132-
}
133-
134-
setProfile(name: string): Promise<void> { throw new Error('Not implemented'); }
135-
136-
serialize(): IUserDataProfilesDto {
108+
protected toUserDataProfile(name: string, location: URI, options: ProfileOptions, defaultProfile: true | IUserDataProfile): IUserDataProfile {
137109
return {
138-
default: this.defaultProfile,
139-
current: this.currentProfile
110+
id: hash(location.toString()).toString(16),
111+
name: name,
112+
location: location,
113+
isDefault: defaultProfile === true,
114+
globalStorageHome: defaultProfile === true || options.uiState ? joinPath(location, 'globalStorage') : defaultProfile.globalStorageHome,
115+
settingsResource: defaultProfile === true || options.settings ? joinPath(location, 'settings.json') : defaultProfile.settingsResource,
116+
keybindingsResource: defaultProfile === true || options.keybindings ? joinPath(location, 'keybindings.json') : defaultProfile.keybindingsResource,
117+
tasksResource: defaultProfile === true || options.tasks ? joinPath(location, 'tasks.json') : defaultProfile.tasksResource,
118+
snippetsHome: defaultProfile === true || options.snippets ? joinPath(location, 'snippets') : defaultProfile.snippetsHome,
119+
extensionsResource: defaultProfile === true && !options.extensions ? undefined : joinPath(location, 'extensions.json'),
140120
};
141121
}
122+
123+
getAllProfiles(): Promise<IUserDataProfile[]> { throw new Error('Not implemented'); }
124+
createProfile(profile: IUserDataProfile, options: ProfileOptions, workspaceIdentifier?: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise<IUserDataProfile> { throw new Error('Not implemented'); }
125+
setProfileForWorkspace(profile: IUserDataProfile, workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): Promise<IUserDataProfile> { throw new Error('Not implemented'); }
126+
getProfile(workspace: URI): IUserDataProfile { throw new Error('Not implemented'); }
127+
removeProfile(profile: IUserDataProfile): Promise<void> { throw new Error('Not implemented'); }
142128
}

0 commit comments

Comments
 (0)