From c8debd01cd57b550f87d9507350b8dd92b3f2274 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Wed, 31 Jan 2024 23:22:46 +0100 Subject: [PATCH] watch: add initial version --- Cargo.lock | 9 ++++++ Cargo.toml | 2 ++ src/uu/watch/Cargo.toml | 17 +++++++++++ src/uu/watch/src/watch.rs | 61 +++++++++++++++++++++++++++++++++++++ src/uu/watch/watch.md | 7 +++++ tests/by-util/test_watch.rs | 14 +++++++++ tests/tests.rs | 4 +++ 7 files changed, 114 insertions(+) create mode 100644 src/uu/watch/Cargo.toml create mode 100644 src/uu/watch/src/watch.rs create mode 100644 src/uu/watch/watch.md create mode 100644 tests/by-util/test_watch.rs diff --git a/Cargo.lock b/Cargo.lock index 65c12e9..479963f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,6 +442,7 @@ dependencies = [ "uu_free", "uu_pwdx", "uu_w", + "uu_watch", "uucore", "xattr", ] @@ -794,6 +795,14 @@ dependencies = [ "uucore", ] +[[package]] +name = "uu_watch" +version = "0.0.1" +dependencies = [ + "clap", + "uucore", +] + [[package]] name = "uucore" version = "0.0.24" diff --git a/Cargo.toml b/Cargo.toml index 1cddd63..4b34ff3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ feat_common_core = [ "pwdx", "free", "w", + "watch", ] [workspace.dependencies] @@ -59,6 +60,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" } w = { optional = true, version = "0.0.1", package = "uu_w", path = "src/uu/w" } +watch = { optional = true, version = "0.0.1", package = "uu_watch", path = "src/uu/watch" } [dev-dependencies] pretty_assertions = "1" diff --git a/src/uu/watch/Cargo.toml b/src/uu/watch/Cargo.toml new file mode 100644 index 0000000..5e39ad8 --- /dev/null +++ b/src/uu/watch/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "uu_watch" +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/watch.rs" + +[[bin]] +name = "watch" +path = "src/main.rs" diff --git a/src/uu/watch/src/watch.rs b/src/uu/watch/src/watch.rs new file mode 100644 index 0000000..2b9a041 --- /dev/null +++ b/src/uu/watch/src/watch.rs @@ -0,0 +1,61 @@ +// 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, ArgAction, Command}; +use clap::{crate_version}; +use std::process::{Command as SystemCommand, Stdio}; +use std::thread::sleep; +use std::time::Duration; +use uucore::{error::UResult, format_usage, help_about, help_usage}; + +const ABOUT: &str = help_about!("watch.md"); +const USAGE: &str = help_usage!("watch.md"); + +#[uucore::main] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { + let matches = uu_app().try_get_matches_from(args)?; + + let command_to_watch = matches.get_one::("command").expect("required argument"); + let interval = 2; // TODO matches.get_one::("interval").map_or(2, |&v| v); + + loop { + let output = SystemCommand::new("sh") + .arg("-c") + .arg(command_to_watch) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output()?; + + if !output.status.success() { + eprintln!("watch: command failed: {:?}", output.status); + break; + } + + sleep(Duration::from_secs(interval)); + } + + 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("command") + .required(true) + .help("Command to be executed"), + ) + .arg( + Arg::new("interval") + .short('n') + .long("interval") + .default_value("2") + .help("Seconds to wait between updates") + .action(ArgAction::Set), + ) +} diff --git a/src/uu/watch/watch.md b/src/uu/watch/watch.md new file mode 100644 index 0000000..0fc7a3b --- /dev/null +++ b/src/uu/watch/watch.md @@ -0,0 +1,7 @@ +# watch + +``` +watch [options] command +``` + +Execute a program periodically, showing output fullscreen \ No newline at end of file diff --git a/tests/by-util/test_watch.rs b/tests/by-util/test_watch.rs new file mode 100644 index 0000000..9a74a89 --- /dev/null +++ b/tests/by-util/test_watch.rs @@ -0,0 +1,14 @@ +// 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); +} diff --git a/tests/tests.rs b/tests/tests.rs index 1b78033..84da36d 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -16,3 +16,7 @@ mod test_free; #[cfg(feature = "w")] #[path = "by-util/test_w.rs"] mod test_w; + +#[cfg(feature = "watch")] +#[path = "by-util/test_watch.rs"] +mod test_watch;