Accept multiple input files in pip-sync and pip-compile (#140)

Closes https://github.com/astral-sh/puffin/issues/126.
This commit is contained in:
Charlie Marsh 2023-10-19 14:17:27 -04:00 committed by GitHub
parent 7ef6c0315c
commit 385345807c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 38 deletions

View file

@ -1,43 +1,33 @@
use fs_err::File;
use std::fmt::Write;
use std::io::{stdout, BufWriter};
use std::path::Path;
use anyhow::Result;
use fs_err::File;
use itertools::Itertools;
use owo_colors::OwoColorize;
use pubgrub::report::Reporter;
use tracing::debug;
use pep508_rs::Requirement;
use platform_host::Platform;
use platform_tags::Tags;
use puffin_client::PypiClientBuilder;
use puffin_interpreter::PythonExecutable;
use puffin_package::requirements_txt::RequirementsTxt;
use crate::commands::{elapsed, ExitStatus};
use crate::printer::Printer;
use crate::requirements::RequirementsSource;
/// Resolve a set of requirements into a set of pinned versions.
pub(crate) async fn pip_compile(
src: &Path,
sources: &[RequirementsSource],
output_file: Option<&Path>,
cache: Option<&Path>,
mut printer: Printer,
) -> Result<ExitStatus> {
let start = std::time::Instant::now();
// Read the `requirements.txt` from disk.
let requirements_txt = RequirementsTxt::parse(src, std::env::current_dir()?)?;
let requirements = requirements_txt
.requirements
.into_iter()
.map(|entry| entry.requirement)
.collect::<Vec<_>>();
if requirements.is_empty() {
writeln!(printer, "No requirements found")?;
return Ok(ExitStatus::Success);
}
// Detect the current Python interpreter.
let platform = Platform::current()?;
let python = PythonExecutable::from_env(platform, cache)?;
@ -46,6 +36,13 @@ pub(crate) async fn pip_compile(
python.executable().display()
);
// Read all requirements from the provided sources.
let requirements = sources
.iter()
.map(RequirementsSource::requirements)
.flatten_ok()
.collect::<Result<Vec<Requirement>>>()?;
// Determine the current environment markers.
let markers = python.markers();

View file

@ -1,7 +1,7 @@
use std::fmt::Write;
use std::path::Path;
use anyhow::{bail, Context, Result};
use anyhow::{Context, Result};
use itertools::Itertools;
use owo_colors::OwoColorize;
use tracing::debug;
@ -16,7 +16,6 @@ use puffin_installer::{
};
use puffin_interpreter::PythonExecutable;
use puffin_package::package_name::PackageName;
use puffin_package::requirements_txt::RequirementsTxt;
use puffin_resolver::Resolution;
use crate::commands::reporters::{
@ -24,23 +23,21 @@ use crate::commands::reporters::{
};
use crate::commands::{elapsed, ExitStatus};
use crate::printer::Printer;
use crate::requirements::RequirementsSource;
/// Install a set of locked requirements into the current Python environment.
pub(crate) async fn pip_sync(
src: &Path,
sources: &[RequirementsSource],
cache: Option<&Path>,
mut printer: Printer,
) -> Result<ExitStatus> {
// Read the `requirements.txt` from disk.
let requirements_txt = RequirementsTxt::parse(src, std::env::current_dir()?)?;
if !requirements_txt.constraints.is_empty() {
bail!("Constraints in requirements.txt are not supported");
}
let requirements = requirements_txt
.requirements
.into_iter()
.map(|entry| entry.requirement)
.collect::<Vec<_>>();
// Read all requirements from the provided sources.
let requirements = sources
.iter()
.map(RequirementsSource::requirements)
.flatten_ok()
.collect::<Result<Vec<Requirement>>>()?;
if requirements.is_empty() {
writeln!(printer, "No requirements found")?;
return Ok(ExitStatus::Success);

View file

@ -55,17 +55,20 @@ enum Commands {
#[derive(Args)]
struct PipCompileArgs {
/// Output `requirements.txt` file
/// Include all packages listed in the given `requirements.in` files.
#[clap(required(true))]
src_file: Vec<PathBuf>,
/// Write the compiled requirements to the given `requirements.txt` file.
#[clap(short, long)]
output_file: Option<PathBuf>,
/// Path to the `requirements.txt` file to compile.
src: PathBuf,
}
#[derive(Args)]
struct PipSyncArgs {
/// Path to the `requirements.txt` file to install.
src: PathBuf,
/// Include all packages listed in the given `requirements.txt` files.
#[clap(required(true))]
src_file: Vec<PathBuf>,
}
#[derive(Args)]
@ -121,12 +124,16 @@ async fn main() -> ExitCode {
printer::Printer::Default
};
let dirs = ProjectDirs::from("", "", "puffin");
let result = match cli.command {
Commands::PipCompile(args) => {
let dirs = ProjectDirs::from("", "", "puffin");
let sources = args
.src_file
.into_iter()
.map(RequirementsSource::from)
.collect::<Vec<_>>();
commands::pip_compile(
&args.src,
&sources,
args.output_file.as_deref(),
dirs.as_ref()
.map(ProjectDirs::cache_dir)
@ -136,8 +143,14 @@ async fn main() -> ExitCode {
.await
}
Commands::PipSync(args) => {
let dirs = ProjectDirs::from("", "", "puffin");
let sources = args
.src_file
.into_iter()
.map(RequirementsSource::from)
.collect::<Vec<_>>();
commands::pip_sync(
&args.src,
&sources,
dirs.as_ref()
.map(ProjectDirs::cache_dir)
.filter(|_| !cli.no_cache),
@ -146,6 +159,7 @@ async fn main() -> ExitCode {
.await
}
Commands::PipUninstall(args) => {
let dirs = ProjectDirs::from("", "", "puffin");
let sources = args
.package
.into_iter()
@ -162,9 +176,11 @@ async fn main() -> ExitCode {
.await
}
Commands::Clean => {
let dirs = ProjectDirs::from("", "", "puffin");
commands::clean(dirs.as_ref().map(ProjectDirs::cache_dir), printer).await
}
Commands::Freeze => {
let dirs = ProjectDirs::from("", "", "puffin");
commands::freeze(
dirs.as_ref()
.map(ProjectDirs::cache_dir)

View file

@ -1,7 +1,7 @@
use std::path::PathBuf;
use std::str::FromStr;
use anyhow::Result;
use anyhow::{bail, Result};
use itertools::Either;
use pep508_rs::Requirement;
@ -37,6 +37,9 @@ impl RequirementsSource {
}
Self::Path(path) => {
let requirements_txt = RequirementsTxt::parse(path, std::env::current_dir()?)?;
if !requirements_txt.constraints.is_empty() {
bail!("Constraints in requirements files are not supported");
}
Ok(Either::Right(
requirements_txt
.requirements