Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions crates/uv-cli/src/options.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use anstream::eprintln;

use uv_cache::Refresh;
use uv_distribution_types::{ConfigSettings, PackageConfigSettings};
use uv_configuration::UpgradeSelection;
use uv_distribution_types::{ConfigSettings, PackageConfigSettings, Requirement};
use uv_resolver::{ExcludeNewer, ExcludeNewerPackage, PrereleaseMode};
use uv_settings::{Combine, PipOptions, ResolverInstallerOptions, ResolverOptions};
use uv_warnings::owo_colors::OwoColorize;
Expand Down Expand Up @@ -333,8 +334,10 @@ pub fn resolver_options(
.filter_map(Maybe::into_option)
.collect()
}),
upgrade: flag(upgrade, no_upgrade, "no-upgrade"),
upgrade_package: Some(upgrade_package),
upgrade: UpgradeSelection::from_args(
flag(upgrade, no_upgrade, "no-upgrade"),
upgrade_package.into_iter().map(Requirement::from).collect(),
),
index_strategy,
keyring_provider,
resolution,
Expand Down Expand Up @@ -442,12 +445,10 @@ pub fn resolver_installer_options(
.filter_map(Maybe::into_option)
.collect()
}),
upgrade: flag(upgrade, no_upgrade, "upgrade"),
upgrade_package: if upgrade_package.is_empty() {
None
} else {
Some(upgrade_package)
},
upgrade: UpgradeSelection::from_args(
flag(upgrade, no_upgrade, "upgrade"),
upgrade_package.into_iter().map(Requirement::from).collect(),
),
reinstall: flag(reinstall, no_reinstall, "reinstall"),
reinstall_package: if reinstall_package.is_empty() {
None
Expand Down
92 changes: 69 additions & 23 deletions crates/uv-configuration/src/package_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,57 @@ impl From<Reinstall> for Refresh {
}
}

/// An upgrade selection as specified by a user on the command line or in a configuration file.
#[derive(Debug, Default, Clone)]
pub enum UpgradeSelection {
/// Prefer pinned versions from the existing lockfile, if possible.
#[default]
None,

/// Allow package upgrades for all packages, ignoring the existing lockfile.
All,

/// Allow package upgrades, but only for the specified packages.
Packages(Vec<Requirement>),
}

impl UpgradeSelection {
/// Determine the upgrade selection strategy from the command-line arguments.
pub fn from_args(upgrade: Option<bool>, upgrade_package: Vec<Requirement>) -> Option<Self> {
match upgrade {
Some(true) => Some(Self::All),
// TODO(charlie): `--no-upgrade` with `--upgrade-package` should allow the specified
// packages to be upgraded. Right now, `--upgrade-package` is silently ignored.
Some(false) => Some(Self::None),
None if upgrade_package.is_empty() => None,
None => Some(Self::Packages(upgrade_package)),
}
}

/// Combine a set of [`UpgradeSelection`] values.
#[must_use]
pub fn combine(self, other: Self) -> Self {
match self {
// Setting `--upgrade` or `--no-upgrade` should clear previous `--upgrade-package` selections.
Self::All | Self::None => self,
Self::Packages(self_packages) => match other {
// If `--upgrade` was enabled previously, `--upgrade-package` is subsumed by upgrading all packages.
Self::All => other,
// If `--no-upgrade` was enabled previously, then `--upgrade-package` enables an explicit upgrade of those packages.
Self::None => Self::Packages(self_packages),
// If `--upgrade-package` was included twice, combine the requirements.
Self::Packages(other_packages) => {
let mut combined = self_packages;
combined.extend(other_packages);
Self::Packages(combined)
}
},
}
}
}

/// Whether to allow package upgrades.
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case", deny_unknown_fields)]
#[derive(Debug, Default, Clone)]
pub enum Upgrade {
/// Prefer pinned versions from the existing lockfile, if possible.
#[default]
Expand All @@ -149,30 +197,28 @@ pub enum Upgrade {
Packages(FxHashMap<PackageName, Vec<Requirement>>),
}

impl Upgrade {
/// Determine the [`Upgrade`] strategy from the command-line arguments.
pub fn from_args(upgrade: Option<bool>, upgrade_package: Vec<Requirement>) -> Self {
match upgrade {
Some(true) => Self::All,
Some(false) => Self::None,
None => {
if upgrade_package.is_empty() {
Self::None
} else {
Self::Packages(upgrade_package.into_iter().fold(
FxHashMap::default(),
|mut map, requirement| {
map.entry(requirement.name.clone())
.or_default()
.push(requirement);
map
},
))
}
}
/// Determine the [`Upgrade`] strategy from the command-line arguments.
impl From<Option<UpgradeSelection>> for Upgrade {
fn from(value: Option<UpgradeSelection>) -> Self {
match value {
None => Self::None,
Some(UpgradeSelection::None) => Self::None,
Some(UpgradeSelection::All) => Self::All,
Some(UpgradeSelection::Packages(requirements)) => Self::Packages(
requirements
.into_iter()
.fold(FxHashMap::default(), |mut map, requirement| {
map.entry(requirement.name.clone())
.or_default()
.push(requirement);
map
}),
),
}
}
}

impl Upgrade {
/// Create an [`Upgrade`] strategy to upgrade a single package.
pub fn package(package_name: PackageName) -> Self {
Self::Packages({
Expand Down
4 changes: 2 additions & 2 deletions crates/uv-scripts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use uv_pep440::VersionSpecifiers;
use uv_pep508::PackageName;
use uv_pypi_types::VerbatimParsedUrl;
use uv_redacted::DisplaySafeUrl;
use uv_settings::{GlobalOptions, ResolverInstallerOptions};
use uv_settings::{GlobalOptions, ResolverInstallerSchema};
use uv_warnings::warn_user;
use uv_workspace::pyproject::{ExtraBuildDependency, Sources};

Expand Down Expand Up @@ -424,7 +424,7 @@ pub struct ToolUv {
#[serde(flatten)]
pub globals: GlobalOptions,
#[serde(flatten)]
pub top_level: ResolverInstallerOptions,
pub top_level: ResolverInstallerSchema,
pub override_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub build_constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
Expand Down
11 changes: 10 additions & 1 deletion crates/uv-settings/src/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use url::Url;

use uv_configuration::{
ExportFormat, IndexStrategy, KeyringProviderType, RequiredVersion, TargetTriple,
TrustedPublishing,
TrustedPublishing, UpgradeSelection,
};
use uv_distribution_types::{
ConfigSettings, ExtraBuildVariables, Index, IndexUrl, PackageConfigSettings, PipExtraIndex,
Expand Down Expand Up @@ -181,6 +181,15 @@ impl Combine for Option<PackageConfigSettings> {
}
}

impl Combine for Option<UpgradeSelection> {
fn combine(self, other: Self) -> Self {
match (self, other) {
(Some(a), Some(b)) => Some(a.combine(b)),
(a, b) => a.or(b),
}
}
}

impl Combine for serde::de::IgnoredAny {
fn combine(self, _other: Self) -> Self {
self
Expand Down
2 changes: 1 addition & 1 deletion crates/uv-settings/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn warn_uv_toml_masked_fields(options: &Options) {
allow_insecure_host,
},
top_level:
ResolverInstallerOptions {
ResolverInstallerSchema {
index,
index_url,
extra_index_url,
Expand Down
Loading
Loading