Deduplicate symbolic links between purelib and platlib (#3002)

## Summary

This PR adds system install tests to verify the behavior described in
#2798. It turns out this behavior _also_ affects Fedora and Amazon
Linux, we just didn't have the right conditions enabled (specifically,
you need to create the virtualenv with `python -m venv` to get these
symlinks), so the test suite was expanded to capture that.

The issue itself is also fixed by way of deduplicating the
`site-packages` entries.

Closes: https://github.com/astral-sh/uv/issues/2798
This commit is contained in:
Charlie Marsh
2024-04-12 17:08:56 -04:00
committed by GitHub
parent 3ae35adc8e
commit ab9cc78b7a
3 changed files with 85 additions and 5 deletions
@@ -1,6 +1,7 @@
use std::env;
use std::path::{Path, PathBuf};
use same_file::is_same_file;
use tracing::{debug, info};
use uv_cache::Cache;
@@ -92,12 +93,17 @@ impl PythonEnvironment {
///
/// In most cases, `purelib` and `platlib` will be the same, and so the iterator will contain
/// a single element; however, in some distributions, they may be different.
///
/// Some distributions also create symbolic links from `purelib` to `platlib`; in such cases, we
/// still deduplicate the entries, returning a single path.
pub fn site_packages(&self) -> impl Iterator<Item = &Path> {
std::iter::once(self.interpreter.purelib()).chain(
if self.interpreter.purelib() == self.interpreter.platlib() {
let purelib = self.interpreter.purelib();
let platlib = self.interpreter.platlib();
std::iter::once(purelib).chain(
if purelib == platlib || is_same_file(purelib, platlib).unwrap_or(false) {
None
} else {
Some(self.interpreter.platlib())
Some(platlib)
},
)
}