spin_oci/
utils.rs

1//! Utilities related to distributing Spin apps via OCI registries
2
3use 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
10/// Create a compressed archive of source, returning its path in working_dir
11pub 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        // Create tar archive file
17        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        // Create encoder
26        // TODO: use zstd? May be more performant
27        let tar_gz_enc = GzEncoder::new(tar_gz, flate2::Compression::default());
28
29        // Build tar archive
30        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        // Finish writing the archive and shut down the encoder.
37        let inner_enc = tar_builder.into_inner()?;
38        inner_enc.finish()?;
39
40        Ok(tar_gz_path)
41    })
42    .await?
43}
44
45/// Unpack a compressed archive existing at source into dest
46pub 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}