Files
cubelinux-2/cubesys/src/bin/cube.rs
T
hermes f264527365 cubefs/phase3: expose 'open'/'seal' as first-class CLI commands; document startup verification points
- cubesys/src/bin/cube.rs: route known command words (prog/write/run/ls/stat/
  seal/open/query/begin/commit/rollback/stats/audit) straight to Session::exec
  from argv, making the coordinate-addressed 'open <path> <K.Z.Y.X> <tf>' surface
  (Phase 3 'open by CZYX + flags') a real CLI command, not REPL/script-only.
  Verified: ./check green; cube open/cube bogus both behave; dispatch reaches
  crypto/run layer over in-process and durable daemon (cubec) paths.
- STARTUP-README.md: add verification points per standing directive; mark
  Phase 2 FS + durability VERIFIED, Phase 3 surface DONE, boot-substrate IN PROGRESS.
- Guest binaries synced to host HEAD f40b448 + this change; OS state now persists
  on the cube store in the VM (/cubefs/c200/...), durable across daemon restart.
2026-08-13 09:32:45 -04:00

139 lines
5.4 KiB
Rust

//! `cube` — the CUBELinux-2 system CLI (local, in-process).
//!
//! One process holds ONE in-memory `CubeStore` shared by cubefs, cubecode and
//! cubecrypt. Commands are issued as a script (file) or interactively (REPL);
//! every command operates on that shared store, so `write` then `run` then
//! `seal` then `open` all see the same cube.
//!
//! For a persistent store served over a socket by a long-running daemon, use
//! `cube-server` + `cubec` instead (see `docs/integration.md`).
//!
//! Usage:
//! cube # print this help
//! cube demo # run the built-in integration demo
//! cube repl # read commands from stdin, one per line
//! cube script <file> # read commands from <file>, one per line
//!
//! Commands (operate on the shared cube):
//! prog <path> <ops...> # write CUBEVM bytecode from op names
//! write <path> <bytes...> # store cubevm bytecode (hex/dec) at a path
//! run <path> # load the code cell at <path> and run the VM
//! ls <dir> # list a cubefs directory
//! stat <path> # getattr via cubefs
//! seal <path> <K.C.Z.Y.X> <tf> # encrypt the record at <path> (tf: none|gcm|chacha|xts)
//! open <path> <K.C.Z.Y.X> <tf> # decrypt + decode + run the sealed record
//!
//! Coordinates are written `C.Z.Y.X` (decimal). Key cells live in Null space,
//! so they are given directly as coordinates, not as cubefs paths.
use std::io::BufRead;
use cubesys::commands::Session;
/// Command words understood by the shared interpreter. When `cube`'s first
/// argument is one of these, it is run as a single command against a fresh
/// in-memory store (the same path as `cube repl`), so the OS / a script can
/// invoke e.g. `cube open /c001/z001/y001/x001 001.001.001.001 none` directly
/// — this is the Phase-3 "open by CZYX + flags" surface made a first-class
/// CLI command rather than REPL-only.
fn is_command_word(w: &str) -> bool {
matches!(
w,
"prog"
| "write"
| "run"
| "ls"
| "stat"
| "seal"
| "open"
| "query"
| "begin"
| "commit"
| "rollback"
| "stats"
| "audit"
)
}
fn main() {
let args: Vec<String> = std::env::args().collect();
match args.get(1).map(|s| s.as_str()) {
None => print_help(),
Some("demo") => cubesys::demo::run(),
// A direct command word (e.g. `cube open <path> <K.Z.Y.X> <tf>`): run it
// against a fresh in-memory session and exit with the result. This makes
// the coordinate-addressed API a real CLI surface the OS can call.
Some(word) if is_command_word(word) => {
let line = args[1..].join(" ");
let mut session = Session::new();
match session.exec(&line) {
Ok(out) => println!("{out}"),
Err(e) => {
eprintln!("error: {e}");
std::process::exit(1);
}
}
}
Some("repl") => {
let mut session = Session::new();
let stdin = std::io::stdin();
let lock = stdin.lock();
for line in lock.lines() {
let line = match line {
Ok(l) => l,
Err(_) => break,
};
if line.trim().is_empty() || line.starts_with('#') {
continue;
}
match session.exec(&line) {
Ok(out) => println!("{out}"),
Err(e) => eprintln!("error: {e}"),
}
}
}
Some("script") => {
let file = args.get(2).expect("script needs <file>");
let text = std::fs::read_to_string(file).expect("cannot read script file");
let mut session = Session::new();
for line in text.lines() {
if line.trim().is_empty() || line.starts_with('#') {
continue;
}
match session.exec(line) {
Ok(out) => println!("{out}"),
Err(e) => {
eprintln!("error: {e}");
std::process::exit(1);
}
}
}
}
Some(other) => {
eprintln!("unknown subcommand: {other}\n");
print_help();
std::process::exit(2);
}
}
}
fn print_help() {
println!(
"cube - CUBELinux-2 system CLI (cubefs + cubecode + cubecrypt over one store)\n\
\n\
Usage:\n \
cube show this help\n \
cube demo run the built-in integration demo\n \
cube repl read commands from stdin (one per line)\n \
cube script <file> run commands from a file\n\
\nCommands:\n \
prog <path> <ops...> write CUBEVM bytecode from op names\n \
write <path> <bytes...> store cubevm bytecode at a path\n \
run <path> run the code cell at <path>\n \
ls <dir> list a cubefs directory\n \
stat <path> getattr via cubefs\n \
seal <path> <K.Z.Y.X> <tf> encrypt a record (tf: none|gcm|chacha|xts)\n \
open <path> <K.Z.Y.X> <tf> decrypt + decode + run a sealed record\n"
);
}