diff --git a/src/common/server.ts b/src/common/server.ts index abc53898..f7a457b1 100644 --- a/src/common/server.ts +++ b/src/common/server.ts @@ -31,6 +31,8 @@ import { supportsNativeServer, versionToString, VersionInfo, + MINIMUM_SUPPORTED_EXECUTABLE_VERSION, + supportsExecutable, MINIMUM_NATIVE_SERVER_VERSION, supportsStableNativeServer, NATIVE_SERVER_STABLE_VERSION, @@ -78,12 +80,33 @@ function executeFile(file: string, args: string[] = []): Promise { * Get the version of the Ruff executable at the given path. */ async function getRuffVersion(executable: string): Promise { - 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. * @@ -108,8 +131,10 @@ async function findRuffBinaryPath(settings: ISettings): Promise { // '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; } } @@ -140,16 +165,21 @@ async function findRuffBinaryPath(settings: ISettings): Promise { 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; } diff --git a/src/common/version.ts b/src/common/version.ts index 30070abc..5d962e42 100644 --- a/src/common/version.ts +++ b/src/common/version.ts @@ -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 }; /** @@ -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 };