Skip to main content

rbnx/cmd/
setup.rs

1// SPDX-License-Identifier: MulanPSL-2.0
2// `rbnx setup` — register the current robonix source tree so out-of-tree packages
3// (their build.sh, codegen calls) can resolve paths via `rbnx path <key>`.
4
5use anyhow::{Context, Result};
6use colored::*;
7use robonix_cli::Config;
8use std::path::{Path, PathBuf};
9
10/// Markers that identify a directory as a valid robonix repo root.
11/// The Cargo workspace lives at the repo root; capabilities/ hosts the
12/// contract TOMLs plus the IDL tree under capabilities/lib (used to be a
13/// symlink into rust/crates/robonix-interfaces/lib; now hosted directly).
14const ROBONIX_ROOT_MARKERS: &[&str] = &["Cargo.toml", "capabilities", "capabilities/lib"];
15
16fn looks_like_robonix_root(dir: &Path) -> bool {
17    ROBONIX_ROOT_MARKERS.iter().all(|m| dir.join(m).exists())
18}
19
20/// Find a robonix root by walking up from `start`.
21fn find_root_upwards(start: &Path) -> Option<PathBuf> {
22    let mut cur = start;
23    loop {
24        if looks_like_robonix_root(cur) {
25            return Some(cur.to_path_buf());
26        }
27        match cur.parent() {
28            Some(p) => cur = p,
29            None => return None,
30        }
31    }
32}
33
34pub async fn execute(_config: Config, path: Option<PathBuf>) -> Result<()> {
35    // Determine candidate: explicit arg, $RBNX_INVOCATION_CWD, then process cwd.
36    let candidate = if let Some(p) = path {
37        if p.is_absolute() {
38            p
39        } else {
40            std::env::current_dir()?.join(p)
41        }
42    } else {
43        let invocation_cwd = std::env::var("RBNX_INVOCATION_CWD").ok();
44        invocation_cwd
45            .map(PathBuf::from)
46            .unwrap_or(std::env::current_dir()?)
47    };
48
49    let candidate = candidate
50        .canonicalize()
51        .with_context(|| format!("Failed to canonicalize {}", candidate.display()))?;
52
53    let root = if looks_like_robonix_root(&candidate) {
54        candidate.clone()
55    } else if let Some(r) = find_root_upwards(&candidate) {
56        r
57    } else {
58        eprintln!(
59            "{}: {} does not look like a robonix source tree.",
60            "error".red().bold(),
61            candidate.display()
62        );
63        eprintln!(
64            "Expected markers (at least one level up): {}",
65            ROBONIX_ROOT_MARKERS.join(", ")
66        );
67        eprintln!("Run `rbnx setup` from inside a cloned robonix repo.");
68        std::process::exit(1);
69    };
70
71    let mut config = Config::load()?;
72    let previous = config.robonix_source_path.clone();
73    config.robonix_source_path = Some(root.clone());
74    config.save()?;
75
76    println!("{} robonix source path registered:", "✓".green().bold());
77    println!("  {}", root.display().to_string().bold().cyan());
78    if let Some(prev) = previous.filter(|p| p != &root) {
79        println!("  (previously: {})", prev.display().to_string().dimmed());
80    }
81    println!(
82        "\nOther packages can now resolve paths via `{}`.",
83        "rbnx path <key>".bold()
84    );
85    println!("Valid keys: root, rust, capabilities, interfaces-lib, runtime-proto, robonix-api");
86    Ok(())
87}