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

Add basic tool.uv.sources support #3263

Merged
merged 31 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a880191
Log which requirements were or weren't satisfied (#3319)
konstin Apr 30, 2024
f20530c
Add `tool.uv.sources` definitions
konstin Apr 25, 2024
b8cb4c1
Add basic `tool.uv.sources` support
konstin Apr 25, 2024
43f2bd3
Add docs
konstin Apr 25, 2024
b9f18e1
Add json schema support
konstin Apr 25, 2024
e4a1f80
Oxford comma
konstin Apr 30, 2024
afcaeb6
Review
konstin Apr 30, 2024
2abb8e2
Port tests
konstin Apr 30, 2024
1a384a3
Merge url and path branch
konstin Apr 30, 2024
9397423
Rustdoc
konstin Apr 30, 2024
2b549dc
Rename UvRequirement -> Requirement, UvSource -> Source
konstin Apr 30, 2024
62b597c
Update schema json
konstin Apr 30, 2024
1d3ba14
Avoid unreachable in planner
konstin May 2, 2024
9cd006d
Avoid `Into::into`
konstin May 2, 2024
6fc3527
Improve schema information leakage comment
konstin May 2, 2024
bc3a5c7
Docstring style
konstin May 2, 2024
052c57f
Improve comment
konstin May 2, 2024
8623935
`UvSourcesLoweringError` -> `LoweringError`
konstin May 2, 2024
1b94cdd
`UvMetadata` back to `Pep621Metadata`
konstin May 2, 2024
5f66e68
Improve comment
konstin May 2, 2024
bc02edc
Improve URL handling
konstin May 2, 2024
eec41bf
Remove `Uv` naming everywhere
konstin May 2, 2024
d2661b6
Use `VerbatimUrl::parse_path`
konstin May 2, 2024
14215e3
Fix clippy and tests
konstin May 2, 2024
ceeaa81
url test error message
konstin May 2, 2024
33d934d
Fix failing tests rebasing
konstin May 2, 2024
89afc8f
Use `pep508_rs::Requirement` in requirements.txt
konstin May 3, 2024
f90f618
Rename `Requirement::from_requirement` to `Requirement::from_pep508`
konstin May 3, 2024
83b6fe0
Cleanup and docs
konstin May 3, 2024
2ee61ab
Tweaks to docs
charliermarsh May 3, 2024
b768af1
Small tweaks to comments, etc.
charliermarsh May 3, 2024
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
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ rmp-serde = { version = "1.1.2" }
rust-netrc = { version = "0.1.1" }
rustc-hash = { version = "1.1.0" }
same-file = { version = "1.0.6" }
schemars = { version = "0.8.16" }
schemars = { version = "0.8.16", features = ["url"] }
seahash = { version = "4.1.0" }
serde = { version = "1.0.197" }
serde_json = { version = "1.0.114" }
Expand Down
17 changes: 10 additions & 7 deletions crates/bench/benches/uv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use std::str::FromStr;

use bench::criterion::black_box;
use bench::criterion::{criterion_group, criterion_main, measurement::WallTime, Criterion};

use pep508_rs::Requirement;
use distribution_types::Requirement;
use uv_cache::Cache;
use uv_client::RegistryClientBuilder;
use uv_resolver::Manifest;
Expand All @@ -15,7 +14,10 @@ fn resolve_warm_jupyter(c: &mut Criterion<WallTime>) {
.unwrap();

let cache = &Cache::from_path(".cache").unwrap();
let manifest = &Manifest::simple(vec![Requirement::from_str("jupyter").unwrap()]);
let manifest = &Manifest::simple(vec![Requirement::from_pep508(
pep508_rs::Requirement::from_str("jupyter").unwrap(),
)
.unwrap()]);
let client = &RegistryClientBuilder::new(cache.clone()).build();

let run = || {
Expand All @@ -35,13 +37,14 @@ criterion_group!(uv, resolve_warm_jupyter);
criterion_main!(uv);

mod resolver {
use anyhow::Result;
use once_cell::sync::Lazy;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use distribution_types::{IndexLocations, Resolution, SourceDist};
use pep508_rs::{MarkerEnvironment, Requirement, StringVersion};
use anyhow::Result;
use once_cell::sync::Lazy;

use distribution_types::{IndexLocations, Requirement, Resolution, SourceDist};
use pep508_rs::{MarkerEnvironment, StringVersion};
use platform_tags::{Arch, Os, Platform, Tags};
use uv_cache::Cache;
use uv_client::RegistryClient;
Expand Down
1 change: 1 addition & 0 deletions crates/distribution-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ uv-normalize = { workspace = true }
anyhow = { workspace = true }
fs-err = { workspace = true }
git2 = { workspace = true }
indexmap = { workspace = true }
itertools = { workspace = true }
once_cell = { workspace = true }
rkyv = { workspace = true }
Expand Down
8 changes: 6 additions & 2 deletions crates/distribution-types/src/cached.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};

use anyhow::Result;
use anyhow::{anyhow, Result};

use distribution_filename::WheelFilename;
use pep508_rs::VerbatimUrl;
Expand Down Expand Up @@ -111,10 +111,14 @@ impl CachedDist {
assert_eq!(dist.url.scheme(), "file", "{}", dist.url);
Ok(Some(ParsedUrl::LocalFile(ParsedLocalFileUrl {
url: dist.url.raw().clone(),
path: dist
.url
.to_file_path()
.map_err(|()| anyhow!("Invalid path in file URL"))?,
editable: dist.editable,
})))
} else {
Ok(Some(ParsedUrl::try_from(dist.url.raw())?))
Ok(Some(ParsedUrl::try_from(dist.url.to_url())?))
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions crates/distribution-types/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use url::Url;

use pep508_rs::VerbatimUrl;
use uv_normalize::PackageName;

#[derive(thiserror::Error, Debug)]
Expand All @@ -23,4 +25,7 @@ pub enum Error {

#[error("Requested package name `{0}` does not match `{1}` in the distribution filename: {2}")]
PackageNameMismatch(PackageName, PackageName, String),

#[error("Only directories can be installed as editable, not filenames: `{0}`")]
EditableFile(VerbatimUrl),
}
9 changes: 6 additions & 3 deletions crates/distribution-types/src/installed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tracing::warn;
use url::Url;

use pep440_rs::Version;
use pypi_types::DirectUrl;
use uv_fs::Simplified;
use uv_normalize::PackageName;

Expand All @@ -32,6 +33,7 @@ pub struct InstalledRegistryDist {
pub struct InstalledDirectUrlDist {
pub name: PackageName,
pub version: Version,
pub direct_url: Box<DirectUrl>,
konstin marked this conversation as resolved.
Show resolved Hide resolved
pub url: Url,
pub editable: bool,
pub path: PathBuf,
Expand Down Expand Up @@ -60,7 +62,8 @@ impl InstalledDist {
Ok(url) => Ok(Some(Self::Url(InstalledDirectUrlDist {
name,
version,
editable: matches!(&direct_url, pypi_types::DirectUrl::LocalDirectory { dir_info, .. } if dir_info.editable == Some(true)),
editable: matches!(&direct_url, DirectUrl::LocalDirectory { dir_info, .. } if dir_info.editable == Some(true)),
direct_url: Box::new(direct_url),
url,
path: path.to_path_buf(),
}))),
Expand Down Expand Up @@ -101,12 +104,12 @@ impl InstalledDist {
}

/// Read the `direct_url.json` file from a `.dist-info` directory.
pub fn direct_url(path: &Path) -> Result<Option<pypi_types::DirectUrl>> {
pub fn direct_url(path: &Path) -> Result<Option<DirectUrl>> {
let path = path.join("direct_url.json");
let Ok(file) = fs_err::File::open(path) else {
return Ok(None);
};
let direct_url = serde_json::from_reader::<fs_err::File, pypi_types::DirectUrl>(file)?;
let direct_url = serde_json::from_reader::<fs_err::File, DirectUrl>(file)?;
Ok(Some(direct_url))
}

Expand Down
25 changes: 19 additions & 6 deletions crates/distribution-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ pub use crate::index_url::*;
pub use crate::installed::*;
pub use crate::parsed_url::*;
pub use crate::prioritized_distribution::*;
pub use crate::requirement::*;
pub use crate::resolution::*;
pub use crate::resolved::*;
pub use crate::specified_requirement::*;
pub use crate::traits::*;

mod any;
Expand All @@ -72,8 +74,10 @@ mod index_url;
mod installed;
mod parsed_url;
mod prioritized_distribution;
mod requirement;
mod resolution;
mod resolved;
mod specified_requirement;
mod traits;

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -228,8 +232,8 @@ impl Dist {
}

/// A remote built distribution (`.whl`) or source distribution from a `http://` or `https://`
/// url.
fn from_http_url(name: PackageName, url: VerbatimUrl) -> Result<Dist, Error> {
/// URL.
pub fn from_http_url(name: PackageName, url: VerbatimUrl) -> Result<Dist, Error> {
if Path::new(url.path())
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("whl"))
Expand All @@ -256,8 +260,12 @@ impl Dist {
}
}

/// A local built or source distribution from a `file://` url.
fn from_file_url(name: PackageName, url: VerbatimUrl) -> Result<Dist, Error> {
/// A local built or source distribution from a `file://` URL.
pub fn from_file_url(
name: PackageName,
url: VerbatimUrl,
editable: bool,
) -> Result<Dist, Error> {
// Store the canonicalized path, which also serves to validate that it exists.
let path = match url
.to_file_path()
Expand Down Expand Up @@ -285,6 +293,10 @@ impl Dist {
));
}

if editable {
return Err(Error::EditableFile(url));
}

Ok(Self::Built(BuiltDist::Path(PathBuiltDist {
filename,
url,
Expand All @@ -295,7 +307,7 @@ impl Dist {
name,
url,
path,
editable: false,
editable,
})))
}
}
Expand All @@ -305,11 +317,12 @@ impl Dist {
Ok(Self::Source(SourceDist::Git(GitSourceDist { name, url })))
}

// TODO(konsti): We should carry the parsed URL through the codebase.
/// Create a [`Dist`] for a URL-based distribution.
pub fn from_url(name: PackageName, url: VerbatimUrl) -> Result<Self, Error> {
match Scheme::parse(url.scheme()) {
Some(Scheme::Http | Scheme::Https) => Self::from_http_url(name, url),
Some(Scheme::File) => Self::from_file_url(name, url),
Some(Scheme::File) => Self::from_file_url(name, url, false),
Some(Scheme::GitSsh | Scheme::GitHttps) => Self::from_git_url(name, url),
Some(Scheme::GitGit | Scheme::GitHttp) => Err(Error::UnsupportedScheme(
url.scheme().to_owned(),
Expand Down
Loading
Loading