1use anyhow::{Context, Result};
14use colored::*;
15use robonix_cli::{Config, SourcePathKey};
16use std::path::{Path, PathBuf};
17use std::process::Command;
18
19use super::codegen::{build_codegen_cmd, locate_codegen_bin, run_cmd};
20
21pub async fn execute(config: Config, out_dir: Option<PathBuf>) -> Result<()> {
22 let root = config.resolve_source_path(SourcePathKey::Root)?;
23 let rust_root = config.resolve_source_path(SourcePathKey::RustRoot)?;
24 let capabilities_dir = config.resolve_source_path(SourcePathKey::Capabilities)?;
25 let interfaces_lib = config.resolve_source_path(SourcePathKey::InterfacesLib)?;
26
27 let out = match out_dir {
30 Some(d) if d.is_absolute() => d,
31 Some(d) => root.join(d),
32 None => root.join("docs").join("src").join("reference"),
33 };
34 std::fs::create_dir_all(&out)
35 .with_context(|| format!("create reference dir {}", out.display()))?;
36
37 let stamp = version_stamp(&root);
38
39 let direct = locate_codegen_bin(&rust_root);
40 let cargo = if direct.is_none() {
41 Some(std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()))
42 } else {
43 None
44 };
45
46 println!(
47 "{} robonix-codegen --lang docs → {}",
48 "[docs]".bold(),
49 out.display()
50 );
51 println!("{} version stamp: {}", "[docs]".bold(), stamp);
52 let mut cmd = build_codegen_cmd(direct.as_ref(), cargo.as_deref(), &rust_root);
53 cmd.args(["--lang", "docs", "-I"])
54 .arg(&interfaces_lib)
55 .arg("--contracts")
56 .arg(&capabilities_dir)
57 .arg("-o")
58 .arg(&out)
59 .arg("--doc-stamp")
60 .arg(&stamp);
61 run_cmd("robonix-codegen docs", &mut cmd)?;
62
63 println!(
64 "{} wrote contracts.md + idl.md. Commit them into the docs repo — \
65 the mdBook / Pages build needs no robonix environment.",
66 "[docs]".green().bold()
67 );
68 Ok(())
69}
70
71fn version_stamp(root: &Path) -> String {
76 let git = |args: &[&str]| -> Option<String> {
77 let out = Command::new("git")
78 .arg("-C")
79 .arg(root)
80 .args(args)
81 .output()
82 .ok()?;
83 if !out.status.success() {
84 return None;
85 }
86 let s = String::from_utf8(out.stdout).ok()?.trim().to_string();
87 (!s.is_empty()).then_some(s)
88 };
89 let sha = git(&["rev-parse", "--short", "HEAD"]).unwrap_or_else(|| "unknown".to_string());
90 let dirty = git(&["status", "--porcelain"]).is_some_and(|s| !s.is_empty());
91 let date = git(&["log", "-1", "--format=%cd", "--date=short"]).unwrap_or_default();
92 let ver = env!("CARGO_PKG_VERSION");
93 let dirty_tag = if dirty { "-dirty" } else { "" };
94 let date_part = if date.is_empty() {
95 String::new()
96 } else {
97 format!(" · {date}")
98 };
99 format!("v{ver} · commit {sha}{dirty_tag}{date_part}")
100}