Skip to content
35 changes: 28 additions & 7 deletions src/common/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
supportsNativeServer,
versionToString,
VersionInfo,
MINIMUM_SUPPORTED_EXECUTABLE_VERSION,
supportsExecutable,
MINIMUM_NATIVE_SERVER_VERSION,
supportsStableNativeServer,
NATIVE_SERVER_STABLE_VERSION,
Expand Down Expand Up @@ -83,6 +85,28 @@ async function getRuffVersion(executable: string): Promise<VersionInfo> {
return { major, minor, patch };
}

/**
* Validate and log executable from given path.
*/
async function validateUsingExecutable(executable: string, strategy: string) {
try {
const ruffVersion = await getRuffVersion(executable);
if (!supportsExecutable(ruffVersion)) {
var message = `Skip unsupported executable from ${strategy}: ${executable}`;
message += `(Reqiuired at least ${versionToString(
MINIMUM_SUPPORTED_EXECUTABLE_VERSION,
)}, but found ${versionToString(ruffVersion)} instead)`;
Comment thread
T-256 marked this conversation as resolved.
Outdated
traceError(message);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should also display this message to the users using vscode.window.showErrorMessage. What do you think?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

during findRuffBinaryPath it may skip several binaries, I think it'd be annoying to send all of them as user facing warnings.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This message shouldn't be required because we already check that later on. Refer to my other comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

🤷‍♂️

return false;
}
traceInfo(`Using ${strategy}: ${executable}`);
return true;
} catch (ex) {
traceInfo(`Skip invalid executable from ${strategy}: ${executable}`);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we include the exception message as well? Are we able to capture the one in #426 ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, makes sense. Since ex maybe multi line error, what is correct format to put it in there? I don't think put it in parantheses be a good style.

traceInfo(`Skip invalid executable from ${strategy}: ${executable}:\n${ex}`);

is this correct to you?

Copy link
Copy Markdown
Member

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 fine but I'd need to play around with it to check how it renders in the output window. I can do that when I'm testing before merging the PR.

return false;
}
}

/**
* Finds the Ruff binary path and returns it.
*
Expand Down Expand Up @@ -110,8 +134,7 @@ async function findRuffBinaryPath(
// 'path' setting takes priority over everything.
if (settings.path.length > 0) {
for (const path of settings.path) {
if (await fsapi.pathExists(path)) {
traceInfo(`Using 'path' setting: ${path}`);
if (await fsapi.pathExists(path) && await validateUsingExecutable(path, "'path' setting")) {
return path;
}
}
Expand Down Expand Up @@ -142,16 +165,14 @@ async function findRuffBinaryPath(
traceError(`Error while trying to find the Ruff binary: ${err}`);
}

if (ruffBinaryPath && ruffBinaryPath.length > 0) {
// First choice: the executable found by the script.
traceInfo(`Using the Ruff binary: ${ruffBinaryPath}`);
// First choice: the executable found by the script.
if (ruffBinaryPath && ruffBinaryPath.length > 0 && await validateUsingExecutable(ruffBinaryPath, "the Ruff binary")) {
return ruffBinaryPath;
}

// Second choice: the executable in the global environment.
const environmentPath = await which(RUFF_BINARY_NAME, { nothrow: true });
if (environmentPath) {
traceInfo(`Using environment executable: ${environmentPath}`);
if (environmentPath && await validateUsingExecutable(environmentPath, "environment executable")) {
return environmentPath;
}

Expand Down
12 changes: 12 additions & 0 deletions src/common/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ function versionGte(a: VersionInfo, b: VersionInfo): boolean {
return false;
}

/**
* The minimum version of the Ruff executable that supports the native server.
*/
export const MINIMUM_SUPPORTED_EXECUTABLE_VERSION: VersionInfo = { major: 0, minor: 1, patch: 0 };
Comment thread
T-256 marked this conversation as resolved.

/**
* Check if the given version of the Ruff executable supports the native server.
*/
export function supportsExecutable(version: VersionInfo): boolean {
return versionGte(version, MINIMUM_SUPPORTED_EXECUTABLE_VERSION);
}

/**
* The minimum version of the Ruff executable that supports the native server.
*/
Expand Down