Skip to content

Commit

Permalink
add autocomplete and clio to mactime2
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Starke committed Aug 23, 2023
1 parent 8acc4d7 commit cf87156
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 87 deletions.
22 changes: 5 additions & 17 deletions src/apps/mactime2/application.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::{Result};
use chrono::offset::TimeZone;
use chrono::{LocalResult, NaiveDateTime};
use chrono_tz::Tz;
use clap::ValueEnum;
use clio::Input;

use super::bodyfile::{BodyfileDecoder, BodyfileSorter, BodyfileReader};
use super::cli::Cli;
Expand Down Expand Up @@ -32,7 +32,7 @@ pub enum OutputFormat {
//#[derive(Builder)]
pub struct Mactime2Application {
format: OutputFormat,
bodyfile: Option<String>,
bodyfile: Input,
src_zone: Tz,
dst_zone: Tz,
strict_mode: bool,
Expand Down Expand Up @@ -60,13 +60,13 @@ impl Mactime2Application {
}
}

pub fn run(&self) -> Result<()> {
pub fn run(&self) -> anyhow::Result<()> {
let options = RunOptions {
strict_mode: self.strict_mode,
src_zone: self.src_zone,
};

let mut reader = <BodyfileReader as StreamReader<String, ()>>::from(&self.bodyfile)?;
let mut reader = <BodyfileReader as StreamReader<String, ()>>::from(self.bodyfile.clone())?;
let mut decoder = BodyfileDecoder::with_receiver(reader.get_receiver(), options);
let mut sorter = self.create_sorter(&mut decoder);
sorter.run();
Expand Down Expand Up @@ -112,7 +112,7 @@ impl From<Cli> for Mactime2Application {

Self {
format,
bodyfile: Some(cli.input_file),
bodyfile: cli.input_file,
src_zone: cli
.src_zone
.map(|tz| tz.parse().unwrap())
Expand All @@ -125,15 +125,3 @@ impl From<Cli> for Mactime2Application {
}
}
}

impl Default for Mactime2Application {
fn default() -> Self {
Self {
format: OutputFormat::CSV,
bodyfile: None,
src_zone: Tz::UTC,
dst_zone: Tz::UTC,
strict_mode: false,
}
}
}
41 changes: 26 additions & 15 deletions src/apps/mactime2/cli.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,66 @@
use clap::{Parser, ValueHint};
use clio::Input;
use log::LevelFilter;

use clap::Parser;
use crate::common::HasVerboseFlag;

use super::OutputFormat;

#[cfg(feature = "gzip")]
const BODYFILE_HELP: &str = "path to input file or '-' for stdin (files ending with .gz will be treated as being gzipped)";
const BODYFILE_HELP: &str =
"path to input file or '-' for stdin (files ending with .gz will be treated as being gzipped)";
#[cfg(not(feature = "gzip"))]
const BODYFILE_HELP: &str = "path to input file or '-' for stdin";

#[derive(Parser)]
#[clap(name="mactime2", author, version, about, long_about = None)]
pub struct Cli {
#[clap(short('b'), default_value="-", help=BODYFILE_HELP, display_order(100))]
pub(crate) input_file: String,
#[clap(short('b'), num_args=1, value_parser, value_hint=ValueHint::FilePath, default_value="-", help=BODYFILE_HELP, display_order(100))]
pub(crate) input_file: Input,

/// output format, if not specified, default value is 'txt'
#[clap(short('F'), long("format"), value_enum, display_order(600))]
#[clap(
short('F'),
num_args = 1,
long("format"),
value_enum,
display_order(600)
)]
pub(crate) output_format: Option<OutputFormat>,

/// output as CSV instead of TXT. This is a conveniance option, which is identical to `--format=csv`
/// and will be removed in a future release. If you specified `--format` and `-d`, the latter will be ignored.
#[clap(short('d'), display_order(610))]
#[clap(short('d'), num_args = 0, display_order(610))]
pub(crate) csv_format: bool,

/// output as JSON instead of TXT. This is a conveniance option, which is identical to `--format=json`
/// and will be removed in a future release. If you specified `--format` and `-j`, the latter will be ignored.
#[clap(short('j'), display_order(620))]
#[clap(short('j'), num_args = 0, display_order(620))]
pub(crate) json_format: bool,

/// name of offset of source timezone (or 'list' to display all possible values
#[clap(short('f'), long("from-timezone"), display_order(300))]
#[clap(short('f'), num_args = 1, long("from-timezone"), display_order(300))]
pub(crate) src_zone: Option<String>,

/// name of offset of destination timezone (or 'list' to display all possible values
#[clap(short('t'), long("to-timezone"), display_order(400))]
#[clap(short('t'), num_args = 1, long("to-timezone"), display_order(400))]
pub(crate) dst_zone: Option<String>,

// /// convert only, but do not sort
// #[clap(short('c'), long("convert-only"), display_order(450))]
// pub(crate) dont_sort: bool,

/// strict mode: do not only warn, but abort if an error occurs
#[clap(long("strict"), display_order(500))]
#[clap(long("strict"), num_args = 0, display_order(500))]
pub(crate) strict_mode: bool,

#[clap(flatten)]
pub(crate) verbose: clap_verbosity_flag::Verbosity,
}

/// print help in markdown format
#[arg(long, hide = true, exclusive=true)]
pub markdown_help: bool,
impl HasVerboseFlag for Cli {
fn log_level_filter(&self) -> LevelFilter {
self.verbose.log_level_filter()
}
}

impl Cli {
Expand All @@ -64,4 +75,4 @@ impl Cli {
pub fn dst_zone(&self) -> &Option<String> {
&self.dst_zone
}
}
}
15 changes: 5 additions & 10 deletions src/apps/mactime2/stream/stream_reader.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,23 @@
use std::{
io::stdin,
sync::mpsc::{self, Receiver, Sender},
thread::{self, JoinHandle},
};

use anyhow::Result;
use clio::Input;

use crate::apps::mactime2::{stream::*, filter::{Joinable, Provider}};

pub(crate) trait StreamReader<T, R>: Sized + StreamWorker<T> + Joinable<R> + Provider<T, R>
where
T: Send + 'static,
{
fn from(filename: &Option<String>) -> Result<Self> {
fn from(input: Input) -> Result<Self> {
let (tx, rx): (Sender<T>, Receiver<T>) = mpsc::channel();

let worker = match StreamSource::from(filename)? {
StreamSource::Stdin => thread::spawn(move || {
<Self as StreamWorker<T>>::worker(stdin(), tx);
}),
StreamSource::File(f) => thread::spawn(move || {
<Self as StreamWorker<T>>::worker(f, tx);
}),
};
let worker = thread::spawn(move || {
<Self as StreamWorker<T>>::worker(StreamSource::from(input), tx);
});

Ok(<Self as StreamReader<T, R>>::new(worker, rx))
}
Expand Down
46 changes: 14 additions & 32 deletions src/apps/mactime2/stream/stream_source.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,23 @@
use std::{io::{Read, BufReader}, fs::File};
use anyhow::Result;
use std::io::Read;

use clio::Input;
#[cfg(feature = "gzip")]
use flate2::read::GzDecoder;
pub(crate) struct StreamSource(Box<dyn Read + Send>);

pub (crate) enum StreamSource {
Stdin,
File(Box<dyn Read + Send>),
}

impl StreamSource {
pub fn from(filename: &Option<String>) -> Result<Self> {
match filename {
None => Ok(StreamSource::Stdin),
Some(filename) => {
if filename == "-" { Ok(StreamSource::Stdin) }
else {
let file = BufReader::new(File::open(filename)?);

#[cfg(not(feature = "gzip"))]
let reader: Box<dyn BufRead> = Box::new(file);

#[cfg(feature = "gzip")]
let reader = Self::open_gzip(filename, file);

Ok(StreamSource::File(reader))
}
}
impl From<Input> for StreamSource {
fn from(input: Input) -> Self {
#[cfg(feature = "gzip")]
if input.path().ends_with(".gz") {
return Self(Box::new(GzDecoder::new(input)));
}

Self(Box::new(input))
}
}

#[cfg(feature = "gzip")]
fn open_gzip<R: Read + Send + 'static>(filename: &str, file: R) -> Box<dyn Read + Send> {
if filename.ends_with(".gz") {
Box::new(GzDecoder::new(file))
} else {
Box::new(file)
}
impl Read for StreamSource {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read(buf)
}
}
15 changes: 2 additions & 13 deletions src/bin/mactime2/main.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
use anyhow::Result;
use clap::Parser;
use simplelog::{TermLogger, Config, TerminalMode, ColorChoice};
use chrono_tz::TZ_VARIANTS;
use dfir_toolkit::common::FancyParser;

use dfir_toolkit::apps::mactime2::Cli;
use dfir_toolkit::apps::mactime2::Mactime2Application;

fn main() -> Result<()> {
if std::env::args().any(|a| &a == "--markdown-help") {
clap_markdown::print_help_markdown::<Cli>();
return Ok(());
}
let cli = Cli::parse();

let _ = TermLogger::init(
cli.verbose().log_level_filter(),
Config::default(),
TerminalMode::Stderr,
ColorChoice::Auto);
let cli: Cli = Cli::parse_cli();

match cli.src_zone().as_deref() {
Some("list") => {display_zones(); return Ok(());}
Expand Down

0 comments on commit cf87156

Please sign in to comment.