1#![forbid(unsafe_code)]
12
13use anyhow::Context;
14use clap::Parser;
15use clap::Subcommand;
16use std::path::Path;
17use std::path::PathBuf;
18
19mod completions;
20pub mod fs_helpers;
21pub mod shell;
22pub mod tasks;
23
24pub const XTASK_PATH_FILE: &str = "./target/xtask-path";
30
31#[derive(Clone)]
33pub struct XtaskCtx {
34 pub root: PathBuf,
36 pub in_git_hook: bool,
38 pub in_run_on_save: bool,
40}
41
42pub trait Xtask: Parser {
44 fn run(self, ctx: XtaskCtx) -> anyhow::Result<()>;
51}
52
53#[derive(Parser)]
54#[clap(name = "xtask", about = "OpenVMM repo automation")]
55struct Cli {
56 #[clap(subcommand)]
57 command: Commands,
58
59 #[clap(long)]
64 custom_root: Option<PathBuf>,
65
66 #[clap(long)]
77 run_on_save: bool,
78}
79
80#[derive(Subcommand)]
81enum Commands {
82 #[clap(hide = true)]
83 Hook(tasks::RunGitHook),
84 #[clap(hide = true)]
85 Complete(clap_dyn_complete::Complete),
86 Completions(completions::Completions),
87
88 Clean(tasks::Clean),
89 Fmt(tasks::Fmt),
90 Fuzz(tasks::Fuzz),
91 GuestTest(tasks::GuestTest),
92 InstallGitHooks(tasks::InstallGitHooks),
93 VerifySize(tasks::VerifySize),
94}
95
96fn main() {
97 ci_logger::init("XTASK_LOG").unwrap();
98
99 if let Err(e) = try_main() {
100 log::error!("Error: {:#}", e);
101 std::process::exit(-1);
102 }
103}
104
105fn try_main() -> anyhow::Result<()> {
106 let cli = Cli::parse();
107
108 let orig_root = Path::new(&env!("CARGO_MANIFEST_DIR"))
109 .ancestors()
110 .nth(1)
111 .unwrap()
112 .to_path_buf();
113
114 let root = cli
115 .custom_root
116 .map(std::path::absolute)
117 .transpose()?
118 .unwrap_or(orig_root.clone());
119
120 std::env::set_current_dir(&root)?;
122
123 if let Ok(path) = std::env::current_exe() {
127 if let Err(e) = fs_err::write(orig_root.join(XTASK_PATH_FILE), path.display().to_string()) {
128 log::debug!("Unable to create XTASK_PATH_FILE: {:#}", e)
129 }
130 }
131
132 if !matches!(cli.command, Commands::Complete(..)) {
133 tasks::update_hooks(&root).context("failed to update git hooks")?;
134 }
135
136 let ctx = XtaskCtx {
137 root,
138 in_git_hook: matches!(cli.command, Commands::Hook(..)),
139 in_run_on_save: cli.run_on_save,
140 };
141
142 match cli.command {
143 Commands::Hook(task) => task.run(ctx),
144 Commands::Completions(task) => task.run(),
145 Commands::Complete(task) => {
146 futures::executor::block_on(task.println_to_stub_script::<Cli>(
147 Some("cargo"),
148 completions::XtaskCompleteFactory { ctx },
149 ));
150 Ok(())
151 }
152
153 Commands::Clean(task) => task.run(ctx),
154 Commands::Fmt(task) => task.run(ctx),
155 Commands::Fuzz(task) => task.run(ctx),
156 Commands::GuestTest(task) => task.run(ctx),
157 Commands::InstallGitHooks(task) => task.run(ctx),
158 Commands::VerifySize(task) => task.run(ctx),
159 }
160}