Avoid canonicalizing user-provided interpreters (#2072)

## Summary

We shouldn't be resolving symlinks on the provided interpreter;
otherwise we break `pyenv`, since running `cargo run pip install mypy
--python .venv/bin/python` will immediately resolve to (e.g.)
`/Users/crmarsh/.pyenv/versions/3.10.2/bin/python3.10`, and pyenv relies
on the path to do its lookups.

Instead, the canonicalizing happens when we query the interpreter
metadata.

Closes https://github.com/astral-sh/uv/issues/2068.

## Test Plan

Ran `cargo run pip install mypy --python .venv/bin/python -v -n` with a
virtualenv created using a pyenv Python; verified that Mypy was
installed into the virtual environment, rather than into the global
environment.
This commit is contained in:
Charlie Marsh 2024-02-28 21:32:52 -05:00 committed by GitHub
parent ef15098288
commit 1f19ef670b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 35 deletions

View file

@ -1,5 +1,5 @@
use std::borrow::Cow;
use std::path::Path;
use std::path::{Component, Path, PathBuf};
pub trait Simplified {
/// Simplify a [`Path`].
@ -46,6 +46,36 @@ pub fn normalize_url_path(path: &str) -> Cow<'_, str> {
}
}
/// Normalize a path, removing things like `.` and `..`.
///
/// Source: <https://github.com/rust-lang/cargo/blob/b48c41aedbd69ee3990d62a0e2006edbb506a480/crates/cargo-util/src/paths.rs#L76C1-L109C2>
pub fn normalize_path(path: impl AsRef<Path>) -> PathBuf {
let mut components = path.as_ref().components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}
#[cfg(test)]
mod tests {
use super::*;