#![deny(warnings)] use std::{fs, path::PathBuf, process::ExitCode}; use build::CheckAction; use clap::{Parser, Subcommand}; use env::{Arch, Profile}; use error::Error; #[macro_use] pub mod util; pub mod build; pub mod check; pub mod env; pub mod error; pub mod qemu; #[derive(Parser)] struct Args { #[clap(long, env, help = "Use --release profile for built components")] release: bool, #[clap( short, long, env, default_value_t, value_enum, help = "Target architecture" )] arch: Arch, #[clap( short, long, help = "Do a clean userspace rebuild (e.g. toolchain has changed)" )] clean_userspace: bool, #[clap( short = 'C', long, default_value = "xtask.toml", help = "Configuration path" )] config_path: PathBuf, #[clap(subcommand)] action: Option, } #[derive(Default, Subcommand)] enum SubArgs { #[default] #[clap(about = "Build the OS")] Build, #[clap(about = "Run `cargo check` on components")] Check, #[clap(about = "Run `cargo clippy` on components")] Clippy, #[clap(about = "Run `cargo test` on components")] Test, #[clap(about = "Clean all build artifacts")] Clean { #[clap(short, long, help = "Clean toolchain as well")] toolchain: bool, }, // #[clap(about = "Print `git status` for the components", alias = "gst")] // GitStatus, #[clap(about = "Run the OS image in QEMU")] Qemu { #[clap( short, long, env, help = "Override the default QEMU binary for the target" )] qemu: Option, #[clap(help = "Extra arguments for QEMU")] extra_args: Vec, }, #[clap(about = "Build the Yggdrasil OS Rust toolchain")] Toolchain { branch: Option }, #[clap(about = "Print the host triple")] HostTriple, } fn run(args: Args) -> Result<(), Error> { let action = args.action.unwrap_or_default(); let workspace_root = std::env::current_dir()?; let profile = if args.release { Profile::Release } else { Profile::Debug }; let config = toml::from_str(&fs::read_to_string(args.config_path)?)?; let env = env::BuildEnv::new(config, profile, args.arch, workspace_root); if args.clean_userspace && !matches!(&action, SubArgs::Clean { .. }) { build::clean_userspace(&env)?; } match action { SubArgs::Build => build::build_all(env).map(|_| ()), SubArgs::Check => build::check_all(env, CheckAction::Check), SubArgs::Clippy => build::check_all(env, CheckAction::Clippy), SubArgs::Test => build::test_all(env), SubArgs::Clean { toolchain } => build::clean_all(&env, toolchain), // SubArgs::GitStatus => util::git_status_all(&env), SubArgs::Qemu { qemu, extra_args } => qemu::run(env, qemu, extra_args), SubArgs::Toolchain { branch } => { let branch = branch.as_ref().unwrap_or(&env.config.toolchain.branch); build::build_toolchain(&env, branch) } SubArgs::HostTriple => { println!("{}", env.host_triple); Ok(()) } } } fn main() -> ExitCode { env_logger::builder() .filter_level(log::LevelFilter::Info) .parse_default_env() .init(); let args = Args::parse(); match run(args) { Ok(()) => ExitCode::SUCCESS, Err(Error::MissingTools(list)) => { eprintln!("Missing some required tools:"); for (tool, guide) in list { eprintln!(" * {}: {}", tool, guide); } ExitCode::FAILURE } Err(err) => { eprintln!("Error: {}", err); ExitCode::FAILURE } } }