#![deny(clippy::missing_errors_doc)]
#![deny(clippy::missing_panics_doc)]
#![deny(clippy::missing_safety_doc)]
#![deny(missing_docs)]
#[cfg_attr(
all(not(feature = "native"), not(target_arch = "wasm32")),
allow(dead_code, unused_imports)
)]
pub mod browse;
pub mod segment_tree;
#[cfg(feature = "native")]
pub mod convert;
#[cfg(feature = "native")]
pub mod datafusion_helper;
#[cfg(feature = "native")]
pub mod inspect;
#[cfg(feature = "native")]
pub mod query;
#[cfg(feature = "native")]
pub mod segments;
#[cfg(feature = "native")]
pub mod tree;
#[cfg(target_arch = "wasm32")]
pub mod wasm;
#[cfg(feature = "native")]
mod native_cli {
use std::ffi::OsString;
use std::path::PathBuf;
use clap::CommandFactory;
use clap::Parser;
use vortex::error::VortexExpect;
use vortex::session::VortexSession;
#[derive(clap::Parser)]
#[command(version)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
#[derive(Debug, clap::Subcommand)]
enum Commands {
Tree(super::tree::TreeArgs),
Convert(#[command(flatten)] super::convert::ConvertArgs),
Browse { file: PathBuf },
Inspect(super::inspect::InspectArgs),
Query(super::query::QueryArgs),
Segments(super::segments::SegmentsArgs),
}
impl Commands {
fn file_path(&self) -> &PathBuf {
match self {
Commands::Tree(args) => match &args.mode {
super::tree::TreeMode::Array { file, .. } => file,
super::tree::TreeMode::Layout { file, .. } => file,
},
Commands::Browse { file } => file,
Commands::Convert(flags) => &flags.file,
Commands::Inspect(args) => &args.file,
Commands::Query(args) => &args.file,
Commands::Segments(args) => &args.file,
}
}
}
pub async fn launch(session: &VortexSession) -> anyhow::Result<()> {
launch_from(session, std::env::args_os()).await
}
pub async fn launch_from(
session: &VortexSession,
args: impl IntoIterator<Item = impl Into<OsString> + Clone>,
) -> anyhow::Result<()> {
let _ = env_logger::try_init();
let cli = Cli::try_parse_from(args)?;
let path = cli.command.file_path();
if !std::fs::exists(path)? {
return Err(Cli::command()
.error(
clap::error::ErrorKind::Io,
format!(
"File '{}' does not exist.",
path.to_str().vortex_expect("file path")
),
)
.into());
}
match cli.command {
Commands::Tree(args) => super::tree::exec_tree(session, args).await?,
Commands::Convert(flags) => super::convert::exec_convert(session, flags).await?,
Commands::Browse { file } => super::browse::exec_tui(session, file).await?,
Commands::Inspect(args) => super::inspect::exec_inspect(session, args).await?,
Commands::Query(args) => super::query::exec_query(session, args).await?,
Commands::Segments(args) => super::segments::exec_segments(session, args).await?,
};
Ok(())
}
#[cfg(test)]
mod tests {
use vortex::VortexSessionDefault;
use vortex::session::VortexSession;
#[tokio::test]
async fn help_flag_surfaces_clap_error() {
let err = super::launch_from(&VortexSession::default(), ["vx", "--help"])
.await
.expect_err("--help must surface as a clap::Error");
assert_eq!(
err.downcast_ref::<clap::Error>().map(clap::Error::kind),
Some(clap::error::ErrorKind::DisplayHelp),
);
}
}
}
#[cfg(feature = "native")]
pub use native_cli::launch;
#[cfg(feature = "native")]
pub use native_cli::launch_from;