Skip to content

Commit

Permalink
Use the config dir for all settings and extensions
Browse files Browse the repository at this point in the history
Closes #4488.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
  • Loading branch information
Akos Kitta committed Feb 26, 2020
1 parent 3a9ca3d commit 6c87fa8
Show file tree
Hide file tree
Showing 27 changed files with 150 additions and 268 deletions.
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@
- `test:references`: fails if typescript references are out of sync.
- `prepare:references`: updates typescript references, if required.
- [repo] the `prepare` script now updates typescript references.
- [core] From now on, downstream projects can refine where the configuration files (such as `settings.json`, `keymaps.json`, `recentworkspace.json`, etc.) will be stored by Theia. [#4488](https://github.com/eclipse-theia/theia/pull/4488)
The default location remains the same: `~/.theia`, however it can be customized by overriding the `#getConfigDirUri` method of the `EnvVariablesServer` API. The easiest way is to subclass the `EnvVariablesServerImpl` and rebind it in your backend module:
```ts
// your-env-variables-server.ts:

import { injectable } from 'inversify';
import { EnvVariablesServerImpl } from '@theia/core/lib/node/env-variables';

@injectable()
export class YourEnvVariableServer extends EnvVariablesServerImpl {

async getConfigDirUri(): Promise<string> {
return 'file:///path/to/your/desired/config/dir';
}

}

// your-backend-application-module.ts:

import { ContainerModule } from 'inversify';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { YourEnvVariableServer } from './your-env-variables-server';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
rebind(EnvVariablesServer).to(YourEnvVariableServer).inSingletonScope();
});
```

Breaking changes:

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/browser/label-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export interface LabelProviderContribution {
/**
* Check whether the given element is affected by the given change event.
* Contributions delegating to the label provider can use this hook
* to perfrom a recursive check.
* to perform a recursive check.
*/
affects?(element: object, event: DidChangeLabelEvent): boolean;

Expand Down
13 changes: 3 additions & 10 deletions packages/core/src/browser/preferences/preference-configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { injectable, inject, named, interfaces } from 'inversify';
import URI from '../../common/uri';
import { ContributionProvider, bindContributionProvider } from '../../common/contribution-provider';
import { EnvVariablesServer } from '../../common/env-variables';

export const PreferenceConfiguration = Symbol('PreferenceConfiguration');
export interface PreferenceConfiguration {
Expand All @@ -35,12 +34,9 @@ export class PreferenceConfigurations {
@inject(ContributionProvider) @named(PreferenceConfiguration)
protected readonly provider: ContributionProvider<PreferenceConfiguration>;

@inject(EnvVariablesServer)
protected readonly envServer: EnvVariablesServer;

/* prefer Theia over VS Code by default */
async getPaths(): Promise<string[]> {
return [await this.envServer.getDataFolderName(), '.vscode'];
getPaths(): string[] {
return ['.theia', '.vscode'];
}

getConfigName(): string {
Expand Down Expand Up @@ -75,10 +71,7 @@ export class PreferenceConfigurations {
return configUri.parent.path.base;
}

async createUri(folder: URI, configPath: string, configName: string = this.getConfigName()): Promise<URI> {
if (!configPath) {
configPath = (await this.getPaths())[0];
}
createUri(folder: URI, configPath: string = this.getPaths()[0], configName: string = this.getConfigName()): URI {
return folder.resolve(configPath).resolve(configName + '.json');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import { interfaces } from 'inversify';
import { PreferenceProvider } from '../';
import { PreferenceScope } from '../preference-scope';
import { PreferenceProviderDataChanges, PreferenceProviderDataChange } from '../preference-provider';
import { EnvVariablesServer } from '../../../common/env-variables/env-variables-protocol';
import { MockEnvVariablesServerImpl } from '../../test/mock-env-variables-server';

export class MockPreferenceProvider extends PreferenceProvider {
readonly prefs: { [p: string]: any } = {};
Expand Down Expand Up @@ -52,9 +50,6 @@ export class MockPreferenceProvider extends PreferenceProvider {
export function bindMockPreferenceProviders(bind: interfaces.Bind, unbind: interfaces.Unbind): void {
unbind(PreferenceProvider);

// Needed for PreferenceConfigurations in PreferenceSchemaProvider
bind(EnvVariablesServer).to(MockEnvVariablesServerImpl).inSingletonScope();

bind(PreferenceProvider).toDynamicValue(ctx => new MockPreferenceProvider(PreferenceScope.User)).inSingletonScope().whenTargetNamed(PreferenceScope.User);
bind(PreferenceProvider).toDynamicValue(ctx => new MockPreferenceProvider(PreferenceScope.Workspace)).inSingletonScope().whenTargetNamed(PreferenceScope.Workspace);
bind(PreferenceProvider).toDynamicValue(ctx => new MockPreferenceProvider(PreferenceScope.Folder)).inSingletonScope().whenTargetNamed(PreferenceScope.Folder);
Expand Down
20 changes: 7 additions & 13 deletions packages/core/src/browser/test/mock-env-variables-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,27 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable } from 'inversify';
import URI from '../../common/uri';
import { EnvVariablesServer, EnvVariable } from '../../common/env-variables';

@injectable()
export class MockEnvVariablesServerImpl implements EnvVariablesServer {
async getDataFolderName(): Promise<string> {
return '.theia';
}

async getUserHomeFolder(): Promise<string> {
return 'file:///home/test';
}
constructor(protected readonly configDirUri: URI) { }

async getUserDataFolder(): Promise<string> {
return 'file:///home/test/.theia';
async getConfigDirUri(): Promise<string> {
return this.configDirUri.toString();
}

getExecPath(): Promise<string> {
throw new Error('Method not implemented.');
}

getVariables(): Promise<EnvVariable[]> {
throw new Error('Method not implemented.');
}

getValue(key: string): Promise<EnvVariable | undefined> {
throw new Error('Method not implemented.');
}
getAppDataFolder(): Promise<string> {
throw new Error('Method not implemented.');
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,7 @@ export interface EnvVariablesServer {
getExecPath(): Promise<string>
getVariables(): Promise<EnvVariable[]>
getValue(key: string): Promise<EnvVariable | undefined>
getUserHomeFolder(): Promise<string>
getDataFolderName(): Promise<string>
getUserDataFolder(): Promise<string>
/** Windows specific. Returns system data folder of Theia. On other than Windows systems is the same as getUserDataFolder */
getAppDataFolder(): Promise<string>
getConfigDirUri(): Promise<string>;
}

export interface EnvVariable {
Expand Down
31 changes: 5 additions & 26 deletions packages/core/src/node/env-variables/env-variables-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,18 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import * as os from 'os';
import { join } from 'path';
import { homedir } from 'os';
import { injectable } from 'inversify';
import { EnvVariable, EnvVariablesServer } from '../../common/env-variables';
import { isWindows } from '../../common/os';
import { FileUri } from '../file-uri';

const THEIA_DATA_FOLDER = '.theia';

const WINDOWS_APP_DATA_DIR = 'AppData';
const WINDOWS_ROAMING_DIR = 'Roaming';

@injectable()
export class EnvVariablesServerImpl implements EnvVariablesServer {

protected readonly envs: { [key: string]: EnvVariable } = {};
protected readonly configDirUri = FileUri.create(join(homedir(), '.theia')).toString();

constructor() {
const prEnv = process.env;
Expand All @@ -52,26 +49,8 @@ export class EnvVariablesServerImpl implements EnvVariablesServer {
return this.envs[key];
}

async getUserHomeFolder(): Promise<string> {
return FileUri.create(os.homedir()).toString();
}

async getDataFolderName(): Promise<string> {
return THEIA_DATA_FOLDER;
}

async getUserDataFolder(): Promise<string> {
return FileUri.create(await this.getUserHomeFolder()).resolve(await this.getDataFolderName()).toString();
}

async getAppDataFolder(): Promise<string> {
const dataFolderUriBuilder = FileUri.create(await this.getUserHomeFolder());
if (isWindows) {
dataFolderUriBuilder.resolve(WINDOWS_APP_DATA_DIR);
dataFolderUriBuilder.resolve(WINDOWS_ROAMING_DIR);
}
dataFolderUriBuilder.resolve(await this.getDataFolderName());
return dataFolderUriBuilder.toString();
async getConfigDirUri(): Promise<string> {
return this.configDirUri;
}

}
3 changes: 0 additions & 3 deletions packages/core/src/node/file-uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ export namespace FileUri {
return fsPathFromVsCodeUri + '\\';
}
}
if (fsPathFromVsCodeUri.startsWith('/file:')) {
return fsPathFromVsCodeUri.substring('/file:'.length);
}
return fsPathFromVsCodeUri;
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/debug/src/browser/debug-configuration-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export class DebugConfigurationManager {
if (configUri && configUri.path.base === 'launch.json') {
uri = configUri;
} else { // fallback
uri = new URI(model.workspaceFolderUri).resolve((await this.preferenceConfigurations.getPaths())[0] + '/launch.json');
uri = new URI(model.workspaceFolderUri).resolve(`${this.preferenceConfigurations.getPaths()[0]}/launch.json`);
}
const debugType = await this.selectDebugType();
const configurations = debugType ? await this.provideDebugConfigurations(debugType, model.workspaceFolderUri) : [];
Expand Down
4 changes: 3 additions & 1 deletion packages/java/src/node/java-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ export class JavaContribution extends BaseLanguageServerContribution {
this.activeDataFolders.add(dataFolderSuffix);
clientConnection.onClose(() => this.activeDataFolders.delete(dataFolderSuffix));

const workspacePath = path.resolve(FileUri.fsPath(await this.envServer.getUserDataFolder()), 'jdt.ls', '_ws_' + dataFolderSuffix);
const configDirUri = await this.envServer.getConfigDirUri();
const configDirFsPath = FileUri.fsPath(configDirUri);
const workspacePath = path.resolve(configDirFsPath, 'jdt.ls', '_ws_' + dataFolderSuffix);
const configuration = configurations.get(process.platform);
if (!configuration) {
throw new Error('Cannot find Java server configuration for ' + process.platform);
Expand Down
7 changes: 0 additions & 7 deletions packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ import { ArgumentProcessor } from '../plugin/command-registry';
import { MaybePromise } from '@theia/core/lib/common/types';
import { QuickOpenItem, QuickOpenItemOptions } from '@theia/core/lib/common/quick-open-model';
import { QuickTitleButton } from '@theia/core/lib/common/quick-open-model';
import { EnvVariable } from '@theia/core/lib/common/env-variables';

export interface PreferenceData {
[scope: number]: any;
Expand Down Expand Up @@ -993,13 +992,7 @@ export interface DocumentsMain {

export interface EnvMain {
$getEnvVariable(envVarName: string): Promise<string | undefined>;
$getAllEnvVariables(): Promise<EnvVariable[]>
$getClientOperatingSystem(): Promise<theia.OperatingSystem>;
$getExecPath(): Promise<string>
$getUserHomeFolderPath(): Promise<string>
$getDataFolderName(): Promise<string>
$getUserDataFolderPath(): Promise<string>
$getAppDataPath(): Promise<string>
}

export interface PreferenceRegistryMain {
Expand Down
28 changes: 16 additions & 12 deletions packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { RPCProtocol, RPCProtocolImpl } from '../../common/rpc-protocol';
import {
Disposable, DisposableCollection,
ILogger, ContributionProvider, CommandRegistry, WillExecuteCommandEvent,
CancellationTokenSource, JsonRpcProxy, ProgressService, Path
CancellationTokenSource, JsonRpcProxy, ProgressService
} from '@theia/core';
import { PreferenceServiceImpl, PreferenceProviderProvider } from '@theia/core/lib/browser/preferences';
import { WorkspaceService } from '@theia/workspace/lib/browser';
Expand All @@ -58,6 +58,7 @@ import { WebviewWidget } from '../../main/browser/webview/webview';
import { WidgetManager } from '@theia/core/lib/browser/widget-manager';
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import URI from '@theia/core/lib/common/uri';

export type PluginHost = 'frontend' | string;
export type DebugActivationEvent = 'onDebugResolve' | 'onDebugInitialConfigurations' | 'onDebugAdapterProtocolTracker';
Expand Down Expand Up @@ -348,9 +349,9 @@ export class HostedPluginSupport {
}
const thenable: Promise<void>[] = [];
const configStorage: ConfigStorage = {
hostLogPath: hostLogPath!,
hostStoragePath: hostStoragePath,
hostGlobalStoragePath: hostGlobalStoragePath!
hostLogPath,
hostStoragePath,
hostGlobalStoragePath
};
for (const [host, hostContributions] of contributionsByHost) {
const manager = await this.obtainManager(host, hostContributions, toDisconnect);
Expand Down Expand Up @@ -470,15 +471,18 @@ export class HostedPluginSupport {
}

protected async getHostGlobalStoragePath(): Promise<string> {
const userDataFolderPath: string = (await this.fileSystem.getFsPath(await this.envServer.getUserDataFolder()))!;
const globalStorageFolderPath = new Path(userDataFolderPath).join('globalStorage').toString();
const configDirUri = await this.envServer.getConfigDirUri();
const globalStorageFolderUri = new URI(configDirUri).resolve('globalStorage').toString();

// Make sure that folder by the path exists
if (! await this.fileSystem.exists(globalStorageFolderPath)) {
await this.fileSystem.createFolder(globalStorageFolderPath);
if (!await this.fileSystem.exists(globalStorageFolderUri)) {
await this.fileSystem.createFolder(globalStorageFolderUri);
}

return globalStorageFolderPath;
const globalStorageFolderFsPath = await this.fileSystem.getFsPath(globalStorageFolderUri);
if (!globalStorageFolderFsPath) {
throw new Error(`Could not resolve the FS path for URI: ${globalStorageFolderUri}`);
}
return globalStorageFolderFsPath;
}

async activateByEvent(activationEvent: string): Promise<void> {
Expand Down Expand Up @@ -624,8 +628,8 @@ export class HostedPluginSupport {
protected logMeasurement(prefix: string, count: number, measurement: () => number): void {
const duration = measurement();
if (duration === Number.NaN) {
// Measurement was prevented by native API, do not log NaN duration
return;
// Measurement was prevented by native API, do not log NaN duration
return;
}

const pluginCount = `${count} plugin${count === 1 ? '' : 's'}`;
Expand Down
27 changes: 1 addition & 26 deletions packages/plugin-ext/src/main/browser/env-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@
********************************************************************************/

import { interfaces } from 'inversify';
import { EnvVariablesServer, EnvVariable } from '@theia/core/lib/common/env-variables';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { RPCProtocol } from '../../common/rpc-protocol';
import { EnvMain } from '../../common/plugin-api-rpc';
import { QueryParameters } from '../../common/env';
import { isWindows, isOSX } from '@theia/core';
import { OperatingSystem } from '../../plugin/types-impl';

export class EnvMainImpl implements EnvMain {

private envVariableServer: EnvVariablesServer;

constructor(rpc: RPCProtocol, container: interfaces.Container) {
Expand All @@ -34,10 +33,6 @@ export class EnvMainImpl implements EnvMain {
return this.envVariableServer.getValue(envVarName).then(result => result ? result.value : undefined);
}

$getAllEnvVariables(): Promise<EnvVariable[]> {
return this.envVariableServer.getVariables();
}

async $getClientOperatingSystem(): Promise<OperatingSystem> {
if (isWindows) {
return OperatingSystem.Windows;
Expand All @@ -47,26 +42,6 @@ export class EnvMainImpl implements EnvMain {
}
return OperatingSystem.Linux;
}

$getExecPath(): Promise<string> {
return this.envVariableServer.getExecPath();
}

$getUserHomeFolderPath(): Promise<string> {
return this.envVariableServer.getUserHomeFolder();
}

$getDataFolderName(): Promise<string> {
return this.envVariableServer.getDataFolderName();
}

$getUserDataFolderPath(): Promise<string> {
return this.envVariableServer.getUserDataFolder();
}

$getAppDataPath(): Promise<string> {
return this.envVariableServer.getAppDataFolder();
}
}

/**
Expand Down
Loading

0 comments on commit 6c87fa8

Please sign in to comment.