]> git.proxmox.com Git - proxmox-backup.git/blob - src/tools/format.rs
use non-panicky timestamp_opt where appropriate
[proxmox-backup.git] / src / tools / format.rs
1 use anyhow::{Error};
2 use serde_json::Value;
3 use chrono::{Local, TimeZone, LocalResult};
4
5 pub fn strip_server_file_expenstion(name: &str) -> String {
6
7 if name.ends_with(".didx") || name.ends_with(".fidx") || name.ends_with(".blob") {
8 name[..name.len()-5].to_owned()
9 } else {
10 name.to_owned() // should not happen
11 }
12 }
13
14 pub fn render_backup_file_list(files: &[String]) -> String {
15 let mut files: Vec<String> = files.iter()
16 .map(|v| strip_server_file_expenstion(&v))
17 .collect();
18
19 files.sort();
20
21 super::join(&files, ' ')
22 }
23
24 pub fn render_epoch(value: &Value, _record: &Value) -> Result<String, Error> {
25 if value.is_null() { return Ok(String::new()); }
26 let text = match value.as_i64() {
27 Some(epoch) => {
28 match Local.timestamp_opt(epoch, 0) {
29 LocalResult::Single(epoch) => epoch.format("%c").to_string(),
30 _ => epoch.to_string(),
31 }
32 },
33 None => {
34 value.to_string()
35 }
36 };
37 Ok(text)
38 }
39
40 pub fn render_task_status(value: &Value, record: &Value) -> Result<String, Error> {
41 if record["endtime"].is_null() {
42 Ok(value.as_str().unwrap_or("running").to_string())
43 } else {
44 Ok(value.as_str().unwrap_or("unknown").to_string())
45 }
46 }
47
48 pub fn render_bool_with_default_true(value: &Value, _record: &Value) -> Result<String, Error> {
49 let value = value.as_bool().unwrap_or(true);
50 Ok((if value { "1" } else { "0" }).to_string())
51 }
52
53 pub struct HumanByte {
54 b: usize,
55 }
56 impl std::fmt::Display for HumanByte {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 if self.b < 1024 {
59 return write!(f, "{} B", self.b);
60 }
61 let kb: f64 = self.b as f64 / 1024.0;
62 if kb < 1024.0 {
63 return write!(f, "{:.2} KiB", kb);
64 }
65 let mb: f64 = kb / 1024.0;
66 if mb < 1024.0 {
67 return write!(f, "{:.2} MiB", mb);
68 }
69 let gb: f64 = mb / 1024.0;
70 if gb < 1024.0 {
71 return write!(f, "{:.2} GiB", gb);
72 }
73 let tb: f64 = gb / 1024.0;
74 if tb < 1024.0 {
75 return write!(f, "{:.2} TiB", tb);
76 }
77 let pb: f64 = tb / 1024.0;
78 return write!(f, "{:.2} PiB", pb);
79 }
80 }
81 impl From<usize> for HumanByte {
82 fn from(v: usize) -> Self {
83 HumanByte { b: v }
84 }
85 }
86 impl From<u64> for HumanByte {
87 fn from(v: u64) -> Self {
88 HumanByte { b: v as usize }
89 }
90 }
91
92 #[test]
93 fn correct_byte_convert() {
94 fn convert(b: usize) -> String {
95 HumanByte::from(b).to_string()
96 }
97 assert_eq!(convert(1023), "1023 B");
98 assert_eq!(convert(1<<10), "1.00 KiB");
99 assert_eq!(convert(1<<20), "1.00 MiB");
100 assert_eq!(convert((1<<30) + (103 * 1<<20)), "1.10 GiB");
101 assert_eq!(convert((2<<50) + (500 * 1<<40)), "2.49 PiB");
102 }