use miette::{Context, IntoDiagnostic, miette};
#[derive(Debug, usage_rs::Args)]
pub struct FallbackArgs {
#[usage(arg, double_dash = "automatic", hide)]
pub args: Vec<String>,
#[usage(flatten)]
pub network: crate::cli_args::NetworkArgs,
}
macro_rules! fallback_alias_args {
($($name:ident),+ $(,)?) => {
$(
#[derive(Debug, usage_rs::Args)]
pub struct $name {
#[usage(flatten)]
pub inner: FallbackArgs,
}
impl std::ops::Deref for $name {
type Target = FallbackArgs;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
)+
};
}
fallback_alias_args!(
OwnerArgs,
PkgArgs,
SearchArgs,
SetScriptArgs,
StageArgs,
TokenArgs,
WhoamiArgs,
);
pub fn run(name: &str, args: &FallbackArgs) -> miette::Result<i32> {
args.network.install_overrides();
let cwd = crate::dirs::cwd()?;
let files = crate::commands::FileSources::load(&cwd);
let empty_ws = std::collections::BTreeMap::new();
let env = aube_settings::values::process_env();
let ctx = files.ctx(&empty_ws, env, &[]);
if let Some(npm_path) = aube_settings::resolved::npm_path(&ctx) {
let mut cmd = std::process::Command::new(&npm_path);
cmd.arg(name)
.args(&args.args)
.stderr(aube_scripts::child_stderr());
if let Some(registry) = args.network.registry.as_deref() {
cmd.arg(format!("--registry={registry}"));
}
let status = cmd
.status()
.into_diagnostic()
.wrap_err_with(|| format!("failed to run configured npmPath `{npm_path}`"))?;
return Ok(child_exit_code(status));
}
Err(miette!(
code = aube_codes::errors::ERR_AUBE_NPM_ONLY_COMMAND,
"`aube {name}` is not implemented. This is an npm-only command — \
run it with `npm {name}` instead, or set `npmPath` to let aube delegate it."
))
}
fn child_exit_code(status: std::process::ExitStatus) -> i32 {
if let Some(code) = status.code() {
return code;
}
#[cfg(unix)]
{
use std::os::unix::process::ExitStatusExt;
if let Some(signal) = status.signal() {
return 128 + signal;
}
}
1
}
#[cfg(test)]
mod tests {
#[cfg(unix)]
use super::child_exit_code;
#[cfg(unix)]
#[test]
fn child_signal_exit_uses_shell_convention() {
use std::os::unix::process::ExitStatusExt;
let status = std::process::ExitStatus::from_raw(2);
assert_eq!(child_exit_code(status), 130);
}
#[cfg(unix)]
#[test]
fn child_normal_exit_code_is_preserved() {
use std::os::unix::process::ExitStatusExt;
let status = std::process::ExitStatus::from_raw(7 << 8);
assert_eq!(child_exit_code(status), 7);
}
}