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 25, 2024
1 parent a53e1ea commit 12928c3
Show file tree
Hide file tree
Showing 5 changed files with 129 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 @@ -45,6 +45,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 @@ -53,7 +55,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 }
62 changes: 56 additions & 6 deletions src/uu/lscpu/src/lscpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,75 @@
// 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 serde_json;
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(Vec<CpuInfo>);

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

impl CpuInfos {
fn new() -> CpuInfos {
CpuInfos(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.0.push(cpu_info);
}
fn to_json(&self) -> serde_json::Result<String> {
serde_json::to_string(self)
}
}

#[uucore::main]
pub fn uumain(_args: impl uucore::Args) -> UResult<()> {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = 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", &format!("{}", 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].to_string());
};
}

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

Expand All @@ -47,4 +91,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,6 +4,7 @@
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir

use serde_json::{self, Value};
use std::path::PathBuf;

use crate::common::util::{TestScenario, UCommand};
Expand All @@ -13,3 +14,11 @@ use crate::common::util::{TestScenario, UCommand};
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 12928c3

Please sign in to comment.