use arcbox_cli::client::{self, ExecCreateRequest, ExecCreateResponse};
use anyhow::Result;
use clap::Args;
#[derive(Args)]
pub struct ExecArgs {
pub container: String,
#[arg(trailing_var_arg = true, required = true)]
pub command: Vec<String>,
#[arg(short, long)]
pub tty: bool,
#[arg(short, long)]
pub interactive: bool,
#[arg(short, long)]
pub detach: bool,
#[arg(short, long)]
pub env: Vec<String>,
#[arg(short, long)]
pub workdir: Option<String>,
#[arg(short, long)]
pub user: Option<String>,
#[arg(long)]
pub privileged: bool,
}
pub async fn execute(args: ExecArgs) -> Result<()> {
let daemon = client::get_client().await?;
let create_path = format!("/v1.43/containers/{}/exec", args.container);
let create_request = ExecCreateRequest {
attach_stdin: args.interactive && !args.detach,
attach_stdout: !args.detach,
attach_stderr: !args.detach,
tty: args.tty,
cmd: args.command.clone(),
env: args.env.clone(),
working_dir: args.workdir.clone(),
};
let create_response: ExecCreateResponse = daemon.post(&create_path, Some(&create_request)).await?;
let exec_id = create_response.id;
let start_path = format!("/v1.43/exec/{}/start", exec_id);
let start_request = ExecStartRequest {
detach: args.detach,
tty: args.tty,
};
if args.detach {
daemon.post_empty(&start_path, Some(&start_request)).await?;
println!("{}", exec_id);
} else {
if args.interactive || args.tty {
tracing::warn!("Interactive/TTY exec mode not fully implemented yet");
}
let output = daemon.post_raw(&start_path, Some(&start_request)).await?;
if !output.is_empty() {
if let Ok(s) = std::str::from_utf8(&output) {
print!("{}", s);
}
}
let inspect_path = format!("/v1.43/exec/{}/json", exec_id);
if let Ok(inspect) = daemon.get::<ExecInspect>(&inspect_path).await {
if inspect.exit_code != 0 {
std::process::exit(inspect.exit_code);
}
}
}
Ok(())
}
#[derive(Debug, Clone, serde::Serialize)]
#[serde(rename_all = "PascalCase")]
struct ExecStartRequest {
detach: bool,
tty: bool,
}
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(rename_all = "PascalCase")]
struct ExecInspect {
#[serde(default)]
exit_code: i32,
running: bool,
}