use std::os::unix::ffi::OsStrExt as _;
use std::path::PathBuf;
use anyhow::Context as _;
use anyhow::Result;
use anyhow::bail;
use clap::ArgAction;
use clap::Parser;
use clap::Subcommand;
use clap::builder::PathBufValueParser;
use clap::builder::TypedValueParser as _;
fn canonicalize_path(p: PathBuf) -> Result<PathBuf> {
let p = p
.canonicalize()
.with_context(|| format!("failed to resolve path `{}`", p.display()))?;
let bytes = p.as_os_str().as_bytes();
if bytes.contains(&b':') || bytes.contains(&b';') {
bail!(
"path `{}` contains reserved delimiter characters (':' or ';')",
p.display()
);
}
Ok(p)
}
#[derive(Debug, Parser)]
#[clap(version = env!("VERSION"), args_conflicts_with_subcommands = true)]
pub struct Args {
#[clap(subcommand)]
pub command: Option<Command>,
#[clap(flatten)]
pub args: RunArgs,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Run(RunArgs),
Embed(EmbedArgs),
}
#[derive(Debug, Parser)]
pub struct RunArgs {
#[clap(short, long)]
pub kernel: Option<PathBuf>,
#[clap(long, default_value_t = 2)]
pub cpus: u8,
#[clap(long, default_value_t = 1024)]
pub memory: u32,
#[clap(long)]
pub net: bool,
#[clap(long)]
pub uds: bool,
#[clap(last = true)]
pub command: Vec<String>,
#[clap(long = "env")]
pub env_vars: Vec<String>,
#[clap(long)]
pub all_envs: bool,
#[clap(long, value_parser = PathBufValueParser::new().try_map(canonicalize_path))]
pub share_rw: Vec<PathBuf>,
#[clap(long, hide = true)]
pub no_uid_map: bool,
#[clap(short = 'v', long = "verbose", global = true, action = ArgAction::Count)]
pub verbosity: u8,
}
#[derive(Debug, Parser)]
pub struct EmbedArgs {
pub kernel: PathBuf,
#[clap(short, long)]
pub output: Option<PathBuf>,
}