mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #1810 from jeckersb/nice-clap
nice: move from getopts to clap #1794
This commit is contained in:
commit
99be7a3172
4 changed files with 104 additions and 56 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1823,8 +1823,9 @@ dependencies = [
|
|||
name = "uu_nice"
|
||||
version = "0.0.4"
|
||||
dependencies = [
|
||||
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.85 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"uucore 0.0.7",
|
||||
"uucore_procs 0.0.5",
|
||||
]
|
||||
|
|
|
@ -15,8 +15,9 @@ edition = "2018"
|
|||
path = "src/nice.rs"
|
||||
|
||||
[dependencies]
|
||||
getopts = "0.2.18"
|
||||
clap = "2.33"
|
||||
libc = "0.2.42"
|
||||
nix = { version="<=0.13" }
|
||||
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
|
||||
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::ffi::CString;
|
|||
use std::io::Error;
|
||||
use std::ptr;
|
||||
|
||||
const NAME: &str = "nice";
|
||||
use clap::{App, AppSettings, Arg};
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
// XXX: PRIO_PROCESS is 0 on at least FreeBSD and Linux. Don't know about Mac OS X.
|
||||
|
@ -26,64 +26,57 @@ extern "C" {
|
|||
fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int;
|
||||
}
|
||||
|
||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||
let args = args.collect_str();
|
||||
|
||||
let mut opts = getopts::Options::new();
|
||||
|
||||
opts.optopt(
|
||||
"n",
|
||||
"adjustment",
|
||||
"add N to the niceness (default is 10)",
|
||||
"N",
|
||||
);
|
||||
opts.optflag("h", "help", "display this help and exit");
|
||||
opts.optflag("V", "version", "output version information and exit");
|
||||
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(err) => {
|
||||
show_error!("{}", err);
|
||||
return 125;
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("version") {
|
||||
println!("{} {}", NAME, VERSION);
|
||||
return 0;
|
||||
pub mod options {
|
||||
pub static ADJUSTMENT: &str = "adjustment";
|
||||
pub static COMMAND: &str = "COMMAND";
|
||||
}
|
||||
|
||||
if matches.opt_present("help") {
|
||||
let msg = format!(
|
||||
"{0} {1}
|
||||
|
||||
Usage:
|
||||
fn get_usage() -> String {
|
||||
format!(
|
||||
"
|
||||
{0} [OPTIONS] [COMMAND [ARGS]]
|
||||
|
||||
Run COMMAND with an adjusted niceness, which affects process scheduling.
|
||||
With no COMMAND, print the current niceness. Niceness values range from at
|
||||
least -20 (most favorable to the process) to 19 (least favorable to the
|
||||
process).",
|
||||
NAME, VERSION
|
||||
);
|
||||
|
||||
print!("{}", opts.usage(&msg));
|
||||
return 0;
|
||||
executable!()
|
||||
)
|
||||
}
|
||||
|
||||
let mut niceness = unsafe { getpriority(PRIO_PROCESS, 0) };
|
||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||
let usage = get_usage();
|
||||
|
||||
let matches = App::new(executable!())
|
||||
.setting(AppSettings::TrailingVarArg)
|
||||
.version(VERSION)
|
||||
.usage(&usage[..])
|
||||
.arg(
|
||||
Arg::with_name(options::ADJUSTMENT)
|
||||
.short("n")
|
||||
.long(options::ADJUSTMENT)
|
||||
.help("add N to the niceness (default is 10)")
|
||||
.takes_value(true)
|
||||
.allow_hyphen_values(true),
|
||||
)
|
||||
.arg(Arg::with_name(options::COMMAND).multiple(true))
|
||||
.get_matches_from(args);
|
||||
|
||||
let mut niceness = unsafe {
|
||||
nix::errno::Errno::clear();
|
||||
getpriority(PRIO_PROCESS, 0)
|
||||
};
|
||||
if Error::last_os_error().raw_os_error().unwrap() != 0 {
|
||||
show_error!("{}", Error::last_os_error());
|
||||
show_error!("getpriority: {}", Error::last_os_error());
|
||||
return 125;
|
||||
}
|
||||
|
||||
let adjustment = match matches.opt_str("adjustment") {
|
||||
let adjustment = match matches.value_of(options::ADJUSTMENT) {
|
||||
Some(nstr) => {
|
||||
if matches.free.is_empty() {
|
||||
if !matches.is_present(options::COMMAND) {
|
||||
show_error!(
|
||||
"A command must be given with an adjustment.
|
||||
Try \"{} --help\" for more information.",
|
||||
args[0]
|
||||
"A command must be given with an adjustment.\nTry \"{} --help\" for more information.",
|
||||
executable!()
|
||||
);
|
||||
return 125;
|
||||
}
|
||||
|
@ -96,7 +89,7 @@ process).",
|
|||
}
|
||||
}
|
||||
None => {
|
||||
if matches.free.is_empty() {
|
||||
if !matches.is_present(options::COMMAND) {
|
||||
println!("{}", niceness);
|
||||
return 0;
|
||||
}
|
||||
|
@ -105,25 +98,23 @@ process).",
|
|||
};
|
||||
|
||||
niceness += adjustment;
|
||||
unsafe {
|
||||
setpriority(PRIO_PROCESS, 0, niceness);
|
||||
}
|
||||
if Error::last_os_error().raw_os_error().unwrap() != 0 {
|
||||
show_warning!("{}", Error::last_os_error());
|
||||
if unsafe { setpriority(PRIO_PROCESS, 0, niceness) } == -1 {
|
||||
show_warning!("setpriority: {}", Error::last_os_error());
|
||||
}
|
||||
|
||||
let cstrs: Vec<CString> = matches
|
||||
.free
|
||||
.iter()
|
||||
.values_of(options::COMMAND)
|
||||
.unwrap()
|
||||
.map(|x| CString::new(x.as_bytes()).unwrap())
|
||||
.collect();
|
||||
|
||||
let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
|
||||
args.push(ptr::null::<c_char>());
|
||||
unsafe {
|
||||
execvp(args[0], args.as_mut_ptr());
|
||||
}
|
||||
|
||||
show_error!("{}", Error::last_os_error());
|
||||
show_error!("execvp: {}", Error::last_os_error());
|
||||
if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
|
||||
127
|
||||
} else {
|
||||
|
|
|
@ -1 +1,56 @@
|
|||
// ToDO: add tests
|
||||
use crate::common::util::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_current_niceness() {
|
||||
// NOTE: this assumes the test suite is being run with a default niceness
|
||||
// of 0, which may not necessarily be true
|
||||
new_ucmd!().run().stdout_is("0\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_negative_adjustment() {
|
||||
// This assumes the test suite is run as a normal (non-root) user, and as
|
||||
// such attempting to set a negative niceness value will be rejected by
|
||||
// the OS. If it gets denied, then we know a negative value was parsed
|
||||
// correctly.
|
||||
|
||||
let res = new_ucmd!().args(&["-n", "-1", "true"]).run();
|
||||
assert!(res.stderr.starts_with("nice: warning: setpriority: Permission denied"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_adjustment_with_no_command_should_error() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "19"])
|
||||
.run()
|
||||
.stderr_is("nice: error: A command must be given with an adjustment.\nTry \"nice --help\" for more information.\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_with_no_adjustment() {
|
||||
new_ucmd!().args(&["echo", "a"]).run().stdout_is("a\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_with_no_args() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "19", "echo"])
|
||||
.run()
|
||||
.stdout_is("\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_with_args() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "19", "echo", "a", "b", "c"])
|
||||
.run()
|
||||
.stdout_is("a b c\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_command_where_command_takes_n_flag() {
|
||||
new_ucmd!()
|
||||
.args(&["-n", "19", "echo", "-n", "a"])
|
||||
.run()
|
||||
.stdout_is("a");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue