mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-12-03 10:16:02 +00:00
feat: Command execution log (#898)
* feat: option to save logs * refact: use time crate * fix: panics * hints * update roadmap
This commit is contained in:
parent
17ff412595
commit
8639da3855
72
Cargo.lock
generated
72
Cargo.lock
generated
|
@ -242,6 +242,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
|
@ -412,9 +421,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
version = "0.2.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||
|
||||
[[package]]
|
||||
name = "linutil_core"
|
||||
|
@ -442,6 +451,7 @@ dependencies = [
|
|||
"ratatui",
|
||||
"temp-dir",
|
||||
"textwrap",
|
||||
"time",
|
||||
"tree-sitter-bash",
|
||||
"tree-sitter-highlight",
|
||||
"tui-term",
|
||||
|
@ -538,6 +548,21 @@ dependencies = [
|
|||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
|
@ -606,6 +631,12 @@ dependencies = [
|
|||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
|
@ -724,9 +755,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.37"
|
||||
version = "0.38.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
|
||||
checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
|
@ -991,6 +1022,39 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.19"
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
### Q4 2024
|
||||
- [x] Finish the foundation of the project's CLI
|
||||
- [x] Implement CLI arguments and configuration support
|
||||
- [ ] Add an option for logging script executions
|
||||
- [x] Add an option for logging script executions
|
||||
|
||||
### Q1 2025
|
||||
- [ ] GUI Brainstorming and Planning
|
||||
|
|
|
@ -20,6 +20,7 @@ portable-pty = "0.8.1"
|
|||
ratatui = "0.29.0"
|
||||
tui-term = "0.2.0"
|
||||
temp-dir = "0.1.14"
|
||||
time = { version = "0.3.36", features = ["local-offset", "macros", "formatting"] }
|
||||
unicode-width = "0.2.0"
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
linutil_core = { path = "../core", version = "24.9.28" }
|
||||
|
|
|
@ -17,11 +17,11 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
thread::JoinHandle,
|
||||
};
|
||||
use time::{macros::format_description, OffsetDateTime};
|
||||
use tui_term::{
|
||||
vt100::{self, Screen},
|
||||
widget::PseudoTerminal,
|
||||
};
|
||||
|
||||
pub struct RunningCommand {
|
||||
/// A buffer to save all the command output (accumulates, until the command exits)
|
||||
buffer: Arc<Mutex<Vec<u8>>>,
|
||||
|
@ -37,6 +37,7 @@ pub struct RunningCommand {
|
|||
writer: Box<dyn Write + Send>,
|
||||
/// Only set after the process has ended
|
||||
status: Option<ExitStatus>,
|
||||
log_path: Option<String>,
|
||||
scroll_offset: usize,
|
||||
}
|
||||
|
||||
|
@ -79,10 +80,20 @@ impl FloatContent for RunningCommand {
|
|||
.style(Style::default()),
|
||||
);
|
||||
|
||||
Block::default()
|
||||
let mut block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_set(ratatui::symbols::border::ROUNDED)
|
||||
.title_top(title_line.centered())
|
||||
.title_top(title_line.centered());
|
||||
|
||||
if let Some(log_path) = &self.log_path {
|
||||
block =
|
||||
block.title_bottom(Line::from(format!(" Log saved: {} ", log_path)).centered());
|
||||
} else {
|
||||
block =
|
||||
block.title_bottom(Line::from(" Press 'l' to save command log ").centered());
|
||||
}
|
||||
|
||||
block
|
||||
};
|
||||
|
||||
// Process the buffer and create the pseudo-terminal widget
|
||||
|
@ -111,6 +122,11 @@ impl FloatContent for RunningCommand {
|
|||
KeyCode::PageDown => {
|
||||
self.scroll_offset = self.scroll_offset.saturating_sub(10);
|
||||
}
|
||||
KeyCode::Char('l') if self.is_finished() => {
|
||||
if let Ok(log_path) = self.save_log() {
|
||||
self.log_path = Some(log_path);
|
||||
}
|
||||
}
|
||||
// Pass other key events to the terminal
|
||||
_ => self.handle_passthrough_key_event(key),
|
||||
}
|
||||
|
@ -134,6 +150,7 @@ impl FloatContent for RunningCommand {
|
|||
Shortcut::new("Close window", ["Enter", "q"]),
|
||||
Shortcut::new("Scroll up", ["Page up"]),
|
||||
Shortcut::new("Scroll down", ["Page down"]),
|
||||
Shortcut::new("Save log", ["l"]),
|
||||
]),
|
||||
)
|
||||
} else {
|
||||
|
@ -237,6 +254,7 @@ impl RunningCommand {
|
|||
pty_master: pair.master,
|
||||
writer,
|
||||
status: None,
|
||||
log_path: None,
|
||||
scroll_offset: 0,
|
||||
}
|
||||
}
|
||||
|
@ -284,6 +302,24 @@ impl RunningCommand {
|
|||
}
|
||||
}
|
||||
|
||||
fn save_log(&self) -> std::io::Result<String> {
|
||||
let mut log_path = std::env::temp_dir();
|
||||
let date_format = format_description!("[year]-[month]-[day]-[hour]-[minute]-[second]");
|
||||
log_path.push(format!(
|
||||
"linutil_log_{}.log",
|
||||
OffsetDateTime::now_local()
|
||||
.unwrap_or(OffsetDateTime::now_utc())
|
||||
.format(&date_format)
|
||||
.unwrap()
|
||||
));
|
||||
|
||||
let mut file = std::fs::File::create(&log_path)?;
|
||||
let buffer = self.buffer.lock().unwrap();
|
||||
file.write_all(&buffer)?;
|
||||
|
||||
Ok(log_path.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
/// Convert the KeyEvent to pty key codes, and send them to the virtual terminal
|
||||
fn handle_passthrough_key_event(&mut self, key: &KeyEvent) {
|
||||
let input_bytes = match key.code {
|
||||
|
|
Loading…
Reference in New Issue
Block a user