tugger/
tarball.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use {
6    anyhow::Result,
7    log::warn,
8    std::{io::Write, path::Path},
9    tar,
10};
11
12/// Create a tarball from a filesystem path.
13///
14/// The uncompressed tar contents will be emitted to the passed writer.
15pub 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    // The tar crate isn't deterministic when iterating directories. So we
26    // do the iteration ourselves.
27    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}