feature(uptime): add option --since

For this, I:
* moved from getops to clap
* remove the millisecond maths
This commit is contained in:
Sylvestre Ledru 2020-05-17 11:36:07 +02:00
parent 8e886c30dc
commit 719f2bf8ae
4 changed files with 55 additions and 37 deletions

2
Cargo.lock generated
View file

@ -1896,6 +1896,8 @@ dependencies = [
name = "uptime"
version = "0.0.1"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.2 (git+https://github.com/uutils/uucore/?tag=0.0.2)",

View file

@ -12,6 +12,8 @@ path = "src/uptime.rs"
[dependencies]
getopts = "0.2.18"
time = "0.1.40"
chrono = "0.4"
clap = "2.32"
uucore = { version = "0.0.2", features = ["utmpx"] }
[[bin]]

View file

@ -12,19 +12,24 @@
/* last synced with: cat (GNU coreutils) 8.13 */
extern crate getopts;
extern crate chrono;
extern crate clap;
extern crate time;
use chrono::{Local, TimeZone, Utc};
use clap::{App, Arg};
#[macro_use]
extern crate uucore;
// import crate time from utmpx
pub use uucore::libc;
use uucore::libc::time_t;
use getopts::Options;
static NAME: &str = "uptime";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Print the current time, the length of time the system has been up,\n\
the number of users on the system, and the average number of jobs\n\
in the run queue over the last 1, 5 and 15 minutes.";
static OPT_SINCE: &str = "SINCE";
#[cfg(unix)]
use libc::getloadavg;
@ -34,38 +39,24 @@ extern "C" {
fn GetTickCount() -> libc::uint32_t;
}
fn get_usage() -> String {
format!("{0} [OPTION]...", executable!())
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("v", "version", "output version information and exit");
opts.optflag("h", "help", "display this help and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f),
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
if matches.opt_present("help") || !matches.free.is_empty() {
println!("{} {}", NAME, VERSION);
println!();
println!("Usage:");
println!(" {0} [OPTION]", NAME);
println!();
println!(
"{}",
opts.usage(
"Print the current time, the length of time the system has been up,\n\
the number of users on the system, and the average number of jobs\n\
in the run queue over the last 1, 5 and 15 minutes."
let usage = get_usage();
let matches = App::new(executable!())
.version(VERSION)
.about(ABOUT)
.usage(&usage[..])
.arg(
Arg::with_name(OPT_SINCE)
.short("s")
.long("since")
.help("system up since"),
)
);
return 0;
}
.get_matches_from(&args);
print_time();
let (boot_time, user_count) = process_utmpx();
let uptime = get_uptime(boot_time);
if uptime < 0 {
@ -73,7 +64,14 @@ pub fn uumain(args: Vec<String>) -> i32 {
1
} else {
let upsecs = uptime / 100;
if matches.is_present(OPT_SINCE) {
let initial_date = Local.timestamp(Utc::now().timestamp() - uptime, 0);
println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
return 0;
}
print_time();
let upsecs = uptime;
print_uptime(upsecs);
print_nusers(user_count);
print_loadavg();
@ -164,7 +162,7 @@ fn get_uptime(boot_time: Option<time_t>) -> i64 {
.ok()
.and_then(|mut f| f.read_to_string(&mut proc_uptime).ok())
.and_then(|_| proc_uptime.split_whitespace().next())
.and_then(|s| s.replace(".", "").parse().ok())
.and_then(|s| s.split('.').next().unwrap_or("0").parse().ok())
{
n
} else {
@ -172,7 +170,7 @@ fn get_uptime(boot_time: Option<time_t>) -> i64 {
Some(t) => {
let now = time::get_time().sec;
let boottime = t as i64;
(now - boottime) * 100
(now - boottime)
}
_ => -1,
}

View file

@ -1,3 +1,5 @@
extern crate regex;
use self::regex::Regex;
use common::util::*;
#[test]
@ -12,3 +14,17 @@ fn test_uptime() {
assert!(result.stdout.contains(" up "));
// Don't check for users as it doesn't show in some CI
}
#[test]
fn test_uptime_since() {
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("--since").succeeds();
println!("stdout = {}", result.stdout);
println!("stderr = {}", result.stderr);
assert!(result.success);
let re = Regex::new(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}").unwrap();
assert!(re.is_match(&result.stdout.trim()));
}