feat: add 'ignored_commands' option to stats (#1722)

This commit is contained in:
David 2024-02-15 10:52:19 -08:00 committed by GitHub
parent 063d9054d7
commit f8d01eef99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 6 deletions

View File

@ -171,3 +171,6 @@ enter_accept = true
## Set commands that should be totally stripped and ignored from stats ## Set commands that should be totally stripped and ignored from stats
#common_prefix = ["sudo"] #common_prefix = ["sudo"]
## Set commands that will be completely ignored from stats
#ignored_commands = ["cd", "ls", "vi"]

View File

@ -270,6 +270,8 @@ pub struct Stats {
pub common_prefix: Vec<String>, // sudo, etc. commands we want to strip off pub common_prefix: Vec<String>, // sudo, etc. commands we want to strip off
#[serde(default = "Stats::common_subcommands_default")] #[serde(default = "Stats::common_subcommands_default")]
pub common_subcommands: Vec<String>, // kubectl, commands we should consider subcommands for pub common_subcommands: Vec<String>, // kubectl, commands we should consider subcommands for
#[serde(default = "Stats::ignored_commands_default")]
pub ignored_commands: Vec<String>, // cd, ls, etc. commands we want to completely hide from stats
} }
impl Stats { impl Stats {
@ -283,6 +285,10 @@ impl Stats {
.map(String::from) .map(String::from)
.collect() .collect()
} }
fn ignored_commands_default() -> Vec<String> {
vec![]
}
} }
impl Default for Stats { impl Default for Stats {
@ -290,6 +296,7 @@ impl Default for Stats {
Self { Self {
common_prefix: Self::common_prefix_default(), common_prefix: Self::common_prefix_default(),
common_subcommands: Self::common_subcommands_default(), common_subcommands: Self::common_subcommands_default(),
ignored_commands: Self::ignored_commands_default(),
} }
} }
} }

View File

@ -24,16 +24,22 @@ pub struct Cmd {
count: usize, count: usize,
} }
fn compute_stats(settings: &Settings, history: &[History], count: usize) { fn compute_stats(settings: &Settings, history: &[History], count: usize) -> (usize, usize) {
let mut commands = HashSet::<&str>::with_capacity(history.len()); let mut commands = HashSet::<&str>::with_capacity(history.len());
let mut prefixes = HashMap::<&str, usize>::with_capacity(history.len()); let mut prefixes = HashMap::<&str, usize>::with_capacity(history.len());
let mut total_unignored = 0;
for i in history { for i in history {
// just in case it somehow has a leading tab or space or something (legacy atuin didn't ignore space prefixes) // just in case it somehow has a leading tab or space or something (legacy atuin didn't ignore space prefixes)
let command = i.command.trim(); let command = i.command.trim();
let prefix = interesting_command(settings, command);
if settings.stats.ignored_commands.iter().any(|c| c == prefix) {
continue;
}
total_unignored += 1;
commands.insert(command); commands.insert(command);
*prefixes *prefixes.entry(prefix).or_default() += 1;
.entry(interesting_command(settings, command))
.or_default() += 1;
} }
let unique = commands.len(); let unique = commands.len();
@ -42,7 +48,7 @@ fn compute_stats(settings: &Settings, history: &[History], count: usize) {
top.truncate(count); top.truncate(count);
if top.is_empty() { if top.is_empty() {
println!("No commands found"); println!("No commands found");
return; return (0, 0);
} }
let max = top.iter().map(|x| x.1).max().unwrap(); let max = top.iter().map(|x| x.1).max().unwrap();
@ -73,8 +79,10 @@ fn compute_stats(settings: &Settings, history: &[History], count: usize) {
command.escape_control() command.escape_control()
); );
} }
println!("Total commands: {}", history.len()); println!("Total commands: {total_unignored}");
println!("Unique commands: {unique}"); println!("Unique commands: {unique}");
(total_unignored, unique)
} }
impl Cmd { impl Cmd {
@ -176,10 +184,36 @@ fn interesting_command<'a>(settings: &Settings, mut command: &'a str) -> &'a str
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use atuin_client::history::History;
use atuin_client::settings::Settings; use atuin_client::settings::Settings;
use time::OffsetDateTime;
use super::compute_stats;
use super::interesting_command; use super::interesting_command;
#[test]
fn ignored_commands() {
let mut settings = Settings::utc();
settings.stats.ignored_commands.push("cd".to_string());
let history = [
History::import()
.timestamp(OffsetDateTime::now_utc())
.command("cd foo")
.build()
.into(),
History::import()
.timestamp(OffsetDateTime::now_utc())
.command("cargo build stuff")
.build()
.into(),
];
let (total, unique) = compute_stats(&settings, &history, 10);
assert_eq!(total, 1);
assert_eq!(unique, 1);
}
#[test] #[test]
fn interesting_commands() { fn interesting_commands() {
let settings = Settings::utc(); let settings = Settings::utc();