1use {
6 anyhow::Result,
7 log::warn,
8 std::{io::Write, path::Path},
9 tar,
10};
11
12pub fn write_tarball_from_directory<W: Write, P: AsRef<Path>>(
16 fh: &mut W,
17 source_path: P,
18 archive_prefix: Option<P>,
19) -> Result<()> {
20 let source_path = source_path.as_ref();
21
22 let mut builder = tar::Builder::new(fh);
23 builder.mode(tar::HeaderMode::Deterministic);
24
25 let walk = walkdir::WalkDir::new(source_path).sort_by(|a, b| a.file_name().cmp(b.file_name()));
28
29 for entry in walk {
30 let entry = entry?;
31
32 let path = entry.path();
33
34 if path == source_path {
35 continue;
36 }
37
38 let rel_path = path.strip_prefix(source_path)?;
39
40 let archive_path = if let Some(prefix) = &archive_prefix {
41 prefix.as_ref().join(rel_path)
42 } else {
43 rel_path.to_path_buf()
44 };
45
46 warn!("adding {} as {}", path.display(), archive_path.display());
47 builder.append_path_with_name(path, &archive_path)?;
48 }
49
50 builder.finish()?;
51
52 Ok(())
53}