Skip to main content

xtask_lib/tasks/
run_emulator.rs

1//! `cargo xtask run-emulator` — run the Cadmus emulator.
2//!
3//! Ensures the native MuPDF build and the embedded documentation EPUB are
4//! ready, then launches `cargo run -p emulator`.  Any extra arguments are
5//! forwarded to the emulator.
6
7use std::path::Path;
8
9use anyhow::Result;
10use clap::Args;
11
12use super::docs::{self, DocsArgs};
13use super::setup_native::{self, SetupNativeArgs};
14use super::util::{cmd, workspace};
15
16/// Arguments for `cargo xtask run-emulator`.
17#[derive(Debug, Args)]
18pub struct RunEmulatorArgs {
19    /// Cargo feature flags forwarded to `cargo run -p emulator`.
20    #[arg(long)]
21    pub features: Option<String>,
22
23    /// Extra arguments forwarded to `cargo run -p emulator`.
24    #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
25    pub extra: Vec<String>,
26}
27
28/// Returns `true` when the documentation EPUB embedded by `cadmus-core` exists.
29fn mdbook_epub_built(root: &Path) -> bool {
30    root.join("docs/book/epub/Cadmus Documentation.epub")
31        .exists()
32}
33
34/// Ensures prerequisites are built then launches the emulator.
35///
36/// # Errors
37///
38/// Returns an error if the native setup, documentation build, or emulator
39/// launch fails.
40pub fn run(args: RunEmulatorArgs) -> Result<()> {
41    let root = workspace::root()?;
42
43    if !setup_native::native_setup_done(&root) {
44        println!("Native setup not found — running setup-native…");
45        setup_native::run(SetupNativeArgs { force: false })?;
46    }
47
48    if !mdbook_epub_built(&root) {
49        println!("Documentation EPUB not found — building mdBook…");
50        docs::run(DocsArgs {
51            base_url: "http://localhost".to_string(),
52            mdbook_only: true,
53        })?;
54    }
55
56    let mut cargo_args = vec!["run", "-p", "emulator"];
57
58    if let Some(features) = args.features.as_deref() {
59        cargo_args.push("--features");
60        cargo_args.push(features);
61    }
62
63    let extra_refs: Vec<&str> = args.extra.iter().map(String::as_str).collect();
64    cargo_args.extend_from_slice(&extra_refs);
65
66    cmd::run("cargo", &cargo_args, &root, &[])
67}