add duration and readme

This commit is contained in:
askiiart 2024-12-30 18:49:22 -06:00
parent 9fea47a275
commit 89097a5bc1
Signed by untrusted user who does not match committer: askiiart
GPG key ID: EA85979611654C30
2 changed files with 62 additions and 50 deletions

5
README.md Normal file
View file

@ -0,0 +1,5 @@
# better-commands
A better way of running commands.
`better-commands` allows you to run commands with both `stdout` and `stderr` properly, with command duration and timestamps for each line built-in.

View file

@ -2,13 +2,14 @@ use std::cmp::Ordering;
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use std::thread;
use std::time::Instant;
use std::time::{Duration, Instant};
/// Holds the output for a command
#[derive(Debug, Clone)]
pub struct CmdOutput {
lines: Vec<Line>,
status: Option<i32>,
duration: Duration,
}
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
@ -18,6 +19,61 @@ pub struct Line {
pub content: String,
}
pub fn run(command: &mut Command) -> CmdOutput {
// https://stackoverflow.com/a/72831067/16432246
let start = Instant::now();
let mut child = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let child_stdout = child.stdout.take().unwrap();
let child_stderr = child.stderr.take().unwrap();
let (stdout_tx, stdout_rx) = std::sync::mpsc::channel();
let (stderr_tx, stderr_rx) = std::sync::mpsc::channel();
let stdout_lines = BufReader::new(child_stdout).lines();
thread::spawn(move || {
for line in stdout_lines {
stdout_tx
.send(Line {
content: line.unwrap(),
stdout: true,
time: Instant::now(),
})
.unwrap();
}
});
let stderr_lines = BufReader::new(child_stderr).lines();
thread::spawn(move || {
for line in stderr_lines {
let time = Instant::now();
stderr_tx
.send(Line {
content: line.unwrap(),
stdout: true,
time: time,
})
.unwrap();
}
});
let status = child.wait().unwrap().code();
let mut lines = stdout_rx.into_iter().collect::<Vec<Line>>();
lines.append(&mut stderr_rx.into_iter().collect::<Vec<Line>>());
lines.sort();
return CmdOutput {
lines: lines,
status: status,
duration: start.elapsed(),
};
}
impl PartialOrd for Line {
fn ge(&self, other: &Line) -> bool {
if self.time >= other.time {
@ -57,52 +113,3 @@ impl PartialOrd for Line {
return Some(Ordering::Equal);
}
}
pub fn run(command: &mut Command) -> CmdOutput {
// https://stackoverflow.com/a/72831067/16432246
let mut child = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let child_stdout = child.stdout.take().unwrap();
let child_stderr = child.stderr.take().unwrap();
let (stdout_tx, stdout_rx) = std::sync::mpsc::channel();
let (stderr_tx, stderr_rx) = std::sync::mpsc::channel();
let stdout_lines = BufReader::new(child_stdout).lines();
thread::spawn(move || {
for line in stdout_lines {
stdout_tx.send(Line {
content: line.unwrap(),
stdout: true,
time: Instant::now(),
}).unwrap();
}
});
let stderr_lines = BufReader::new(child_stderr).lines();
thread::spawn(move || {
for line in stderr_lines {
let time = Instant::now();
stderr_tx.send(Line {
content: line.unwrap(),
stdout: true,
time: time,
}).unwrap();
}
});
let status = child.wait().unwrap().code();
let mut lines = stdout_rx.into_iter().collect::<Vec<Line>>();
lines.append(&mut stderr_rx.into_iter().collect::<Vec<Line>>());
lines.sort();
return CmdOutput {
lines: lines,
status: status,
};
}