mod commands;
use clap::{Parser, Subcommand};
use commands::build::{BuildOptions, CompressionOption};
use commands::bundle::PageIndexPolicy;
use tracing_subscriber::EnvFilter;
#[derive(Parser)]
#[command(name = "parx")]
#[command(about = "Build and inspect PARX sidecar files for Parquet")]
#[command(version)]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Build {
#[arg(value_name = "PARQUET_FILE")]
input: String,
#[arg(short, long)]
output: Option<String>,
#[arg(long, default_value = "none")]
compress: String,
},
Inspect {
#[arg(value_name = "PARX_FILE")]
input: String,
},
Verify {
#[arg(value_name = "PARX_FILE")]
input: String,
#[arg(long)]
with_source: bool,
},
Bundle {
#[command(subcommand)]
action: BundleAction,
},
}
#[derive(Subcommand)]
enum BundleAction {
Build {
#[arg(value_name = "DIRECTORY")]
input: String,
#[arg(short, long)]
output: Option<String>,
#[arg(long, default_value_t = false)]
include_page_indexes: bool,
#[arg(long, default_value_t = 262_144)]
max_page_index_bytes_per_file: usize,
#[arg(long, default_value_t = 16_777_216)]
max_total_page_index_bytes: usize,
},
Inspect {
#[arg(value_name = "BUNDLE_FILE")]
input: String,
},
Verify {
#[arg(value_name = "BUNDLE_FILE")]
input: String,
#[arg(long)]
with_sources: bool,
},
Extract {
#[arg(value_name = "BUNDLE_FILE")]
input: String,
#[arg(short, long)]
output: String,
},
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.init();
let cli = Cli::parse();
match cli.command {
Commands::Build {
input,
output,
compress,
} => {
let compression: CompressionOption =
compress.parse().map_err(|e: String| anyhow::anyhow!(e))?;
let options = BuildOptions { compression };
commands::build::run_with_options(&input, output.as_deref(), options).await?;
}
Commands::Inspect { input } => {
commands::inspect::run(&input).await?;
}
Commands::Verify { input, with_source } => {
commands::verify::run(&input, with_source).await?;
}
Commands::Bundle { action } => match action {
BundleAction::Build {
input,
output,
include_page_indexes,
max_page_index_bytes_per_file,
max_total_page_index_bytes,
} => {
let policy = PageIndexPolicy {
enabled: include_page_indexes,
max_per_file_bytes: max_page_index_bytes_per_file,
max_total_bytes: max_total_page_index_bytes,
};
commands::bundle::build(&input, output.as_deref(), policy).await?;
}
BundleAction::Inspect { input } => {
commands::bundle::inspect(&input).await?;
}
BundleAction::Verify {
input,
with_sources,
} => {
commands::bundle::verify(&input, with_sources).await?;
}
BundleAction::Extract { input, output } => {
commands::bundle::extract(&input, &output).await?;
}
},
}
Ok(())
}