mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 16:08:05 +00:00
fix(sdk): keep the drive letter of a JDK home on a mapped drive
A JDK on a mapped network drive was canonicalized to \\?\UNC\server\share\… too, so Maven ran with that JAVA_HOME and mvn.cmd failed with "The system cannot find the path specified" even with a local Maven home. JDK homes (configured, JAVA_HOME, the java on PATH) now keep their drive letter like Maven homes do.
This commit is contained in:
@@ -545,7 +545,7 @@ fn jdk() -> Vec<Sdk> {
|
||||
|
||||
/// A JDK as the SDK pickers list it (`Eclipse Adoptium 25.0.1`).
|
||||
pub fn jdk_sdk(j: &crate::java::Jdk) -> Sdk {
|
||||
let java_home = std::env::var_os("JAVA_HOME").and_then(|h| dunce::canonicalize(h).ok());
|
||||
let java_home = std::env::var_os("JAVA_HOME").and_then(|h| crate::launch_path(Path::new(&h)).ok());
|
||||
let release = std::fs::read_to_string(j.home.join("release")).unwrap_or_default();
|
||||
let version = release_value(&release, "JAVA_VERSION").unwrap_or_else(|| j.major.to_string());
|
||||
let name = match release_value(&release, "IMPLEMENTOR") {
|
||||
@@ -579,31 +579,6 @@ fn maven_version(home: &Path) -> Option<String> {
|
||||
})
|
||||
}
|
||||
|
||||
/// `path` with symlinks resolved (Homebrew's `bin/mvn` → its Cellar), except that a Windows
|
||||
/// drive letter is kept: on a mapped network drive or a `subst` drive canonicalizing gives
|
||||
/// `\\?\UNC\server\share\…` or another drive, and cmd.exe can't start `mvn.cmd` from a
|
||||
/// `\\?\` path (nor is it the path the user knows).
|
||||
fn launch_path(path: &Path) -> std::io::Result<PathBuf> {
|
||||
let real = dunce::canonicalize(path)?;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::path::{Component, Prefix};
|
||||
let drive = |p: &Path| match p.components().next() {
|
||||
Some(Component::Prefix(x)) => match x.kind() {
|
||||
Prefix::Disk(d) | Prefix::VerbatimDisk(d) => Some(d.to_ascii_uppercase()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
if let Some(d) = drive(path)
|
||||
&& drive(&real) != Some(d)
|
||||
{
|
||||
return std::path::absolute(path);
|
||||
}
|
||||
}
|
||||
Ok(real)
|
||||
}
|
||||
|
||||
/// A Maven home (`bin/mvn` and `lib/`); Homebrew's formula keeps it in `libexec`.
|
||||
fn maven_home(dir: &Path) -> Option<PathBuf> {
|
||||
let mvn = if cfg!(windows) { "mvn.cmd" } else { "mvn" };
|
||||
@@ -620,7 +595,7 @@ fn maven() -> Vec<Sdk> {
|
||||
} else {
|
||||
which("mvn")
|
||||
};
|
||||
if let Some(mvn) = on_path.and_then(|p| launch_path(&p).ok())
|
||||
if let Some(mvn) = on_path.and_then(|p| crate::launch_path(&p).ok())
|
||||
&& let Some(home) = mvn.parent().and_then(Path::parent)
|
||||
{
|
||||
found.push((home.to_path_buf(), "path"));
|
||||
@@ -654,7 +629,7 @@ fn maven() -> Vec<Sdk> {
|
||||
let mut out = Vec::new();
|
||||
for (dir, source) in found {
|
||||
let Some(home) = maven_home(&dir) else { continue };
|
||||
let home = launch_path(&home).unwrap_or(home);
|
||||
let home = crate::launch_path(&home).unwrap_or(home);
|
||||
if !seen.insert(home.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,7 @@ pub fn jdk_at(home: &Path) -> Option<Jdk> {
|
||||
if !home.join("bin").join(crate::exe("java")).is_file() {
|
||||
return None;
|
||||
}
|
||||
Some(Jdk {
|
||||
major: parse_release(&release)?,
|
||||
home: dunce::canonicalize(home).unwrap_or_else(|_| home.to_path_buf()),
|
||||
})
|
||||
Some(Jdk { major: parse_release(&release)?, home: crate::launch_path(home).unwrap_or_else(|_| home.to_path_buf()) })
|
||||
}
|
||||
|
||||
fn children(dir: &Path) -> Vec<PathBuf> {
|
||||
@@ -90,7 +87,7 @@ fn scan() -> Vec<Jdk> {
|
||||
let path = std::env::var_os("PATH").unwrap_or_default();
|
||||
if let Some(java) = std::env::split_paths(&path).map(|d| d.join(crate::exe("java"))).find(|j| j.is_file()) {
|
||||
// Through symlinks (`/usr/bin/java`, Homebrew, SDKMAN `current`) to `<home>/bin/java`.
|
||||
if let Some(home) = dunce::canonicalize(java).ok().and_then(|j| j.parent()?.parent().map(Path::to_path_buf)) {
|
||||
if let Some(home) = crate::launch_path(&java).ok().and_then(|j| j.parent()?.parent().map(Path::to_path_buf)) {
|
||||
homes.push(home);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,31 @@ pub(crate) fn exe(name: &str) -> String {
|
||||
if cfg!(windows) { format!("{name}.exe") } else { name.to_owned() }
|
||||
}
|
||||
|
||||
/// `path` with symlinks resolved (Homebrew's `bin/mvn` → its Cellar), except that a Windows
|
||||
/// drive letter is kept: on a mapped network drive or a `subst` drive canonicalizing gives
|
||||
/// `\\?\UNC\server\share\…` or another drive, and cmd.exe can't start a script from a
|
||||
/// `\\?\` path (`mvn.cmd`, or `mvn.cmd` with such a `JAVA_HOME`), nor is it the path the user knows.
|
||||
pub(crate) fn launch_path(path: &Path) -> std::io::Result<PathBuf> {
|
||||
let real = dunce::canonicalize(path)?;
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::path::{Component, Prefix};
|
||||
let drive = |p: &Path| match p.components().next() {
|
||||
Some(Component::Prefix(x)) => match x.kind() {
|
||||
Prefix::Disk(d) | Prefix::VerbatimDisk(d) => Some(d.to_ascii_uppercase()),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
};
|
||||
if let Some(d) = drive(path)
|
||||
&& drive(&real) != Some(d)
|
||||
{
|
||||
return std::path::absolute(path);
|
||||
}
|
||||
}
|
||||
Ok(real)
|
||||
}
|
||||
|
||||
pub(crate) fn home_dir() -> Option<PathBuf> {
|
||||
std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE")).map(PathBuf::from)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user