Skip to main content

st/formatters/
tsv.rs

1use super::Formatter;
2use crate::scanner::{FileNode, TreeStats};
3use anyhow::Result;
4use chrono::{DateTime, Local};
5use std::io::Write;
6use std::path::Path;
7
8pub struct TsvFormatter;
9
10impl Default for TsvFormatter {
11    fn default() -> Self {
12        Self::new()
13    }
14}
15
16impl TsvFormatter {
17    pub fn new() -> Self {
18        Self
19    }
20}
21
22impl Formatter for TsvFormatter {
23    fn format(
24        &self,
25        writer: &mut dyn Write,
26        nodes: &[FileNode],
27        _stats: &TreeStats,
28        root_path: &Path,
29    ) -> Result<()> {
30        // Write header
31        writeln!(
32            writer,
33            "path\ttype\tsize\tpermissions\tuid\tgid\tmodified\tdepth"
34        )?;
35
36        // Sort nodes by path
37        let mut sorted_nodes = nodes.to_vec();
38        sorted_nodes.sort_by(|a, b| a.path.cmp(&b.path));
39
40        for node in &sorted_nodes {
41            let rel_path = if node.path == root_path {
42                ".".to_string()
43            } else {
44                node.path
45                    .strip_prefix(root_path)
46                    .unwrap_or(&node.path)
47                    .to_string_lossy()
48                    .to_string()
49            };
50
51            let file_type = if node.is_dir { "d" } else { "f" };
52            let datetime = DateTime::<Local>::from(node.modified);
53
54            writeln!(
55                writer,
56                "{}\t{}\t{}\t{:o}\t{}\t{}\t{}\t{}",
57                rel_path,
58                file_type,
59                node.size,
60                node.permissions,
61                node.uid,
62                node.gid,
63                datetime.to_rfc3339(),
64                node.depth
65            )?;
66        }
67
68        Ok(())
69    }
70}