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:
Charlie Marsh 2024-04-15 16:24:08 -04:00 committed by GitHub
parent 37a43f4b48
commit 1f626bfc73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 96 additions and 61 deletions

View file

@ -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")]

View 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)
}
}

View file

@ -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;

View file

@ -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
}

View file

@ -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 {

View file

@ -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.

View file

@ -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 {

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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'.
"###