1use std::io::Read;
4
5use camino::Utf8PathBuf;
6
7use crate::{Content, Decoder};
8
9#[derive(Debug)]
10pub enum ReadContent {
11 Directory,
12 Symlink {
13 target: Utf8PathBuf,
14 },
15 File {
16 executable: bool,
17 size: u64,
18 offset: u64,
19 data: Vec<u8>,
20 },
21}
22
23#[allow(clippy::needless_pass_by_value)]
44pub fn pretty_print_nar_content<R: Read>(dec: Decoder<R>) -> String {
45 use ReadContent as RC;
46 let mut res = vec![];
47 for (path, content) in decode_nar(&dec) {
48 let path = match path {
49 None => "ROOT".into(),
50 Some(path) => {
51 let path = path.to_string();
52 let components: Vec<&str> =
53 path.split(std::path::MAIN_SEPARATOR).collect();
54 match components.last() {
55 Some(basename) => {
56 let depth = components.len();
57 let mut indented = String::new();
58 for _ in 0..depth - 1 {
59 indented.push_str("│ ");
60 }
61 indented.push_str("├── ");
62 indented.push_str(basename);
63 indented
64 }
65 None => String::new(),
66 }
67 }
68 };
69 res.push(match content {
70 RC::Directory => path,
71 RC::Symlink { target } => format!("{path} -> {target}"),
72 RC::File {
73 executable,
74 size,
75 offset,
76 data,
77 } => format!(
78 "{path}: executable={executable}, size={size}, offset={offset}, data='{}'",
79 std::str::from_utf8(&data)
80 .unwrap()
81 .escape_default()
82 ),
83 });
84 }
85 res.join("\n")
86}
87
88fn decode_nar<R: Read>(dec: &Decoder<R>) -> Vec<(Option<Utf8PathBuf>, ReadContent)> {
89 let mut res = vec![];
90 for entry in dec.entries().unwrap() {
91 let entry = entry.unwrap();
92 let read_content = match entry.content {
93 Content::Symlink { target } => ReadContent::Symlink { target },
94 Content::Directory => ReadContent::Directory,
95 Content::File {
96 executable,
97 size,
98 offset,
99 mut data,
100 } => {
101 let mut read_data: Vec<u8> = vec![];
102 data.read_to_end(&mut read_data).unwrap();
103 ReadContent::File {
104 executable,
105 size,
106 offset,
107 data: read_data,
108 }
109 }
110 };
111 res.push((entry.path, read_content));
112 }
113 res
114}