1use anyhow::{Context, Result};
4use flate2::read::GzDecoder;
5use flate2::write::GzEncoder;
6use spin_common::ui::quoted_path;
7use std::path::{Path, PathBuf};
8use tar::Archive;
9
10pub async fn archive(source: &Path, working_dir: &Path) -> Result<PathBuf> {
12 let source = source.to_owned();
13 let working_dir = working_dir.to_owned();
14
15 tokio::task::spawn_blocking(move || {
16 let tar_gz_path = working_dir
18 .join(source.file_name().unwrap())
19 .with_extension("tar.gz");
20 let tar_gz = std::fs::File::create(tar_gz_path.as_path()).context(format!(
21 "Unable to create tar archive for source {}",
22 quoted_path(&source)
23 ))?;
24
25 let tar_gz_enc = GzEncoder::new(tar_gz, flate2::Compression::default());
28
29 let mut tar_builder = tar::Builder::new(tar_gz_enc);
31 tar_builder.append_dir_all(".", &source).context(format!(
32 "Unable to create tar archive for source {}",
33 quoted_path(&source)
34 ))?;
35
36 let inner_enc = tar_builder.into_inner()?;
38 inner_enc.finish()?;
39
40 Ok(tar_gz_path)
41 })
42 .await?
43}
44
45pub async fn unarchive(source: &Path, dest: &Path) -> Result<()> {
47 let source = source.to_owned();
48 let dest = dest.to_owned();
49
50 tokio::task::spawn_blocking(move || {
51 let decoder = GzDecoder::new(std::fs::File::open(&source)?);
52 let mut archive = Archive::new(decoder);
53 if let Err(e) = archive.unpack(&dest) {
54 return Err(e.into());
55 };
56 Ok(())
57 })
58 .await?
59}