mirror of
https://github.com/babichjacob/ac-qu-ai-nt.git
synced 2025-10-02 04:47:53 -04:00
feat(multibinary): support running the binary without arguments (using a sensible user interface as the default), and improve error reporting by using snafu
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
use std::{fs::create_dir_all, io::ErrorKind, path::PathBuf};
|
||||
use std::{
|
||||
fs::create_dir_all,
|
||||
io::ErrorKind,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use clap::{Parser, Subcommand};
|
||||
use snafu::{ResultExt, Snafu};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
@@ -11,24 +17,91 @@ struct Args {
|
||||
)]
|
||||
application_data_directory: PathBuf,
|
||||
|
||||
// If there is a GUI or TUI available from this binary,
|
||||
// then calling this program without arguments
|
||||
// is acceptable: it will launch a user interface
|
||||
#[cfg(any(feature = "gui-eframe", feature = "tui-ratatui"))]
|
||||
#[command(subcommand)]
|
||||
command: Option<Command>,
|
||||
|
||||
#[cfg(not(any(feature = "gui-eframe", feature = "tui-ratatui")))]
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Command {
|
||||
#[cfg(feature = "cli-clap")]
|
||||
#[command(alias = "cli")]
|
||||
CliClap(ac_qu_ai_nt_cli_clap::Args),
|
||||
#[cfg(feature = "gui-eframe")]
|
||||
#[command(alias = "gui")]
|
||||
GuiEframe,
|
||||
|
||||
#[cfg(feature = "tui-ratatui")]
|
||||
#[command(alias = "tui")]
|
||||
TuiRatatui,
|
||||
|
||||
#[cfg(feature = "cli-clap")]
|
||||
#[command(alias = "cli")]
|
||||
CliClap(ac_qu_ai_nt_cli_clap::Args),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// When this program is run without arguments,
|
||||
// it will launch a user interface
|
||||
cfg_if!(
|
||||
// with the GUI (made with eframe)
|
||||
// being considered more appealing (made the default)
|
||||
if #[cfg(feature = "gui-eframe")] {
|
||||
impl Default for Command {
|
||||
fn default() -> Self {
|
||||
Command::GuiEframe
|
||||
}
|
||||
}
|
||||
}
|
||||
// than the TUI (made with Ratatui)
|
||||
else if #[cfg(feature = "tui-ratatui")] {
|
||||
impl Default for Command {
|
||||
fn default() -> Self {
|
||||
Command::TuiRatatui
|
||||
}
|
||||
}
|
||||
}
|
||||
// with it not being logical to specify
|
||||
// the CLI (made with clap)
|
||||
// as an option,
|
||||
// because if `ac-qu-ai-nt ask "why is the sky blue?"`
|
||||
// were accepted and worked when `cli-clap` was the only
|
||||
// interface enabled, then when another interface
|
||||
// like `gui-eframe` were enabled, it would stop working
|
||||
// (only able to work as `ac-qu-ai-nt cli-clap ask "why is the sky blue?"`)
|
||||
// so it should be required to do it the way that would work
|
||||
// in both cases from the beginning
|
||||
);
|
||||
|
||||
#[derive(Debug, Snafu)]
|
||||
enum ApplicationError {
|
||||
#[snafu(display("failed to create the {path:?} directory"))]
|
||||
DirectoryCreationError {
|
||||
path: PathBuf,
|
||||
source: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
/// Create the directory and its parents,
|
||||
/// but don't return an error if it already exists and is a directory
|
||||
fn create_dir_all_exist_ok(path: impl AsRef<Path>) -> Result<(), std::io::Error> {
|
||||
match create_dir_all(&path) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::AlreadyExists && path.as_ref().is_dir() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[snafu::report]
|
||||
fn main() -> Result<(), ApplicationError> {
|
||||
let Args {
|
||||
application_data_directory,
|
||||
command,
|
||||
@@ -37,23 +110,19 @@ fn main() {
|
||||
#[cfg(feature = "tracing")]
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
match create_dir_all(&application_data_directory) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
|
||||
Err(e) => {
|
||||
panic!("{}", e);
|
||||
create_dir_all_exist_ok(&application_data_directory).with_context(|_| {
|
||||
DirectoryCreationSnafu {
|
||||
path: application_data_directory.clone(),
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
let tracing_directory = application_data_directory.join("logs");
|
||||
create_dir_all_exist_ok(&tracing_directory).with_context(|_| DirectoryCreationSnafu {
|
||||
path: tracing_directory.clone(),
|
||||
})?;
|
||||
|
||||
match create_dir_all(&tracing_directory) {
|
||||
Ok(()) => {}
|
||||
Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
|
||||
Err(e) => {
|
||||
panic!("{}", e);
|
||||
}
|
||||
}
|
||||
#[cfg(any(feature = "gui-eframe", feature = "tui-ratatui"))]
|
||||
let command = command.unwrap_or_default();
|
||||
|
||||
match command {
|
||||
#[cfg(feature = "cli-clap")]
|
||||
@@ -63,4 +132,6 @@ fn main() {
|
||||
#[cfg(feature = "tui-ratatui")]
|
||||
Command::TuiRatatui => ac_qu_ai_nt_tui_ratatui::main(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Reference in New Issue
Block a user