use clap::{Arg, Command};
use frameassembly::backend::generate_pcap;
use frameassembly::parser::parse_program;
use miette::{IntoDiagnostic, Result};
use std::fs;
fn build_cli() -> Command {
Command::new("frameassembly")
.version(env!("CARGO_PKG_VERSION"))
.about("Declarative network packet crafting DSL compiler generating deterministic .pcap/.pcapng captures across 81 L2-L7 protocols")
.arg(
Arg::new("input")
.help("Path to the .fasm source file")
.required(true)
.index(1),
)
.arg(
Arg::new("output")
.short('o')
.long("output")
.help("Path to the output PCAP file")
.default_value("output.pcap"),
)
}
fn main() -> Result<()> {
let matches = build_cli().get_matches();
let file = matches
.get_one::<String>("input")
.ok_or_else(|| miette::miette!("Missing input file"))?;
let output_pcap = matches
.get_one::<String>("output")
.map(|s| s.as_str())
.unwrap_or("output.pcap");
let code = fs::read_to_string(file).into_diagnostic()?;
let program =
parse_program(&code).map_err(|e| miette::Report::new(e).with_source_code(code.clone()))?;
println!(
"Successfully parsed {} hosts, {} flows",
program.hosts.len(),
program.flows.len(),
);
println!("Starting PCAP compilation...");
generate_pcap(&program, output_pcap).map_err(|e| miette::miette!("Backend error: {}", e))?;
println!("Successfully generated {}", output_pcap);
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_cli_invariants() {
build_cli().debug_assert();
}
}