Skip to content

Commit

Permalink
lscpu: Add option --json
Browse files Browse the repository at this point in the history
closes uutils#15
  • Loading branch information
howjmay committed Jul 29, 2024
1 parent e0e29e5 commit fc7bf39
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 7 deletions.
58 changes: 58 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ textwrap = { version = "0.16.0", features = ["terminal_size"] }
xattr = "1.3.1"
tempfile = "3.9.0"
rand = { version = "0.8", features = ["small_rng"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[dependencies]
clap = { workspace = true }
Expand All @@ -54,7 +56,8 @@ clap_mangen = { workspace = true }
uucore = { workspace = true }
phf = { workspace = true }
textwrap = { workspace = true }

serde = { workspace = true }
serde_json = { workspace = true }

#
lscpu = { optional = true, version = "0.0.1", package = "uu_lscpu", path = "src/uu/lscpu" }
Expand Down
2 changes: 2 additions & 0 deletions src/uu/lscpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ regex = { workspace = true }
sysinfo = { workspace = true }
uucore = { workspace = true }
clap = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
64 changes: 58 additions & 6 deletions src/uu/lscpu/src/lscpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,78 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use clap::{crate_version, Command};
use clap::{crate_version, Arg, ArgAction, Command};
use regex::Regex;
use std::fs;
use serde::Serialize;
use std::{fs, str::FromStr};
use sysinfo::System;
use uucore::{error::UResult, format_usage, help_about, help_usage};

mod options {
pub const JSON: &str = "json";
}

const ABOUT: &str = help_about!("lscpu.md");
const USAGE: &str = help_usage!("lscpu.md");

#[derive(Serialize)]
struct CpuInfos {
lscpu: Vec<CpuInfo>,
}

#[derive(Serialize)]
struct CpuInfo {
field: String,
data: String,
}

impl CpuInfos {
fn new() -> CpuInfos {
CpuInfos {
lscpu: Vec::<CpuInfo>::new(),
}
}
fn push(&mut self, field: &str, data: &str) {
let cpu_info = CpuInfo {
field: String::from_str(field).unwrap(),
data: String::from_str(data).unwrap(),
};
self.lscpu.push(cpu_info);
}
fn to_json(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let _matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;
let matches: clap::ArgMatches = uu_app().try_get_matches_from(args)?;

let json = matches.get_flag(options::JSON);

let system = System::new_all();
let _cpu = system.global_cpu_info();

println!("Architecture: {}", get_architecture());
println!("CPU(s): {}", system.cpus().len());
let mut cpu_infos = CpuInfos::new();
cpu_infos.push("Architecture", &get_architecture());
cpu_infos.push("CPU(s)", &format!("{}", system.cpus().len()));
// Add more CPU information here...

if let Ok(contents) = fs::read_to_string("/proc/cpuinfo") {
let re = Regex::new(r"^model name\s+:\s+(.*)$").unwrap();
// Assuming all CPUs have the same model name
if let Some(cap) = re.captures_iter(&contents).next() {
println!("Model name: {}", &cap[1]);
cpu_infos.push("Model name", &cap[1]);
};
}

if json {
println!("{}", cpu_infos.to_json());
} else {
for elt in cpu_infos.lscpu {
println!("{}: {}", elt.field, elt.data);
}
}
Ok(())
}

Expand All @@ -48,4 +94,10 @@ pub fn uu_app() -> Command {
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.arg(
Arg::new(options::JSON)
.long("json")
.help("Use JSON output format for the default summary or extended output (see --extended). For backward compatibility, JSON output follows the default summary behavior for non-terminals (e.g., pipes) where subsections are missing. See also --hierarchic.")
.action(ArgAction::SetTrue),
)
}
9 changes: 9 additions & 0 deletions tests/by-util/test_lscpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,18 @@
// file that was distributed with this source code.

use crate::common::util::TestScenario;
use serde_json::{self, Value};

#[test]
#[ignore]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}

#[test]
fn test_json() {
let result = new_ucmd!().arg("--json").succeeds();
let stdout_bytes = result.stdout();
let res: Result<Value, _> = serde_json::from_slice(&stdout_bytes);
assert!(res.is_ok(), "invalid json output");
}

0 comments on commit fc7bf39

Please sign in to comment.