Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve tilde handling #86

Merged
merged 7 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 6 additions & 8 deletions src/exe_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn get_search_origins() -> HashSet<(PathBuf, bool)> {

// Return True if the path points to a python executable. We assume this has already been proven to exist.
fn is_exe(path: &Path) -> bool {
return match path.file_name().and_then(|f| f.to_str()) {
match path.file_name().and_then(|f| f.to_str()) {
Some(file_name) if file_name.starts_with("python") => {
let suffix = &file_name[6..];
if suffix.is_empty() || suffix.chars().all(|c| c.is_ascii_digit() || c == '.')
Expand All @@ -95,7 +95,7 @@ fn is_exe(path: &Path) -> bool {
}
}
_ => false,
};
}
}

fn is_symlink(path: &Path) -> bool {
Expand All @@ -105,19 +105,17 @@ fn is_symlink(path: &Path) -> bool {
}
}

const PY_SYS_EXE: &str = "import sys;print(sys.executable)";

// Use the default Python to get its executable path.
fn get_exe_default() -> Option<PathBuf> {
return match Command::new("python3")
.arg("-c")
.arg("import sys;print(sys.executable)")
.output()
{
match Command::new("python3").arg("-c").arg(PY_SYS_EXE).output() {
Ok(output) => match std::str::from_utf8(&output.stdout) {
Ok(s) => Some(PathBuf::from(s.trim())),
Err(_) => None,
},
Err(_) => None,
};
}
}
/// Try to find all Python executables given a starting directory. This will recursively search all directories that are not symlinks.
fn find_exe_inner(
Expand Down
14 changes: 10 additions & 4 deletions src/scan_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ pub(crate) enum Anchor {
}

//------------------------------------------------------------------------------
const PY_SITE_PACKAGES: &str = "import site;print(site.ENABLE_USER_SITE);print(\"\\n\".join(site.getsitepackages()));print(site.getusersitepackages())";

/// Given a path to a Python binary, call out to Python to get all known site packages; some site packages may not exist; we do not filter them here. This will include "dist-packages" on Linux. If `force_usite` is false, we use ENABLE_USER_SITE to determine if we should include the user site packages; if `force_usite` is true, we always include usite.
fn get_site_package_dirs(executable: &Path, force_usite: bool) -> Vec<PathShared> {
let py = "import site;print(site.ENABLE_USER_SITE);print(\"\\n\".join(site.getsitepackages()));print(site.getusersitepackages())";
return match Command::new(executable).arg("-c").arg(py).output() {
// let py = "import site;print(site.ENABLE_USER_SITE);print(\"\\n\".join(site.getsitepackages()));print(site.getusersitepackages())";
match Command::new(executable)
.arg("-c")
.arg(PY_SITE_PACKAGES)
.output()
{
Ok(output) => {
let mut paths = Vec::new();
let mut usite_enabled = false;
Expand All @@ -60,10 +66,10 @@ fn get_site_package_dirs(executable: &Path, force_usite: bool) -> Vec<PathShared
paths
}
Err(e) => {
eprintln!("Failed to execute command: {}", e); // log this
eprintln!("Failed to execute command with {:?}: {}", executable, e); // log this
Vec::with_capacity(0)
}
};
}
}

// Given a package directory, collect the name of all packages.
Expand Down
18 changes: 13 additions & 5 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ pub(crate) fn path_normalize(path: &Path) -> ResultDynError<PathBuf> {
let mut fp = path.to_path_buf();
if let Some(path_str) = fp.to_str() {
if path_str.starts_with('~') {
if let Some(home) = path_home() {
fp = home.join(path_str.trim_start_matches('~'));
} else {
return Err("Usage of `~` unresolved.".into());
}
let home = path_home().ok_or("Cannot get home directory")?;
let path_stripped =
fp.strip_prefix("~").map_err(|_| "Failed to strip prefix")?;
fp = home.join(path_stripped);
println!("post conversion: {:?}", fp);
}
}
// Only expand relative paths if there is more than one component
Expand Down Expand Up @@ -112,4 +112,12 @@ mod tests {
let s2 = url_strip_user(&s1);
assert_eq!(s2, "git+https://github.com/pypa/packaging.git@cf2cbe2aec28f87c6228a6fb136c27931c9af407")
}

#[test]
fn test_path_normalize_a() {
let p1 = Path::new("~/foo/bar");
let p2 = path_normalize(&p1).unwrap();
let home = path_home().unwrap();
assert!(p2.starts_with(home));
}
}
Loading