tessera-mobile 0.0.0

Rust on mobile made easy.
Documentation
use thiserror::Error;

use crate::{
    DuctExpressionExt,
    util::cli::{Report, Reportable},
};

#[cfg(not(target_os = "macos"))]
use crate::util;
#[cfg(not(target_os = "macos"))]
use std::path::PathBuf;

#[cfg(not(target_os = "macos"))]
pub const BUNDLE_TOOL_JAR_INFO: BundletoolJarInfo = BundletoolJarInfo { version: "1.8.0" };

#[cfg(not(target_os = "macos"))]
pub struct BundletoolJarInfo {
    version: &'static str,
}

#[cfg(not(target_os = "macos"))]
impl BundletoolJarInfo {
    fn file_name(&self) -> String {
        format!("bundletool-all-{}.jar", self.version)
    }

    fn installation_path(&self) -> PathBuf {
        util::tools_dir()
            .map(|tools_dir| tools_dir.join(self.file_name()))
            .unwrap()
    }

    fn download_url(&self) -> String {
        format!(
            "https://github.com/google/bundletool/releases/download/{}/{}",
            self.version,
            self.file_name()
        )
    }

    fn run_command(&self) -> duct::Expression {
        let installation_path = self.installation_path();
        duct::cmd("java", ["-jar"])
            .dup_stdio()
            .before_spawn(move |cmd| {
                cmd.arg(&installation_path);
                Ok(())
            })
    }
}

pub fn command() -> duct::Expression {
    #[cfg(not(target_os = "macos"))]
    {
        BUNDLE_TOOL_JAR_INFO.run_command()
    }
    #[cfg(target_os = "macos")]
    {
        duct::cmd!("bundletool").dup_stdio()
    }
}

#[cfg(target_os = "macos")]
#[derive(Debug, Error)]
#[error(transparent)]
pub struct InstallError(crate::apple::deps::Error);

#[cfg(target_os = "macos")]
impl Reportable for InstallError {
    fn report(&self) -> Report {
        Report::error("Failed to install `bundletool`", &self.0)
    }
}

#[cfg(not(target_os = "macos"))]
#[derive(Debug, Error)]
pub enum InstallError {
    #[error("Failed to download `bundletool`: {0}")]
    Download(Box<ureq::Error>),
    #[error("Failed to create bundletool.jar at {path}: {cause}")]
    JarFileCreation {
        path: PathBuf,
        cause: std::io::Error,
    },
    #[error("Failed to copy content into bundletool.jar at {path}: {cause}")]
    CopyToFile {
        path: PathBuf,
        cause: std::io::Error,
    },
}

#[cfg(not(target_os = "macos"))]
impl Reportable for InstallError {
    fn report(&self) -> Report {
        match self {
            Self::Download(err) => Report::error("Failed to download `bundletool`", err),
            Self::JarFileCreation { path, cause } => Report::error(
                format!("Failed to create bundletool.jar at {:?}", path),
                cause,
            ),
            Self::CopyToFile { path, cause } => Report::error(
                format!("Failed to copy content into bundletool.jar at {:?}", path),
                cause,
            ),
        }
    }
}

pub fn install(reinstall_deps: bool) -> Result<(), InstallError> {
    #[cfg(not(target_os = "macos"))]
    {
        let jar_path = BUNDLE_TOOL_JAR_INFO.installation_path();
        if !jar_path.exists() || reinstall_deps {
            let response = ureq::get(&BUNDLE_TOOL_JAR_INFO.download_url())
                .call()
                .map_err(Box::new)
                .map_err(InstallError::Download)?;
            let tools_dir = util::tools_dir().unwrap();
            std::fs::create_dir_all(&tools_dir).map_err(|cause| InstallError::JarFileCreation {
                path: tools_dir,
                cause,
            })?;
            let mut out = std::fs::File::create(&jar_path).map_err(|cause| {
                InstallError::JarFileCreation {
                    path: jar_path.clone(),
                    cause,
                }
            })?;
            std::io::copy(&mut response.into_body().into_reader(), &mut out).map_err(|cause| {
                InstallError::CopyToFile {
                    path: jar_path,
                    cause,
                }
            })?;
        }
    }
    #[cfg(target_os = "macos")]
    {
        use crate::apple::deps::{GemCache, PackageSpec};
        PackageSpec::brew("bundletool")
            .install(reinstall_deps, &mut GemCache::new())
            .map_err(InstallError)?;
    }
    Ok(())
}