pyapp 0.29.0

Runtime installer for Python applications
use std::fs::File;
use std::path::Path;

use anyhow::{bail, Result};

use crate::terminal;

pub fn unpack(
    format: String,
    archive: impl AsRef<Path>,
    destination: impl AsRef<Path>,
) -> Result<()> {
    let wait_message = format!("Unpacking distribution ({})", format);
    match format.as_ref() {
        "tar|bzip2" => unpack_tar_bzip2(archive, destination, wait_message)?,
        "tar|gzip" => unpack_tar_gzip(archive, destination, wait_message)?,
        "tar|zstd" => unpack_tar_zstd(archive, destination, wait_message)?,
        "zip" => unpack_zip(archive, destination, wait_message)?,
        _ => bail!("unsupported distribution format: {}", format),
    }

    Ok(())
}

fn unpack_tar_bzip2(
    path: impl AsRef<Path>,
    destination: impl AsRef<Path>,
    wait_message: String,
) -> Result<()> {
    let bz = bzip2::read::BzDecoder::new(File::open(path)?);
    let mut archive = tar::Archive::new(bz);

    let spinner = terminal::spinner(wait_message);
    let result = archive.unpack(destination);
    spinner.finish_and_clear();
    result?;

    Ok(())
}

pub fn unpack_tar_gzip(
    path: impl AsRef<Path>,
    destination: impl AsRef<Path>,
    wait_message: String,
) -> Result<()> {
    let gz = flate2::read::GzDecoder::new(File::open(path)?);
    let mut archive = tar::Archive::new(gz);

    let spinner = terminal::spinner(wait_message);
    let result = archive.unpack(destination);
    spinner.finish_and_clear();
    result?;

    Ok(())
}

fn unpack_tar_zstd(
    path: impl AsRef<Path>,
    destination: impl AsRef<Path>,
    wait_message: String,
) -> Result<()> {
    let zst = zstd::stream::read::Decoder::new(File::open(path)?)?;
    let mut archive = tar::Archive::new(zst);

    let spinner = terminal::spinner(wait_message);
    let result = archive.unpack(destination);
    spinner.finish_and_clear();
    result?;

    Ok(())
}

pub fn unpack_zip(
    path: impl AsRef<Path>,
    destination: impl AsRef<Path>,
    wait_message: String,
) -> Result<()> {
    let mut archive = zip::ZipArchive::new(File::open(path)?)?;

    let spinner = terminal::spinner(wait_message);
    let result = archive.extract(destination);
    spinner.finish_and_clear();
    result?;

    Ok(())
}