data,apt/release,distro_info,new: replace lazy_static with LazyLock

Unify the lazily-initialized statics on std::sync::LazyLock, which the
newer code already uses: the embed_data! macro expands to a plain
static now, which also removes the visibility-forwarding workaround the
lazy_static! matcher forced on it (the @expand arm wrapping vis in
parentheses), and the 'static ref' spelling is kept at the call sites.
distro_info's HTTP client, the apt keyring cache and the new-template
registry follow the same pattern.
This commit is contained in:
2026-10-03 02:17:22 +02:00
parent dc01812847
commit 239bcb28df
4 changed files with 36 additions and 49 deletions
+5 -6
View File
@@ -45,7 +45,6 @@
//! keyserver responses are armored) are dearmored in-process, so no `gpg` //! keyserver responses are armored) are dearmored in-process, so no `gpg`
//! binary is needed. //! binary is needed.
use lazy_static::lazy_static;
use log::{debug, warn}; use log::{debug, warn};
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
@@ -53,6 +52,7 @@ use std::error::Error;
use std::fmt; use std::fmt;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::LazyLock;
use std::sync::Mutex; use std::sync::Mutex;
use std::sync::PoisonError; use std::sync::PoisonError;
@@ -793,11 +793,10 @@ async fn fetch_optional(url: &str) -> Option<Vec<u8>> {
None None
} }
lazy_static! { /// Downloaded keyrings, keyed by URL: keyrings are small but would
/// Downloaded keyrings, keyed by URL: keyrings are small but would /// otherwise be re-downloaded once per series/pocket lookup
/// otherwise be re-downloaded once per series/pocket lookup static KEYRING_CACHE: LazyLock<Mutex<HashMap<String, Vec<u8>>>> =
static ref KEYRING_CACHE: Mutex<HashMap<String, Vec<u8>>> = Mutex::new(HashMap::new()); LazyLock::new(|| Mutex::new(HashMap::new()));
}
/// Read the keyring cache, ignoring poisoning (the map is only corrupted on /// Read the keyring cache, ignoring poisoning (the map is only corrupted on
/// panics, in which case a fresh map is just as good) /// panics, in which case a fresh map is just as good)
+13 -24
View File
@@ -13,7 +13,7 @@
//! data/quirks.yml) through the [`embed_data!`] macro below, so data //! data/quirks.yml) through the [`embed_data!`] macro below, so data
//! and its accessors stay together and a diff touching one domain cannot //! and its accessors stay together and a diff touching one domain cannot
//! half-touch another. The macro embeds the file at compile time and //! half-touch another. The macro embeds the file at compile time and
//! parses it once into a `lazy_static` on first use; since the data ships //! parses it once into a [`LazyLock`] on first use; since the data ships
//! inside the binary, a parse failure is a build-time bug that cannot be //! inside the binary, a parse failure is a build-time bug that cannot be
//! recovered from at runtime, and the macro panics on it. //! recovered from at runtime, and the macro panics on it.
//! //!
@@ -30,8 +30,9 @@
/// the invoking source file (`"../data/distro_info.yml"` from /// the invoking source file (`"../data/distro_info.yml"` from
/// `src/distro_info.rs`, `"../../data/host_keys.yml"` from /// `src/distro_info.rs`, `"../../data/host_keys.yml"` from
/// `src/put/ssh.rs`, ...), and expands to the house `include_str!` → /// `src/put/ssh.rs`, ...), and expands to the house `include_str!` →
/// `lazy_static` → parse pattern — only the embed+parse boilerplate is /// parse-on-first-use pattern — only the embed+parse boilerplate is
/// generated. /// generated. The `static ref` spelling is kept from the macro's
/// `lazy_static!` ancestry; it expands to a plain `LazyLock` static.
/// ///
/// ```ignore /// ```ignore
/// embed_data! { /// embed_data! {
@@ -39,31 +40,19 @@
/// } /// }
/// ``` /// ```
macro_rules! embed_data { macro_rules! embed_data {
// Internal arm: the visibility arrives wrapped in parentheses (empty for ($vis:vis static ref $name:ident : $ty:ty = $path:literal) => {
// private statics) because `lazy_static!` only re-matches literal // The YAML is include_str!'d at compile time and statically
// `pub`/`pub(...)` token sequences, not an opaque forwarded `vis`. // valid; if it ever failed to parse it would be a build-time bug
(@expand ($($vis:tt)*) static ref $name:ident : $ty:ty = $path:literal) => { // that cannot be recovered from at runtime, so panicking here is
lazy_static::lazy_static! { // acceptable.
// The YAML is include_str!'d at compile time and statically $vis static $name: ::std::sync::LazyLock<$ty> = ::std::sync::LazyLock::new(|| {
// valid; if it ever failed to parse it would be a build-time bug serde_yaml::from_str(include_str!($path))
// that cannot be recovered from at runtime, so panicking here is
// acceptable.
$($vis)* static ref $name: $ty = serde_yaml::from_str(include_str!($path))
.expect(concat!( .expect(concat!(
"built-in ", "built-in ",
$path, $path,
" data is statically valid and must parse" " data is statically valid and must parse"
)); ))
} });
};
(static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand () static ref $name : $ty = $path);
};
(pub static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand (pub) static ref $name : $ty = $path);
};
(pub ($($vis:tt)+) static ref $name:ident : $ty:ty = $path:literal) => {
$crate::data::embed_data!(@expand (pub ($($vis)+)) static ref $name : $ty = $path);
}; };
} }
+10 -10
View File
@@ -1,10 +1,10 @@
use crate::data::embed_data; use crate::data::embed_data;
use chrono::NaiveDate; use chrono::NaiveDate;
use lazy_static::lazy_static;
use serde::Deserialize; use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use std::sync::LazyLock;
use std::time::Duration; use std::time::Duration;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -104,20 +104,20 @@ embed_data! {
static ref DATA: Data = "../data/distro_info.yml" static ref DATA: Data = "../data/distro_info.yml"
} }
lazy_static! { // Shared HTTP client used for all outgoing plain requests: timeouts keep
// Shared HTTP client used for all outgoing plain requests: timeouts keep // a hanging remote (connect or transfer) from stalling pkh indefinitely.
// a hanging remote (connect or transfer) from stalling pkh indefinitely. // The short pool idle timeout and TCP keepalive avoid reusing keep-alive
// The short pool idle timeout and TCP keepalive avoid reusing keep-alive // connections that the remote closed in the meantime, which surfaces as
// connections that the remote closed in the meantime, which surfaces as // spurious 'error sending request' failures on busy mirrors/CDNs.
// spurious 'error sending request' failures on busy mirrors/CDNs. static HTTP_CLIENT: LazyLock<reqwest::Client> = LazyLock::new(|| {
static ref HTTP_CLIENT: reqwest::Client = reqwest::Client::builder() reqwest::Client::builder()
.connect_timeout(Duration::from_secs(10)) .connect_timeout(Duration::from_secs(10))
.timeout(Duration::from_secs(30)) .timeout(Duration::from_secs(30))
.pool_idle_timeout(Duration::from_secs(10)) .pool_idle_timeout(Duration::from_secs(10))
.tcp_keepalive(Duration::from_secs(30)) .tcp_keepalive(Duration::from_secs(30))
.build() .build()
.expect("building the shared HTTP client with static options cannot fail"); .expect("building the shared HTTP client with static options cannot fail")
} });
/// Shared HTTP client with a connect timeout (10s) and a total request /// Shared HTTP client with a connect timeout (10s) and a total request
/// timeout (30s), to be used for all outgoing plain HTTP(S) requests /// timeout (30s), to be used for all outgoing plain HTTP(S) requests
+8 -9
View File
@@ -52,6 +52,7 @@ pub mod rust;
pub mod shell; pub mod shell;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use serde::Deserialize; use serde::Deserialize;
@@ -478,15 +479,13 @@ static TEMPLATE_SOURCES: &[TemplateSources] = &[
}, },
]; ];
lazy_static::lazy_static! { /// The parsed registry: manifest data plus resolved hooks, in the
/// The parsed registry: manifest data plus resolved hooks, in the /// order of [`TEMPLATE_SOURCES`] (wizard menu = detection priority).
/// order of [`TEMPLATE_SOURCES`] (wizard menu = detection priority). static REGISTRY: LazyLock<Vec<Template>> = LazyLock::new(build_registry);
static ref REGISTRY: Vec<Template> = build_registry(); /// The registry ids ([`Template::id`]), cached for the `TemplateId`
/// The registry ids ([`Template::id`]), cached for the `TemplateId` /// accessors.
/// accessors. static REGISTRY_IDS: LazyLock<Vec<TemplateId>> =
static ref REGISTRY_IDS: Vec<TemplateId> = LazyLock::new(|| REGISTRY.iter().map(Template::id).collect());
REGISTRY.iter().map(Template::id).collect();
}
/// Parse and cross-check every embedded manifest into the registry. The /// Parse and cross-check every embedded manifest into the registry. The
/// files ship inside the binary, so anything malformed here is a build-time /// files ship inside the binary, so anything malformed here is a build-time