diff --git a/.dockerignore b/.dockerignore index 4884de171..bb1683336 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,8 +3,6 @@ target # This one can have large .qcow2 files written by coreos-assembler .cosa -# These directories don't contribute to our container build -docs/ # TMT interprets these, not the container build plans/ # These only affect flow outside of the container diff --git a/Cargo.lock b/Cargo.lock index a15cf90b0..fec557ea9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3392,11 +3392,13 @@ checksum = "32ac00cd3f8ec9c1d33fb3e7958a82df6989c42d747bd326c822b1d625283547" name = "xtask" version = "0.1.0" dependencies = [ + "anstream", "anyhow", "camino", "chrono", "fn-error-context", "mandown", + "owo-colors", "serde", "serde_json", "tar", diff --git a/Dockerfile b/Dockerfile index 3f1c747a6..bef8163dc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,7 +63,7 @@ COPY --from=src /src /src WORKDIR /src # See https://www.reddit.com/r/rust/comments/126xeyx/exploring_the_problem_of_faster_cargo_docker/ # We aren't using the full recommendations there, just the simple bits. -RUN --mount=type=cache,target=/build/target --mount=type=cache,target=/var/roothome < Result { - let json_output = cmd!(sh, "cargo run --features=docgen -- internals dump-cli-json") - .read() - .context("Running CLI JSON dump command")?; + // If we have a release binary, assume that we should compile + // in release mode as hopefully we'll have incremental compilation + // enabled. + let releasebin = Utf8Path::new("target/release/bootc"); + let release = releasebin + .try_exists() + .context("Querying release bin")? + .then_some("--release"); + let json_output = cmd!( + sh, + "cargo run {release...} --features=docgen -- internals dump-cli-json" + ) + .read() + .context("Running CLI JSON dump command")?; let cli_structure: CliCommand = serde_json::from_str(&json_output).context("Parsing CLI JSON output")?; @@ -253,6 +266,7 @@ pub fn update_markdown_with_options( } /// Discover man page files and infer their command paths from filenames +#[context("Querying man page mappings")] fn discover_man_page_mappings( cli_structure: &CliCommand, ) -> Result>)>> { @@ -260,7 +274,7 @@ fn discover_man_page_mappings( let mut mappings = Vec::new(); // Read all .md files in the man directory - for entry in fs::read_dir(man_dir)? { + for entry in fs::read_dir(man_dir).context("Reading docs/src/man")? { let entry = entry?; let path = entry.path(); @@ -278,7 +292,7 @@ fn discover_man_page_mappings( .ok_or_else(|| anyhow::anyhow!("Invalid filename"))?; // Check if the file contains generation markers - let content = fs::read_to_string(&path)?; + let content = fs::read_to_string(&path).with_context(|| format!("Reading {path:?}"))?; if !content.contains("") && !content.contains("") { @@ -331,6 +345,7 @@ fn find_command_path_for_filename( } /// Sync all man pages with their corresponding CLI commands +#[context("Syncing man pages")] pub fn sync_all_man_pages(sh: &Shell) -> Result<()> { let cli_structure = extract_cli_json(sh)?; @@ -382,12 +397,14 @@ pub fn sync_all_man_pages(sh: &Shell) -> Result<()> { } /// Generate man pages from hand-written markdown sources +#[context("Generating manpages")] pub fn generate_man_pages(sh: &Shell) -> Result<()> { let man_src_dir = Utf8Path::new("docs/src/man"); let man_output_dir = Utf8Path::new("target/man"); // Ensure output directory exists - sh.create_dir(man_output_dir)?; + sh.create_dir(man_output_dir) + .with_context(|| format!("Creating {man_output_dir}"))?; // First, sync the markdown files with current CLI options sync_all_man_pages(sh)?; @@ -396,7 +413,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> { let version = get_package_version()?; // Convert each markdown file to man page format - for entry in fs::read_dir(man_src_dir)? { + for entry in fs::read_dir(man_src_dir).context("Reading manpages")? { let entry = entry?; let path = entry.path(); @@ -421,7 +438,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> { let output_file = man_output_dir.join(format!("{}.{}", base_name, section)); // Read markdown content and replace version placeholders - let content = fs::read_to_string(&path)?; + let content = fs::read_to_string(&path).with_context(|| format!("Reading {path:?}"))?; let content_with_version = content.replace("", &version); // Check if we need to regenerate by comparing input and output modification times @@ -437,16 +454,14 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> { if should_regenerate { // Create temporary file with version-replaced content - let temp_path = format!("{}.tmp", path.display()); - fs::write(&temp_path, content_with_version)?; + let mut tmpf = tempfile::NamedTempFile::new_in(path.parent().unwrap())?; + tmpf.write_all(content_with_version.as_bytes())?; + let tmpf = tmpf.path(); - cmd!(sh, "go-md2man -in {temp_path} -out {output_file}") + cmd!(sh, "go-md2man -in {tmpf} -out {output_file}") .run() .with_context(|| format!("Converting {} to man page", path.display()))?; - // Clean up temporary file - fs::remove_file(&temp_path)?; - println!("Generated {}", output_file); } } @@ -458,6 +473,7 @@ pub fn generate_man_pages(sh: &Shell) -> Result<()> { } /// Get version from Cargo.toml +#[context("Querying package version")] fn get_package_version() -> Result { let cargo_toml = fs::read_to_string("crates/lib/Cargo.toml").context("Reading crates/lib/Cargo.toml")?; @@ -596,6 +612,7 @@ TODO: Add practical examples showing how to use this command. } /// Apply post-processing fixes to generated man pages +#[context("Fixing man pages")] fn apply_man_page_fixes(sh: &Shell, dir: &Utf8Path) -> Result<()> { // Fix apostrophe rendering issue for entry in fs::read_dir(dir)? { @@ -608,7 +625,7 @@ fn apply_man_page_fixes(sh: &Shell, dir: &Utf8Path) -> Result<()> { .map_or(false, |e| e.chars().all(|c| c.is_numeric())) { // Check if the file already has the fix applied - let content = fs::read_to_string(&path)?; + let content = fs::read_to_string(&path).with_context(|| format!("Reading {path:?}"))?; if content.starts_with(".ds Aq \\(aq\n") { // Already fixed, skip continue; diff --git a/crates/xtask/src/xtask.rs b/crates/xtask/src/xtask.rs index acc314c24..21b303d6e 100644 --- a/crates/xtask/src/xtask.rs +++ b/crates/xtask/src/xtask.rs @@ -27,8 +27,13 @@ const TAR_REPRODUCIBLE_OPTS: &[&str] = &[ ]; fn main() { + use std::io::Write as _; + + use owo_colors::OwoColorize; if let Err(e) = try_main() { - eprintln!("error: {e:?}"); + let mut stderr = anstream::stderr(); + // Don't panic if writing fails. + let _ = writeln!(stderr, "{}{:#}", "error: ".red(), e); std::process::exit(1); } } @@ -56,7 +61,10 @@ fn try_main() -> Result<()> { } } // Otherwise verify we're in the toplevel - if !Utf8Path::new("ADOPTERS.md").try_exists()? { + if !Utf8Path::new("ADOPTERS.md") + .try_exists() + .context("Checking for toplevel")? + { anyhow::bail!("Not in toplevel") } } @@ -69,11 +77,11 @@ fn try_main() -> Result<()> { .iter() .find_map(|(k, f)| (*k == cmd).then_some(*f)) .unwrap_or(print_help); - f(&sh)?; + return f(&sh); } else { print_help(&sh)?; + Ok(()) } - Ok(()) } fn gitrev_to_version(v: &str) -> String {