2020-08-21 19:51:29 +02:00
|
|
|
use crate::prelude::*;
|
2021-01-10 03:50:49 +01:00
|
|
|
use nu_engine::WholeStreamCommand;
|
2020-08-21 19:51:29 +02:00
|
|
|
use nu_errors::ShellError;
|
2021-04-06 18:19:43 +02:00
|
|
|
use nu_protocol::{ReturnValue, Signature, SyntaxShape, UntaggedValue};
|
2020-08-21 19:51:29 +02:00
|
|
|
use nu_source::Tagged;
|
2020-09-16 18:14:33 +02:00
|
|
|
use std::{
|
|
|
|
sync::atomic::Ordering,
|
|
|
|
thread,
|
2021-04-06 18:19:43 +02:00
|
|
|
time::{Duration, Instant},
|
2020-09-16 18:14:33 +02:00
|
|
|
};
|
2020-08-21 19:51:29 +02:00
|
|
|
|
2020-09-16 18:14:33 +02:00
|
|
|
const CTRL_C_CHECK_INTERVAL: Duration = Duration::from_millis(100);
|
2020-08-21 19:51:29 +02:00
|
|
|
|
|
|
|
pub struct Sleep;
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct SleepArgs {
|
2020-09-17 01:34:37 +02:00
|
|
|
pub duration: Tagged<u64>,
|
2020-08-21 19:51:29 +02:00
|
|
|
pub rest: Vec<Tagged<u64>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WholeStreamCommand for Sleep {
|
|
|
|
fn name(&self) -> &str {
|
|
|
|
"sleep"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn signature(&self) -> Signature {
|
|
|
|
Signature::build("sleep")
|
|
|
|
.required("duration", SyntaxShape::Unit, "time to sleep")
|
|
|
|
.rest(SyntaxShape::Unit, "additional time")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn usage(&self) -> &str {
|
2021-03-08 00:57:58 +01:00
|
|
|
"Delay for a specified amount of time."
|
2020-08-21 19:51:29 +02:00
|
|
|
}
|
|
|
|
|
2021-04-12 04:35:01 +02:00
|
|
|
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
2020-09-16 18:14:33 +02:00
|
|
|
let ctrl_c = args.ctrl_c().clone();
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
let (SleepArgs { duration, rest }, _) = args.process()?;
|
2020-09-16 18:14:33 +02:00
|
|
|
|
2020-09-17 01:34:37 +02:00
|
|
|
let total_dur = Duration::from_nanos(duration.item)
|
|
|
|
+ rest
|
|
|
|
.iter()
|
|
|
|
.map(|val| Duration::from_nanos(val.item))
|
|
|
|
.sum::<Duration>();
|
2020-09-16 18:14:33 +02:00
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
//SleepHandler::new(total_dur, ctrl_c);
|
2020-09-17 01:34:37 +02:00
|
|
|
// this is necessary because the following 2 commands gave different results:
|
|
|
|
// `echo | sleep 1sec` - nothing
|
|
|
|
// `sleep 1sec` - table with 0 elements
|
2021-04-06 18:19:43 +02:00
|
|
|
|
2021-04-12 04:35:01 +02:00
|
|
|
Ok(SleepIterator::new(total_dur, ctrl_c).to_action_stream())
|
2021-04-06 18:19:43 +02:00
|
|
|
|
|
|
|
// if input.is_empty() {
|
|
|
|
// Ok(OutputStream::empty())
|
|
|
|
// } else {
|
|
|
|
// Ok(input.into())
|
|
|
|
// }
|
2020-08-21 19:51:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn examples(&self) -> Vec<Example> {
|
|
|
|
vec![
|
|
|
|
Example {
|
|
|
|
description: "Sleep for 1sec",
|
|
|
|
example: "sleep 1sec",
|
|
|
|
result: None,
|
|
|
|
},
|
|
|
|
Example {
|
|
|
|
description: "Sleep for 3sec",
|
|
|
|
example: "sleep 1sec 1sec 1sec",
|
|
|
|
result: None,
|
|
|
|
},
|
2020-09-17 01:34:37 +02:00
|
|
|
Example {
|
2021-04-06 18:19:43 +02:00
|
|
|
description: "Send output after 1sec",
|
|
|
|
example: "sleep 1sec; echo done",
|
|
|
|
result: Some(vec![UntaggedValue::string("done").into()]),
|
2020-09-17 01:34:37 +02:00
|
|
|
},
|
2020-08-21 19:51:29 +02:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
struct SleepIterator {
|
|
|
|
total_dur: Duration,
|
|
|
|
ctrl_c: Arc<AtomicBool>,
|
2020-09-16 18:14:33 +02:00
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
impl SleepIterator {
|
|
|
|
pub fn new(total_dur: Duration, ctrl_c: Arc<AtomicBool>) -> Self {
|
|
|
|
Self { total_dur, ctrl_c }
|
2020-09-16 18:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
impl Iterator for SleepIterator {
|
|
|
|
type Item = ReturnValue;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
let start = Instant::now();
|
|
|
|
loop {
|
|
|
|
thread::sleep(CTRL_C_CHECK_INTERVAL);
|
|
|
|
if start.elapsed() >= self.total_dur {
|
|
|
|
break;
|
|
|
|
}
|
2020-09-16 18:14:33 +02:00
|
|
|
|
2021-04-06 18:19:43 +02:00
|
|
|
if self.ctrl_c.load(Ordering::SeqCst) {
|
|
|
|
break;
|
2020-09-16 18:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
2021-04-06 18:19:43 +02:00
|
|
|
|
|
|
|
None
|
2020-09-16 18:14:33 +02:00
|
|
|
}
|
2020-08-21 19:51:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::Sleep;
|
2020-10-03 16:06:02 +02:00
|
|
|
use nu_errors::ShellError;
|
2020-08-21 19:51:29 +02:00
|
|
|
use std::time::Instant;
|
|
|
|
|
|
|
|
#[test]
|
2020-10-03 16:06:02 +02:00
|
|
|
fn examples_work_as_expected() -> Result<(), ShellError> {
|
2020-08-21 19:51:29 +02:00
|
|
|
use crate::examples::test as test_examples;
|
|
|
|
|
|
|
|
let start = Instant::now();
|
2020-10-03 16:06:02 +02:00
|
|
|
let results = test_examples(Sleep {});
|
2020-08-21 19:51:29 +02:00
|
|
|
let elapsed = start.elapsed();
|
|
|
|
println!("{:?}", elapsed);
|
2020-09-17 01:34:37 +02:00
|
|
|
// only examples with actual output are run
|
|
|
|
assert!(elapsed >= std::time::Duration::from_secs(1));
|
|
|
|
assert!(elapsed < std::time::Duration::from_secs(2));
|
2020-10-03 16:06:02 +02:00
|
|
|
|
2021-02-12 11:13:14 +01:00
|
|
|
results
|
2020-08-21 19:51:29 +02:00
|
|
|
}
|
|
|
|
}
|