fix(tools): keep searching past broken Python aliases

Цей коміт міститься в:
l0ng-ai committed 2026-11-05 10:59:36 +08:00
1 джерело ad1fdf9e0e
коміт d3950f8a66
2 files changed
+36 -13

No files matched your search

+18 -7
Переглянути файл
@@ -504,13 +504,24 @@ impl Tools {
if self.platform.os != Os::Windows {
return self.which_any(&["python3", "python"]);
}
["python", "py", "python3"].into_iter().filter_map(|c| self.which(c)).find(|p| {
!is_app_execution_alias(p) || {
let mut c = self.python_command(p);
c.arg("--version");
run_quiet(c, Duration::from_secs(5)).is_some_and(|(ok, _)| ok)
}
})
["python", "py", "python3"]
.into_iter()
.flat_map(|command| {
std::env::split_paths(&self.system_path).filter_map(move |dir| {
if dir.as_os_str().is_empty() {
return None;
}
let search = std::env::join_paths([dir]).ok()?;
ide_core::tool_path::find_command(command, &search, &self.root)
})
})
.find(|p| {
!is_app_execution_alias(p) || {
let mut c = self.python_command(p);
c.arg("--version");
run_quiet(c, Duration::from_secs(5)).is_some_and(|(ok, _)| ok)
}
})
}
/// Executable `cmd` inside `dir`, honouring Windows suffixes.
+18 -6
Переглянути файл
@@ -37,6 +37,12 @@ impl Env {
fs::write(&p, format!("#!/bin/sh\n{body}\n")).unwrap();
archive::make_executable(&p).unwrap();
}
#[cfg(windows)]
fn script(&self, dir: &Path, name: &str, body: &str) {
fs::create_dir_all(dir).unwrap();
fs::write(dir.join(format!("{name}.cmd")), format!("@echo off\r\n{body}\r\n")).unwrap();
}
}
fn find<'a>(list: &'a [ToolInfo], name: &str) -> &'a ToolInfo {
@@ -702,7 +708,6 @@ fn rust_analyzer_managed_copy_survives_rustup_becoming_available() {
/// Windows has `python.exe` and `py`, not `python3.exe`; the `WindowsApps` aliases only count
/// when the Store's Python behind them runs.
#[cfg(unix)]
#[test]
fn windows_python_skips_store_aliases_that_do_not_run() {
let env = Env::new();
@@ -713,13 +718,20 @@ fn windows_python_skips_store_aliases_that_do_not_run() {
let windows = Platform { os: Os::Windows, arch: platform::Arch::X64 };
let found = || {
let dirs = std::env::join_paths([aliases.clone(), env.sys.clone()]).unwrap();
let python = Tools::with_paths(env.root.clone(), dirs, windows).python().unwrap();
let dir = python.parent().unwrap().file_name().unwrap().to_string_lossy().into_owned();
format!("{dir}/{}", python.file_name().unwrap().to_string_lossy())
Tools::with_paths(env.root.clone(), dirs, windows).python().map(|python| {
let dir = python.parent().unwrap().file_name().unwrap().to_string_lossy().into_owned();
format!("{dir}/{}", python.file_stem().unwrap().to_string_lossy())
})
};
assert_eq!(found(), "sysbin/py");
assert_eq!(found().as_deref(), Some("sysbin/py"));
fs::remove_file(env.sys.join(if cfg!(windows) { "py.cmd" } else { "py" })).unwrap();
assert_eq!(found(), None, "only broken aliases are available");
env.script(&env.sys, "python3", "echo Python 3.12.0");
assert_eq!(found().as_deref(), Some("sysbin/python3"), "python3 is the final fallback");
env.script(&env.sys, "python", "echo Python 3.12.0");
assert_eq!(found().as_deref(), Some("sysbin/python"), "a broken alias must not hide a later interpreter");
env.script(&aliases, "python", "echo Python 3.13.0");
assert_eq!(found(), "WindowsApps/python", "the Store's Python runs");
assert_eq!(found().as_deref(), Some("WindowsApps/python"), "the Store's Python runs");
}
#[cfg(unix)]