Skip to content

Commit

Permalink
log: Introduce --lastmerge option
Browse files Browse the repository at this point in the history
This currently somewhat mirrors what qlop offers, as an MVP to get a feel of the implementation. I
initially wrote a single-pass version (droping previous table rows when encountering a command), but
the two-pass version is fast enough that `--lastmerge` is about as fast as `--last`, and offers more
flexibility.

Tentative todo:
* Allow `--lastmerge <N>`
* Move into `--from '1 command'` (simpler and more consistent)
* Optionaly ignore non-merge commands (qlop always/only does that, but it's a failible heuristic)
* Investigate `--to` support
* Move code into get_hist (DRY, and optimization opportunities)
* Test and document
  • Loading branch information
vincentdephily committed Nov 21, 2024
1 parent 2c43167 commit 4ac3beb
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 4 deletions.
7 changes: 6 additions & 1 deletion src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ use std::{collections::{BTreeMap, HashMap, HashSet},
/// Straightforward display of merge events
///
/// We store the start times in a hashmap to compute/print the duration when we reach a stop event.
pub fn cmd_log(gc: Conf, sc: ConfLog) -> Result<bool, Error> {
pub fn cmd_log(mut gc: Conf, sc: ConfLog) -> Result<bool, Error> {
if sc.lastmerge {
if let Some(t) = parse::get_cmd_times(&gc.logfile, gc.from, gc.to)?.last() {
gc.from = Some(*t);
}
}
let hist = get_hist(&gc.logfile, gc.from, gc.to, sc.show, &sc.search, sc.exact)?;
let mut merges: HashMap<String, i64> = HashMap::new();
let mut unmerges: HashMap<String, i64> = HashMap::new();
Expand Down
4 changes: 3 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub struct ConfLog {
pub starttime: bool,
pub first: usize,
pub last: usize,
pub lastmerge: bool,
}
pub struct ConfPred {
pub show: Show,
Expand Down Expand Up @@ -186,7 +187,8 @@ impl ConfLog {
exact: cli.get_flag("exact"),
starttime: sel!(cli, toml, log, starttime, (), false)?,
first: *cli.get_one("first").unwrap_or(&usize::MAX),
last: *cli.get_one("last").unwrap_or(&usize::MAX) })
last: *cli.get_one("last").unwrap_or(&usize::MAX),
lastmerge: cli.get_flag("lastmerge") })
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/config/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ pub fn build_cli() -> Command {
.long_help("Show only the last <num> entries\n \
(empty)|1: last entry\n \
5: last 5 entries\n");
let lastmerge = Arg::new("lastmerge").long("lastmerge")
.action(SetTrue)
.display_order(8)
.help_heading("Filter")
.help("Show only the last merge");
let h = "Use main, backup, either, or no portage resume list\n\
This is ignored if STDIN is a piped `emerge -p` output\n \
(default)|auto|a: Use main or backup resume list, if currently emerging\n \
Expand All @@ -140,7 +145,7 @@ pub fn build_cli() -> Command {
.hide_possible_values(true)
.num_args(..=1)
.default_missing_value("either")
.display_order(8)
.display_order(9)
.help_heading("Filter")
.help(h.split_once('\n').unwrap().0)
.long_help(h);
Expand Down Expand Up @@ -337,6 +342,7 @@ pub fn build_cli() -> Command {
.arg(starttime)
.arg(&first)
.arg(&last)
.arg(lastmerge)
.arg(show_l)
.arg(&exact)
.arg(&pkg);
Expand Down
2 changes: 1 addition & 1 deletion src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod proces;

pub use ansi::{Ansi, AnsiStr};
pub use current::{get_buildlog, get_emerge, get_pretend, get_resume, Pkg};
pub use history::{get_hist, Hist};
pub use history::{get_cmd_times, get_hist, Hist};
#[cfg(test)]
pub use proces::tests::procs;
pub use proces::{get_all_proc, FmtProc, ProcKind, ProcList};
31 changes: 31 additions & 0 deletions src/parse/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,37 @@ pub fn get_hist(file: &str,
Ok(rx)
}

/// Parse emerge log into a Vec of emerge command starts
///
/// This is a specialized version of get_hist(), about 20% faster for this usecase
pub fn get_cmd_times(file: &str,
min_ts: Option<i64>,
max_ts: Option<i64>)
-> Result<Vec<i64>, Error> {
let mut buf = open_any_buffered(file)?;
let (ts_min, ts_max) = filter_ts(min_ts, max_ts)?;
let mut line = Vec::with_capacity(255);
let mut res = vec![];
loop {
match buf.read_until(b'\n', &mut line) {
// End of file
Ok(0) => break,
// Got a line, see if one of the funs match it
Ok(_) => {
if let Some((t, s)) = parse_ts(&line, ts_min, ts_max) {
if s.starts_with(b"*** emerge") {
res.push(t)
}
}
},
// Could be invalid UTF8, system read error...
Err(_) => (),
}
line.clear();
}
Ok(res)
}

/// Return min/max timestamp depending on options.
fn filter_ts(min: Option<i64>, max: Option<i64>) -> Result<(i64, i64), Error> {
match (min, max) {
Expand Down

0 comments on commit 4ac3beb

Please sign in to comment.