Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

crates/nornir-warehouse-embed/examples/room_ask.rs

//! **Ask the code room what a pane asks — from a shell.**
//!
//! Every code-graph pane of the dwarves UI draws an answer of nornir's code room
//! (`CodeRoom.Answer`). This is the shell-side twin of those panes: the SAME question
//! over the SAME client, printed as the JSON the server sent — so the number on a
//! pane can be put beside the number the server gives.
//!
//! ```text
//! # through the dwarves HOST's proxy (the path the UI takes)
//! NORNIR_SERVER=http://127.0.0.1:7900 NORNIR_WORKSPACE=nordisk \
//!   cargo run -p nornir-warehouse-embed --example room_ask -- ask Viz.CrateGraph '{"universe":true}'
//!
//! # straight at nornir (no forge in between)
//! NORNIR_SERVER=http://127.0.0.1:7878 … -- ask Knowledge.TestReach
//! ```
//!
//! Other verbs, for standing a workspace up without a UI:
//!
//! | verb | does |
//! |---|---|
//! | `ask <surface> [params-json]` | `CodeRoom.Answer`; prints the body |
//! | `state <surface> [params-json]` | the same, one line: state · room · evidence |
//! | `lens <ChangeRisk\|ZombieFeatures\|GenericCost\|SimilarCode\|WeakTests\|BenchGaps\|Villa> ` | the `Mimir.*` lens; prints the envelope |
//! | `register <name> <descriptor.toml>` | `Workspaces.Register` (monitored, eager), shipping the file's content |
//! | `fetch <name>` | `Workspaces.Fetch { force }` |
//! | `get <name>` | `Workspaces.Get`: the members and the snapshot |
//! | `scan <table> [limit]` | `Warehouse.Scan`: row count and the first rows |
//!
//! `NORNIR_SERVER_TOKEN` supplies the bearer (empty ⇒ open).

use nornir_warehouse_embed::{mimir, pb, room};

fn main() {
    let endpoint =
        std::env::var("NORNIR_SERVER").unwrap_or_else(|_| "http://127.0.0.1:7878".into());
    let token = std::env::var("NORNIR_SERVER_TOKEN").unwrap_or_default();
    let workspace = std::env::var("NORNIR_WORKSPACE").unwrap_or_default();
    let args: Vec<String> = std::env::args().skip(1).collect();
    let arg = |i: usize| args.get(i).map(String::as_str).unwrap_or("");
    let params = |i: usize| -> serde_json::Value {
        match arg(i) {
            "" => serde_json::json!({}),
            text => serde_json::from_str(text).unwrap_or_else(|e| {
                eprintln!("room_ask: params are not JSON ({e}): {text}");
                std::process::exit(2);
            }),
        }
    };
    let pretty = |v: &serde_json::Value| serde_json::to_string_pretty(v).unwrap_or_default();
    match arg(0) {
        "ask" => {
            let a = room::ask(&endpoint, &token, &workspace, arg(1), &params(2));
            eprintln!(
                "{} — state `{}`{}",
                a.via,
                a.state,
                if a.is_measured() {
                    ""
                } else {
                    " (not a measurement)"
                }
            );
            if a.body.is_null() {
                println!("{}", pretty(&a.state_json()));
            } else {
                println!("{}", pretty(&a.body));
            }
        }
        "state" => {
            let a = room::ask(&endpoint, &token, &workspace, arg(1), &params(2));
            println!(
                "{} · state {} · room [{}] · {}",
                a.via,
                a.state,
                a.room_line(),
                a.evidence_text()
            );
        }
        "lens" => {
            let res = match arg(1) {
                "ChangeRisk" => mimir::change_risk(&endpoint, &token, &workspace, "", 0),
                "ZombieFeatures" => mimir::zombie_features(&endpoint, &token, &workspace, "", 0),
                "GenericCost" => mimir::generic_cost(&endpoint, &token, &workspace, "", 0, 0),
                "SimilarCode" => mimir::similar_code(&endpoint, &token, &workspace, "", 0),
                "WeakTests" => mimir::weak_tests(&endpoint, &token, &workspace, "", 0),
                "BenchGaps" => mimir::bench_gaps(&endpoint, &token, &workspace, "", 0),
                "Villa" => mimir::villa(&endpoint, &token, &workspace, "", 0),
                other => {
                    eprintln!("room_ask: no lens `{other}` here");
                    std::process::exit(2);
                }
            };
            match res {
                Ok(v) => println!("{}", pretty(&v)),
                Err(e) => {
                    eprintln!("Mimir.{}: {e}", arg(1));
                    std::process::exit(1);
                }
            }
        }
        "register" => {
            let content = std::fs::read_to_string(arg(2)).unwrap_or_else(|e| {
                eprintln!("room_ask: read descriptor {}: {e}", arg(2));
                std::process::exit(2);
            });
            let (name, url) = (arg(1).to_string(), endpoint.clone());
            let rt = tokio::runtime::Builder::new_current_thread()
                .enable_all()
                .build()
                .expect("runtime");
            let rec = rt.block_on(async move {
                let mut client = pb::workspaces_client::WorkspacesClient::connect(url)
                    .await
                    .map_err(|e| e.to_string())?;
                client
                    .register(pb::RegisterWorkspaceRequest {
                        name,
                        descriptor: String::new(),
                        mode: "monitored".into(),
                        poll: String::new(),
                        lazy: false,
                        descriptor_content: content,
                    })
                    .await
                    .map(|r| r.into_inner())
                    .map_err(|s| format!("{} ({:?})", s.message(), s.code()))
            });
            match rec {
                Ok(r) => println!(
                    "registered `{}` mode {} snapshot `{}` members {:?}",
                    r.name,
                    r.mode,
                    r.current_snapshot,
                    r.members
                        .iter()
                        .map(|m| format!("{}@{} [{}]", m.name, m.last_seen_sha, m.sync_state))
                        .collect::<Vec<_>>()
                ),
                Err(e) => {
                    eprintln!("Workspaces.Register: {e}");
                    std::process::exit(1);
                }
            }
        }
        "fetch" => {
            match nornir_warehouse_embed::populate_warehouse(&endpoint, &token, arg(1), true) {
                Ok(o) => println!(
                    "fetched {} member(s), changed {:?}, errors {:?}, snapshot `{}`",
                    o.fetched, o.changed, o.errors, o.snapshot
                ),
                Err(e) => {
                    eprintln!("Workspaces.Fetch: {e:#}");
                    std::process::exit(1);
                }
            }
        }
        "get" => match nornir_warehouse_embed::get_warehouse(&endpoint, &token, arg(1)) {
            Ok(w) => println!("{}", serde_json::to_string_pretty(&w).unwrap_or_default()),
            Err(e) => {
                eprintln!("Workspaces.Get: {e:#}");
                std::process::exit(1);
            }
        },
        "scan" => {
            let limit = arg(2).parse().unwrap_or(5);
            match nornir_warehouse_embed::scan_warehouse_table(
                &endpoint,
                &token,
                &workspace,
                arg(1),
                limit,
            ) {
                Ok(s) => {
                    println!("{}: {} row(s) {:?}", arg(1), s.rows.len(), s.columns);
                    for r in s.rows.iter().take(5) {
                        println!("  {r:?}");
                    }
                }
                Err(e) => {
                    eprintln!("Warehouse.Scan {}: {e}", arg(1));
                    std::process::exit(1);
                }
            }
        }
        _ => {
            eprintln!("usage: room_ask ask|state <surface> [params-json] | lens <Name> | register <name> <descriptor.toml> | fetch <name> | get <name> | scan <table> [limit]");
            std::process::exit(2);
        }
    }
}