From ccdf2d793bbc2401c891b799772f615a28607e79 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 2 Sep 2024 22:12:29 -0400 Subject: [PATCH] Add `--no-hashes` to `uv export` (#6954) ## Summary Closes https://github.com/astral-sh/uv/issues/6944. --- crates/uv-cli/src/lib.rs | 8 ++++ .../uv-resolver/src/lock/requirements_txt.rs | 24 +++++++----- crates/uv/src/commands/project/export.rs | 10 ++++- crates/uv/src/lib.rs | 1 + crates/uv/src/settings.rs | 4 ++ crates/uv/tests/export.rs | 38 +++++++++++++++++++ docs/reference/cli.md | 2 + 7 files changed, 76 insertions(+), 11 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index c6131cc8e..ce0f2f5c4 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2802,6 +2802,14 @@ pub struct ExportArgs { #[arg(long, overrides_with("dev"))] pub no_dev: bool, + /// Include hashes for all dependencies. + #[arg(long, overrides_with("no_hashes"), hide = true)] + pub hashes: bool, + + /// Omit hashes in the generated output. + #[arg(long, overrides_with("hashes"))] + pub no_hashes: bool, + /// Assert that the `uv.lock` will remain unchanged. /// /// Requires that the lockfile is up-to-date. If the lockfile is missing or diff --git a/crates/uv-resolver/src/lock/requirements_txt.rs b/crates/uv-resolver/src/lock/requirements_txt.rs index bdeeb3d59..e5de97673 100644 --- a/crates/uv-resolver/src/lock/requirements_txt.rs +++ b/crates/uv-resolver/src/lock/requirements_txt.rs @@ -24,7 +24,10 @@ type LockGraph<'lock> = Graph, Edge, Directed>; /// An export of a [`Lock`] that renders in `requirements.txt` format. #[derive(Debug)] -pub struct RequirementsTxtExport<'lock>(LockGraph<'lock>); +pub struct RequirementsTxtExport<'lock> { + graph: LockGraph<'lock>, + hashes: bool, +} impl<'lock> RequirementsTxtExport<'lock> { pub fn from_lock( @@ -32,6 +35,7 @@ impl<'lock> RequirementsTxtExport<'lock> { root_name: &PackageName, extras: &ExtrasSpecification, dev: &[GroupName], + hashes: bool, ) -> Result { let size_guess = lock.packages.len(); let mut petgraph = LockGraph::with_capacity(size_guess, size_guess); @@ -114,7 +118,7 @@ impl<'lock> RequirementsTxtExport<'lock> { let graph = propagate_markers(petgraph); - Ok(Self(graph)) + Ok(Self { graph, hashes }) } } @@ -122,7 +126,7 @@ impl std::fmt::Display for RequirementsTxtExport<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { // Collect all packages. let mut nodes = self - .0 + .graph .raw_nodes() .iter() .map(|node| &node.weight) @@ -197,12 +201,14 @@ impl std::fmt::Display for RequirementsTxtExport<'_> { write!(f, " ; {contents}")?; } - let hashes = package.hashes(); - if !hashes.is_empty() { - for hash in &hashes { - writeln!(f, " \\")?; - write!(f, " --hash=")?; - write!(f, "{hash}")?; + if self.hashes { + let hashes = package.hashes(); + if !hashes.is_empty() { + for hash in &hashes { + writeln!(f, " \\")?; + write!(f, " --hash=")?; + write!(f, "{hash}")?; + } } } diff --git a/crates/uv/src/commands/project/export.rs b/crates/uv/src/commands/project/export.rs index 185c3a2ca..52eb0734d 100644 --- a/crates/uv/src/commands/project/export.rs +++ b/crates/uv/src/commands/project/export.rs @@ -22,6 +22,7 @@ use crate::settings::ResolverSettings; pub(crate) async fn export( format: ExportFormat, package: Option, + hashes: bool, extras: ExtrasSpecification, dev: bool, locked: bool, @@ -112,8 +113,13 @@ pub(crate) async fn export( // Generate the export. match format { ExportFormat::RequirementsTxt => { - let export = - RequirementsTxtExport::from_lock(&lock, project.project_name(), &extras, &dev)?; + let export = RequirementsTxtExport::from_lock( + &lock, + project.project_name(), + &extras, + &dev, + hashes, + )?; anstream::println!( "{}", "# This file was autogenerated via `uv export`.".green() diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index e9535db71..66a66e25a 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1273,6 +1273,7 @@ async fn run_project( commands::export( args.format, args.package, + args.hashes, args.extras, args.dev, args.locked, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 1534de957..c8a39d736 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -944,6 +944,7 @@ pub(crate) struct ExportSettings { pub(crate) package: Option, pub(crate) extras: ExtrasSpecification, pub(crate) dev: bool, + pub(crate) hashes: bool, pub(crate) locked: bool, pub(crate) frozen: bool, pub(crate) python: Option, @@ -963,6 +964,8 @@ impl ExportSettings { no_all_extras, dev, no_dev, + hashes, + no_hashes, locked, frozen, resolver, @@ -979,6 +982,7 @@ impl ExportSettings { extra.unwrap_or_default(), ), dev: flag(dev, no_dev).unwrap_or(true), + hashes: flag(hashes, no_hashes).unwrap_or(true), locked, frozen, python, diff --git a/crates/uv/tests/export.rs b/crates/uv/tests/export.rs index bab185aea..63c04a478 100644 --- a/crates/uv/tests/export.rs +++ b/crates/uv/tests/export.rs @@ -632,3 +632,41 @@ fn dev() -> Result<()> { Ok(()) } + +#[test] +fn no_hashes() -> Result<()> { + let context = TestContext::new("3.12"); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str( + r#" + [project] + name = "project" + version = "0.1.0" + requires-python = ">=3.12" + dependencies = ["anyio==3.7.0"] + + [build-system] + requires = ["setuptools>=42"] + build-backend = "setuptools.build_meta" + "#, + )?; + + context.lock().assert().success(); + + uv_snapshot!(context.filters(), context.export().arg("--no-hashes"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated via `uv export`. + -e . + anyio==3.7.0 + idna==3.6 + sniffio==1.3.1 + + ----- stderr ----- + Resolved 4 packages in [TIME] + "###); + + Ok(()) +} diff --git a/docs/reference/cli.md b/docs/reference/cli.md index f0f0a670c..d2664d9d9 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -1738,6 +1738,8 @@ uv export [OPTIONS]
--no-dev

Omit development dependencies

+
--no-hashes

Omit hashes in the generated output

+
--no-index

Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via --find-links

--no-progress

Hide all progress outputs.