From 530edb6e397a2fae6776d6552e06b62f3e210f0d Mon Sep 17 00:00:00 2001 From: konsti Date: Thu, 12 Oct 2023 20:42:06 +0200 Subject: [PATCH] Add output file option to compile (#93) `pip-compile` has the same option. I need this esp. since piping doesn't work as we write to stdout. --- crates/puffin-cli/src/commands/compile.rs | 14 ++++++++------ crates/puffin-cli/src/main.rs | 7 +++++-- crates/puffin-resolver/src/resolution.rs | 10 ++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/crates/puffin-cli/src/commands/compile.rs b/crates/puffin-cli/src/commands/compile.rs index ebd81b3a6..ac305b03a 100644 --- a/crates/puffin-cli/src/commands/compile.rs +++ b/crates/puffin-cli/src/commands/compile.rs @@ -1,4 +1,6 @@ use std::fmt::Write; +use std::fs::File; +use std::io::{stdout, BufWriter}; use std::path::Path; use anyhow::Result; @@ -18,6 +20,7 @@ use crate::printer::Printer; /// Resolve a set of requirements into a set of pinned versions. pub(crate) async fn compile( src: &Path, + output_file: Option<&Path>, cache: Option<&Path>, mut printer: Printer, ) -> Result { @@ -80,12 +83,11 @@ pub(crate) async fn compile( .dimmed() )?; - for (name, package) in resolution.iter() { - #[allow(clippy::print_stdout)] - { - println!("{}=={}", name, package.version()); - } - } + if let Some(output_file) = output_file { + resolution.write_requirement_format(&mut BufWriter::new(File::create(output_file)?))?; + } else { + resolution.write_requirement_format(&mut stdout().lock())?; + }; Ok(ExitStatus::Success) } diff --git a/crates/puffin-cli/src/main.rs b/crates/puffin-cli/src/main.rs index 80fd08071..f6eb5930c 100644 --- a/crates/puffin-cli/src/main.rs +++ b/crates/puffin-cli/src/main.rs @@ -1,12 +1,11 @@ use std::path::PathBuf; use std::process::ExitCode; +use crate::commands::ExitStatus; use clap::{Args, Parser, Subcommand}; use colored::Colorize; use directories::ProjectDirs; -use crate::commands::ExitStatus; - mod commands; mod logging; mod printer; @@ -49,6 +48,9 @@ enum Commands { #[derive(Args)] struct CompileArgs { + /// Output `requirements.txt` file + #[clap(short, long)] + output_file: Option, /// Path to the `requirements.txt` file to compile. src: PathBuf, } @@ -104,6 +106,7 @@ async fn main() -> ExitCode { Commands::Compile(args) => { commands::compile( &args.src, + args.output_file.as_deref(), dirs.as_ref() .map(ProjectDirs::cache_dir) .filter(|_| !cli.no_cache), diff --git a/crates/puffin-resolver/src/resolution.rs b/crates/puffin-resolver/src/resolution.rs index 1c5bafad1..55a6d4724 100644 --- a/crates/puffin-resolver/src/resolution.rs +++ b/crates/puffin-resolver/src/resolution.rs @@ -1,4 +1,6 @@ use std::collections::BTreeMap; +use std::io; +use std::io::Write; use pep440_rs::Version; use puffin_client::File; @@ -33,6 +35,14 @@ impl Resolution { pub fn is_empty(&self) -> bool { self.0.is_empty() } + + /// Write the resolution in the `{name}=={version}` format of requirements.txt that pip uses. + pub fn write_requirement_format(&self, writer: &mut impl Write) -> io::Result<()> { + for (name, package) in self.iter() { + writeln!(writer, "{}=={}", name, package.version())?; + } + Ok(()) + } } impl std::fmt::Display for Resolution {