174 lines
5.3 KiB
Rust
174 lines
5.3 KiB
Rust
use std::process::{Command, ExitStatus};
|
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
/// Helper program to start ic10emu and website.
|
|
///
|
|
/// Can be invoked as `cargo xtask <command>`
|
|
#[derive(Debug, Parser)]
|
|
#[command(bin_name = "cargo xtask")]
|
|
struct Args {
|
|
/// Package manager to use
|
|
#[arg(long, global = true, default_value = "pnpm")]
|
|
manager: String,
|
|
/// wasm-pack executable
|
|
#[arg(long, global = true, default_value = "wasm-pack")]
|
|
wasm_pack: String,
|
|
#[command(subcommand)]
|
|
task: Task,
|
|
}
|
|
|
|
const PACKAGES: &[&str] = &["ic10lsp_wasm", "ic10emu_wasm"];
|
|
|
|
#[derive(Debug, Subcommand)]
|
|
enum Task {
|
|
/// Build the packages
|
|
Build {
|
|
/// Build in release mode
|
|
#[arg(long)]
|
|
release: bool,
|
|
/// Packages to build
|
|
#[arg(long, short = 'p', default_values = PACKAGES)]
|
|
packages: Vec<String>,
|
|
/// Additional arguments to pass to wasm-pack, use another `--` to pass to cargo build
|
|
#[arg(last = true, default_values = ["--","-q"])]
|
|
// #[arg(last = true)]
|
|
rest: Vec<std::ffi::OsString>,
|
|
},
|
|
/// Start the server
|
|
///
|
|
/// This does not build the packages, use `build` first
|
|
Start {},
|
|
/// Runs production page under 'www/dist', Run `build` first.
|
|
Deploy {},
|
|
}
|
|
|
|
#[derive(thiserror::Error)]
|
|
enum Error {
|
|
#[error("building package {0} failed. Command: `{1}` Status code {2}")]
|
|
BuildFailed(String, String, std::process::ExitStatus),
|
|
#[error("failed to run command `{0}`")]
|
|
Command(String, #[source] std::io::Error),
|
|
}
|
|
|
|
impl std::fmt::Debug for Error {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
use std::error::Error;
|
|
use std::fmt::*;
|
|
write!(f, "Error: {}", self)?;
|
|
let mut err: &dyn Error = self;
|
|
while let Some(cause) = err.source() {
|
|
write!(f, "\nCaused by: ")?;
|
|
Display::fmt(&cause, f)?;
|
|
err = cause;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<(), Error> {
|
|
let args = Args::parse();
|
|
let workspace = {
|
|
let out = Command::new("cargo")
|
|
.arg("metadata")
|
|
.arg("--no-deps")
|
|
.arg("--format-version=1")
|
|
.output()
|
|
.map_err(|e| Error::Command("cargo metadata".to_string(), e))?;
|
|
let s = std::str::from_utf8(&out.stdout).unwrap();
|
|
let Some((_, s)) = s.split_once(r#"workspace_root":""#) else {
|
|
panic!("couldn't find workspace root");
|
|
};
|
|
let Some((path, _)) = s.split_once("\",") else {
|
|
panic!("couldn't find workspace root");
|
|
};
|
|
std::path::PathBuf::from(path)
|
|
};
|
|
match &args.task {
|
|
Task::Build {
|
|
release,
|
|
packages,
|
|
rest,
|
|
} => {
|
|
build(&args, packages, *release, &workspace, rest)?;
|
|
}
|
|
Task::Start {} => {
|
|
pnpm_install(&args, &workspace)?;
|
|
eprintln!("Starting server");
|
|
let mut cmd = Command::new(&args.manager);
|
|
cmd.current_dir(&workspace.join("www"));
|
|
cmd.args(["run", "start"]).status().map_err(|e| {
|
|
Error::Command(format!("{}", cmd.get_program().to_string_lossy()), e)
|
|
})?;
|
|
},
|
|
Task::Deploy {} => {
|
|
pnpm_install(&args, &workspace)?;
|
|
eprintln!("Production Build");
|
|
let mut cmd = Command::new(&args.manager);
|
|
cmd.current_dir(&workspace.join("www"));
|
|
cmd.args(["run", "build"]).status().map_err(|e| {
|
|
Error::Command(format!("{}", cmd.get_program().to_string_lossy()), e)
|
|
})?;
|
|
},
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn build<P: AsRef<std::ffi::OsStr> + std::fmt::Debug + std::fmt::Display>(
|
|
args: &Args,
|
|
packages: &[P],
|
|
release: bool,
|
|
workspace: &std::path::Path,
|
|
rest: &[std::ffi::OsString],
|
|
) -> Result<(), Error> {
|
|
if packages.is_empty() {
|
|
panic!("no package(s) specified")
|
|
}
|
|
eprintln!("Building packages: {:?}, release: {}", packages, release);
|
|
for package in packages {
|
|
eprintln!("Building package: {}", package);
|
|
eprintln!(
|
|
"Running command: {} build {} {} {}",
|
|
&args.wasm_pack,
|
|
if release { "--release" } else { "--dev" },
|
|
package,
|
|
rest.join(std::ffi::OsStr::new(" ")).to_string_lossy(),
|
|
);
|
|
let mut cmd = Command::new(&args.wasm_pack);
|
|
cmd.current_dir(workspace);
|
|
cmd.arg("build");
|
|
if release {
|
|
cmd.arg("--release");
|
|
} else {
|
|
cmd.arg("--dev");
|
|
}
|
|
cmd.arg(package);
|
|
cmd.args(rest);
|
|
let status = cmd
|
|
.status()
|
|
.map_err(|e| Error::Command(format!("{}", cmd.get_program().to_string_lossy()), e))?;
|
|
if status.success() {
|
|
eprintln!("{} built successfully", package);
|
|
} else {
|
|
return Err(Error::BuildFailed(
|
|
package.to_string(),
|
|
format!("{cmd:?}"),
|
|
status,
|
|
));
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn pnpm_install(
|
|
args: &Args,
|
|
workspace: &std::path::Path,
|
|
) -> Result<ExitStatus, Error> {
|
|
eprintln!("Running `pnpm install`");
|
|
let mut cmd = Command::new(&args.manager);
|
|
cmd.current_dir(&workspace.join("www"));
|
|
cmd.args(["install"])
|
|
.status()
|
|
.map_err(|e| Error::Command(format!("{}", cmd.get_program().to_string_lossy()), e))
|
|
}
|