extract(cubecli): move cube CLI out of cubesys into standalone crate
The `cube` binary (REPL + script runner over one shared CubeStore) is now its own crate at `cubecli/`, matching the spec's package outline that lists cubecli as a separate crate from the composition layer. What changed: - New `cubecli/` crate with `Cargo.toml` (deps: cubecoords, cubestore, cubefs, cubecode, cubecrypt, cubesys) and `src/main.rs` (copy of the former `cubesys/src/bin/cube.rs`). - `cubesys/Cargo.toml`: removed the `[[bin]]` entry for `cube`; keeps `cube-demo`, `cube-server`, and `cubec` as before. - `Cargo.toml` (workspace): added `cubecli` to members. - `cubesys/src/bin/cube.rs` removed (code now lives in cubecli). The `cube` binary is unchanged: same CLI surface, same demo, same commands. The `cube-demo` binary in cubesys still wraps `cubesys::demo::run()` and is unaffected. Verification: `./check` gate passes (fmt + tests + clippy -D warnings); `cube --help` and `cube demo` both work. Co-Authored-By: Hermes Agent
This commit is contained in:
co-authored by
Hermes Agent
parent
fdfcd2c728
commit
ce8ac78a24
@@ -0,0 +1,141 @@
|
||||
//! `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.Z.Y.X|auto> <tf> # encrypt the record at <path> (tf: none|gcm|chacha|xts)
|
||||
//! open <path> <K.Z.Y.X|auto> <tf> # decrypt + decode + run the sealed record
|
||||
//! keyinit # ensure the OS Null-space keystore exists
|
||||
//!
|
||||
//! 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 auto 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"
|
||||
| "keyinit"
|
||||
| "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|auto> <tf> encrypt a record (tf: none|gcm|chacha|xts)\n \
|
||||
open <path> <K.Z.Y.X|auto> <tf> decrypt + decode + run a sealed record\n \
|
||||
keyinit ensure the OS Null-space keystore exists\n"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user