// main.mbt
//
// The `regolith` CLI: subcommand-style argument parsing via core/argparse,
// with the actual command logic in clicore. Storage lives under
// regolith-data/ (git-ignored). Run with:
//
// moon run --target js cli -- set hello regolith
// moon run cli -- get hello (native backend, needs a C compiler)
fn err_text(e : @QYF795/regolith.DbError) -> String {
match e {
@QYF795/regolith.DbError::Io(m) => m
@QYF795/regolith.DbError::Corrupt(m) => m
@QYF795/regolith.DbError::Fault(m) => m
}
}
fn main {
let cmd = @argparse.Command(
"regolith",
about="月壤 CLI — embedded LSM-tree KV store",
version="0.1.0",
subcommands=[
@argparse.Command(
"set",
about="write key=value",
positionals=[
@argparse.PositionArg("key", num_args=@argparse.ValueRange::single()),
@argparse.PositionArg("value", num_args=@argparse.ValueRange::single()),
],
),
@argparse.Command(
"get",
about="read a key",
positionals=[@argparse.PositionArg("key", num_args=@argparse.ValueRange::single())],
),
@argparse.Command(
"del",
about="delete a key",
positionals=[@argparse.PositionArg("key", num_args=@argparse.ValueRange::single())],
),
@argparse.Command(
"batch",
about="atomic multi-key write: (put | del )...",
positionals=[@argparse.PositionArg("ops", num_args=@argparse.ValueRange(lower=1))],
),
@argparse.Command("scan", about="list all live entries"),
@argparse.Command(
"scan_prefix",
about="list entries whose key starts with the prefix",
positionals=[@argparse.PositionArg("prefix", num_args=@argparse.ValueRange::single())],
),
@argparse.Command(
"scan_range",
about="list entries with start <= key < end (empty end = unbounded)",
positionals=[
@argparse.PositionArg("start", num_args=@argparse.ValueRange::single()),
@argparse.PositionArg("end", num_args=@argparse.ValueRange::single()),
],
),
@argparse.Command("flush", about="flush the memtable to L0"),
@argparse.Command("compact", about="merge everything into the bottom level (L2)"),
@argparse.Command("stats", about="storage statistics"),
],
subcommand_required=true,
)
// Parse failures already carry display-ready text with full help.
let matches = try {
cmd.parse()
} catch {
e => {
println(e.to_string())
return
}
}
// Flatten the parsed subcommand back into a token array for clicore:
// ["set", key, value] / ["get", key] / ["batch", op, ...] / ...
let argv : Array[String] = match matches.subcommand {
Some((name, m)) => {
let a : Array[String] = [name]
for p in ["key", "value", "prefix", "start", "end", "ops"] {
match m.values.get(p) {
Some(vs) => {
for v in vs {
a.push(v)
}
}
None => ()
}
}
a
}
None => return // unreachable: subcommand_required
}
let db = try {
@QYF795/regolith.Db::open("regolith-data")
} catch {
e => {
println("error: \{err_text(e)}")
return
}
}
let out = try {
@clicore.run(db, argv)
} catch {
e => {
println("error: \{err_text(e)}")
return
}
}
println(out)
}