Skip to content

Commit 3600c73

Browse files
committed
refactor(log): generate RunId with time parsing
1 parent e187686 commit 3600c73

File tree

1 file changed

+80
-13
lines changed

1 file changed

+80
-13
lines changed

src/cargo/util/logger.rs

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! Build analysis logging infrastructure.
22
3+
use std::hash::Hash;
34
use std::io::{BufWriter, Write};
45
use std::mem::ManuallyDrop;
56
use std::path::Path;
67
use std::sync::mpsc;
78
use std::sync::mpsc::Sender;
89
use std::thread::JoinHandle;
910

11+
use anyhow::Context as _;
1012
use cargo_util::paths;
1113

1214
use crate::CargoResult;
@@ -17,7 +19,7 @@ use crate::util::short_hash;
1719
/// Logger for `-Zbuild-analysis`.
1820
pub struct BuildLogger {
1921
tx: ManuallyDrop<Sender<LogMessage>>,
20-
run_id: String,
22+
run_id: RunId,
2123
handle: Option<JoinHandle<()>>,
2224
}
2325

@@ -38,7 +40,7 @@ impl BuildLogger {
3840
}
3941

4042
fn new(ws: &Workspace<'_>) -> CargoResult<Self> {
41-
let run_id = Self::generate_run_id(ws)?;
43+
let run_id = Self::generate_run_id(ws);
4244

4345
let log_dir = ws.gctx().home().join("log");
4446
paths::create_dir_all(log_dir.as_path_unlocked())?;
@@ -52,11 +54,11 @@ impl BuildLogger {
5254

5355
let (tx, rx) = mpsc::channel::<LogMessage>();
5456

55-
let run_id_clone = run_id.clone();
57+
let run_id_str = run_id.to_string();
5658
let handle = std::thread::spawn(move || {
5759
let mut writer = BufWriter::new(log_file);
5860
for msg in rx {
59-
let _ = msg.write_json_log(&mut writer, &run_id_clone);
61+
let _ = msg.write_json_log(&mut writer, &run_id_str);
6062
}
6163
let _ = writer.flush();
6264
});
@@ -69,18 +71,12 @@ impl BuildLogger {
6971
}
7072

7173
/// Generates a unique run ID.
72-
///
73-
/// The format is `{timestamp}-{hash}`, with `:` and `.` in the timestamp
74-
/// removed to make it safe for filenames.
75-
/// For example, `20251024T194502773638Z-f891d525d52ecab3`.
76-
pub fn generate_run_id(ws: &Workspace<'_>) -> CargoResult<String> {
77-
let hash = short_hash(&ws.root());
78-
let timestamp = jiff::Timestamp::now().to_string().replace([':', '.'], "");
79-
Ok(format!("{timestamp}-{hash}"))
74+
pub fn generate_run_id(ws: &Workspace<'_>) -> RunId {
75+
RunId::new(&ws.root())
8076
}
8177

8278
/// Returns the run ID for this build session.
83-
pub fn run_id(&self) -> &str {
79+
pub fn run_id(&self) -> &RunId {
8480
&self.run_id
8581
}
8682

@@ -103,3 +99,74 @@ impl Drop for BuildLogger {
10399
}
104100
}
105101
}
102+
103+
/// A unique identifier for a Cargo invocation.
104+
#[derive(Clone)]
105+
pub struct RunId {
106+
timestamp: jiff::Timestamp,
107+
hash: String,
108+
}
109+
110+
impl RunId {
111+
const FORMAT: &str = "%Y-%m-%dT%H%M%S%3fZ";
112+
113+
pub fn new<H: Hash>(h: &H) -> RunId {
114+
RunId {
115+
timestamp: jiff::Timestamp::now(),
116+
hash: short_hash(h),
117+
}
118+
}
119+
120+
pub fn timestamp(&self) -> &jiff::Timestamp {
121+
&self.timestamp
122+
}
123+
124+
/// Checks whether ID was generated from the same workspace.
125+
pub fn same_workspace(&self, other: &RunId) -> bool {
126+
self.hash == other.hash
127+
}
128+
}
129+
130+
impl std::fmt::Display for RunId {
131+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132+
let hash = &self.hash;
133+
let timestamp = self.timestamp.strftime(Self::FORMAT);
134+
write!(f, "{timestamp}-{hash}")
135+
}
136+
}
137+
138+
impl std::str::FromStr for RunId {
139+
type Err = anyhow::Error;
140+
141+
fn from_str(s: &str) -> Result<Self, Self::Err> {
142+
let msg =
143+
|| format!("expect run ID in format `2006-07-24T012128000Z-<16-char-hex>`, got `{s}`");
144+
let Some((timestamp, hash)) = s.rsplit_once('-') else {
145+
anyhow::bail!(msg());
146+
};
147+
148+
if hash.len() != 16 || !hash.chars().all(|c| c.is_ascii_hexdigit()) {
149+
anyhow::bail!(msg());
150+
}
151+
let timestamp = jiff::civil::DateTime::strptime(Self::FORMAT, timestamp)
152+
.and_then(|dt| dt.to_zoned(jiff::tz::TimeZone::UTC))
153+
.map(|zoned| zoned.timestamp())
154+
.with_context(msg)?;
155+
156+
Ok(RunId {
157+
timestamp,
158+
hash: hash.into(),
159+
})
160+
}
161+
}
162+
163+
#[cfg(test)]
164+
mod tests {
165+
use super::*;
166+
167+
#[test]
168+
fn run_id_round_trip() {
169+
let id = "2006-07-24T012128000Z-b0fd440798ab3cfb";
170+
assert_eq!(id, &id.parse::<RunId>().unwrap().to_string());
171+
}
172+
}

0 commit comments

Comments
 (0)