1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use super::errors::*;
use super::Settings;
use glob::glob;
use std::cmp::Ordering;
use std::path::{Path, PathBuf};

impl Settings {
    pub fn clean(&self) -> Result<()> {
        let mut command_paths = self.command_log_paths(self.log_limit * 2, "*")?;

        if command_paths.len() > self.log_limit {
            command_paths.reverse();
            for path in command_paths
                .iter()
                .take(command_paths.len() - self.log_limit)
            {
                std::fs::remove_file(path)?;
            }
        }

        Ok(())
    }

    pub fn command_log_paths(&self, limit: usize, pattern: &str) -> Result<Vec<PathBuf>> {
        get_command_paths(&self.log_path, limit, pattern)
    }
}
impl Default for Settings {
    fn default() -> Self {
        Settings {
            log_path: default_log_path(),
            log_limit: 1000,
            log_to_console: true,
        }
    }
}

fn default_log_path() -> PathBuf {
    std::env::temp_dir().join("commands")
}

fn get_command_paths(search_path: &Path, limit: usize, pattern: &str) -> Result<Vec<PathBuf>> {
    let mut all_path_bufs = Vec::new();
    let cur_dir = std::env::current_dir()?;
    std::env::set_current_dir(search_path)?;

    let paths = glob(pattern)?;
    for entry in paths {
        match entry {
            Ok(path_buf) => {
                let file_path = search_path.to_path_buf().join(path_buf);
                all_path_bufs.push(file_path);
            }
            Err(_) => {}
        }
    }

    all_path_bufs.sort_by(|a, b| match partial_cmp(a, b) {
        Some(ordering) => ordering,
        None => Ordering::Less,
    });

    let mut path_bufs = Vec::new();
    for path_buf in all_path_bufs {
        if path_bufs.len() < limit {
            path_bufs.push(path_buf);
        }
    }

    std::env::set_current_dir(&cur_dir)?;
    Ok(path_bufs)
}

fn partial_cmp(a: &Path, b: &Path) -> Option<Ordering> {
    match a.metadata() {
        Ok(a_meta) => match b.metadata() {
            Ok(b_meta) => match a_meta.modified() {
                Ok(a_mod) => match b_meta.modified() {
                    Ok(b_mod) => b_mod.partial_cmp(&a_mod),
                    Err(_) => Some(Ordering::Greater),
                },
                Err(_) => None,
            },
            Err(_) => None,
        },
        Err(_) => Some(Ordering::Less),
    }
}