Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retrieving launch configurations using Plugin API #4743

Closed

Conversation

akurinnoy
Copy link
Contributor

@akurinnoy akurinnoy commented Mar 28, 2019

This PR aims to fix #4188. In order to fix the issue following improvements are introduced:

  • [plugin-ext] getting and inspecting configuration for a resource
  • [preferences] handling preference properties that are not valid at the time of reading and re-validating them later on new preference schema has been set.
  • [preferences] handling launch.json to retrieve launch configurations
  • [debug] handling changes of launch configuration in order to build new preference schema

This PR also fixes #2290

@akurinnoy akurinnoy changed the title Allow retrieving launch configurations using Plugin API Retrieving launch configurations using Plugin API Mar 28, 2019
@akosyakov
Copy link
Member

@akurinnoy tests are red

@akurinnoy
Copy link
Contributor Author

@akosyakov tests are green, please have a look

@akosyakov
Copy link
Member

@akurinnoy i will test tomorrow morning

@@ -53,6 +54,7 @@ export class PreferenceSchemaProvider extends PreferenceProvider {

protected readonly preferences: { [name: string]: any } = {};
protected readonly combinedSchema: PreferenceDataSchema = { properties: {}, patternProperties: {} };
private remoteSchemas: IJSONSchema[] = [];
Copy link
Member

@akosyakov akosyakov Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is special about remoteSchema? Why cannot be incorporated in combinedSchema and should be validated separately?

After reading code it does not seem to affect combined schemas, but just passed here to reuse validate function for launch folder providers?

PreferenceSchemaProvider is responsible for providing a schema for settings files, validating it and used for getting default values of settings. It does not have anything to do with launch preferences. I think we should have a separate Ajv validator for launch file not aware of settings schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading code it does not seem to affect combined schemas, but just passed here to reuse validate function for launch folder providers?

You're right, but not only for launch folder provider but for any preference provider. Each time a launch configuration is added, renamed or removed we need new schema which restricts possible names of configuration available for compound sub-section.

PreferenceSchemaProvider is responsible for providing a schema for settings files, validating it and used for getting default values of settings. It does not have anything to do with launch preferences.

User might have a global or workspace wide launch configuration placed in corresponding settings file, and a project might contain no launch file at all. That is why I treated launch configuration as any other property.

Copy link
Member

@akosyakov akosyakov Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User might have a global or workspace wide launch configuration placed in corresponding settings file

Wow, did not know it, ok, will test how it works. So i should get content assist in settings.json for launch property and registered debug configurations similar to VS Code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no content assist support for launch property and launch configurations in 'settings.json` as in VS Code. Looking at the code this property should be provided by https://github.com/akurinnoy/theia/blob/397f360422dae3dc590e58665fd526d04d7810c7/packages/debug/src/browser/debug-schema-updater.ts#L77-L88 not by remote schemas.

I'm still confused why we need remoteSchemas here? How do they affect settings schema and values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking of content assist I meant this:

launch-content-assist

I'm still confused why we need remoteSchemas here? How do they affect settings schema and values?

That's the point. Remote schema doesn't affect setting a values. It affects only validation. Remote schema only makes things easier allowing to replace a part of preference schema without calling doSetSchema(), thus allows to easily update validation function.

The main part of launch preference schema is set only once. Since then only remote part of schema become updated.
https://github.com/theia-ide/theia/pull/4743/files#diff-2dd1a479f035ae6ce8c1517929d4568dR70

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try again tomorrow. Tried the same today and did not get any content assist. The problematic part with it that these settings not respected by DebugConfigurationWidget and we don't have an implementation for compounds anywhere. We either have to implement it or keep content assist out of scope of this PR.

}
}

// debug general schema
const defaultCompound = { name: 'Compound', configurations: [] };
export const defaultCompound = { name: 'Compound', configurations: [] };
Copy link
Member

@akosyakov akosyakov Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean that we support compound configurations now? Does a user can get a false impression via UI that we do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't mean that. It's only about providing preference schema and validating a launch configuration.

Which UI do you mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

content assist in launch.json should not provide what is not implemented

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a property is not valid then user can't retrieve it using plugin API.

Could we instead provide a diagnostics for content assist for compounds property key to warn user that compound configurations are not supported?

Copy link
Member

@akosyakov akosyakov Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it should be stubbed somehow in the plugin ext for now without leaking anything to UI and adding half-baked code to other extensions.

Copy link
Contributor Author

@akurinnoy akurinnoy Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could It be done in the following way?

At this point
https://github.com/theia-ide/theia/blob/397f360422dae3dc590e58665fd526d04d7810c7/packages/debug/src/browser/debug-schema-updater.ts#L113
clone the schema. Then one of schemas could go to provide content assist. And the second one could be populated with configuration names and used for validation purpose.

This allows to validate preferences and will not affect UI.

this.toDispose.push(this.onDidLaunchChangedEmitter);
this.toDispose.push(
this.preferenceProvider.onDidNotValidPreferencesRead(prefs => {
if (!prefs || !GlobalLaunchConfig.is(prefs.launch)) {
Copy link
Member

@akosyakov akosyakov Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it go here and cannot happen in launch preference provider? then we don't need a new event onDidNotValidPreferencesRead and can do GlobalLaunchConfig.is check in one place.

Also wondering after reading code, looks like if you don't use the validation function aware of setting schema for launch folder preferences maybe you won't get some false possible validation results and getting rid of an event would be easier.

Copy link
Contributor Author

@akurinnoy akurinnoy Mar 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it go here and cannot happen in launch preference provider? then we don't need a new event onDidNotValidPreferencesRead and can do GlobalLaunchConfig.is check in one place.

Event onDidNotValidPreferencesRead triggers creating new preference schema for launch property, so I don't see how we can't get rid of it.

looks like if you don't use the validation function aware of setting schema for launch folder preferences maybe you won't get some false possible validation results and getting rid of an event would be easier.

I'm not sure I understood what you meant... Could you elaborate on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to create preferences from invalid data? If it is valid then it should be part of onDidPreferencesChanged. Could you elaborate on an example when preferences are not valid but we still want to use them?

Copy link
Contributor Author

@akurinnoy akurinnoy Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because how launch preference schema is defined.

https://github.com/theia-ide/theia/blob/397f360422dae3dc590e58665fd526d04d7810c7/packages/debug/src/browser/debug-schema-updater.ts#L186-L189

In order to build this schema I need to get all configuration names to fill the enum. On the other hand, to get them launch configurations need to be validated against launch preference schema which is not built yet.

Imagine, you have launch configuration

	"launch": {
		"confugurations": [
			{ "name": "Launch Backend", ...},
			{ "name": "Launch Frontend", ...}
		],
		"compounds": [
			{
				"name": "Compound",
				"configurations": [
					"Launch Backend", // valid
					"Launch Frontend", // valid
					"Run Tests" // not valid
				]
			}
		]
       }

And you need to restrict possible values of configurations in compounds section to only available configuration names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean if someone add Run Tests to compounds.configurations then the whole launch preference marked as invalid and not available to a user?
Do you also mean that we reparse launch json twice, once to create a schema and second time to validate data?

How about having custom validation for launch preferences to exclude only bogus compound configuration, break a cycle between schema and data, avoid parsing data twice and introducing a new event? I don't think you need to check each property in this case of each configuration just top-level structure, like here https://github.com/akurinnoy/theia/blob/397f360422dae3dc590e58665fd526d04d7810c7/packages/debug/src/browser/debug-configuration-model.ts#L74

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether launch launch configs in user settings makes sense at all? Should not we just stub it with default values? Docs does not say anything about user settings:

Note: Workspace and Workspace Folder configurations contains launch and tasks settings.

Copy link
Contributor Author

@akurinnoy akurinnoy Apr 16, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you seen default settings and explanation near launch property?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think launch config in user settings shouldn't be stabbed, and Theia should use a global launch config if a project doesn't have its own.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean that it's stubbed with such value and data from user settings json are ignored? Do I read it correctly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wrong. My user settings already had launch section that's why i got such results. If i try to changes it changes are reflected into expectations, so we should read launch section user settings as well.

I will update tests with expectations that user settings does not contain launch section.

@akosyakov
Copy link
Member

I don't see that DebugConfigurationWidget is getting launch from preferences now, but continues using own logic.

async getUri(): Promise<URI | undefined> {
this.folderUri = new URI(this.options.folder.uri);
if (await this.fileSystem.exists(this.folderUri.toString())) {
const uri = this.folderUri.resolve('.theia').resolve('launch.json');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should respect launch.json from vscode as well. See logic in DebugConfigurationWidget, if we move it here it should be properly reimplemented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be separate issue and another pull request because there are some things to discuss. For example, if a project has one launch configurations for Theia and one for VScode which names are same but they differ in other fields. Which one should be returned if a user gets configuration by name? How a user should update or delete a concrete launch configuration?

@akosyakov do you mind if I open an issue?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should work as on master. If a folder has .theia then theia settings is used, if not then VS Code settings.

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
This allows to re-validate such properties when a corresponding
schema has been set.

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
…schema

`UserLaunchProvider`, `WorkspaceLaunchProvider` and `FoldersLaunchProvider`
handle changing of 'launch' section of preferences without paying
attention whether configuration is valid or not. Once it happens a new
preference schema for launch configurations builds.

Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
Signed-off-by: Oleksii Kurinnyi <okurinny@redhat.com>
@akosyakov
Copy link
Member

With which VS Code extension it's possible to reproduce issues like access compound configurations and so on?

@@ -3,6 +3,7 @@
## v0.6.0

- [filesystem] added the menu item `Upload Files...` to easily upload files into a workspace
- [preferences] changed signature for methods `getProvider`, `setProvider` and `createFolderPreferenceProvider` of `FoldersPreferenceProvider`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

breaking changes should go in its own section, see below for 0.5.0

It would be nice also cover what for they were changed, see examples in breaknig changes for other releases

this.toDispose.push(this.onDidLaunchChangedEmitter);
this.toDispose.push(
this.preferenceProvider.onDidNotValidPreferencesRead(prefs => {
if (!prefs || !GlobalLaunchConfig.is(prefs.launch)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to create preferences from invalid data? If it is valid then it should be part of onDidPreferencesChanged. Could you elaborate on an example when preferences are not valid but we still want to use them?

}
}

// debug general schema
const defaultCompound = { name: 'Compound', configurations: [] };
export const defaultCompound = { name: 'Compound', configurations: [] };
Copy link
Member

@akosyakov akosyakov Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it should be stubbed somehow in the plugin ext for now without leaking anything to UI and adding half-baked code to other extensions.

@@ -21,87 +21,113 @@ import { FolderPreferenceProvider, FolderPreferenceProviderFactory } from './fol
import { FileSystem, FileStat } from '@theia/filesystem/lib/common';
import URI from '@theia/core/lib/common/uri';

export const LAUNCH_PROPERTY_NAME = 'launch';
export type ResourceKind = 'settings' | 'launch';
Copy link
Member

@akosyakov akosyakov Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use unique naming, see naming conventions

i.e. FolderPreferenceKind

Resource already has a meaning in Theia, i.e git and file are kind of resources

@@ -53,6 +54,7 @@ export class PreferenceSchemaProvider extends PreferenceProvider {

protected readonly preferences: { [name: string]: any } = {};
protected readonly combinedSchema: PreferenceDataSchema = { properties: {}, patternProperties: {} };
private remoteSchemas: IJSONSchema[] = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no content assist support for launch property and launch configurations in 'settings.json` as in VS Code. Looking at the code this property should be provided by https://github.com/akurinnoy/theia/blob/397f360422dae3dc590e58665fd526d04d7810c7/packages/debug/src/browser/debug-schema-updater.ts#L77-L88 not by remote schemas.

I'm still confused why we need remoteSchemas here? How do they affect settings schema and values?

@l0rd l0rd mentioned this pull request Apr 2, 2019
@@ -215,7 +221,11 @@ export class PreferenceRegistryExtImpl implements PreferenceRegistryExt {
const defaultConfiguration = this.getConfigurationModel(data[PreferenceScope.Default]);
const userConfiguration = this.getConfigurationModel(data[PreferenceScope.User]);
const workspaceConfiguration = this.getConfigurationModel(data[PreferenceScope.Workspace]);
return new Configuration(defaultConfiguration, userConfiguration, workspaceConfiguration);
const folderConfigurations = {} as { [resource: string]: ConfigurationModel };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to have a named type if this construction is used in several files.

@@ -113,20 +139,34 @@ export class FoldersPreferencesProvider extends PreferenceProvider {
return provider;
}

protected createFolderPreferenceProvider(folder: FileStat): FolderPreferenceProvider {
const provider = this.folderPreferenceProviderFactory({ folder });
protected setProvider(provider: FolderPreferenceProvider, kind: ResourceKind): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me addProvider suits better here

@tsmaeder tsmaeder dismissed their stale review April 2, 2019 14:17

Got my explanation

@tsmaeder
Copy link
Contributor

tsmaeder commented Apr 9, 2019

This PR is also required for finishing eclipse-che/che#12446: we cannot enable logging and debugging in jdt.ls right now.

@akosyakov
Copy link
Member

akosyakov commented Apr 11, 2019

@tsmaeder I understand and also want to see it merged, but the current state does not look good to me. If you don't mind we can collaborate on this PR, i.e. i will push commits to finish it up.

@tsmaeder
Copy link
Contributor

If you don't mind we can collaborate on this PR, i.e. i will push commits to finish it up.

@akosyakov as I am not the author of the PR, I don't really have a say in that ;-). I cross-linked the other issue to make the link for planning purposes.
👍 for working towards making the PR better. That's what reviews are for.

@akosyakov
Copy link
Member

@akurinnoy let me know if it would be fine with you to work together on this PR

@akurinnoy
Copy link
Contributor Author

@akosyakov I'm OK to work on this PR together. How do we split the work?

@akosyakov
Copy link
Member

akosyakov commented Apr 15, 2019

I could work on integration with Theia UI, you with VS Code extensions.

I can look into hooking DebugConfigurationWidget first and preferring vscode launch config over theia if latter is missing, maybe in support compound configurations if it's easy. You can make sure that launch configuration are read and stored in the way how VS Code expects it.

I can open a PR against this PR for my changes.

if (resourceUri && this.providers.length > 0) {
const provider = this.getProvider(resourceUri);
if (resourceUri) {
const resourceKind = preferenceName === LAUNCH_PROPERTY_NAME ? 'launch' : 'settings';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why do we check both? settings can provide as well, can't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK VS Code doesn't provide launch from folder's settings in multi-root scope

const launchProvider = this.getProvider(resourceUri, 'launch');
const launch = launchProvider ? launchProvider.getPreferences() : {};

const result = Object.assign({}, prefs, launch);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not the last arg be { launch } and only if launch is defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@injectable()
export class FoldersPreferencesProvider extends PreferenceProvider {

@inject(WorkspaceService) protected readonly workspaceService: WorkspaceService;
@inject(FileSystem) protected readonly fileSystem: FileSystem;
@inject(FolderPreferenceProviderFactory) protected readonly folderPreferenceProviderFactory: FolderPreferenceProviderFactory;

private providers: FolderPreferenceProvider[] = [];
private providersByKind: Map<ResourceKind, FolderPreferenceProvider[]> = new Map();
private resourceKinds: ResourceKind[] = ['launch', 'settings'];

@postConstruct()
protected async init(): Promise<void> {
await this.workspaceService.roots;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've started rewriting this code. It's unnecessary complicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've started reworking code as we decided earlier, so it will be much simpler.

@benoitf
Copy link
Contributor

benoitf commented Apr 18, 2019

hello, any news on when we're able to merge this PR ?
21 days seems to be too long.

@akosyakov
Copy link
Member

It cannot be merged. It does not pass any VS Code compatibility test and breaks Theia UI. I've strarted reworking it here: https://github.com/theia-ide/theia/tree/ak/laung_preferences will open a PR then it is finished

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants