diff --git a/Cargo.lock b/Cargo.lock index 820e00c0cb..65016a2eeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1747,7 +1747,7 @@ dependencies = [ "gix-date", "gix-object", "gix-worktree-stream", - "jiff", + "jiff 0.1.29", "thiserror 2.0.12", ] @@ -1871,7 +1871,7 @@ checksum = "c57c477b645ee248b173bb1176b52dd528872f12c50375801a58aaf5ae91113f" dependencies = [ "bstr", "itoa", - "jiff", + "jiff 0.1.29", "thiserror 2.0.12", ] @@ -2746,12 +2746,6 @@ dependencies = [ "libm", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "hyper" version = "1.6.0" @@ -3279,6 +3273,32 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "jiff" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d699bc6dfc879fb1bf9bdff0d4c56f0884fc6f0d0eb0fba397a6d00cd9a6b85e" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", + "windows-sys 0.59.0", +] + +[[package]] +name = "jiff-static" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "jiff-tzdb" version = "0.1.3" @@ -3672,13 +3692,13 @@ dependencies = [ "globset", "heck 0.5.0", "homedir", - "humantime", "indenter", "indexmap 2.7.1", "indicatif", "indoc", "insta", "itertools 0.14.0", + "jiff 0.2.4", "junction", "log", "md-5", diff --git a/Cargo.toml b/Cargo.toml index 5f093d6862..21f1d17d16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,6 @@ fslock = "0.2.1" glob = "0.3" globset = "0.4" heck = "0.5" -humantime = "2" indenter = "0.3" indexmap = { version = "2", features = ["serde"] } indicatif = { version = "0.17", features = ["default", "improved_unicode"] } @@ -151,6 +150,7 @@ xz2 = "0.1" zip = { version = "2", default-features = false, features = ["deflate"] } zstd = "0.13" gix = { version = "<1", features = ["worktree-mutation"] } +jiff = "0.2" [target.'cfg(unix)'.dependencies] exec = "0.3" diff --git a/deny.toml b/deny.toml index 825aa85388..6b9aab2f7a 100644 --- a/deny.toml +++ b/deny.toml @@ -72,7 +72,6 @@ feature-depth = 1 ignore = [ { id = "RUSTSEC-2024-0370", reason = "subdependency cannot be updated" }, { id = "RUSTSEC-2024-0436", reason = "subdependency cannot be updated" }, - { id = "RUSTSEC-2025-0014", reason = "humantime is unmaintained" }, #"RUSTSEC-0000-0000", #{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" }, #"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish diff --git a/src/cli/settings/set.rs b/src/cli/settings/set.rs index df26b7eb41..3d3634e04a 100644 --- a/src/cli/settings/set.rs +++ b/src/cli/settings/set.rs @@ -2,7 +2,7 @@ use eyre::{Result, bail, eyre}; use toml_edit::DocumentMut; use crate::config::settings::{SETTINGS_META, SettingsFile, SettingsType}; -use crate::{config, file}; +use crate::{config, duration, file}; /// Add/update a setting /// @@ -107,7 +107,7 @@ fn parse_i64(value: &str) -> Result { } fn parse_duration(value: &str) -> Result { - humantime::parse_duration(value)?; + duration::parse_duration(value)?; Ok(value.into()) } diff --git a/src/config/settings.rs b/src/config/settings.rs index 42d1a19fd3..6adc233f92 100644 --- a/src/config/settings.rs +++ b/src/config/settings.rs @@ -1,5 +1,6 @@ use crate::cli::Cli; use crate::config::ALL_TOML_CONFIG_FILES; +use crate::duration; use crate::file::FindUp; use crate::{dirs, env, file}; #[allow(unused_imports)] @@ -364,14 +365,12 @@ impl Settings { } pub fn cache_prune_age_duration(&self) -> Option { - if self.cache_prune_age == "0" { - return None; - } - Some(humantime::parse_duration(&self.cache_prune_age).unwrap()) + let age = duration::parse_duration(&self.cache_prune_age).unwrap(); + if age.as_secs() == 0 { None } else { Some(age) } } pub fn fetch_remote_versions_timeout(&self) -> Duration { - humantime::parse_duration(&self.fetch_remote_versions_timeout).unwrap() + duration::parse_duration(&self.fetch_remote_versions_timeout).unwrap() } /// duration that remote version cache is kept for @@ -383,10 +382,14 @@ impl Settings { if *env::PREFER_STALE { None } else { - Some(humantime::parse_duration(&self.fetch_remote_versions_cache).unwrap()) + Some(duration::parse_duration(&self.fetch_remote_versions_cache).unwrap()) } } + pub fn http_timeout(&self) -> Duration { + duration::parse_duration(&self.http_timeout).unwrap() + } + pub fn log_level(&self) -> log::LevelFilter { self.log_level.parse().unwrap_or(log::LevelFilter::Info) } diff --git a/src/duration.rs b/src/duration.rs index 71483602e2..e0524f72d1 100644 --- a/src/duration.rs +++ b/src/duration.rs @@ -1,5 +1,22 @@ pub use std::time::Duration; +use eyre::{Result, bail}; +use jiff::{Span, civil::date}; + pub const HOURLY: Duration = Duration::from_secs(60 * 60); pub const DAILY: Duration = Duration::from_secs(60 * 60 * 24); pub const WEEKLY: Duration = Duration::from_secs(60 * 60 * 24 * 7); + +pub fn parse_duration(s: &str) -> Result { + match s.parse::() { + Ok(span) => { + // we must provide a relative date to determine the duration with months and years + let duration = span.to_duration(date(2025, 1, 1))?; + if duration.is_negative() { + bail!("duration must not be negative: {}", s); + } + Ok(duration.unsigned_abs()) + } + Err(_) => Ok(Duration::from_secs(s.parse()?)), + } +} diff --git a/src/http.rs b/src/http.rs index 6e7927f06e..f9973b4d1f 100644 --- a/src/http.rs +++ b/src/http.rs @@ -19,16 +19,10 @@ use crate::{env, file}; pub static HTTP_VERSION_CHECK: Lazy = Lazy::new(|| Client::new(Duration::from_secs(3)).unwrap()); -pub static HTTP: Lazy = Lazy::new(|| { - let duration = humantime::parse_duration(&SETTINGS.http_timeout) - .unwrap_or_else(|_| Duration::from_secs(SETTINGS.http_timeout.parse().unwrap())); - Client::new(duration).unwrap() -}); - -pub static HTTP_FETCH: Lazy = Lazy::new(|| { - Client::new(humantime::parse_duration(&SETTINGS.fetch_remote_versions_timeout).unwrap()) - .unwrap() -}); +pub static HTTP: Lazy = Lazy::new(|| Client::new(SETTINGS.http_timeout()).unwrap()); + +pub static HTTP_FETCH: Lazy = + Lazy::new(|| Client::new(SETTINGS.fetch_remote_versions_timeout()).unwrap()); #[derive(Debug)] pub struct Client { diff --git a/src/tera.rs b/src/tera.rs index 9e8a025f00..431606f2c7 100644 --- a/src/tera.rs +++ b/src/tera.rs @@ -13,7 +13,7 @@ use versions::{Requirement, Versioning}; use crate::cache::CacheManagerBuilder; use crate::cmd::cmd; use crate::env_diff::EnvMap; -use crate::{dirs, env, hash}; +use crate::{dirs, duration, env, hash}; pub static BASE_CONTEXT: Lazy = Lazy::new(|| { let mut context = Context::new(); @@ -314,11 +314,12 @@ pub fn tera_exec( _ => return Err("exec cache_key must be a string".into()), }; let cache_duration = match args.get("cache_duration") { - Some(Value::String(duration)) => match humantime::parse_duration(&duration.to_string()) - { - Ok(duration) => Some(duration), - Err(e) => return Err(format!("exec cache_duration: {}", e).into()), - }, + Some(Value::String(duration)) => { + match duration::parse_duration(&duration.to_string()) { + Ok(duration) => Some(duration), + Err(e) => return Err(format!("exec cache_duration: {}", e).into()), + } + } None => None, _ => return Err("exec cache_duration must be an integer".into()), };