Skip to content

Commit 4be57b5

Browse files
authored
Merge pull request #337 from HallerPatrick/master
Add JSON Output Support
2 parents b48efa3 + ffcb73e commit 4be57b5

12 files changed

+166
-20
lines changed

Diff for: Cargo.lock

+8-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ image = "0.23.12"
3333
regex = "1"
3434
error-chain = "0.12"
3535
toml = "0.5.7"
36+
serde = "1.0.118"
37+
serde_json = "1.0.60"
3638

3739
[target.'cfg(windows)'.dependencies]
3840
ansi_term = "0.12"

Diff for: src/main.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,17 @@ fn run() -> Result<()> {
3030
return Err("please run onefetch inside of a non-bare git repository".into());
3131
}
3232

33+
let format = config.format.clone();
34+
3335
let info = info::Info::new(config)?;
3436

3537
let mut printer = Printer::new(io::BufWriter::new(io::stdout()), info);
3638

37-
printer.print()?;
39+
match format.as_str() {
40+
"human" => printer.print()?,
41+
"json" => printer.print_json()?,
42+
_ => printer.print()?,
43+
}
3844

3945
Ok(())
4046
}

Diff for: src/onefetch/cli.rs

+12
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct Cli {
3131
pub excluded: Vec<String>,
3232
pub print_languages: bool,
3333
pub print_package_managers: bool,
34+
pub format: String,
3435
pub true_color: bool,
3536
pub art_off: bool,
3637
pub text_colors: Vec<String>,
@@ -228,6 +229,15 @@ impl Cli {
228229
.takes_value(true)
229230
.help("Ignore all files & directories matching EXCLUDE."),
230231
)
232+
.arg(
233+
Arg::with_name("format")
234+
.short("f")
235+
.long("format")
236+
.help("Select a output format.")
237+
.takes_value(true)
238+
.default_value("human")
239+
.possible_values(&["human", "json"])
240+
)
231241
.get_matches();
232242

233243
let true_color = cli_utils::is_truecolor_terminal();
@@ -236,6 +246,7 @@ impl Cli {
236246
let no_color_palette = matches.is_present("no-color-palette");
237247
let print_languages = matches.is_present("languages");
238248
let print_package_managers = matches.is_present("package-managers");
249+
let format = matches.value_of("format").map(String::from).unwrap();
239250

240251
let fields_to_hide: Vec<String> = if let Some(values) = matches.values_of("disable-fields")
241252
{
@@ -331,6 +342,7 @@ impl Cli {
331342
excluded,
332343
print_languages,
333344
print_package_managers,
345+
format,
334346
true_color,
335347
text_colors,
336348
art_off,

Diff for: src/onefetch/commit_info.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use git2::Oid;
2+
use serde::ser::SerializeStruct;
3+
use serde::Serialize;
24

35
pub struct CommitInfo {
46
commit: Oid,
@@ -27,3 +29,16 @@ impl std::fmt::Display for CommitInfo {
2729
}
2830
}
2931
}
32+
33+
impl Serialize for CommitInfo {
34+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
35+
where
36+
S: serde::Serializer,
37+
{
38+
let mut state = serializer.serialize_struct("CommitInfo", 2)?;
39+
state.serialize_field("refs", &self.refs)?;
40+
state
41+
.serialize_field("oid", &self.commit.to_string().chars().take(7).collect::<String>())?;
42+
state.end()
43+
}
44+
}

Diff for: src/onefetch/git_utils.rs

+22-8
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,20 @@ pub fn get_number_of_commits(git_history: &[String]) -> String {
7474
number_of_commits.to_string()
7575
}
7676

77-
pub fn get_packed_size(dir: &str) -> Result<String> {
77+
pub fn get_packed_size(repo_size: String, files_count: Option<u64>) -> Result<String> {
78+
match files_count {
79+
Some(files_count) => {
80+
let res = format!("{} ({} files)", repo_size, files_count.to_string());
81+
Ok(res)
82+
}
83+
None => {
84+
let res = repo_size;
85+
Ok(res.into())
86+
}
87+
}
88+
}
89+
90+
pub fn get_repo_size(dir: &str) -> String {
7891
let output = Command::new("git")
7992
.arg("-C")
8093
.arg(dir)
@@ -88,10 +101,13 @@ pub fn get_packed_size(dir: &str) -> Result<String> {
88101
let size_line = lines.split('\n').find(|line| line.starts_with("size-pack:"));
89102

90103
let repo_size = match size_line {
91-
None => "",
92-
Some(size_str) => &(size_str[11..]),
104+
None => String::new(),
105+
Some(size_str) => String::from(&(size_str[11..])),
93106
};
107+
repo_size
108+
}
94109

110+
pub fn get_files_count(dir: &str) -> Option<u64> {
95111
let output = Command::new("git")
96112
.arg("-C")
97113
.arg(dir)
@@ -106,15 +122,13 @@ pub fn get_packed_size(dir: &str) -> Result<String> {
106122

107123
let lines = output.to_string();
108124
let files_list = lines.split('\n');
109-
let mut files_count: u128 = 0;
125+
let mut files_count: u64 = 0;
110126
for _file in files_list {
111127
files_count += 1;
112128
}
113129
files_count -= 1; // As splitting giving one line extra(blank).
114-
let res = repo_size.to_owned() + (" (") + &(files_count.to_string()) + (" files)");
115-
Ok(res)
130+
Some(files_count)
116131
} else {
117-
let res = repo_size;
118-
Ok(res.into())
132+
None
119133
}
120134
}

Diff for: src/onefetch/info.rs

+58-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use {
44
language::Language, license::Detector, repo::Repo, text_color::TextColor,
55
},
66
colored::{Color, ColoredString, Colorize},
7+
serde::ser::SerializeStruct,
8+
serde::Serialize,
79
};
810

911
pub struct Info {
@@ -23,6 +25,8 @@ pub struct Info {
2325
repo_url: String,
2426
number_of_commits: String,
2527
lines_of_code: usize,
28+
packed_repo_size: String,
29+
files_count: Option<u64>,
2630
repo_size: String,
2731
license: String,
2832
pub dominant_language: Language,
@@ -168,12 +172,12 @@ impl std::fmt::Display for Info {
168172
)?;
169173
}
170174

171-
if !self.config.disabled_fields.size && !self.repo_size.is_empty() {
175+
if !self.config.disabled_fields.size && !self.packed_repo_size.is_empty() {
172176
writeln!(
173177
f,
174178
"{}{}",
175179
&self.get_formatted_subtitle_label("Size"),
176-
&self.repo_size.color(self.text_colors.info),
180+
&self.packed_repo_size.color(self.text_colors.info),
177181
)?;
178182
}
179183

@@ -222,7 +226,11 @@ impl Info {
222226
let authors = git_utils::get_authors(&git_history, config.number_of_authors);
223227
let last_change = git_utils::get_date_of_last_commit(&git_history)?;
224228
let git_version = cli_utils::get_git_version()?;
225-
let repo_size = git_utils::get_packed_size(&workdir)?;
229+
230+
let files_count = git_utils::get_files_count(&workdir);
231+
let repo_size = git_utils::get_repo_size(&workdir);
232+
let packed_repo_size = git_utils::get_packed_size(repo_size.clone(), files_count)?;
233+
226234
let license = Detector::new()?.get_license(&workdir)?;
227235
let dependencies = deps::DependencyDetector::new().get_dependencies(&workdir)?;
228236
let (languages, lines_of_code) =
@@ -253,6 +261,8 @@ impl Info {
253261
repo_url,
254262
number_of_commits,
255263
lines_of_code,
264+
packed_repo_size,
265+
files_count,
256266
repo_size,
257267
license,
258268
dominant_language,
@@ -371,3 +381,48 @@ impl Info {
371381
}
372382
}
373383
}
384+
385+
impl Serialize for Info {
386+
fn serialize<S>(&self, serializer: S) -> serde::export::Result<S::Ok, S::Error>
387+
where
388+
S: serde::Serializer,
389+
{
390+
let mut state = serializer.serialize_struct("Info", 21)?;
391+
// Only collect the version number
392+
let git_version_split: Vec<String> =
393+
self.git_version.split(" ").map(|s| s.to_string()).collect();
394+
395+
state.serialize_field("gitVersion", &git_version_split[2])?;
396+
state.serialize_field("gitUsername", &self.git_username)?;
397+
state.serialize_field("repoName", &self.repo_name)?;
398+
state.serialize_field("numberOfTags", &self.number_of_tags)?;
399+
state.serialize_field("numberOfBranches", &self.number_of_branches)?;
400+
state.serialize_field("headRefs", &self.head_refs)?;
401+
state.serialize_field("pendingChanges", &self.pending_changes)?;
402+
state.serialize_field("version", &self.version)?;
403+
state.serialize_field("creationDate", &self.creation_date)?;
404+
state.serialize_field("languages", &self.languages)?;
405+
406+
let dependencies_split: Vec<String> =
407+
self.dependencies.split(" ").map(|s| s.to_string()).collect();
408+
409+
state.serialize_field("dependencies", &dependencies_split[0])?;
410+
state.serialize_field("authors", &self.authors)?;
411+
state.serialize_field("lastChange", &self.last_change)?;
412+
state.serialize_field("repoUrl", &self.repo_url)?;
413+
state.serialize_field("numberOfCommits", &self.number_of_commits)?;
414+
state.serialize_field("linesOfCode", &self.lines_of_code)?;
415+
state.serialize_field("packedRepoSize", &self.packed_repo_size)?;
416+
state.serialize_field("repoSize", &self.repo_size)?;
417+
418+
match &self.files_count {
419+
Some(files_count) => state.serialize_field("filesCount", files_count)?,
420+
None => {}
421+
}
422+
423+
state.serialize_field("license", &self.license)?;
424+
state.serialize_field("dominantLanguage", &self.dominant_language)?;
425+
state.serialize_field("textColors", &self.text_colors)?;
426+
state.end()
427+
}
428+
}

Diff for: src/onefetch/language.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use {
22
crate::onefetch::{error::*, utils::num_to_color},
33
colored::Color,
44
regex::Regex,
5+
serde::Serialize,
56
std::collections::HashMap,
67
std::env,
78
strum::{EnumIter, EnumString, IntoStaticStr},
@@ -22,7 +23,7 @@ macro_rules! define_languages {
2223
($( { $name:ident, $ascii:literal, $display:literal, $colors:expr $(, $serialize:literal )? } ),* ,) => {
2324

2425
#[strum(serialize_all = "lowercase")]
25-
#[derive(PartialEq, Eq, Hash, Clone, EnumString, EnumIter, IntoStaticStr)]
26+
#[derive(PartialEq, Eq, Hash, Clone, EnumString, EnumIter, IntoStaticStr, Serialize)]
2627
pub enum Language {
2728
$(
2829
$( #[strum(serialize = $serialize)] )?

Diff for: src/onefetch/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ mod language;
1212
mod license;
1313
pub mod printer;
1414
pub mod repo;
15+
mod serializer;
1516
mod text_color;
1617
mod utils;

Diff for: src/onefetch/printer.rs

+5
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ impl<W: Write> Printer<W> {
7171
Ok(())
7272
}
7373

74+
pub fn print_json(&mut self) -> Result<()> {
75+
write!(self.writer, "{}", serde_json::to_string_pretty(&self.info).unwrap())?;
76+
Ok(())
77+
}
78+
7479
fn get_ascii(&self) -> &str {
7580
let language = if let Some(ascii_language) = &self.info.config.ascii_language {
7681
ascii_language

Diff for: src/onefetch/serializer.rs

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use {colored::Color, serde::Serialize};
2+
3+
#[derive(Serialize)]
4+
#[serde(remote = "Color")]
5+
pub enum ColorDef {
6+
Black,
7+
Red,
8+
Green,
9+
Yellow,
10+
Blue,
11+
Magenta,
12+
Cyan,
13+
White,
14+
BrightBlack,
15+
BrightRed,
16+
BrightGreen,
17+
BrightYellow,
18+
BrightBlue,
19+
BrightMagenta,
20+
BrightCyan,
21+
BrightWhite,
22+
TrueColor { r: u8, g: u8, b: u8 },
23+
}

Diff for: src/onefetch/text_color.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
use {crate::onefetch::utils::num_to_color, colored::Color};
1+
use {
2+
crate::onefetch::serializer::ColorDef, crate::onefetch::utils::num_to_color, colored::Color,
3+
serde::Serialize,
4+
};
25

6+
#[derive(Serialize)]
37
pub struct TextColor {
8+
#[serde(with = "ColorDef")]
49
pub title: Color,
10+
#[serde(with = "ColorDef")]
511
pub tilde: Color,
12+
#[serde(with = "ColorDef")]
613
pub underline: Color,
14+
#[serde(with = "ColorDef")]
715
pub subtitle: Color,
16+
#[serde(with = "ColorDef")]
817
pub colon: Color,
18+
#[serde(with = "ColorDef")]
919
pub info: Color,
1020
}
1121

0 commit comments

Comments
 (0)