Skip to content
46 changes: 38 additions & 8 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 @@ -78,12 +80,33 @@ function executeFile(file: string, args: string[] = []): Promise<string> {
* Get the version of the Ruff executable at the given path.
*/
async function getRuffVersion(executable: string): Promise<VersionInfo> {
const stdout = await executeFile(executable, ["--version"]);
const stdout = await executeFile(executable, ["version"]);
const version = stdout.trim().split(" ")[1];
const [major, minor, patch] = version.split(".").map((x) => parseInt(x, 10));
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)) {
const message = `Skip unsupported executable from ${strategy}: ${executable} (Reqiuired at least ${versionToString(
MINIMUM_SUPPORTED_EXECUTABLE_VERSION,
)}, but found ${versionToString(ruffVersion)} instead)`;
logger.error(message);
return false;
}
logger.info(`Using ${strategy}: ${executable}`);
return true;
} catch (ex) {
logger.info(`Skip invalid executable from ${strategy}: ${executable}`);
return false;
}
}

/**
* Finds the Ruff binary path and returns it.
*
Expand All @@ -108,8 +131,10 @@ async function findRuffBinaryPath(settings: ISettings): Promise<string> {
// 'path' setting takes priority over everything.
if (settings.path.length > 0) {
for (const path of settings.path) {
if (await fsapi.pathExists(path)) {
logger.info(`Using 'path' setting: ${path}`);
if (
(await fsapi.pathExists(path)) &&
(await validateUsingExecutable(path, "'path' setting"))
) {
return path;
}
}
Expand Down Expand Up @@ -140,16 +165,21 @@ async function findRuffBinaryPath(settings: ISettings): Promise<string> {
logger.error(`Error while trying to find the Ruff binary: ${err}`);
}

if (ruffBinaryPath && ruffBinaryPath.length > 0) {
// First choice: the executable found by the script.
logger.info(`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) {
logger.info(`Using environment executable: ${environmentPath}`);
if (
environmentPath &&
(await validateUsingExecutable(environmentPath, "environment executable"))
) {
return environmentPath;
}

Expand Down
14 changes: 14 additions & 0 deletions src/common/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ function versionGte(a: VersionInfo, b: VersionInfo): boolean {
/**
* 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 };

/**
* 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.
* TODO: remove this when dropped `ruff-lsp` and bumped `MINIMUM_SUPPORTED_EXECUTABLE_VERSION` to 0.3.5
*/
export const MINIMUM_NATIVE_SERVER_VERSION: VersionInfo = { major: 0, minor: 3, patch: 5 };

/**
Expand All @@ -48,6 +61,7 @@ export function supportsNativeServer(version: VersionInfo): boolean {

/**
* The version of the Ruff executable that made the native server stable.
* TODO: remove this when bumped `MINIMUM_SUPPORTED_EXECUTABLE_VERSION` to 0.5.3
*/
export const NATIVE_SERVER_STABLE_VERSION: VersionInfo = { major: 0, minor: 5, patch: 3 };

Expand Down