///|
fn print_help() -> Unit {
println(@lib.banner())
println("Read-only SQLite database and WAL analysis")
println("")
println("Usage:")
println(" pagelens inspect [--json]")
println(" pagelens wal [--json]")
println(" pagelens snapshot [--wal ] [--json]")
println(" pagelens check [--wal ] [--json]")
println("")
println("Options:")
println(" --json emit one machine-readable JSON value")
println(" --wal use an explicit WAL path (default: -wal)")
println(" -h, --help show this help")
println(" --version show the PageLens version")
println("")
println("PageLens never executes SQL and never writes to the input files.")
}
///|
fn has_flag(args : Array[String], flag : String) -> Bool {
for arg in args {
if arg == flag {
return true
}
}
false
}
///|
fn option_value(args : Array[String], option : String) -> String? {
for index = 0; index < args.length(); index = index + 1 {
if args[index] == option && index + 1 < args.length() {
return Some(args[index + 1])
}
}
None
}
///|
fn read_file(path : String) -> Bytes? {
Some(@fs.read_file_to_bytes(path)) catch {
@fs.IOError(message) => {
println("PageLens error: cannot read '" + path + "': " + message)
None
}
}
}
///|
fn read_optional_wal(path : String) -> Bytes? {
if @fs.path_exists(path) {
read_file(path)
} else {
None
}
}
///|
fn run_inspect(args : Array[String], json : Bool) -> Int {
guard args.length() >= 3 else {
println("PageLens error: inspect requires a database path")
print_help()
return 2
}
guard read_file(args[2]) is Some(data) else { return 2 }
try {
let inspection = @lib.inspect_database(data)
println(
if json {
@lib.render_database_json(inspection)
} else {
@lib.render_database_text(inspection)
},
)
0
} catch {
error => {
println("PageLens error: " + error.message())
2
}
}
}
///|
fn run_wal(args : Array[String], json : Bool) -> Int {
guard args.length() >= 3 else {
println("PageLens error: wal requires a WAL file path")
print_help()
return 2
}
guard read_file(args[2]) is Some(data) else { return 2 }
try {
let wal = @lib.parse_wal(data)
println(
if json {
@lib.render_wal_json(wal)
} else {
@lib.render_wal_text(wal)
},
)
if wal.diagnostics.length() == 0 {
0
} else {
1
}
} catch {
error => {
println("PageLens error: " + error.message())
2
}
}
}
///|
fn selected_wal_path(args : Array[String], database_path : String) -> String {
match option_value(args, "--wal") {
Some(path) => path
None => database_path + "-wal"
}
}
///|
fn run_snapshot(args : Array[String], json : Bool) -> Int {
guard args.length() >= 3 else {
println("PageLens error: snapshot requires a database path")
print_help()
return 2
}
let database_path = args[2]
let wal_path = selected_wal_path(args, database_path)
guard read_file(database_path) is Some(database_data) else { return 2 }
guard read_file(wal_path) is Some(wal_data) else { return 2 }
try {
let database = @lib.DatabaseImage::open(database_data)
let wal = @lib.parse_wal(wal_data)
let snapshot = @lib.open_snapshot(database, wal)
println(
if json {
@lib.render_snapshot_json(snapshot)
} else {
@lib.render_snapshot_text(snapshot)
},
)
0
} catch {
error => {
println("PageLens error: " + error.message())
2
}
}
}
///|
fn run_check(args : Array[String], json : Bool) -> Int {
guard args.length() >= 3 else {
println("PageLens error: check requires a database path")
print_help()
return 2
}
let database_path = args[2]
guard read_file(database_path) is Some(database_data) else { return 2 }
let wal_path = selected_wal_path(args, database_path)
let wal_data = read_optional_wal(wal_path)
let report = match wal_data {
Some(bytes) => @lib.check_database(database_data, wal_data=bytes)
None => @lib.check_database(database_data)
}
println(
if json {
@lib.render_integrity_json(report)
} else {
@lib.render_integrity_text(report)
},
)
if report.is_ok() {
0
} else {
1
}
}
///|
fn run(args : Array[String]) -> Int {
if args.length() <= 1 || has_flag(args, "--help") || has_flag(args, "-h") {
print_help()
return 0
}
if args[1] == "--version" {
println(@lib.version)
return 0
}
let json = has_flag(args, "--json")
match args[1] {
"inspect" => run_inspect(args, json)
"wal" => run_wal(args, json)
"snapshot" => run_snapshot(args, json)
"check" => run_check(args, json)
command => {
println("PageLens error: unknown command '" + command + "'")
print_help()
2
}
}
}
///|
fn main {
@sys.exit(run(@env.args()))
}