From 361a2039d2af678fcaf352b7ac81faf1a1d4e648 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Fri, 26 Jan 2024 04:14:18 -0800 Subject: [PATCH] Add `--no-annotate` and `--no-header` flags (#1117) Closes #1107. Closes #1108. --- crates/puffin-resolver/src/resolution.rs | 68 +++++++++-------- crates/puffin/src/commands/pip_compile.rs | 31 +++++--- crates/puffin/src/main.rs | 10 +++ crates/puffin/tests/pip_compile.rs | 91 +++++++++++++++++++++++ 4 files changed, 159 insertions(+), 41 deletions(-) diff --git a/crates/puffin-resolver/src/resolution.rs b/crates/puffin-resolver/src/resolution.rs index 7337e43ff..6f500bdf7 100644 --- a/crates/puffin-resolver/src/resolution.rs +++ b/crates/puffin-resolver/src/resolution.rs @@ -224,21 +224,29 @@ pub struct DisplayResolutionGraph<'a> { resolution: &'a ResolutionGraph, /// Whether to include hashes in the output. show_hashes: bool, -} - -impl<'a> DisplayResolutionGraph<'a> { - /// Create a new [`DisplayResolutionGraph`] for the given graph. - pub fn new(underlying: &'a ResolutionGraph, show_hashes: bool) -> DisplayResolutionGraph<'a> { - Self { - resolution: underlying, - show_hashes, - } - } + /// Whether to include annotations in the output, to indicate which dependency or dependencies + /// requested each package. + include_annotations: bool, } impl<'a> From<&'a ResolutionGraph> for DisplayResolutionGraph<'a> { fn from(resolution: &'a ResolutionGraph) -> Self { - Self::new(resolution, false) + Self::new(resolution, false, true) + } +} + +impl<'a> DisplayResolutionGraph<'a> { + /// Create a new [`DisplayResolutionGraph`] for the given graph. + pub fn new( + underlying: &'a ResolutionGraph, + show_hashes: bool, + include_annotations: bool, + ) -> DisplayResolutionGraph<'a> { + Self { + resolution: underlying, + show_hashes, + include_annotations, + } } } @@ -281,26 +289,28 @@ impl std::fmt::Display for DisplayResolutionGraph<'_> { } writeln!(f)?; - // Display all dependencies. - let mut edges = self - .resolution - .petgraph - .edges_directed(index, Direction::Incoming) - .map(|edge| &self.resolution.petgraph[edge.source()]) - .collect::>(); - edges.sort_unstable_by_key(|package| package.name()); + if self.include_annotations { + // Display all dependencies. + let mut edges = self + .resolution + .petgraph + .edges_directed(index, Direction::Incoming) + .map(|edge| &self.resolution.petgraph[edge.source()]) + .collect::>(); + edges.sort_unstable_by_key(|package| package.name()); - match edges.len() { - 0 => {} - 1 => { - for dependency in edges { - writeln!(f, "{}", format!(" # via {}", dependency.name()).green())?; + match edges.len() { + 0 => {} + 1 => { + for dependency in edges { + writeln!(f, "{}", format!(" # via {}", dependency.name()).green())?; + } } - } - _ => { - writeln!(f, "{}", " # via".green())?; - for dependency in edges { - writeln!(f, "{}", format!(" # {}", dependency.name()).green())?; + _ => { + writeln!(f, "{}", " # via".green())?; + for dependency in edges { + writeln!(f, "{}", format!(" # {}", dependency.name()).green())?; + } } } } diff --git a/crates/puffin/src/commands/pip_compile.rs b/crates/puffin/src/commands/pip_compile.rs index dcfc9d172..0006072b1 100644 --- a/crates/puffin/src/commands/pip_compile.rs +++ b/crates/puffin/src/commands/pip_compile.rs @@ -42,7 +42,7 @@ use crate::requirements::{ExtrasSpecification, RequirementsSource, RequirementsS const VERSION: &str = env!("CARGO_PKG_VERSION"); /// Resolve a set of requirements into a set of pinned versions. -#[allow(clippy::too_many_arguments)] +#[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)] pub(crate) async fn pip_compile( requirements: &[RequirementsSource], constraints: &[RequirementsSource], @@ -53,6 +53,8 @@ pub(crate) async fn pip_compile( prerelease_mode: PreReleaseMode, upgrade: Upgrade, generate_hashes: bool, + include_annotations: bool, + include_header: bool, index_locations: IndexLocations, setup_py: SetupPyStrategy, no_build: bool, @@ -324,21 +326,26 @@ pub(crate) async fn pip_compile( Box::new(AutoStream::auto(stdout())) }; - writeln!( - writer, - "{}", - format!("# This file was autogenerated by Puffin v{VERSION} via the following command:") + if include_header { + writeln!( + writer, + "{}", + format!( + "# This file was autogenerated by Puffin v{VERSION} via the following command:" + ) .green() - )?; - writeln!( - writer, - "{}", - format!("# puffin {}", env::args().skip(1).join(" ")).green() - )?; + )?; + writeln!( + writer, + "{}", + format!("# puffin {}", env::args().skip(1).join(" ")).green() + )?; + } + write!( writer, "{}", - DisplayResolutionGraph::new(&resolution, generate_hashes) + DisplayResolutionGraph::new(&resolution, generate_hashes, include_annotations) )?; Ok(ExitStatus::Success) diff --git a/crates/puffin/src/main.rs b/crates/puffin/src/main.rs index 293aa7af3..93adae7b6 100644 --- a/crates/puffin/src/main.rs +++ b/crates/puffin/src/main.rs @@ -200,6 +200,14 @@ struct PipCompileArgs { #[clap(short, long)] output_file: Option, + /// Exclude comment annotations indicating the source of each package. + #[clap(long)] + no_annotate: bool, + + /// Exclude the comment header at the top of the generated output file. + #[clap(long)] + no_header: bool, + /// Refresh all cached data. #[clap(long)] refresh: bool, @@ -679,6 +687,8 @@ async fn inner() -> Result { args.prerelease, upgrade, args.generate_hashes, + !args.no_annotate, + !args.no_header, index_urls, if args.legacy_setup_py { SetupPyStrategy::Setuptools diff --git a/crates/puffin/tests/pip_compile.rs b/crates/puffin/tests/pip_compile.rs index a0792dd15..ac1c7d0a7 100644 --- a/crates/puffin/tests/pip_compile.rs +++ b/crates/puffin/tests/pip_compile.rs @@ -3697,3 +3697,94 @@ fn missing_package_name() -> Result<()> { Ok(()) } + +/// Exclude annotations from the output. +#[test] +fn no_annotate() -> Result<()> { + let temp_dir = TempDir::new()?; + let cache_dir = TempDir::new()?; + let venv = create_venv_py312(&temp_dir, &cache_dir); + + let requirements_in = temp_dir.child("requirements.in"); + requirements_in.write_str("black==23.10.1")?; + + insta::with_settings!({ + filters => INSTA_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .arg("pip") + .arg("compile") + .arg("requirements.in") + .arg("--no-annotate") + .arg("--cache-dir") + .arg(cache_dir.path()) + .arg("--exclude-newer") + .arg(EXCLUDE_NEWER) + .env("VIRTUAL_ENV", venv.as_os_str()) + .current_dir(&temp_dir), @r###" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by Puffin v[VERSION] via the following command: + # puffin pip compile requirements.in --no-annotate --cache-dir [CACHE_DIR] + black==23.10.1 + click==8.1.7 + mypy-extensions==1.0.0 + packaging==23.2 + pathspec==0.11.2 + platformdirs==4.0.0 + + ----- stderr ----- + Resolved 6 packages in [TIME] + "###); + }); + + Ok(()) +} + +/// Exclude header from the output. +#[test] +fn no_header() -> Result<()> { + let temp_dir = TempDir::new()?; + let cache_dir = TempDir::new()?; + let venv = create_venv_py312(&temp_dir, &cache_dir); + + let requirements_in = temp_dir.child("requirements.in"); + requirements_in.write_str("black==23.10.1")?; + + insta::with_settings!({ + filters => INSTA_FILTERS.to_vec() + }, { + assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME)) + .arg("pip") + .arg("compile") + .arg("requirements.in") + .arg("--no-header") + .arg("--cache-dir") + .arg(cache_dir.path()) + .arg("--exclude-newer") + .arg(EXCLUDE_NEWER) + .env("VIRTUAL_ENV", venv.as_os_str()) + .current_dir(&temp_dir), @r###" + success: true + exit_code: 0 + ----- stdout ----- + black==23.10.1 + click==8.1.7 + # via black + mypy-extensions==1.0.0 + # via black + packaging==23.2 + # via black + pathspec==0.11.2 + # via black + platformdirs==4.0.0 + # via black + + ----- stderr ----- + Resolved 6 packages in [TIME] + "###); + }); + + Ok(()) +}