implement the first version of free

This commit is contained in:
Sylvestre Ledru
2024-01-26 22:35:52 +01:00
parent 21ce645097
commit dc06ab730d
8 changed files with 218 additions and 0 deletions
Generated
+9
View File
@@ -351,6 +351,7 @@ dependencies = [
"rlimit",
"tempfile",
"textwrap",
"uu_free",
"uu_pwdx",
"uucore",
"xattr",
@@ -562,6 +563,14 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "uu_free"
version = "0.0.1"
dependencies = [
"clap",
"uucore",
]
[[package]]
name = "uu_pwdx"
version = "0.0.1"
+2
View File
@@ -26,6 +26,7 @@ default = ["feat_common_core"]
feat_common_core = [
"pwdx",
"free",
]
[workspace.dependencies]
@@ -54,6 +55,7 @@ textwrap = { workspace = true }
#
pwdx = { optional = true, version = "0.0.1", package = "uu_pwdx", path = "src/uu/pwdx" }
free = { optional = true, version = "0.0.1", package = "uu_free", path = "src/uu/free" }
[dev-dependencies]
pretty_assertions = "1"
+17
View File
@@ -0,0 +1,17 @@
[package]
name = "uu_free"
version = "0.0.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
uucore = { workspace = true }
clap = { workspace = true }
[lib]
path = "src/free.rs"
[[bin]]
name = "free"
path = "src/main.rs"
+7
View File
@@ -0,0 +1,7 @@
# free
```
free [options]
```
Display amount of free and used memory in the system
+151
View File
@@ -0,0 +1,151 @@
// This file is part of the uutils procps package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use clap::Arg;
use clap::ArgAction;
use clap::{crate_version, Command};
use std::env;
use std::fs;
use std::process;
use uucore::{error::UResult, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("free.md");
const USAGE: &str = help_usage!("free.md");
fn parse_meminfo() -> Result<(u64, u64, u64, u64, u64, u64, u64, u64, u64, u64), std::io::Error> {
let contents = fs::read_to_string("/proc/meminfo")?;
let mut total = 0;
let mut free = 0;
let mut available = 0;
let mut shared = 0;
let mut buffers = 0;
let mut cached = 0;
let mut swap_total = 0;
let mut swap_free = 0;
let mut reclaimable = 0;
for line in contents.lines() {
if let Some((key, value)) = line.split_once(':') {
let parsed_value = parse_meminfo_value(value)?;
match key.trim() {
"MemTotal" => total = parsed_value,
"MemFree" => free = parsed_value,
"MemAvailable" => available = parsed_value,
"Shmem" => shared = parsed_value,
"Buffers" => buffers = parsed_value,
"Cached" => cached = parsed_value,
"SwapTotal" => swap_total = parsed_value,
"SwapFree" => swap_free = parsed_value,
"SReclaimable" => reclaimable = parsed_value,
_ => {}
}
}
}
Ok((
total,
free,
available,
shared,
buffers,
cached,
swap_total,
swap_free,
swap_total - swap_free,
reclaimable,
))
}
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
let wide = matches.get_flag("wide");
match parse_meminfo() {
Ok((
total,
free,
available,
shared,
buffers,
cached,
swap_total,
swap_free,
swap_used,
reclaimable,
)) => {
let buff_cache = if wide { buffers } else { buffers + cached };
let cache = if wide { cached } else { 0 };
let used = total - free;
if wide {
println!(" total used free shared buffers cache available");
println!(
"Mem: {:12} {:12} {:12} {:12} {:12} {:12} {:12}",
total,
used,
free,
shared,
buff_cache,
cache + reclaimable,
available
);
} else {
println!(" total used free shared buff/cache available");
println!(
"Mem: {:12} {:12} {:12} {:12} {:12} {:12}",
total,
used,
free,
shared,
buff_cache + reclaimable,
available
);
}
println!("Swap: {:12} {:12} {:12}", swap_total, swap_used, swap_free);
}
Err(e) => {
eprintln!("free: failed to read memory info: {}", e);
process::exit(1);
}
}
Ok(())
}
pub fn uu_app() -> Command {
Command::new(uucore::util_name())
.version(crate_version!())
.about(ABOUT)
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.arg(
Arg::new("wide")
.short('w')
.long("wide")
.help("wide output")
.action(ArgAction::SetTrue),
)
}
fn parse_meminfo_value(value: &str) -> Result<u64, std::io::Error> {
value
.split_whitespace()
.next()
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Invalid memory info format",
)
})
.and_then(|v| {
v.parse::<u64>().map_err(|_| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Invalid memory info format",
)
})
})
}
+1
View File
@@ -0,0 +1 @@
uucore::bin!(uu_free);
+27
View File
@@ -0,0 +1,27 @@
// This file is part of the uutils procps package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) symdir somefakedir
use std::path::PathBuf;
use crate::common::util::{TestScenario, UCommand};
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}
#[test]
fn test_free() {
let result = new_ucmd!().succeeds();
assert!(result.stdout_str().contains("Mem:"))
}
#[test]
fn test_free_wide() {
let result = new_ucmd!().arg("--wide").succeeds();
assert!(result.stdout_str().contains("Mem:"));
assert!(!result.stdout_str().contains("buff/cache"));
}
+4
View File
@@ -8,3 +8,7 @@ mod common;
#[cfg(feature = "pwdx")]
#[path = "by-util/test_pwdx.rs"]
mod test_pwdx;
#[cfg(feature = "free")]
#[path = "by-util/test_free.rs"]
mod test_free;