From c6032aa102b6beef0235184ed714d91beae8f1eb Mon Sep 17 00:00:00 2001 From: kernel-sanders <1490292+kernel-sanders@users.noreply.github.com> Date: Sat, 9 Jan 2021 18:06:41 -0500 Subject: [PATCH 1/6] Add YAML output (-y) and ISO 8601 date format option (-z) --- Cargo.lock | 19 +++++++++++++++++++ Cargo.toml | 8 ++++---- src/main.rs | 3 +++ src/onefetch/cli.rs | 18 ++++++++++++++++++ src/onefetch/info.rs | 4 ++-- src/onefetch/printer.rs | 5 +++++ src/onefetch/repo.rs | 8 ++++---- src/onefetch/utils.rs | 14 ++++++++++---- 8 files changed, 65 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59a3ea754..91a6f3fbf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,6 +460,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dtoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" + [[package]] name = "either" version = "1.6.1" @@ -1019,6 +1025,7 @@ dependencies = [ "regex", "serde", "serde_json", + "serde_yaml", "strum", "term_size", "tokei", @@ -1366,6 +1373,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "971be8f6e4d4a47163b405a3df70d14359186f9ab0f3a3ec37df144ca1ce089f" +dependencies = [ + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", +] + [[package]] name = "sha-1" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 50f58ebda..3a15ba94c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,10 @@ repository = "https://github.com/o2sh/onefetch" exclude = ["assets/*", "tools/*"] [package.metadata.deb] -maintainer = "o2sh " extended-description = """\ -Onefetch is a command-line Git information tool written in Rust \ -that displays project information and code statistics \ -for a local Git repository directly on your terminal.""" +Onefetch is a command line tool that displays information about your Git repository directly on your terminal. \ +Onefetch supports more than 50 different programming languages. If your language of choice isn't supported: Open up an issue and support will be added. \ +""" depends = "$auto" section = "utility" priority = "optional" @@ -37,6 +36,7 @@ toml = "0.5.8" yaml-rust = "0.4" serde = "1.0.118" serde_json = "1.0.61" +serde_yaml = "0.8" chrono = "0.4" chrono-humanize = "0.1.1" diff --git a/src/main.rs b/src/main.rs index 0ee440492..bf7fe68c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ fn run() -> Result<()> { return Err("please run onefetch inside of a non-bare git repository".into()); } let print_in_json_format = config.print_in_json_format; + let print_in_yaml_format = config.print_in_yaml_format; let info = info::Info::new(config)?; @@ -33,6 +34,8 @@ fn run() -> Result<()> { if print_in_json_format { printer.print_json()? + } else if print_in_yaml_format { + printer.print_yaml()? } else { printer.print()? } diff --git a/src/onefetch/cli.rs b/src/onefetch/cli.rs index 5f40ccef9..e5e51239a 100644 --- a/src/onefetch/cli.rs +++ b/src/onefetch/cli.rs @@ -32,9 +32,11 @@ pub struct Cli { pub print_languages: bool, pub print_package_managers: bool, pub print_in_json_format: bool, + pub print_in_yaml_format: bool, pub true_color: bool, pub art_off: bool, pub text_colors: Vec, + pub iso_time: bool, } impl Cli { @@ -65,6 +67,18 @@ impl Cli { .long("json") .help("Outputs Onefetch in JSON format.") ) + .arg( + Arg::with_name("yaml") + .short("y") + .long("yaml") + .help("Outputs Onefetch in YAML format.") + ) + .arg( + Arg::with_name("isotime") + .short("z") + .long("isotime") + .help("Outputs Onefetch with ISO 8601 formated timestamps") + ) .arg( Arg::with_name("languages") .short("l") @@ -244,6 +258,8 @@ impl Cli { let print_languages = matches.is_present("languages"); let print_package_managers = matches.is_present("package-managers"); let print_in_json_format = matches.is_present("json"); + let print_in_yaml_format = matches.is_present("yaml"); + let iso_time = matches.is_present("isotime"); let fields_to_hide: Vec = if let Some(values) = matches.values_of("disable-fields") { @@ -340,9 +356,11 @@ impl Cli { print_languages, print_package_managers, print_in_json_format, + print_in_yaml_format, true_color, text_colors, art_off, + iso_time, }) } } diff --git a/src/onefetch/info.rs b/src/onefetch/info.rs index 3cc9f6028..d4766c5e1 100644 --- a/src/onefetch/info.rs +++ b/src/onefetch/info.rs @@ -219,10 +219,10 @@ impl Info { let git_username = internal_repo.get_git_username()?; let number_of_tags = internal_repo.get_number_of_tags()?; let number_of_branches = internal_repo.get_number_of_branches()?; - let creation_date = internal_repo.get_creation_date()?; + let creation_date = internal_repo.get_creation_date(config.iso_time)?; let number_of_commits = internal_repo.get_number_of_commits(); let authors = internal_repo.get_authors(config.number_of_authors); - let last_change = internal_repo.get_date_of_last_commit(); + let last_change = internal_repo.get_date_of_last_commit(config.iso_time); let (repo_size, file_count) = internal_repo.get_repo_size(); let workdir = internal_repo.get_work_dir()?; let license = Detector::new()?.get_license(&workdir)?; diff --git a/src/onefetch/printer.rs b/src/onefetch/printer.rs index 54f605e85..0d0443283 100644 --- a/src/onefetch/printer.rs +++ b/src/onefetch/printer.rs @@ -76,6 +76,11 @@ impl Printer { Ok(()) } + pub fn print_yaml(&mut self) -> Result<()> { + write!(self.writer, "{}", serde_yaml::to_string(&self.info).unwrap())?; + Ok(()) + } + fn get_ascii(&self) -> &str { let language = if let Some(ascii_language) = &self.info.config.ascii_language { ascii_language diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index 55b3fcc1e..c8eb2a6b6 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -32,12 +32,12 @@ impl<'a> Repo<'a> { Ok(logs) } - pub fn get_creation_date(&self) -> Result { + pub fn get_creation_date(&self, rfc_time: bool) -> Result { let first_commit = self.logs.last(); let output = match first_commit { Some(commit) => { let time = commit.time(); - utils::git_time_to_human_time(&time) + utils::git_time_to_formatted_time(&time, rfc_time) } None => "".into(), }; @@ -84,11 +84,11 @@ impl<'a> Repo<'a> { authors } - pub fn get_date_of_last_commit(&self) -> String { + pub fn get_date_of_last_commit(&self, rfc_time: bool) -> String { let last_commit = self.logs.first(); match last_commit { - Some(commit) => utils::git_time_to_human_time(&commit.time()), + Some(commit) => utils::git_time_to_formatted_time(&commit.time(), rfc_time), None => "".into(), } } diff --git a/src/onefetch/utils.rs b/src/onefetch/utils.rs index 75e4b4300..1c0e6b0bd 100644 --- a/src/onefetch/utils.rs +++ b/src/onefetch/utils.rs @@ -32,7 +32,7 @@ pub fn bytes_to_human_readable(bytes: u128) -> String { byte.get_appropriate_unit(true).to_string() } -pub fn git_time_to_human_time(time: &Time) -> String { +pub fn git_time_to_formatted_time(time: &Time, rfc_time: bool) -> String { let (offset, _) = match time.offset_minutes() { n if n < 0 => (-n, '-'), n => (n, '+'), @@ -40,6 +40,12 @@ pub fn git_time_to_human_time(time: &Time) -> String { let offset = FixedOffset::west(offset); let dt_with_tz = offset.timestamp(time.seconds(), 0); - let ht = HumanTime::from(dt_with_tz); - ht.to_text_en(Accuracy::Rough, Tense::Past) -} + if rfc_time { + dt_with_tz.with_timezone(&chrono::Utc).to_rfc3339_opts(chrono::SecondsFormat::Secs, true) + } + //dt_with_tz.timestamp().to_string() + else { + let ht = HumanTime::from(dt_with_tz); + ht.to_text_en(Accuracy::Rough, Tense::Past) + } +} \ No newline at end of file From 7cc3beac4385118b70affe9c2ffc6d5928902364 Mon Sep 17 00:00:00 2001 From: kernel-sanders <1490292+kernel-sanders@users.noreply.github.com> Date: Sat, 9 Jan 2021 18:12:44 -0500 Subject: [PATCH 2/6] Bump Cargo.toml to match master --- Cargo.toml | 7 ++++--- src/onefetch/utils.rs | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3a15ba94c..9780d9759 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,10 +10,11 @@ repository = "https://github.com/o2sh/onefetch" exclude = ["assets/*", "tools/*"] [package.metadata.deb] +maintainer = "o2sh " extended-description = """\ -Onefetch is a command line tool that displays information about your Git repository directly on your terminal. \ -Onefetch supports more than 50 different programming languages. If your language of choice isn't supported: Open up an issue and support will be added. \ -""" +Onefetch is a command-line Git information tool written in Rust \ +that displays project information and code statistics \ +for a local Git repository directly on your terminal.""" depends = "$auto" section = "utility" priority = "optional" diff --git a/src/onefetch/utils.rs b/src/onefetch/utils.rs index 1c0e6b0bd..d35aa9511 100644 --- a/src/onefetch/utils.rs +++ b/src/onefetch/utils.rs @@ -43,7 +43,6 @@ pub fn git_time_to_formatted_time(time: &Time, rfc_time: bool) -> String { if rfc_time { dt_with_tz.with_timezone(&chrono::Utc).to_rfc3339_opts(chrono::SecondsFormat::Secs, true) } - //dt_with_tz.timestamp().to_string() else { let ht = HumanTime::from(dt_with_tz); ht.to_text_en(Accuracy::Rough, Tense::Past) From 06ef34ef4f7e84b836eb9264d45f1250e6e10d1b Mon Sep 17 00:00:00 2001 From: kernel-sanders <1490292+kernel-sanders@users.noreply.github.com> Date: Sat, 9 Jan 2021 18:16:35 -0500 Subject: [PATCH 3/6] Standardize iso_time flag across files --- src/onefetch/repo.rs | 8 ++++---- src/onefetch/utils.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index c8eb2a6b6..f1176839c 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -32,12 +32,12 @@ impl<'a> Repo<'a> { Ok(logs) } - pub fn get_creation_date(&self, rfc_time: bool) -> Result { + pub fn get_creation_date(&self, iso_time: bool) -> Result { let first_commit = self.logs.last(); let output = match first_commit { Some(commit) => { let time = commit.time(); - utils::git_time_to_formatted_time(&time, rfc_time) + utils::git_time_to_formatted_time(&time, iso_time) } None => "".into(), }; @@ -84,11 +84,11 @@ impl<'a> Repo<'a> { authors } - pub fn get_date_of_last_commit(&self, rfc_time: bool) -> String { + pub fn get_date_of_last_commit(&self, iso_time: bool) -> String { let last_commit = self.logs.first(); match last_commit { - Some(commit) => utils::git_time_to_formatted_time(&commit.time(), rfc_time), + Some(commit) => utils::git_time_to_formatted_time(&commit.time(), iso_time), None => "".into(), } } diff --git a/src/onefetch/utils.rs b/src/onefetch/utils.rs index d35aa9511..1789ace02 100644 --- a/src/onefetch/utils.rs +++ b/src/onefetch/utils.rs @@ -32,7 +32,7 @@ pub fn bytes_to_human_readable(bytes: u128) -> String { byte.get_appropriate_unit(true).to_string() } -pub fn git_time_to_formatted_time(time: &Time, rfc_time: bool) -> String { +pub fn git_time_to_formatted_time(time: &Time, iso_time: bool) -> String { let (offset, _) = match time.offset_minutes() { n if n < 0 => (-n, '-'), n => (n, '+'), @@ -40,7 +40,7 @@ pub fn git_time_to_formatted_time(time: &Time, rfc_time: bool) -> String { let offset = FixedOffset::west(offset); let dt_with_tz = offset.timestamp(time.seconds(), 0); - if rfc_time { + if iso_time { dt_with_tz.with_timezone(&chrono::Utc).to_rfc3339_opts(chrono::SecondsFormat::Secs, true) } else { From 366efcce7e8b77b39447e0c6772cfca29bcd0655 Mon Sep 17 00:00:00 2001 From: kernel-sanders <1490292+kernel-sanders@users.noreply.github.com> Date: Sat, 9 Jan 2021 18:25:24 -0500 Subject: [PATCH 4/6] cargo fmt updates --- src/onefetch/utils.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/onefetch/utils.rs b/src/onefetch/utils.rs index 1789ace02..2485912ab 100644 --- a/src/onefetch/utils.rs +++ b/src/onefetch/utils.rs @@ -42,9 +42,8 @@ pub fn git_time_to_formatted_time(time: &Time, iso_time: bool) -> String { let dt_with_tz = offset.timestamp(time.seconds(), 0); if iso_time { dt_with_tz.with_timezone(&chrono::Utc).to_rfc3339_opts(chrono::SecondsFormat::Secs, true) - } - else { + } else { let ht = HumanTime::from(dt_with_tz); ht.to_text_en(Accuracy::Rough, Tense::Past) } -} \ No newline at end of file +} From a871c07efe6150e78884245a9ea93a6bcc6e3d95 Mon Sep 17 00:00:00 2001 From: o2sh Date: Sun, 10 Jan 2021 02:21:31 +0100 Subject: [PATCH 5/6] replace json and yaml flag with output format --- src/main.rs | 11 +--- src/onefetch/cli.rs | 35 +++++------ src/onefetch/printer.rs | 126 ++++++++++++++++++++++------------------ 3 files changed, 88 insertions(+), 84 deletions(-) diff --git a/src/main.rs b/src/main.rs index bf7fe68c4..d7bbfa9a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,20 +25,11 @@ fn run() -> Result<()> { if !repo::is_valid(&config.repo_path)? { return Err("please run onefetch inside of a non-bare git repository".into()); } - let print_in_json_format = config.print_in_json_format; - let print_in_yaml_format = config.print_in_yaml_format; - let info = info::Info::new(config)?; let mut printer = Printer::new(io::BufWriter::new(io::stdout()), info); - if print_in_json_format { - printer.print_json()? - } else if print_in_yaml_format { - printer.print_yaml()? - } else { - printer.print()? - } + printer.print()?; Ok(()) } diff --git a/src/onefetch/cli.rs b/src/onefetch/cli.rs index e5e51239a..9a93bc4e8 100644 --- a/src/onefetch/cli.rs +++ b/src/onefetch/cli.rs @@ -5,6 +5,7 @@ use { image_backends, info_field::{InfoField, InfoFieldOff}, language::Language, + printer::SerializationFormat, }, clap::{crate_description, crate_name, crate_version, App, AppSettings, Arg}, image::DynamicImage, @@ -31,8 +32,7 @@ pub struct Cli { pub excluded: Vec, pub print_languages: bool, pub print_package_managers: bool, - pub print_in_json_format: bool, - pub print_in_yaml_format: bool, + pub output: Option, pub true_color: bool, pub art_off: bool, pub text_colors: Vec, @@ -62,22 +62,20 @@ impl Cli { .help("Run as if onefetch was started in instead of the current working directory.", )) .arg( - Arg::with_name("json") - .short("j") - .long("json") - .help("Outputs Onefetch in JSON format.") - ) - .arg( - Arg::with_name("yaml") - .short("y") - .long("yaml") - .help("Outputs Onefetch in YAML format.") + Arg::with_name("output") + .short("o") + .long("output") + .help("Outputs Onefetch in a specific format (json, yaml).") + .takes_value(true) + .possible_values(&SerializationFormat::iter() + .map(|format| format.into()) + .collect::>()) ) .arg( Arg::with_name("isotime") .short("z") .long("isotime") - .help("Outputs Onefetch with ISO 8601 formated timestamps") + .help("Outputs Onefetch with ISO 8601 formated timestamps") ) .arg( Arg::with_name("languages") @@ -257,10 +255,14 @@ impl Cli { let no_color_palette = matches.is_present("no-color-palette"); let print_languages = matches.is_present("languages"); let print_package_managers = matches.is_present("package-managers"); - let print_in_json_format = matches.is_present("json"); - let print_in_yaml_format = matches.is_present("yaml"); let iso_time = matches.is_present("isotime"); + let output = if let Some(output) = matches.value_of("output") { + Some(SerializationFormat::from_str(&output).unwrap()) + } else { + None + }; + let fields_to_hide: Vec = if let Some(values) = matches.values_of("disable-fields") { values.map(String::from).collect() @@ -355,8 +357,7 @@ impl Cli { excluded, print_languages, print_package_managers, - print_in_json_format, - print_in_yaml_format, + output, true_color, text_colors, art_off, diff --git a/src/onefetch/printer.rs b/src/onefetch/printer.rs index 0d0443283..382820ad0 100644 --- a/src/onefetch/printer.rs +++ b/src/onefetch/printer.rs @@ -1,9 +1,17 @@ use crate::onefetch::{ascii_art::AsciiArt, error::*, info::Info}; use colored::Color; use std::io::Write; +use strum::{EnumIter, EnumString, IntoStaticStr}; const CENTER_PAD_LENGTH: usize = 3; +#[derive(EnumString, EnumIter, IntoStaticStr)] +#[strum(serialize_all = "lowercase")] +pub enum SerializationFormat { + Json, + Yaml, +} + pub struct Printer { writer: W, info: Info, @@ -15,69 +23,73 @@ impl Printer { } pub fn print(&mut self) -> Result<()> { - let center_pad = " ".repeat(CENTER_PAD_LENGTH); - let info_str = format!("{}", &self.info); - let mut info_lines = info_str.lines(); - let colors: Vec = Vec::new(); - let mut buf = String::new(); + match &self.info.config.output { + Some(format) => match format { + SerializationFormat::Json => { + write!(self.writer, "{}", serde_json::to_string_pretty(&self.info).unwrap())? + } + SerializationFormat::Yaml => { + write!(self.writer, "{}", serde_yaml::to_string(&self.info).unwrap())? + } + }, + None => { + let center_pad = " ".repeat(CENTER_PAD_LENGTH); + let info_str = format!("{}", &self.info); + let mut info_lines = info_str.lines(); + let colors: Vec = Vec::new(); + let mut buf = String::new(); - if self.info.config.art_off { - buf.push_str(&info_str); - } else if let Some(custom_image) = &self.info.config.image { - buf.push_str( - &self - .info - .config - .image_backend - .as_ref() - .unwrap() - .add_image( - info_lines.map(|s| format!("{}{}", center_pad, s)).collect(), - custom_image, - self.info.config.image_color_resolution, - ) - .chain_err(|| "Error while drawing image")?, - ); - } else { - let mut logo_lines = if let Some(custom_ascii) = &self.info.config.ascii_input { - AsciiArt::new(custom_ascii, &colors, !self.info.config.no_bold) - } else { - AsciiArt::new(self.get_ascii(), &self.info.ascii_colors, !self.info.config.no_bold) - }; + if self.info.config.art_off { + buf.push_str(&info_str); + } else if let Some(custom_image) = &self.info.config.image { + buf.push_str( + &self + .info + .config + .image_backend + .as_ref() + .unwrap() + .add_image( + info_lines.map(|s| format!("{}{}", center_pad, s)).collect(), + custom_image, + self.info.config.image_color_resolution, + ) + .chain_err(|| "Error while drawing image")?, + ); + } else { + let mut logo_lines = if let Some(custom_ascii) = &self.info.config.ascii_input { + AsciiArt::new(custom_ascii, &colors, !self.info.config.no_bold) + } else { + AsciiArt::new( + self.get_ascii(), + &self.info.ascii_colors, + !self.info.config.no_bold, + ) + }; - loop { - match (logo_lines.next(), info_lines.next()) { - (Some(logo_line), Some(info_line)) => { - buf.push_str(&format!("{}{}{:^}\n", logo_line, center_pad, info_line)) - } - (Some(logo_line), None) => buf.push_str(&format!("{}\n", logo_line)), - (None, Some(info_line)) => buf.push_str(&format!( - "{: { - buf.push('\n'); - break; + loop { + match (logo_lines.next(), info_lines.next()) { + (Some(logo_line), Some(info_line)) => buf + .push_str(&format!("{}{}{:^}\n", logo_line, center_pad, info_line)), + (Some(logo_line), None) => buf.push_str(&format!("{}\n", logo_line)), + (None, Some(info_line)) => buf.push_str(&format!( + "{: { + buf.push('\n'); + break; + } + } } } + + write!(self.writer, "{}", buf)?; } } - - write!(self.writer, "{}", buf)?; - - Ok(()) - } - - pub fn print_json(&mut self) -> Result<()> { - write!(self.writer, "{}", serde_json::to_string_pretty(&self.info).unwrap())?; - Ok(()) - } - - pub fn print_yaml(&mut self) -> Result<()> { - write!(self.writer, "{}", serde_yaml::to_string(&self.info).unwrap())?; Ok(()) } From c6318934b29fed839b248b6a01017a511ad4c4c2 Mon Sep 17 00:00:00 2001 From: Ossama Hjaji Date: Sun, 10 Jan 2021 14:57:39 +0100 Subject: [PATCH 6/6] Update src/onefetch/cli.rs Co-authored-by: Spenser Black --- src/onefetch/cli.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/onefetch/cli.rs b/src/onefetch/cli.rs index 9a93bc4e8..0d7f68ffe 100644 --- a/src/onefetch/cli.rs +++ b/src/onefetch/cli.rs @@ -257,11 +257,7 @@ impl Cli { let print_package_managers = matches.is_present("package-managers"); let iso_time = matches.is_present("isotime"); - let output = if let Some(output) = matches.value_of("output") { - Some(SerializationFormat::from_str(&output).unwrap()) - } else { - None - }; + let output = matches.value_of("output").map(SerializationFormat::from_str).transpose().unwrap(); let fields_to_hide: Vec = if let Some(values) = matches.values_of("disable-fields") {