use clap::Parser;
use quack_builder::{ConfigBuilder, errors::Error, types::FileDescriptor};
use std::path::{Path, PathBuf};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct Cli {
#[arg(short, long)]
output: Option<String>,
#[arg(short = 'd', long)]
output_directory: Option<String>,
#[arg(short = 'I', long)]
include: Option<String>,
#[arg(short, long)]
single_mod: bool,
#[arg(short, long)]
no_output: bool,
#[arg(required = true)]
input: Vec<String>,
#[arg(short, long)]
error_cycle: bool,
#[arg(short = 'H', long)]
no_headers: bool,
#[arg(short = 'C', long)]
custom_struct_derive: Option<String>,
#[arg(short = 'R', long)]
custom_repr: Option<String>,
#[arg(short = 'D', long)]
dont_use_cow: bool,
#[arg(long)]
owned: bool,
#[arg(long)]
nostd: bool,
#[arg(long)]
hashbrown: bool,
#[arg(long)]
gen_info: bool,
#[arg(long)]
add_deprecated_fields: bool,
#[arg(long)]
generate_getters: bool,
}
fn run() -> Result<(), Error> {
let cli = Cli::parse();
if let Some(output) = &cli.output {
validate_extension(output, "rs").map_err(|e| Error::OutputFile(e))?;
}
for input in &cli.input {
validate_extension(input, "proto").map_err(|e| Error::InputFile(e))?;
}
let in_files: Vec<PathBuf> = cli.input.iter().map(PathBuf::from).collect();
let include_paths = cli
.include
.map(|p| vec![PathBuf::from(p)])
.unwrap_or_default();
let out_file = cli.output.map(PathBuf::from);
let out_dir = cli.output_directory.map(PathBuf::from);
let custom_repr = cli.custom_repr;
let custom_struct_derive: Vec<String> = cli
.custom_struct_derive
.unwrap_or_default()
.split(',')
.map(|s| s.to_string())
.collect();
let compiler = ConfigBuilder::new(
&in_files,
out_file.as_ref(),
out_dir.as_ref(),
&include_paths,
)?
.single_module(cli.single_mod)
.no_output(cli.no_output)
.error_cycle(cli.error_cycle)
.headers(!cli.no_headers)
.dont_use_cow(cli.dont_use_cow)
.custom_struct_derive(custom_struct_derive)
.nostd(cli.nostd)
.hashbrown(cli.hashbrown)
.custom_repr(custom_repr)
.owned(cli.owned)
.add_deprecated_fields(cli.add_deprecated_fields)
.generate_getters(cli.generate_getters);
FileDescriptor::run(&compiler.build())
}
fn validate_extension(
path: &str,
expected: &str,
) -> Result<(), String> {
match Path::new(path).extension() {
Some(x) if x == expected => Ok(()),
Some(x) => Err(format!(
"Expected path with extension '{}', not: '{}'",
expected,
x.to_string_lossy()
)),
None => Err(format!("Expected path with extension '{}'", expected)),
}
}
fn main() {
::std::process::exit({
if let Err(e) = run() {
eprintln!("quack-builder fatal error {}", e);
let mut e: &dyn std::error::Error = &e;
while let Some(err) = e.source() {
eprintln!("caused by: {}", err);
e = err;
}
1
} else {
0
}
});
}