mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-01 09:32:18 +00:00
Move ExcludeNewer
into its own type (#3041)
## Summary This makes it easier to add (e.g.) JSON Schema derivations to the type. If we have support for other dates in the future, we can generalize it to a `UserDate` or similar.
This commit is contained in:
parent
37a43f4b48
commit
1f626bfc73
12 changed files with 96 additions and 61 deletions
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||
|
||||
use anstream::println;
|
||||
use anyhow::{Context, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use fs_err::File;
|
||||
use itertools::Itertools;
|
||||
|
@ -17,7 +17,7 @@ use uv_configuration::{ConfigSettings, NoBinary, NoBuild, SetupPyStrategy};
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_installer::SitePackages;
|
||||
use uv_interpreter::PythonEnvironment;
|
||||
use uv_resolver::{FlatIndex, InMemoryIndex, Manifest, Options, Resolver};
|
||||
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, Manifest, Options, Resolver};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
#[derive(ValueEnum, Default, Clone)]
|
||||
|
@ -42,7 +42,7 @@ pub(crate) struct ResolveCliArgs {
|
|||
#[command(flatten)]
|
||||
cache_args: CacheArgs,
|
||||
#[arg(long)]
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
#[clap(long, short, env = "UV_INDEX_URL")]
|
||||
index_url: Option<IndexUrl>,
|
||||
#[clap(long, env = "UV_EXTRA_INDEX_URL")]
|
||||
|
|
53
crates/uv-resolver/src/exclude_newer.rs
Normal file
53
crates/uv-resolver/src/exclude_newer.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use chrono::{DateTime, Days, NaiveDate, NaiveTime, Utc};
|
||||
|
||||
/// A timestamp that excludes files newer than it.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ExcludeNewer(DateTime<Utc>);
|
||||
|
||||
impl ExcludeNewer {
|
||||
/// Returns the timestamp in milliseconds.
|
||||
pub fn timestamp_millis(&self) -> i64 {
|
||||
self.0.timestamp_millis()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DateTime<Utc>> for ExcludeNewer {
|
||||
fn from(datetime: DateTime<Utc>) -> Self {
|
||||
Self(datetime)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ExcludeNewer {
|
||||
type Err = String;
|
||||
|
||||
/// Parse an [`ExcludeNewer`] from a string.
|
||||
///
|
||||
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and UTC dates in the same
|
||||
/// format (e.g., `2006-12-02`).
|
||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||
let date_err = match NaiveDate::from_str(input) {
|
||||
Ok(date) => {
|
||||
// Midnight that day is 00:00:00 the next day
|
||||
return Ok(Self(
|
||||
(date + Days::new(1)).and_time(NaiveTime::MIN).and_utc(),
|
||||
));
|
||||
}
|
||||
Err(err) => err,
|
||||
};
|
||||
let datetime_err = match DateTime::parse_from_rfc3339(input) {
|
||||
Ok(datetime) => return Ok(Self(datetime.with_timezone(&Utc))),
|
||||
Err(err) => err,
|
||||
};
|
||||
Err(format!(
|
||||
"`{input}` is neither a valid date ({date_err}) nor a valid datetime ({datetime_err})"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ExcludeNewer {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
pub use dependency_mode::DependencyMode;
|
||||
pub use error::ResolveError;
|
||||
pub use exclude_newer::ExcludeNewer;
|
||||
pub use exclusions::Exclusions;
|
||||
pub use flat_index::FlatIndex;
|
||||
pub use manifest::Manifest;
|
||||
|
@ -24,6 +25,7 @@ mod dependency_mode;
|
|||
mod dependency_provider;
|
||||
mod editables;
|
||||
mod error;
|
||||
mod exclude_newer;
|
||||
mod exclusions;
|
||||
mod flat_index;
|
||||
mod manifest;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::{DependencyMode, PreReleaseMode, ResolutionMode};
|
||||
use crate::{DependencyMode, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
|
||||
/// Options for resolving a manifest.
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
|
@ -8,7 +6,7 @@ pub struct Options {
|
|||
pub resolution_mode: ResolutionMode,
|
||||
pub prerelease_mode: PreReleaseMode,
|
||||
pub dependency_mode: DependencyMode,
|
||||
pub exclude_newer: Option<DateTime<Utc>>,
|
||||
pub exclude_newer: Option<ExcludeNewer>,
|
||||
}
|
||||
|
||||
/// Builder for [`Options`].
|
||||
|
@ -17,7 +15,7 @@ pub struct OptionsBuilder {
|
|||
resolution_mode: ResolutionMode,
|
||||
prerelease_mode: PreReleaseMode,
|
||||
dependency_mode: DependencyMode,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
}
|
||||
|
||||
impl OptionsBuilder {
|
||||
|
@ -49,7 +47,7 @@ impl OptionsBuilder {
|
|||
|
||||
/// Sets the exclusion date.
|
||||
#[must_use]
|
||||
pub fn exclude_newer(mut self, exclude_newer: Option<DateTime<Utc>>) -> Self {
|
||||
pub fn exclude_newer(mut self, exclude_newer: Option<ExcludeNewer>) -> Self {
|
||||
self.exclude_newer = exclude_newer;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use std::future::Future;
|
||||
|
||||
use anyhow::Result;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use distribution_types::{Dist, IndexLocations};
|
||||
use platform_tags::Tags;
|
||||
|
||||
use uv_client::RegistryClient;
|
||||
use uv_configuration::{NoBinary, NoBuild};
|
||||
use uv_distribution::{ArchiveMetadata, DistributionDatabase};
|
||||
|
@ -16,6 +14,7 @@ use crate::flat_index::FlatIndex;
|
|||
use crate::python_requirement::PythonRequirement;
|
||||
use crate::version_map::VersionMap;
|
||||
use crate::yanks::AllowedYanks;
|
||||
use crate::ExcludeNewer;
|
||||
|
||||
pub type PackageVersionsResult = Result<VersionsResponse, uv_client::Error>;
|
||||
pub type WheelMetadataResult = Result<MetadataResponse, uv_distribution::Error>;
|
||||
|
@ -84,7 +83,7 @@ pub struct DefaultResolverProvider<'a, Context: BuildContext + Send + Sync> {
|
|||
python_requirement: PythonRequirement,
|
||||
allowed_yanks: AllowedYanks,
|
||||
hasher: HashStrategy,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
no_binary: NoBinary,
|
||||
no_build: NoBuild,
|
||||
}
|
||||
|
@ -100,7 +99,7 @@ impl<'a, Context: BuildContext + Send + Sync> DefaultResolverProvider<'a, Contex
|
|||
python_requirement: PythonRequirement,
|
||||
allowed_yanks: AllowedYanks,
|
||||
hasher: &'a HashStrategy,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
no_binary: &'a NoBinary,
|
||||
no_build: &'a NoBuild,
|
||||
) -> Self {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use std::collections::btree_map::{BTreeMap, Entry};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use rkyv::{de::deserializers::SharedDeserializeMap, Deserialize};
|
||||
use rustc_hash::FxHashSet;
|
||||
use tracing::instrument;
|
||||
|
@ -21,7 +20,7 @@ use uv_types::HashStrategy;
|
|||
use uv_warnings::warn_user_once;
|
||||
|
||||
use crate::flat_index::FlatDistributions;
|
||||
use crate::{python_requirement::PythonRequirement, yanks::AllowedYanks};
|
||||
use crate::{python_requirement::PythonRequirement, yanks::AllowedYanks, ExcludeNewer};
|
||||
|
||||
/// A map from versions to distributions.
|
||||
#[derive(Debug)]
|
||||
|
@ -49,7 +48,7 @@ impl VersionMap {
|
|||
python_requirement: &PythonRequirement,
|
||||
allowed_yanks: &AllowedYanks,
|
||||
hasher: &HashStrategy,
|
||||
exclude_newer: Option<&DateTime<Utc>>,
|
||||
exclude_newer: Option<&ExcludeNewer>,
|
||||
flat_index: Option<FlatDistributions>,
|
||||
no_binary: &NoBinary,
|
||||
no_build: &NoBuild,
|
||||
|
@ -304,7 +303,7 @@ struct VersionMapLazy {
|
|||
/// exists) is satisfied or not.
|
||||
python_requirement: PythonRequirement,
|
||||
/// Whether files newer than this timestamp should be excluded or not.
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
/// Which yanked versions are allowed
|
||||
allowed_yanks: FxHashSet<Version>,
|
||||
/// The hashes of allowed distributions.
|
||||
|
|
|
@ -18,7 +18,7 @@ use uv_client::RegistryClientBuilder;
|
|||
use uv_configuration::{BuildKind, Constraints, NoBinary, NoBuild, Overrides, SetupPyStrategy};
|
||||
use uv_interpreter::{find_default_python, Interpreter, PythonEnvironment};
|
||||
use uv_resolver::{
|
||||
DisplayResolutionGraph, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options,
|
||||
DisplayResolutionGraph, ExcludeNewer, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options,
|
||||
OptionsBuilder, PreReleaseMode, Preference, ResolutionGraph, ResolutionMode, Resolver,
|
||||
};
|
||||
use uv_types::{
|
||||
|
@ -26,10 +26,12 @@ use uv_types::{
|
|||
};
|
||||
|
||||
// Exclude any packages uploaded after this date.
|
||||
static EXCLUDE_NEWER: Lazy<DateTime<Utc>> = Lazy::new(|| {
|
||||
DateTime::parse_from_rfc3339("2023-11-18T12:00:00Z")
|
||||
.unwrap()
|
||||
.with_timezone(&Utc)
|
||||
static EXCLUDE_NEWER: Lazy<ExcludeNewer> = Lazy::new(|| {
|
||||
ExcludeNewer::from(
|
||||
DateTime::parse_from_rfc3339("2023-11-18T12:00:00Z")
|
||||
.unwrap()
|
||||
.with_timezone(&Utc),
|
||||
)
|
||||
});
|
||||
|
||||
struct DummyContext {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::path::PathBuf;
|
|||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use chrono::{DateTime, Days, NaiveDate, NaiveTime, Utc};
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
|
||||
use distribution_types::{FlatIndexLocation, IndexUrl};
|
||||
|
@ -11,7 +11,7 @@ use uv_cache::CacheArgs;
|
|||
use uv_configuration::IndexStrategy;
|
||||
use uv_configuration::{ConfigSettingEntry, PackageNameSpecifier};
|
||||
use uv_normalize::{ExtraName, PackageName};
|
||||
use uv_resolver::{AnnotationStyle, PreReleaseMode, ResolutionMode};
|
||||
use uv_resolver::{AnnotationStyle, ExcludeNewer, PreReleaseMode, ResolutionMode};
|
||||
use uv_toolchain::PythonVersion;
|
||||
|
||||
use crate::commands::{extra_name_with_clap_error, ListFormat, VersionFormat};
|
||||
|
@ -178,24 +178,6 @@ pub(crate) enum PipCommand {
|
|||
Check(PipCheckArgs),
|
||||
}
|
||||
|
||||
/// Clap parser for the union of date and datetime
|
||||
fn date_or_datetime(input: &str) -> Result<DateTime<Utc>, String> {
|
||||
let date_err = match NaiveDate::from_str(input) {
|
||||
Ok(date) => {
|
||||
// Midnight that day is 00:00:00 the next day
|
||||
return Ok((date + Days::new(1)).and_time(NaiveTime::MIN).and_utc());
|
||||
}
|
||||
Err(err) => err,
|
||||
};
|
||||
let datetime_err = match DateTime::parse_from_rfc3339(input) {
|
||||
Ok(datetime) => return Ok(datetime.with_timezone(&Utc)),
|
||||
Err(err) => err,
|
||||
};
|
||||
Err(format!(
|
||||
"Neither a valid date ({date_err}) not a valid datetime ({datetime_err})"
|
||||
))
|
||||
}
|
||||
|
||||
/// A re-implementation of `Option`, used to avoid Clap's automatic `Option` flattening in
|
||||
/// [`parse_index_url`].
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -446,8 +428,8 @@ pub(crate) struct PipCompileArgs {
|
|||
///
|
||||
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and UTC dates in the same
|
||||
/// format (e.g., `2006-12-02`).
|
||||
#[arg(long, value_parser = date_or_datetime)]
|
||||
pub(crate) exclude_newer: Option<DateTime<Utc>>,
|
||||
#[arg(long)]
|
||||
pub(crate) exclude_newer: Option<ExcludeNewer>,
|
||||
|
||||
/// Specify a package to omit from the output resolution. Its dependencies will still be
|
||||
/// included in the resolution. Equivalent to pip-compile's `--unsafe-package` option.
|
||||
|
@ -965,8 +947,8 @@ pub(crate) struct PipInstallArgs {
|
|||
///
|
||||
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and UTC dates in the same
|
||||
/// format (e.g., `2006-12-02`).
|
||||
#[arg(long, value_parser = date_or_datetime)]
|
||||
pub(crate) exclude_newer: Option<DateTime<Utc>>,
|
||||
#[arg(long)]
|
||||
pub(crate) exclude_newer: Option<ExcludeNewer>,
|
||||
|
||||
/// Perform a dry run, i.e., don't actually install anything but resolve the dependencies and
|
||||
/// print the resulting plan.
|
||||
|
@ -1309,8 +1291,8 @@ pub(crate) struct VenvArgs {
|
|||
///
|
||||
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and UTC dates in the same
|
||||
/// format (e.g., `2006-12-02`).
|
||||
#[arg(long, value_parser = date_or_datetime)]
|
||||
pub(crate) exclude_newer: Option<DateTime<Utc>>,
|
||||
#[arg(long)]
|
||||
pub(crate) exclude_newer: Option<ExcludeNewer>,
|
||||
|
||||
#[command(flatten)]
|
||||
pub(crate) compat_args: compat::VenvCompatArgs,
|
||||
|
|
|
@ -8,7 +8,6 @@ use std::str::FromStr;
|
|||
|
||||
use anstream::{eprint, AutoStream, StripStream};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use tempfile::tempdir_in;
|
||||
|
@ -35,8 +34,9 @@ use uv_requirements::{
|
|||
RequirementsSource, RequirementsSpecification, SourceTreeResolver,
|
||||
};
|
||||
use uv_resolver::{
|
||||
AnnotationStyle, DependencyMode, DisplayResolutionGraph, Exclusions, FlatIndex, InMemoryIndex,
|
||||
Manifest, OptionsBuilder, PreReleaseMode, PythonRequirement, ResolutionMode, Resolver,
|
||||
AnnotationStyle, DependencyMode, DisplayResolutionGraph, ExcludeNewer, Exclusions, FlatIndex,
|
||||
InMemoryIndex, Manifest, OptionsBuilder, PreReleaseMode, PythonRequirement, ResolutionMode,
|
||||
Resolver,
|
||||
};
|
||||
use uv_toolchain::PythonVersion;
|
||||
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy, InFlight};
|
||||
|
@ -77,7 +77,7 @@ pub(crate) async fn pip_compile(
|
|||
no_build_isolation: bool,
|
||||
no_build: NoBuild,
|
||||
python_version: Option<PythonVersion>,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
annotation_style: AnnotationStyle,
|
||||
native_tls: bool,
|
||||
quiet: bool,
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::path::Path;
|
|||
|
||||
use anstream::eprint;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use itertools::Itertools;
|
||||
use owo_colors::OwoColorize;
|
||||
use tempfile::tempdir_in;
|
||||
|
@ -38,8 +38,8 @@ use uv_requirements::{
|
|||
RequirementsSpecification, SourceTreeResolver,
|
||||
};
|
||||
use uv_resolver::{
|
||||
DependencyMode, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options, OptionsBuilder,
|
||||
PreReleaseMode, Preference, ResolutionGraph, ResolutionMode, Resolver,
|
||||
DependencyMode, ExcludeNewer, Exclusions, FlatIndex, InMemoryIndex, Manifest, Options,
|
||||
OptionsBuilder, PreReleaseMode, Preference, ResolutionGraph, ResolutionMode, Resolver,
|
||||
};
|
||||
use uv_types::{BuildIsolation, HashStrategy, InFlight};
|
||||
use uv_warnings::warn_user;
|
||||
|
@ -75,7 +75,7 @@ pub(crate) async fn pip_install(
|
|||
no_build: NoBuild,
|
||||
no_binary: NoBinary,
|
||||
strict: bool,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
python: Option<String>,
|
||||
system: bool,
|
||||
break_system_packages: bool,
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::vec;
|
|||
|
||||
use anstream::eprint;
|
||||
use anyhow::Result;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use itertools::Itertools;
|
||||
use miette::{Diagnostic, IntoDiagnostic};
|
||||
use owo_colors::OwoColorize;
|
||||
|
@ -21,7 +21,7 @@ use uv_configuration::{ConfigSettings, IndexStrategy, NoBinary, NoBuild, SetupPy
|
|||
use uv_dispatch::BuildDispatch;
|
||||
use uv_fs::Simplified;
|
||||
use uv_interpreter::{find_default_python, find_requested_python, Error};
|
||||
use uv_resolver::{FlatIndex, InMemoryIndex, OptionsBuilder};
|
||||
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder};
|
||||
use uv_types::{BuildContext, BuildIsolation, HashStrategy, InFlight};
|
||||
|
||||
use crate::commands::ExitStatus;
|
||||
|
@ -41,7 +41,7 @@ pub(crate) async fn venv(
|
|||
system_site_packages: bool,
|
||||
connectivity: Connectivity,
|
||||
seed: bool,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
native_tls: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
|
@ -104,7 +104,7 @@ async fn venv_impl(
|
|||
system_site_packages: bool,
|
||||
connectivity: Connectivity,
|
||||
seed: bool,
|
||||
exclude_newer: Option<DateTime<Utc>>,
|
||||
exclude_newer: Option<ExcludeNewer>,
|
||||
native_tls: bool,
|
||||
cache: &Cache,
|
||||
printer: Printer,
|
||||
|
|
|
@ -2253,7 +2253,7 @@ fn compile_exclude_newer() -> Result<()> {
|
|||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: invalid value '2022-04-04+02:00' for '--exclude-newer <EXCLUDE_NEWER>': Neither a valid date (trailing input) not a valid datetime (input contains invalid characters)
|
||||
error: invalid value '2022-04-04+02:00' for '--exclude-newer <EXCLUDE_NEWER>': `2022-04-04+02:00` is neither a valid date (trailing input) nor a valid datetime (input contains invalid characters)
|
||||
|
||||
For more information, try '--help'.
|
||||
"###
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue