initial commit
This commit is contained in:
commit
9fea47a275
4 changed files with 125 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "better-commands"
|
||||
version = "0.1.0"
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "better-commands"
|
||||
description = "Better commands - get stdout and stderr together, with timestamps"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "GPL-3.0-only"
|
||||
keywords = ["command", "cmd"]
|
||||
|
||||
[dependencies]
|
108
src/lib.rs
Normal file
108
src/lib.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
|
||||
/// Holds the output for a command
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CmdOutput {
|
||||
lines: Vec<Line>,
|
||||
status: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
|
||||
pub struct Line {
|
||||
pub stdout: bool,
|
||||
pub time: Instant,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl PartialOrd for Line {
|
||||
fn ge(&self, other: &Line) -> bool {
|
||||
if self.time >= other.time {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn gt(&self, other: &Self) -> bool {
|
||||
if self.time > other.time {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn le(&self, other: &Self) -> bool {
|
||||
if self.time <= other.time {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn lt(&self, other: &Self) -> bool {
|
||||
if self.time < other.time {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
if self < other {
|
||||
return Some(Ordering::Less);
|
||||
}
|
||||
if self > other {
|
||||
return Some(Ordering::Greater);
|
||||
}
|
||||
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,
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue