pacenotes_installer\runlog/
run_log.rs1pub struct Log {
2 header: Vec<String>,
3 entries: Vec<Entry>,
4 clock: fn() -> i64,
5 path: Option<std::path::PathBuf>,
6 file: Option<std::fs::File>,
7}
8
9struct Entry {
12 said_at: i64,
13 text: String,
14}
15
16impl Log {
17 pub fn create(header: Vec<String>, path: Option<std::path::PathBuf>) -> Log {
21 Log::with_clock(header, path, crate::utc_time::unix_now)
22 }
23
24 pub fn with_clock(
26 header: Vec<String>,
27 path: Option<std::path::PathBuf>,
28 clock: fn() -> i64,
29 ) -> Log {
30 let mut log = Log {
31 header,
32 entries: Vec::new(),
33 clock,
34 path: None,
35 file: None,
36 };
37 if let Some(path) = path {
38 log.attach(path);
39 }
40 log
41 }
42
43 pub fn attach(&mut self, path: std::path::PathBuf) {
47 if let Some(parent) = path.parent() {
48 let _ = std::fs::create_dir_all(parent);
49 super::prune(parent, super::KEEP_LOGS.saturating_sub(1));
50 }
51 let Ok(mut file) = std::fs::File::create(&path) else {
52 return;
53 };
54 let lines = self
55 .header
56 .iter()
57 .cloned()
58 .chain(std::iter::once(String::new()))
59 .chain(self.entries.iter().map(stamped));
60 for line in lines {
61 let _ = std::io::Write::write_all(&mut file, format!("{line}\n").as_bytes());
62 }
63 let _ = std::io::Write::flush(&mut file);
64 self.file = Some(file);
65 self.path = Some(path);
66 }
67
68 pub fn line(&mut self, text: impl Into<String>) {
70 let entry = Entry {
71 said_at: (self.clock)(),
72 text: text.into(),
73 };
74 if let Some(file) = self.file.as_mut() {
75 let _ = std::io::Write::write_all(file, format!("{}\n", stamped(&entry)).as_bytes());
76 let _ = std::io::Write::flush(file);
77 }
78 self.entries.push(entry);
79 }
80
81 pub fn lines(&self) -> impl Iterator<Item = &str> {
83 self.entries.iter().map(|entry| entry.text.as_str())
84 }
85
86 pub fn text(&self) -> String {
88 self.lines().collect::<Vec<_>>().join("\r\n")
89 }
90
91 pub fn path(&self) -> Option<&std::path::Path> {
93 self.path.as_deref()
94 }
95
96 pub fn is_empty(&self) -> bool {
97 self.entries.is_empty()
98 }
99}
100
101fn stamped(entry: &Entry) -> String {
103 format!(
104 "{} {}",
105 crate::utc_time::iso_stamp(entry.said_at),
106 entry.text
107 )
108}