#![cfg_attr(not(any(windows, unix)), no_std)]
#![cfg(any(windows, unix))]
use clap::{Args, Parser, Subcommand};
use crate::{arceos::ArceOS, axloader::Axloader, axvisor::Axvisor, starry::Starry};
mod agent_review_bench;
pub mod arceos;
pub mod axloader;
pub mod axvisor;
mod backtrace;
mod board;
mod build;
mod clippy;
pub mod context;
pub mod image;
mod ktest;
mod rootfs;
mod spin_lint;
pub mod starry;
mod support;
mod sync_lint;
mod test;
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Args, Clone, Debug, PartialEq, Eq)]
pub(crate) struct ClippyArgs {
#[arg(long)]
pub(crate) all: bool,
#[arg(long = "package", value_name = "PACKAGE")]
pub(crate) packages: Vec<String>,
#[arg(long, value_name = "REF")]
pub(crate) since: Option<String>,
}
#[derive(Args, Clone, Debug, PartialEq, Eq)]
pub(crate) struct SyncLintArgs {
#[arg(long, value_name = "REF")]
pub(crate) since: Option<String>,
}
#[derive(Subcommand)]
enum Commands {
AgentReviewBench {
#[command(subcommand)]
command: agent_review_bench::Command,
},
Test,
Ktest(ktest::ArgsKtest),
Clippy(ClippyArgs),
SyncLint(SyncLintArgs),
SpinLint,
Board {
#[command(subcommand)]
command: board::Command,
},
Backtrace {
#[command(subcommand)]
command: backtrace::Command,
},
Image(image::ImageArgs),
Axvisor {
#[command(subcommand)]
command: axvisor::Command,
},
Axloader {
#[command(subcommand)]
command: axloader::Command,
},
Arceos {
#[command(subcommand)]
command: arceos::Command,
},
Starry {
#[command(subcommand)]
command: starry::Command,
},
}
pub async fn run() -> anyhow::Result<()> {
let cli = Cli::parse();
run_root_cli(cli).await
}
async fn run_root_cli(cli: Cli) -> anyhow::Result<()> {
match cli.command {
Commands::AgentReviewBench { command } => agent_review_bench::execute(command).await,
Commands::Test => test::std::run_std_test_command(),
Commands::Ktest(args) => ktest::run(args).await,
Commands::Clippy(args) => clippy::run_workspace_clippy_command(&args),
Commands::SyncLint(args) => sync_lint::run_sync_lint_command(&args),
Commands::SpinLint => spin_lint::run_spin_lint_command(),
Commands::Board { command } => board::execute(command).await,
Commands::Backtrace { command } => backtrace::execute(command),
Commands::Image(args) => image::run(args).await,
Commands::Axvisor { command } => Axvisor::new()?.execute(command).await,
Commands::Axloader { command } => Axloader::new()?.execute(command).await,
Commands::Arceos { command } => ArceOS::new()?.execute(command).await,
Commands::Starry { command } => Starry::new()?.execute(command).await,
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use clap::Parser;
use super::*;
#[derive(Parser)]
struct TestCli {
#[command(subcommand)]
command: Commands,
}
fn assert_os_command_contract(os: &'static str, command: &[&'static str]) {
let mut args = vec!["xtask", os];
args.extend_from_slice(command);
TestCli::try_parse_from(args).unwrap_or_else(|err| {
panic!(
"{os} must support the shared CLI contract `{}`: {err}",
command.join(" ")
)
});
}
#[test]
fn arceos_starry_and_axvisor_share_the_base_cli_contract() {
let common_commands: &[&[&str]] = &[
&[
"build",
"--config",
"build.toml",
"--arch",
"aarch64",
"--target",
"aarch64-unknown-none-softfloat",
"--smp",
"2",
"--debug",
],
&[
"qemu",
"--config",
"build.toml",
"--arch",
"aarch64",
"--target",
"aarch64-unknown-none-softfloat",
"--smp",
"2",
"--debug",
"--qemu-config",
"qemu.toml",
"--rootfs",
"rootfs.img",
],
&[
"uboot",
"--config",
"build.toml",
"--arch",
"aarch64",
"--target",
"aarch64-unknown-none-softfloat",
"--smp",
"2",
"--debug",
"--uboot-config",
"uboot.toml",
],
&[
"board",
"--config",
"build.toml",
"--arch",
"aarch64",
"--target",
"aarch64-unknown-none-softfloat",
"--smp",
"2",
"--debug",
"--board-config",
"board.toml",
"--board-type",
"qemu",
"--server",
"127.0.0.1",
"--port",
"5555",
],
&["defconfig", "qemu-aarch64"],
&["config", "ls"],
&["test", "qemu", "--list"],
&["test", "board", "--list"],
];
for os in ["arceos", "starry", "axvisor"] {
for command in common_commands {
assert_os_command_contract(os, command);
}
}
}
#[test]
fn os_specific_cli_extensions_remain_additive() {
assert_os_command_contract(
"arceos",
&[
"qemu",
"--package",
"arceos-helloworld",
"--target",
"aarch64-unknown-none-softfloat",
],
);
assert_os_command_contract(
"axvisor",
&[
"qemu",
"--target",
"aarch64-unknown-none-softfloat",
"--vmconfigs",
"vm-1.toml",
"--vmconfigs",
"vm-2.toml",
],
);
assert_os_command_contract("axvisor", &["test", "uboot", "--board", "qemu-aarch64"]);
}
#[test]
fn command_parses_ktest_qemu() {
let cli = TestCli::try_parse_from([
"xtask",
"ktest",
"qemu",
"-p",
"starry-kernel",
"--test",
"axtest_kernel",
"--arch",
"x86_64",
"--qemu-config",
"qemu.toml",
"--coverage",
"--out-fmt",
"html",
])
.unwrap();
match cli.command {
Commands::Ktest(args) => match args.command {
ktest::Command::Qemu(args) => {
assert_eq!(args.package, "starry-kernel");
assert_eq!(args.test.as_deref(), Some("axtest_kernel"));
assert_eq!(args.arch.as_deref(), Some("x86_64"));
assert_eq!(args.qemu_config, Some(PathBuf::from("qemu.toml")));
assert!(args.coverage);
assert_eq!(args.out_fmt, Some(ktest::KtestCoverageOutFmt::Html));
}
_ => panic!("expected ktest qemu command"),
},
_ => panic!("expected ktest command"),
}
}
#[test]
fn command_parses_ktest_board() {
let cli = TestCli::try_parse_from([
"xtask",
"ktest",
"board",
"-p",
"starry-kernel",
"--test",
"axtest_kernel",
"-b",
"orangepi-5-plus",
"--board-config",
"board.toml",
"--board-type",
"OrangePi-5-Plus",
"--server",
"10.0.0.2",
"--port",
"9000",
])
.unwrap();
match cli.command {
Commands::Ktest(args) => match args.command {
ktest::Command::Board(args) => {
assert_eq!(args.package, "starry-kernel");
assert_eq!(args.test, "axtest_kernel");
assert_eq!(args.board, "orangepi-5-plus");
assert_eq!(args.board_config, Some(PathBuf::from("board.toml")));
assert_eq!(args.board_type.as_deref(), Some("OrangePi-5-Plus"));
assert_eq!(args.server.as_deref(), Some("10.0.0.2"));
assert_eq!(args.port, Some(9000));
}
_ => panic!("expected ktest board command"),
},
_ => panic!("expected ktest command"),
}
}
}