From 55a9a7759d5c77ca6256170396053d918fa58827 Mon Sep 17 00:00:00 2001 From: Zachary Cauchi Date: Mon, 30 Dec 2024 22:56:56 +0100 Subject: [PATCH] feat: Improve cli and dod parsing --- src/cli.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 77 +++------------------------------------------ 2 files changed, 96 insertions(+), 72 deletions(-) create mode 100644 src/cli.rs diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..f1f828a --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,91 @@ +use std::{fmt::Display, path::PathBuf}; + +use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; +use clap::{command, Args, Parser, ValueEnum}; + +use crate::{ + data_providers::{ + flightradar24_provider::FlightRadar24ApiProvider, json_provider::FlightDataFileProvider, + FlightDataProvider, + }, + models::result::{GTError, GTResult}, +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] +pub enum FlightDataSrc { + Json, + Api, +} + +impl Display for FlightDataSrc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let text = match self { + Self::Json => "json", + Self::Api => "api", + }; + f.write_str(text) + } +} + +fn parse_dod_date(s: &str) -> Result, String> { + match NaiveDate::parse_from_str(s, "%d %b %Y") { + Ok(date) => { + let dod = NaiveDateTime::new( + date, + NaiveTime::from_num_seconds_from_midnight_opt(0, 0) + .expect("Midnight value should have succeeded."), + ); + + Ok(dod.and_utc()) + } + Err(e) => Err(format!("Invalid dod value provided ('{s}'). Error: {e}")), + } +} + +#[derive(Args)] +#[command(version, about)] +pub struct TagArgs { + /// The flight code of the flight on which the images were taken. + #[arg(long)] + pub flight_code: String, + + /// Which source to use for flight geodata. + #[arg(short, long, name = "src", default_value_t = FlightDataSrc::Json)] + pub flight_data_src: FlightDataSrc, + + /// Date of flight departure. + #[arg(short, long, name = "dod", value_parser = parse_dod_date, default_value_t = Utc::now())] + pub date_of_departure: DateTime, + + /// File path to flight geodata json file. + #[arg(short, long)] + pub json_file: Option, + + /// Path to directory containing all images to geotag. + pub images_dir: PathBuf, +} + +impl TagArgs { + pub fn try_get_provider(&self) -> GTResult> { + match self.flight_data_src { + FlightDataSrc::Json => { + if let Some(ref path) = self.json_file { + Ok(Box::new(FlightDataFileProvider::new(path.clone()))) + } else { + GTResult::Err(GTError::Args("Invalid configuration.".to_string())) + } + } + FlightDataSrc::Api => Ok(Box::new(FlightRadar24ApiProvider::new( + self.flight_code.clone(), + self.date_of_departure, + ))), + } + } +} + +#[derive(Parser)] +#[command(name = "airmode-tagger")] +#[command(bin_name = "airmode-tagger")] +pub enum Cli { + Tag(TagArgs), +} diff --git a/src/main.rs b/src/main.rs index dd44fa7..321c708 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,82 +1,15 @@ +mod cli; mod data_providers; mod image_geotagger; mod models; mod parsers; -use std::{fmt::Display, path::PathBuf, process::exit}; +use std::process::exit; -use chrono::{DateTime, Utc}; -use clap::{Args, Parser, ValueEnum}; -use data_providers::{ - flightradar24_provider::FlightRadar24ApiProvider, json_provider::FlightDataFileProvider, - FlightDataProvider, -}; +use clap::Parser; +use cli::{Cli, TagArgs}; use image_geotagger::ImageGeotagger; -use models::result::{GTError, GTResult}; - -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -enum FlightDataSrc { - Json, - Api, -} - -impl Display for FlightDataSrc { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let text = match self { - Self::Json => "json", - Self::Api => "api", - }; - f.write_str(text) - } -} - -#[derive(Args)] -#[command(version, about)] -struct TagArgs { - /// The flight code of the flight on which the images were taken. - #[arg(long)] - flight_code: String, - - /// Which source to use for flight geodata. - #[arg(short, long, name = "src", default_value_t = FlightDataSrc::Json)] - flight_data_src: FlightDataSrc, - - /// Date of flight departure. - #[arg(short, long, name = "dod", default_value_t = Utc::now())] - date_of_departure: DateTime, - - /// File path to flight geodata json file. - #[arg(short, long)] - json_file: Option, - - /// Path to directory containing all images to geotag. - images_dir: PathBuf, -} - -impl TagArgs { - pub fn try_get_provider(&self) -> GTResult> { - match self.flight_data_src { - FlightDataSrc::Json => { - if let Some(ref path) = self.json_file { - Ok(Box::new(FlightDataFileProvider::new(path.clone()))) - } else { - GTResult::Err(GTError::Args("Invalid configuration.".to_string())) - } - } - FlightDataSrc::Api => Ok(Box::new(FlightRadar24ApiProvider::new( - self.flight_code.clone(), - self.date_of_departure, - ))), - } - } -} - -#[derive(Parser)] -#[command(name = "airmode-tagger")] -#[command(bin_name = "airmode-tagger")] -enum Cli { - Tag(TagArgs), -} +use models::result::GTResult; fn main() { let Cli::Tag(tag) = Cli::parse();