boatctl 0.1.0

CLI for Blueboat Cloud.
Documentation
use std::{collections::BTreeMap, path::Path, process::Command};

use crate::config::{AppConfig, AppSpec};
use tempdir::TempDir;

pub fn build_package(
  spec_path: &Path,
  spec: &AppSpec,
  config: &AppConfig,
) -> anyhow::Result<Vec<u8>> {
  let spec_dir = spec_path
    .parent()
    .ok_or_else(|| anyhow::anyhow!("cannot resolve spec parent dir"))?
    .to_path_buf();

  if let Some(build) = &spec.build {
    let mut newenv: BTreeMap<String, String> = std::env::vars().collect();
    for (k, v) in &config.env {
      newenv.insert(format!("BLUEBOAT_{}", k.get_ref()), v.to_string());
    }

    let status = Command::new("sh")
      .envs(newenv)
      .current_dir(&spec_dir)
      .args(["-c", build.as_str()])
      .status()?;
    if !status.success() {
      anyhow::bail!("build failed: {}", status.code().unwrap_or(1));
    }
  }

  let td = TempDir::new("bbcli-deploy")?;
  if let Some(d) = &spec._static {
    let status = {
      #[cfg(target_os = "macos")]
      {
        let mut d = spec_dir.join(d).canonicalize()?;
        d.push("");
        Command::new("cp")
          .args([Path::new("-r"), &d, td.path()])
          .status()?
      }
      #[cfg(not(target_os = "macos"))]
      {
        let d = spec_dir.join(d).canonicalize()?;
        Command::new("cp")
          .args([Path::new("-rT"), &d, td.path()])
          .status()?
      }
    };
    if !status.success() {
      anyhow::bail!("copy static failed: {}", status.code().unwrap_or(1));
    }
  }

  let mut artifact_target_path = td.path().to_path_buf();
  artifact_target_path.push("index.js");
  let artifact_source_path = spec_dir.join(&spec.artifact).canonicalize()?;
  std::fs::copy(&artifact_source_path, &artifact_target_path)?;

  let mut tar_builder = tar::Builder::new(Vec::new());
  tar_builder.append_dir_all(".", td.path())?;
  let image = tar_builder.into_inner()?;
  log::info!("Image size is {} bytes.", image.len());

  Ok(image)
}