Skip to content

Commit 3e9cd24

Browse files
Add YAML output (-y) and ISO 8601 date format option (-z) (#370)
1 parent 30afb06 commit 3e9cd24

File tree

8 files changed

+125
-75
lines changed

8 files changed

+125
-75
lines changed

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ toml = "0.5.8"
3737
yaml-rust = "0.4"
3838
serde = "1.0.118"
3939
serde_json = "1.0.61"
40+
serde_yaml = "0.8"
4041

4142
chrono = "0.4"
4243
chrono-humanize = "0.1.1"

src/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,11 @@ fn run() -> Result<()> {
2525
if !repo::is_valid(&config.repo_path)? {
2626
return Err("please run onefetch inside of a non-bare git repository".into());
2727
}
28-
let print_in_json_format = config.print_in_json_format;
29-
3028
let info = info::Info::new(config)?;
3129

3230
let mut printer = Printer::new(io::BufWriter::new(io::stdout()), info);
3331

34-
if print_in_json_format {
35-
printer.print_json()?
36-
} else {
37-
printer.print()?
38-
}
32+
printer.print()?;
3933

4034
Ok(())
4135
}

src/onefetch/cli.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use {
55
image_backends,
66
info_field::{InfoField, InfoFieldOff},
77
language::Language,
8+
printer::SerializationFormat,
89
},
910
clap::{crate_description, crate_name, crate_version, App, AppSettings, Arg},
1011
image::DynamicImage,
@@ -31,10 +32,11 @@ pub struct Cli {
3132
pub excluded: Vec<String>,
3233
pub print_languages: bool,
3334
pub print_package_managers: bool,
34-
pub print_in_json_format: bool,
35+
pub output: Option<SerializationFormat>,
3536
pub true_color: bool,
3637
pub art_off: bool,
3738
pub text_colors: Vec<String>,
39+
pub iso_time: bool,
3840
}
3941

4042
impl Cli {
@@ -60,10 +62,20 @@ impl Cli {
6062
.help("Run as if onefetch was started in <input> instead of the current working directory.",
6163
))
6264
.arg(
63-
Arg::with_name("json")
64-
.short("j")
65-
.long("json")
66-
.help("Outputs Onefetch in JSON format.")
65+
Arg::with_name("output")
66+
.short("o")
67+
.long("output")
68+
.help("Outputs Onefetch in a specific format (json, yaml).")
69+
.takes_value(true)
70+
.possible_values(&SerializationFormat::iter()
71+
.map(|format| format.into())
72+
.collect::<Vec<&str>>())
73+
)
74+
.arg(
75+
Arg::with_name("isotime")
76+
.short("z")
77+
.long("isotime")
78+
.help("Outputs Onefetch with ISO 8601 formated timestamps")
6779
)
6880
.arg(
6981
Arg::with_name("languages")
@@ -243,7 +255,9 @@ impl Cli {
243255
let no_color_palette = matches.is_present("no-color-palette");
244256
let print_languages = matches.is_present("languages");
245257
let print_package_managers = matches.is_present("package-managers");
246-
let print_in_json_format = matches.is_present("json");
258+
let iso_time = matches.is_present("isotime");
259+
260+
let output = matches.value_of("output").map(SerializationFormat::from_str).transpose().unwrap();
247261

248262
let fields_to_hide: Vec<String> = if let Some(values) = matches.values_of("disable-fields")
249263
{
@@ -339,10 +353,11 @@ impl Cli {
339353
excluded,
340354
print_languages,
341355
print_package_managers,
342-
print_in_json_format,
356+
output,
343357
true_color,
344358
text_colors,
345359
art_off,
360+
iso_time,
346361
})
347362
}
348363
}

src/onefetch/info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,10 @@ impl Info {
219219
let git_username = internal_repo.get_git_username()?;
220220
let number_of_tags = internal_repo.get_number_of_tags()?;
221221
let number_of_branches = internal_repo.get_number_of_branches()?;
222-
let creation_date = internal_repo.get_creation_date()?;
222+
let creation_date = internal_repo.get_creation_date(config.iso_time)?;
223223
let number_of_commits = internal_repo.get_number_of_commits();
224224
let authors = internal_repo.get_authors(config.number_of_authors);
225-
let last_change = internal_repo.get_date_of_last_commit();
225+
let last_change = internal_repo.get_date_of_last_commit(config.iso_time);
226226
let (repo_size, file_count) = internal_repo.get_repo_size();
227227
let workdir = internal_repo.get_work_dir()?;
228228
let license = Detector::new()?.get_license(&workdir)?;

src/onefetch/printer.rs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
use crate::onefetch::{ascii_art::AsciiArt, error::*, info::Info};
22
use colored::Color;
33
use std::io::Write;
4+
use strum::{EnumIter, EnumString, IntoStaticStr};
45

56
const CENTER_PAD_LENGTH: usize = 3;
67

8+
#[derive(EnumString, EnumIter, IntoStaticStr)]
9+
#[strum(serialize_all = "lowercase")]
10+
pub enum SerializationFormat {
11+
Json,
12+
Yaml,
13+
}
14+
715
pub struct Printer<W> {
816
writer: W,
917
info: Info,
@@ -15,64 +23,73 @@ impl<W: Write> Printer<W> {
1523
}
1624

1725
pub fn print(&mut self) -> Result<()> {
18-
let center_pad = " ".repeat(CENTER_PAD_LENGTH);
19-
let info_str = format!("{}", &self.info);
20-
let mut info_lines = info_str.lines();
21-
let colors: Vec<Color> = Vec::new();
22-
let mut buf = String::new();
26+
match &self.info.config.output {
27+
Some(format) => match format {
28+
SerializationFormat::Json => {
29+
write!(self.writer, "{}", serde_json::to_string_pretty(&self.info).unwrap())?
30+
}
31+
SerializationFormat::Yaml => {
32+
write!(self.writer, "{}", serde_yaml::to_string(&self.info).unwrap())?
33+
}
34+
},
35+
None => {
36+
let center_pad = " ".repeat(CENTER_PAD_LENGTH);
37+
let info_str = format!("{}", &self.info);
38+
let mut info_lines = info_str.lines();
39+
let colors: Vec<Color> = Vec::new();
40+
let mut buf = String::new();
2341

24-
if self.info.config.art_off {
25-
buf.push_str(&info_str);
26-
} else if let Some(custom_image) = &self.info.config.image {
27-
buf.push_str(
28-
&self
29-
.info
30-
.config
31-
.image_backend
32-
.as_ref()
33-
.unwrap()
34-
.add_image(
35-
info_lines.map(|s| format!("{}{}", center_pad, s)).collect(),
36-
custom_image,
37-
self.info.config.image_color_resolution,
38-
)
39-
.chain_err(|| "Error while drawing image")?,
40-
);
41-
} else {
42-
let mut logo_lines = if let Some(custom_ascii) = &self.info.config.ascii_input {
43-
AsciiArt::new(custom_ascii, &colors, !self.info.config.no_bold)
44-
} else {
45-
AsciiArt::new(self.get_ascii(), &self.info.ascii_colors, !self.info.config.no_bold)
46-
};
42+
if self.info.config.art_off {
43+
buf.push_str(&info_str);
44+
} else if let Some(custom_image) = &self.info.config.image {
45+
buf.push_str(
46+
&self
47+
.info
48+
.config
49+
.image_backend
50+
.as_ref()
51+
.unwrap()
52+
.add_image(
53+
info_lines.map(|s| format!("{}{}", center_pad, s)).collect(),
54+
custom_image,
55+
self.info.config.image_color_resolution,
56+
)
57+
.chain_err(|| "Error while drawing image")?,
58+
);
59+
} else {
60+
let mut logo_lines = if let Some(custom_ascii) = &self.info.config.ascii_input {
61+
AsciiArt::new(custom_ascii, &colors, !self.info.config.no_bold)
62+
} else {
63+
AsciiArt::new(
64+
self.get_ascii(),
65+
&self.info.ascii_colors,
66+
!self.info.config.no_bold,
67+
)
68+
};
4769

48-
loop {
49-
match (logo_lines.next(), info_lines.next()) {
50-
(Some(logo_line), Some(info_line)) => {
51-
buf.push_str(&format!("{}{}{:^}\n", logo_line, center_pad, info_line))
52-
}
53-
(Some(logo_line), None) => buf.push_str(&format!("{}\n", logo_line)),
54-
(None, Some(info_line)) => buf.push_str(&format!(
55-
"{:<width$}{}{:^}\n",
56-
"",
57-
center_pad,
58-
info_line,
59-
width = logo_lines.width()
60-
)),
61-
(None, None) => {
62-
buf.push('\n');
63-
break;
70+
loop {
71+
match (logo_lines.next(), info_lines.next()) {
72+
(Some(logo_line), Some(info_line)) => buf
73+
.push_str(&format!("{}{}{:^}\n", logo_line, center_pad, info_line)),
74+
(Some(logo_line), None) => buf.push_str(&format!("{}\n", logo_line)),
75+
(None, Some(info_line)) => buf.push_str(&format!(
76+
"{:<width$}{}{:^}\n",
77+
"",
78+
center_pad,
79+
info_line,
80+
width = logo_lines.width()
81+
)),
82+
(None, None) => {
83+
buf.push('\n');
84+
break;
85+
}
86+
}
6487
}
6588
}
89+
90+
write!(self.writer, "{}", buf)?;
6691
}
6792
}
68-
69-
write!(self.writer, "{}", buf)?;
70-
71-
Ok(())
72-
}
73-
74-
pub fn print_json(&mut self) -> Result<()> {
75-
write!(self.writer, "{}", serde_json::to_string_pretty(&self.info).unwrap())?;
7693
Ok(())
7794
}
7895

src/onefetch/repo.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ impl<'a> Repo<'a> {
3232
Ok(logs)
3333
}
3434

35-
pub fn get_creation_date(&self) -> Result<String> {
35+
pub fn get_creation_date(&self, iso_time: bool) -> Result<String> {
3636
let first_commit = self.logs.last();
3737
let output = match first_commit {
3838
Some(commit) => {
3939
let time = commit.time();
40-
utils::git_time_to_human_time(&time)
40+
utils::git_time_to_formatted_time(&time, iso_time)
4141
}
4242
None => "".into(),
4343
};
@@ -84,11 +84,11 @@ impl<'a> Repo<'a> {
8484
authors
8585
}
8686

87-
pub fn get_date_of_last_commit(&self) -> String {
87+
pub fn get_date_of_last_commit(&self, iso_time: bool) -> String {
8888
let last_commit = self.logs.first();
8989

9090
match last_commit {
91-
Some(commit) => utils::git_time_to_human_time(&commit.time()),
91+
Some(commit) => utils::git_time_to_formatted_time(&commit.time(), iso_time),
9292
None => "".into(),
9393
}
9494
}

src/onefetch/utils.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ pub fn bytes_to_human_readable(bytes: u128) -> String {
3232
byte.get_appropriate_unit(true).to_string()
3333
}
3434

35-
pub fn git_time_to_human_time(time: &Time) -> String {
35+
pub fn git_time_to_formatted_time(time: &Time, iso_time: bool) -> String {
3636
let (offset, _) = match time.offset_minutes() {
3737
n if n < 0 => (-n, '-'),
3838
n => (n, '+'),
3939
};
4040

4141
let offset = FixedOffset::west(offset);
4242
let dt_with_tz = offset.timestamp(time.seconds(), 0);
43-
let ht = HumanTime::from(dt_with_tz);
44-
ht.to_text_en(Accuracy::Rough, Tense::Past)
43+
if iso_time {
44+
dt_with_tz.with_timezone(&chrono::Utc).to_rfc3339_opts(chrono::SecondsFormat::Secs, true)
45+
} else {
46+
let ht = HumanTime::from(dt_with_tz);
47+
ht.to_text_en(Accuracy::Rough, Tense::Past)
48+
}
4549
}

0 commit comments

Comments
 (0)