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

Fix electron extension host #96

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

sgraband
Copy link

@sgraband sgraband commented Jun 13, 2024

What it does

Before yarn electron start was invoked.
This does not work, as the cli tools will not be available when bundled.
Adjust the getStartCommand in AbstractHostedInstanceManager to work for both the browser and electron case.
Additionally, add --electronUserData to the electron case.
This will avoid odd behavior between the two instances running.
Use a timestamp folder in the tmp folder of the os in order to keep things clean on the machine and between different debugging sessions.

Fixes https://github.com/eclipse-theia/theia-blueprint/issues/ 281 (will remove the whitespace in the real PR)

How to test

  1. Create a packaged electron version either via electron-builder or by linking the packages into the theia-ide
  2. Create a workspace with a vscode extension with the yeoman generator
  3. Open the workspace with the theia application
  4. You will need to slightly adapt the launch.json, due to other bugs. Comment out the preLaunchTask line
  5. Run the Run extension debug config.
  6. Notice, that a extension host comes up that has the extension installed.
  7. You can also test closing the host and restarting the debug config as well as that a new folder in your tmp folder is created everytime you start a new extension host.

Follow-ups

I will check if there are already tickets and will open tickets for any issues that i have found, that do not have one yet.
One example is that apparently ${defaultBuildTask}' is not supported in launch.json

Review checklist

Reminder for reviewers

Before `yarn electron start` was invoked.
This does not work, as the cli tools will not be available when bundled.
Adjust the `getStartCommand` in `AbstractHostedInstanceManager` to work
for both the browser and electron case.
Additionally, add `--electronUserData` to the electron case.
This will avoid odd behavior between the two instances running.
Use a timestamp folder in the tmp folder of the os in order to keep things
clean on the machine and between different debugging sessions.
@sgraband
Copy link
Author

@tsmaeder can you take a look and let me know what you think or if you have any objections/suggestions?

Note this only fixes the problem that the start command was wrong. Other issues with the debugging are not handled here.

@tsmaeder
Copy link
Collaborator

@sgraband sure. Might be next week, though...moving house on monday.

@sgraband
Copy link
Author

@tsmaeder Could you take a look, this or next week?

@tsmaeder
Copy link
Collaborator

Sorry, got sidetracked with PRs for the release today. Feel free to nag me again tomorrow and every day if I don't get my fingers out of my butt.

@sgraband
Copy link
Author

sgraband commented Jul 1, 2024

@tsmaeder No worries. If you would have time this week it would be great, as i would have time to respond to feedback/suggestions.

@@ -240,23 +241,22 @@ export abstract class AbstractHostedInstanceManager implements HostedInstanceMan
}

protected async getStartCommand(port?: number, debugConfig?: PluginDebugConfiguration): Promise<string[]> {

if (!port) {
port = process.env.HOSTED_PLUGIN_PORT ?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I tried running the plugin a second time, but that failed. My suspicion is that we're trying to run a second instance with the same port. We need some algorithm to assign unique, free ports per instance.

Copy link
Author

Choose a reason for hiding this comment

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

Is it actually intended, that we will ever get a second instance? I just tested it in VSCode and there i will only get one extension host. If i start the same config again, while the old one is still running it will just kill the first debug session.

Of course the handling here could be improved, but i am not sure if we need to handle mutliple ports? WDYT?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, but something just not working without any indication why is simply a bug. If VS Code jumped out the Window, would you follow? ;-) There might be good reasons why we can't implement this, but then we need to catch it and inform the user. Is there a good reason we can't allocate a new random port?

Copy link
Author

Choose a reason for hiding this comment

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

I do not have any objections to support mutliple Hosted Plugin instances, but the current implementation seems like it was build under the assumption that only one will be possible (e.g. the cli parameter to specify one port, or the UI in the parent instance). As this would require additional changes, outside the scope of this PR, i would suggest to handle this in a follow up ticket. Does that sound good to you?

}

@injectable()
export class ElectronNodeHostedPluginRunner extends AbstractHostedInstanceManager {
protected override async getStartCommand(port?: number, debugConfig?: PluginDebugConfiguration): Promise<string[]> {
const command = await super.getStartCommand(port, debugConfig);
command.push(`--electronUserData="${this.getTempDir()}/theia-extension-host/${this.getTimestamp()}"`);
Copy link
Collaborator

Choose a reason for hiding this comment

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

IMO, we should track this directory and remove it once the hosted instance exits.

Copy link
Author

Choose a reason for hiding this comment

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

You mean, once the hosted instance is removed/terminated?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes.


protected getTempDir(): string {
const tempDir = os.tmpdir();
return process.platform === 'darwin' ? fs.realpathSync(tempDir) : tempDir;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could use a comment. Why the special case?

}

protected getTimestamp(): string {
return `${Math.round(new Date().getTime() / 1000)}`;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not just move this into getTempDir()? Also: doesn't this limit the rate of temp dir creation to one per second? I would be more comfortable with a random directory + checking for existence.

// remove --port=X and --port X arguments if set
// remove --plugins arguments
if (arg.startsWith('--port') || args[index - 1] === '--port') {
return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know you didn't invent this code, but it would be much clearer if we just returned true/false instead of arg and undefined. "truthiness" is bogus enough without us adding to the confusion. Also, it might be wrong: the empty string is falsy, so if we actually have an empty argument, it borks! 🤦

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

Successfully merging this pull request may close these issues.

2 participants