Commit c8b43fe2 authored by BuggStream's avatar BuggStream Committed by Michael Aaron Murphy
Browse files

feat: Set $CMD_DURATION variable after each command

The variable is equal to the amount of WHOLE seconds spent executing the
previous command.

This variable is currently not set when running the PROMPT function,
because this would mean that the CMD_DURATION would always refer to
the time spent in the PROMPT function when running in interactive mode.
parent 5a9025af
......@@ -304,7 +304,7 @@ impl<'a> InteractiveShell<'a> {
self.terminated.set(true);
{
let mut shell = self.shell.borrow_mut();
match shell.on_command(&cmd) {
match shell.on_command(&cmd, true) {
Ok(_) => (),
Err(IonError::PipelineExecutionError(
PipelineError::CommandNotFound(command),
......
......@@ -13,30 +13,31 @@ impl<'a> InteractiveShell<'a> {
let blocks = if self.terminated.get() { shell.block_len() } else { shell.block_len() + 1 };
if blocks == 0 {
let out = shell.command("PROMPT").map(|res| res.to_string()).unwrap_or_else(|err| {
if let expansion::Error::Subprocess(err) = err {
if let IonError::PipelineExecutionError(PipelineError::CommandNotFound(_)) =
*err
{
match shell
.variables()
.get_str("PROMPT")
.and_then(|prompt| shell.get_string(&prompt))
let out =
shell.command("PROMPT", false).map(|res| res.to_string()).unwrap_or_else(|err| {
if let expansion::Error::Subprocess(err) = err {
if let IonError::PipelineExecutionError(PipelineError::CommandNotFound(_)) =
*err
{
Ok(prompt) => prompt.to_string(),
Err(err) => {
eprintln!("ion: prompt expansion failed: {}", err);
">>> ".into()
match shell
.variables()
.get_str("PROMPT")
.and_then(|prompt| shell.get_string(&prompt))
{
Ok(prompt) => prompt.to_string(),
Err(err) => {
eprintln!("ion: prompt expansion failed: {}", err);
">>> ".into()
}
}
} else {
eprintln!("ion: prompt expansion failed: {}", err);
">>> ".into()
}
} else {
eprintln!("ion: prompt expansion failed: {}", err);
">>> ".into()
panic!("Only a subprocess error should happen inside the pipeline");
}
} else {
panic!("Only a subprocess error should happen inside the pipeline");
}
});
});
shell.set_previous_status(previous_status); // Set the previous exit code again
let key_bindings = self.context.borrow().key_bindings;
match key_bindings {
......
......@@ -127,7 +127,11 @@ pub trait Expander: Sized {
/// Expand a string variable given if it's quoted / unquoted
fn string(&self, _name: &str) -> Result<types::Str, Self::Error>;
/// Expand a subshell expression.
fn command(&mut self, _command: &str) -> Result<types::Str, Self::Error>;
fn command(
&mut self,
_command: &str,
_set_cmd_duration: bool,
) -> Result<types::Str, Self::Error>;
/// Iterating upon key-value maps.
fn map_keys(&self, _name: &str) -> Result<Args, Self::Error>;
/// Iterating upon key-value maps.
......@@ -171,7 +175,7 @@ trait ExpanderInternal: Expander {
command: &str,
selection: &Option<&'a str>,
) -> Result<(), Self::Error> {
let result = self.command(command)?;
let result = self.command(command, true)?;
self.slice(current, result.trim_end_matches('\n'), selection)
}
......@@ -703,7 +707,13 @@ pub(crate) mod test {
}
}
fn command(&mut self, cmd: &str) -> Result<types::Str, Self::Error> { Ok(cmd.into()) }
fn command(
&mut self,
cmd: &str,
_set_cmd_duration: bool,
) -> Result<types::Str, Self::Error> {
Ok(cmd.into())
}
fn tilde(&self, input: &str) -> Result<types::Str, Self::Error> { Ok(input.into()) }
......
......@@ -17,7 +17,7 @@ use crate::{
use err_derive::Error;
use itertools::Itertools;
use nix::unistd::Pid;
use std::rc::Rc;
use std::{rc::Rc, time::SystemTime};
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum Condition {
......@@ -531,7 +531,7 @@ impl<'a> Shell<'a> {
});
if let Some(statement) = case.conditional.as_ref() {
self.on_command(statement)?;
self.on_command(statement, true)?;
if self.previous_status.is_failure() {
continue;
}
......@@ -558,7 +558,13 @@ impl<'a> Shell<'a> {
}
/// Receives a command and attempts to execute the contents.
pub fn on_command(&mut self, command_string: &str) -> std::result::Result<(), IonError> {
pub fn on_command(
&mut self,
command_string: &str,
set_cmd_duration: bool,
) -> std::result::Result<(), IonError> {
let command_start_time = if set_cmd_duration { Some(SystemTime::now()) } else { None };
for stmt in command_string.bytes().batching(|cmd| Terminator::new(cmd).terminate()) {
// Go through all of the statements and build up the block stack
// When block is done return statement for execution.
......@@ -569,6 +575,13 @@ impl<'a> Shell<'a> {
}
}
}
if let Some(start_time) = command_start_time {
if let Ok(elapsed_time) = start_time.elapsed() {
self.variables_mut().set("CMD_DURATION", elapsed_time.as_secs().to_string());
}
}
Ok(())
}
}
......
......@@ -271,7 +271,7 @@ impl<'a> Shell<'a> {
.filter_map(Result::ok)
.batching(|bytes| Terminator::new(bytes).terminate())
{
self.on_command(&cmd)?;
self.on_command(&cmd, true)?;
}
if let Some(block) = self.flow_control.last().map(Statement::to_string) {
......
......@@ -16,7 +16,11 @@ impl<'a, 'b> Expander for Shell<'b> {
type Error = IonError;
/// Uses a subshell to expand a given command.
fn command(&mut self, command: &str) -> Result<types::Str, Self::Error> {
fn command(
&mut self,
command: &str,
set_cmd_duration: bool,
) -> Result<types::Str, Self::Error> {
let (mut reader, writer) = create_pipe()
.map_err(|err| Error::Subprocess(Box::new(IonError::PipelineExecutionError(err))))?;
let null_file = File::open(NULL_PATH).map_err(|err| {
......@@ -30,7 +34,9 @@ impl<'a, 'b> Expander for Shell<'b> {
let prev_stderr = self.stderr(null_file);
// Execute the command
let result = self.on_command(command).map_err(|err| Error::Subprocess(Box::new(err)));
let result = self
.on_command(command, set_cmd_duration)
.map_err(|err| Error::Subprocess(Box::new(err)));
// Reset the pipes, droping the stdout
self.stdout(prev_stdout);
......
......@@ -286,7 +286,13 @@ pub(crate) mod tests {
Err(expansion::Error::VarNotFound)
}
fn command(&mut self, cmd: &str) -> Result<types::Str, Self::Error> { Ok(cmd.into()) }
fn command(
&mut self,
cmd: &str,
_set_cmd_duration: bool,
) -> Result<types::Str, Self::Error> {
Ok(cmd.into())
}
fn tilde(&self, input: &str) -> Result<types::Str, Self::Error> { Ok(input.into()) }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment