1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Conserve backup system.
// Copyright 2018 Martin Pool.

//! Text output formats for structured data.
//!
//! These are objects that accept iterators of different types of content, and write it to a
//! file (typically stdout).

use super::*;

use chrono::Local;

/// Show something about an archive.
pub trait ShowArchive {
    fn show_archive(&self, _: &Archive) -> Result<()>;
}

#[derive(Debug, Default)]
pub struct ShortVersionList {}

impl ShowArchive for ShortVersionList {
    fn show_archive(&self, archive: &Archive) -> Result<()> {
        for band_id in archive.list_bands()? {
            println!("{}", band_id);
        }
        Ok(())
    }
}

#[derive(Debug, Default)]
pub struct VerboseVersionList {
    show_sizes: bool,
}

impl VerboseVersionList {
    // Control whether to show the size of version disk usage.
    //
    // Setting this requires walking the band directories which takes some extra time.
    pub fn show_sizes(self, show_sizes: bool) -> VerboseVersionList {
        VerboseVersionList { show_sizes }
    }
}

impl ShowArchive for VerboseVersionList {
    fn show_archive(&self, archive: &Archive) -> Result<()> {
        let report = archive.report();
        for band_id in archive.list_bands()? {
            let band = match Band::open(&archive, &band_id) {
                Ok(band) => band,
                Err(e) => {
                    report.problem(&format!("Failed to open band {:?}: {:?}", band_id, e));
                    continue;
                }
            };
            let info = match band.get_info(archive.report()) {
                Ok(info) => info,
                Err(e) => {
                    report.problem(&format!("Failed to read band tail {:?}: {:?}", band_id, e));
                    continue;
                }
            };
            let is_complete_str = if info.is_closed {
                "complete"
            } else {
                "incomplete"
            };
            let start_time_str = info.start_time.with_timezone(&Local).to_rfc3339();
            let duration_str = info.end_time.map_or_else(String::new, |t| {
                format!("{}s", (t - info.start_time).num_seconds())
            });
            if self.show_sizes {
                let disk_bytes = band.get_disk_size()?;
                println!(
                    "{:<26} {:<10} {} {:>7} {:>8}MB",
                    band_id,
                    is_complete_str,
                    start_time_str,
                    duration_str,
                    disk_bytes / 1_000_000,
                );
            } else {
                println!(
                    "{:<26} {:<10} {} {:>7}",
                    band_id, is_complete_str, start_time_str, duration_str,
                );
            }
        }
        Ok(())
    }
}