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: start runner if configuration did not change after installation #1040

Merged
merged 1 commit into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/safe-ds-lang/src/language/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { pipVersionRange, RPC_RUNNER_INSTALL, RPC_RUNNER_STARTED } from './runner/safe-ds-runner.js';
import { pipVersionRange, RPC_RUNNER_INSTALL, RPC_RUNNER_START, RPC_RUNNER_STARTED } from './runner/safe-ds-runner.js';

// Services
export type { SafeDsServices } from './safe-ds-module.js';
Expand All @@ -23,6 +23,7 @@ export * as messages from './runner/messages.js';
// Remote procedure calls
export const rpc = {
runnerInstall: RPC_RUNNER_INSTALL,
runnerStart: RPC_RUNNER_START,
runnerStarted: RPC_RUNNER_STARTED,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { SafeDsMessagingProvider } from '../../communication/safe-ds-messaging-p
// Most of the functionality cannot be tested automatically as a functioning runner setup would always be required

export const RPC_RUNNER_INSTALL = 'runner/install';
export const RPC_RUNNER_START = 'runner/start';
export const RPC_RUNNER_STARTED = 'runner/started';

const LOWEST_SUPPORTED_RUNNER_VERSION = '0.10.0';
Expand Down Expand Up @@ -59,7 +60,7 @@ export class SafeDsRunner {
constructor(services: SafeDsServices) {
this.annotations = services.builtins.Annotations;
this.generator = services.generation.PythonGenerator;
this.messaging = services.lsp.MessagingProvider;
this.messaging = services.communication.MessagingProvider;

// Register listeners
this.registerMessageLoggingCallbacks();
Expand All @@ -68,6 +69,12 @@ export class SafeDsRunner {
await this.updateRunnerCommand(newValue);
});

this.messaging.onNotification(RPC_RUNNER_START, async () => {
if (!this.isPythonServerAvailable()) {
await this.startPythonServer();
}
});

services.shared.lsp.Connection?.onShutdown(async () => {
await this.stopPythonServer();
});
Expand Down
14 changes: 9 additions & 5 deletions packages/safe-ds-lang/src/language/safe-ds-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export type SafeDsAddedServices = {
Enums: SafeDsEnums;
ImpurityReasons: SafeDsImpurityReasons;
};
communication: {
MessagingProvider: SafeDsMessagingProvider;
};
documentation: {
DocumentationProvider: SafeDsDocumentationProvider;
};
Expand All @@ -81,7 +84,6 @@ export type SafeDsAddedServices = {
NodeMapper: SafeDsNodeMapper;
};
lsp: {
MessagingProvider: SafeDsMessagingProvider;
NodeInfoProvider: SafeDsNodeInfoProvider;
};
purity: {
Expand Down Expand Up @@ -132,6 +134,9 @@ export const SafeDsModule: Module<SafeDsServices, PartialLangiumServices & SafeD
Enums: (services) => new SafeDsEnums(services),
ImpurityReasons: (services) => new SafeDsImpurityReasons(services),
},
communication: {
MessagingProvider: (services) => new SafeDsMessagingProvider(services),
},
documentation: {
CommentProvider: (services) => new SafeDsCommentProvider(services),
DocumentationProvider: (services) => new SafeDsDocumentationProvider(services),
Expand All @@ -156,7 +161,6 @@ export const SafeDsModule: Module<SafeDsServices, PartialLangiumServices & SafeD
DocumentSymbolProvider: (services) => new SafeDsDocumentSymbolProvider(services),
Formatter: () => new SafeDsFormatter(),
InlayHintProvider: (services) => new SafeDsInlayHintProvider(services),
MessagingProvider: (services) => new SafeDsMessagingProvider(services),
NodeInfoProvider: (services) => new SafeDsNodeInfoProvider(services),
RenameProvider: (services) => new SafeDsRenameProvider(services),
SemanticTokenProvider: (services) => new SafeDsSemanticTokenProvider(services),
Expand Down Expand Up @@ -242,11 +246,11 @@ export const createSafeDsServices = async function (
// Apply options
if (options?.logger) {
/* c8 ignore next 2 */
SafeDs.lsp.MessagingProvider.setLogger(options.logger);
SafeDs.communication.MessagingProvider.setLogger(options.logger);
}
if (options?.messageBroker) {
/* c8 ignore next 2 */
SafeDs.lsp.MessagingProvider.setMessageBroker(options.messageBroker);
SafeDs.communication.MessagingProvider.setMessageBroker(options.messageBroker);
}
if (!options?.omitBuiltins) {
await shared.workspace.WorkspaceManager.initializeWorkspace([]);
Expand All @@ -257,7 +261,7 @@ export const createSafeDsServices = async function (
}
if (options?.userMessageProvider) {
/* c8 ignore next 2 */
SafeDs.lsp.MessagingProvider.setUserMessageProvider(options.userMessageProvider);
SafeDs.communication.MessagingProvider.setUserMessageProvider(options.userMessageProvider);
}

return { shared, SafeDs };
Expand Down
43 changes: 25 additions & 18 deletions packages/safe-ds-vscode/src/extension/commands/installRunner.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,44 @@
import vscode, { ExtensionContext, Uri } from 'vscode';
import child_process from 'node:child_process';
import semver from 'semver';
import { dependencies, SafeDsServices } from '@safe-ds/lang';
import { dependencies, rpc, SafeDsServices } from '@safe-ds/lang';
import { logError, printOutputMessage } from '../output.js';
import fs from 'node:fs';
import { LanguageClient } from 'vscode-languageclient/node.js';

const pythonCommandCandidates = ['python3', 'python', 'py'];

const LOWEST_SUPPORTED_PYTHON_VERSION = '3.11.0';
const LOWEST_UNSUPPORTED_PYTHON_VERSION = '3.13.0';
const npmVersionRange = `>=${LOWEST_SUPPORTED_PYTHON_VERSION} <${LOWEST_UNSUPPORTED_PYTHON_VERSION}`;

export const installRunner = (context: ExtensionContext, services: SafeDsServices) => async () => {
// If the runner is already started, do nothing
if (services.runtime.Runner.isPythonServerAvailable()) {
vscode.window.showInformationMessage('The runner is already installed and running.');
return;
}

// Install the runner if it is not already installed
if (!fs.existsSync(getRunnerCommand(context))) {
const success = await doInstallRunner(context);
if (!success) {
export const installRunner = (context: ExtensionContext, client: LanguageClient, services: SafeDsServices) => {
return async () => {
// If the runner is already started, do nothing
if (services.runtime.Runner.isPythonServerAvailable()) {
vscode.window.showInformationMessage('The runner is already installed and running.');
return;
}
}

// Set the runner command in the configuration
await vscode.workspace
.getConfiguration()
.update('safe-ds.runner.command', getRunnerCommand(context), vscode.ConfigurationTarget.Global);
// Install the runner if it is not already installed
if (!fs.existsSync(getRunnerCommand(context))) {
const success = await doInstallRunner(context);
if (!success) {
return;
}
}

// Set the runner command in the configuration
await vscode.workspace
.getConfiguration()
.update('safe-ds.runner.command', getRunnerCommand(context), vscode.ConfigurationTarget.Global);

// Start the runner (needed if the configuration did not change, so no event is fired)
await client.sendNotification(rpc.runnerStart);

vscode.window.showInformationMessage('The runner has been installed successfully.');
// Inform the user
vscode.window.showInformationMessage('The runner has been installed successfully.');
};
};

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/safe-ds-vscode/src/extension/mainClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const activate = async function (context: vscode.ExtensionContext) {

const registerNotificationListeners = function (context: vscode.ExtensionContext) {
client.onNotification(rpc.runnerInstall, async () => {
await installRunner(context, services)();
await installRunner(context, client, services)();
});
client.onNotification(rpc.runnerStarted, async (port: number) => {
await services.runtime.Runner.connectToPort(port);
Expand Down Expand Up @@ -112,7 +112,7 @@ const registerVSCodeCommands = function (context: vscode.ExtensionContext) {

context.subscriptions.push(vscode.commands.registerCommand('safe-ds.dumpDiagnostics', dumpDiagnostics(context)));
context.subscriptions.push(
vscode.commands.registerCommand('safe-ds.installRunner', installRunner(context, services)),
vscode.commands.registerCommand('safe-ds.installRunner', installRunner(context, client, services)),
);
context.subscriptions.push(
vscode.commands.registerCommand('safe-ds.openDiagnosticsDumps', openDiagnosticsDumps(context)),
Expand Down