Respect existing versions in "lockfile" (#187)

Like `pip-compile`, we now respect existing versions from the
`requirements.txt` provided via `--output-file`, unless you pass a
`--upgrade` flag.

Closes #166.
This commit is contained in:
Charlie Marsh 2023-10-25 21:28:58 -07:00 committed by GitHub
parent 9f894213e0
commit 6faaf4bc24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 347 additions and 122 deletions

View file

@ -7,15 +7,16 @@ use anyhow::Result;
use colored::Colorize;
use fs_err::File;
use itertools::Itertools;
use pubgrub::report::Reporter;
use tracing::debug;
use pep508_rs::Requirement;
use platform_host::Platform;
use platform_tags::Tags;
use pubgrub::report::Reporter;
use puffin_client::RegistryClientBuilder;
use puffin_dispatch::BuildDispatch;
use puffin_interpreter::Virtualenv;
use puffin_resolver::ResolutionMode;
use tracing::debug;
use puffin_resolver::{Manifest, ResolutionMode};
use crate::commands::{elapsed, ExitStatus};
use crate::index_urls::IndexUrls;
@ -25,11 +26,13 @@ use crate::requirements::RequirementsSource;
const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Resolve a set of requirements into a set of pinned versions.
#[allow(clippy::too_many_arguments)]
pub(crate) async fn pip_compile(
requirements: &[RequirementsSource],
constraints: &[RequirementsSource],
output_file: Option<&Path>,
mode: ResolutionMode,
resolution_mode: ResolutionMode,
upgrade_mode: UpgradeMode,
index_urls: Option<IndexUrls>,
cache: Option<&Path>,
mut printer: Printer,
@ -47,6 +50,19 @@ pub(crate) async fn pip_compile(
.map(RequirementsSource::requirements)
.flatten_ok()
.collect::<Result<Vec<Requirement>>>()?;
let preferences: Vec<Requirement> = output_file
.filter(|_| upgrade_mode.is_prefer_pinned())
.filter(|output_file| output_file.exists())
.map(Path::to_path_buf)
.map(RequirementsSource::from)
.as_ref()
.map(RequirementsSource::requirements)
.transpose()?
.map(Iterator::collect)
.unwrap_or_default();
// Create a manifest of the requirements.
let manifest = Manifest::new(requirements, constraints, preferences, resolution_mode);
// Detect the current Python interpreter.
let platform = Platform::current()?;
@ -88,9 +104,7 @@ pub(crate) async fn pip_compile(
// Resolve the dependencies.
let resolver = puffin_resolver::Resolver::new(
requirements,
constraints,
mode,
manifest,
venv.interpreter_info().markers(),
&tags,
&client,
@ -155,3 +169,28 @@ pub(crate) async fn pip_compile(
Ok(ExitStatus::Success)
}
/// Whether to allow package upgrades.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum UpgradeMode {
/// Allow package upgrades, ignoring the existing lockfile.
AllowUpgrades,
/// Prefer pinned versions from the existing lockfile, if possible.
PreferPinned,
}
impl UpgradeMode {
fn is_prefer_pinned(self) -> bool {
self == Self::PreferPinned
}
}
impl From<bool> for UpgradeMode {
fn from(value: bool) -> Self {
if value {
Self::AllowUpgrades
} else {
Self::PreferPinned
}
}
}

View file

@ -89,6 +89,10 @@ struct PipCompileArgs {
/// Ignore the package index, instead relying on local archives and caches.
#[clap(long, conflicts_with = "index_url", conflicts_with = "extra_index_url")]
no_index: bool,
/// Allow package upgrades, ignoring pinned versions in the existing output file.
#[clap(long)]
upgrade: bool,
}
#[derive(Args)]
@ -196,6 +200,7 @@ async fn main() -> ExitCode {
&constraints,
args.output_file.as_deref(),
args.resolution.unwrap_or_default(),
args.upgrade.into(),
index_urls,
cache_dir,
printer,