use anyhow::{Context as _, Result};
use command_group::AsyncCommandGroup;
use std::path::{Path, PathBuf};
use std::process::Stdio;
use tokio::fs::metadata;
use tokio::process::{Child, Command};
use tracing::warn;
use super::download_binary_from_github;
use crate::common::CommandGroupUsage;
const WADM_GITHUB_RELEASE_URL: &str = "https://github.com/wasmcloud/wadm/releases/download";
pub const WADM_PID: &str = "wadm.pid";
#[cfg(target_family = "unix")]
pub const WADM_BINARY: &str = "wadm";
#[cfg(target_family = "windows")]
pub const WADM_BINARY: &str = "wadm.exe";
pub async fn ensure_wadm<P>(version: &str, dir: P) -> Result<PathBuf>
where
P: AsRef<Path>,
{
ensure_wadm_for_os_arch_pair(std::env::consts::OS, std::env::consts::ARCH, version, dir).await
}
pub async fn ensure_wadm_for_os_arch_pair<P>(
os: &str,
arch: &str,
version: &str,
dir: P,
) -> Result<PathBuf>
where
P: AsRef<Path>,
{
let wadm_bin_path = dir.as_ref().join(WADM_BINARY);
if let Ok(_md) = metadata(&wadm_bin_path).await {
if let Ok(output) = Command::new(&wadm_bin_path).arg("--version").output().await {
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
eprintln!("👀 Found wadm version on the disk: {}", stdout.trim_end());
let re = regex::Regex::new(r"^wadm[^\s]*").unwrap();
if re.replace(&stdout, "").to_string().trim() == version.trim_start_matches('v') {
return Ok(wadm_bin_path);
}
}
}
eprintln!(
"🎣 Downloading new wadm from {}",
&wadm_url(os, arch, version)
);
let res = download_binary_from_github(&wadm_url(os, arch, version), dir, WADM_BINARY).await;
if let Ok(ref path) = res {
eprintln!("🎯 Saved wadm to {}", path.display());
}
res
}
pub async fn download_wadm<P>(version: &str, dir: P) -> Result<PathBuf>
where
P: AsRef<Path>,
{
download_binary_from_github(
&wadm_url(std::env::consts::OS, std::env::consts::ARCH, version),
dir,
WADM_BINARY,
)
.await
}
#[derive(Clone)]
pub struct WadmConfig {
pub structured_logging: bool,
pub js_domain: Option<String>,
pub nats_server_url: String,
pub nats_credsfile: Option<PathBuf>,
}
pub async fn start_wadm<T>(
state_dir: impl AsRef<Path>,
bin_path: impl AsRef<Path>,
stderr: T,
config: Option<WadmConfig>,
command_group: CommandGroupUsage,
) -> Result<Child>
where
T: Into<Stdio>,
{
let mut cmd = Command::new(bin_path.as_ref());
cmd.stderr(stderr).stdin(Stdio::null());
if let Some(wadm_config) = config {
cmd.arg("--nats-server");
cmd.arg(wadm_config.nats_server_url);
if wadm_config.structured_logging {
cmd.arg("--structured-logging");
}
if let Some(domain) = wadm_config.js_domain.as_ref() {
cmd.arg("-d");
cmd.arg(domain);
}
if let Some(credsfile) = wadm_config.nats_credsfile.as_ref() {
cmd.arg("--nats-creds-file");
cmd.arg(credsfile);
}
}
let child = if command_group == CommandGroupUsage::CreateNew {
cmd.group_spawn().map_err(anyhow::Error::from)?.into_inner()
} else {
cmd.spawn().map_err(anyhow::Error::from)?
};
let pid = child
.id()
.context("unexpectedly missing pid for spawned process")?;
let pid_path = state_dir.as_ref().join(WADM_PID);
if let Err(e) = tokio::fs::write(pid_path, pid.to_string()).await {
warn!("Couldn't write wadm pidfile: {e}");
}
Ok(child)
}
fn wadm_url(os: &str, arch: &str, version: &str) -> String {
let arch = match arch {
"x86_64" => "amd64",
_ => arch,
};
format!("{WADM_GITHUB_RELEASE_URL}/{version}/wadm-{version}-{os}-{arch}.tar.gz")
}