Annotate sources of requirements (#3269)

## Summary

Fixes https://github.com/astral-sh/uv/issues/1343. This is kinda a first
draft at the moment, but does at least mostly work locally (barring some
bits of the test suite that seem to not work for me in general).

## Test Plan

Mostly running the existing tests and checking the revised output is
sane

## Outstanding issues

Most of these come down to "AFAIK, the existing tools don't support
these patterns, but `uv` does" and so I'm not sure there's an existing
good answer here! Most of the answers so far are "whatever was easiest
to build"

- [x] ~~Is "-r pyproject.toml" correct? Should it show something else or
get skipped entirely~~ No it wasn't. Fixed in
3044fa8b86
- [ ] If the requirements file is stdin, that just gets skipped. Should
it be recorded?
- [ ] Overrides get shown as "--override<override.txt>". Correct?
- [x] ~~Some of the tests (e.g.
`dependency_excludes_non_contiguous_range_of_compatible_versions`) make
assumptions about the order of package versions being outputted, which
this PR breaks. I'm not sure if the text is fairly arbitrary and can be
replaced or whether the behaviour needs fixing?~~ - fixed by removing
the custom pubgrub PartialEq/Hash
- [ ] Are all the `TrackedFromStr` et al changes needed, or is there an
easier way? I don't think so, I think it's necessary to track these sort
of things fairly comprehensively to make this feature work, and this
sort of invasive change feels necessary, but happy to be proved wrong
there :)
- [x] ~~If you have a requirement coming in from two or more different
requirements files only one turns up. I've got a closed-source example
for this (can go into more detail if needed), mostly consisting of a
complicated set of common deps creating a larger set. It's a rarer case,
but worth considering.~~ 042432b200
- [ ] Doesn't add annotations for `setup.py` yet
- This is pretty hard, as the correct location to insert the path is
`crates/pypi-types/src/metadata.rs`'s `parse_pkg_info`, which as it's
based off a source distribution has entirely thrown away such matters as
"where did this package requirement get built from". Could add "`built
package name`" as a dep, but that's a little odd.
This commit is contained in:
Tom Parker-Shemilt 2024-05-09 04:19:22 +01:00 committed by GitHub
parent 367958e6b2
commit bc963d13cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1295 additions and 331 deletions

View file

@ -3,11 +3,16 @@ use std::path::{Component, Path, PathBuf};
use once_cell::sync::Lazy;
pub static CWD: Lazy<PathBuf> = Lazy::new(|| {
/// The current working directory.
pub static CWD: Lazy<PathBuf> =
Lazy::new(|| std::env::current_dir().expect("The current directory must exist"));
/// The current working directory, canonicalized.
pub static CANONICAL_CWD: Lazy<PathBuf> = Lazy::new(|| {
std::env::current_dir()
.unwrap()
.canonicalize()
.expect("The current directory must exist")
.canonicalize()
.expect("The current directory must be canonicalized")
});
pub trait Simplified {
@ -22,6 +27,9 @@ pub trait Simplified {
/// equivalent to [`std::path::Display`].
fn simplified_display(&self) -> std::path::Display;
/// Canonicalize a path without a `\\?\` prefix on Windows.
fn simple_canonicalize(&self) -> std::io::Result<PathBuf>;
/// Render a [`Path`] for user-facing display.
///
/// Like [`simplified_display`], but relativizes the path against the current working directory.
@ -37,10 +45,20 @@ impl<T: AsRef<Path>> Simplified for T {
dunce::simplified(self.as_ref()).display()
}
fn simple_canonicalize(&self) -> std::io::Result<PathBuf> {
dunce::canonicalize(self.as_ref())
}
fn user_display(&self) -> std::path::Display {
let path = dunce::simplified(self.as_ref());
// Attempt to strip the current working directory, then the canonicalized current working
// directory, in case they differ.
path.strip_prefix(CWD.simplified())
.unwrap_or(path)
.unwrap_or_else(|_| {
path.strip_prefix(CANONICAL_CWD.simplified())
.unwrap_or(path)
})
.display()
}
}
@ -136,7 +154,7 @@ pub fn normalize_path(path: &Path) -> Result<PathBuf, std::io::Error> {
pub fn absolutize_path(path: &Path) -> Result<Cow<Path>, std::io::Error> {
use path_absolutize::Absolutize;
path.absolutize_from(&*CWD)
path.absolutize_from(CWD.simplified())
}
/// Like `fs_err::canonicalize`, but with permissive failures on Windows.