summaryrefslogtreecommitdiffstats
path: root/atuin-client/src/import/bash.rs
diff options
context:
space:
mode:
Diffstat (limited to 'atuin-client/src/import/bash.rs')
-rw-r--r--atuin-client/src/import/bash.rs121
1 files changed, 88 insertions, 33 deletions
diff --git a/atuin-client/src/import/bash.rs b/atuin-client/src/import/bash.rs
index d5fbef46..1a171625 100644
--- a/atuin-client/src/import/bash.rs
+++ b/atuin-client/src/import/bash.rs
@@ -1,63 +1,77 @@
-use std::io::{BufRead, BufReader};
-use std::{fs::File, path::Path};
+use std::{
+ fs::File,
+ io::{BufRead, BufReader, Read, Seek},
+ path::{Path, PathBuf},
+};
+use directories::UserDirs;
use eyre::{eyre, Result};
-use super::count_lines;
+use super::{count_lines, Importer};
use crate::history::History;
#[derive(Debug)]
-pub struct Bash {
- file: BufReader<File>,
-
- pub loc: u64,
- pub counter: i64,
+pub struct Bash<R> {
+ file: BufReader<R>,
+ strbuf: String,
+ loc: usize,
+ counter: i64,
}
-impl Bash {
- pub fn new(path: impl AsRef<Path>) -> Result<Self> {
- let file = File::open(path)?;
- let mut buf = BufReader::new(file);
+impl<R: Read + Seek> Bash<R> {
+ fn new(r: R) -> Result<Self> {
+ let mut buf = BufReader::new(r);
let loc = count_lines(&mut buf)?;
Ok(Self {
file: buf,
- loc: loc as u64,
+ strbuf: String::new(),
+ loc,
counter: 0,
})
}
+}
- fn read_line(&mut self) -> Option<Result<String>> {
- let mut line = String::new();
+impl Importer for Bash<File> {
+ const NAME: &'static str = "bash";
- match self.file.read_line(&mut line) {
- Ok(0) => None,
- Ok(_) => Some(Ok(line)),
- Err(e) => Some(Err(eyre!("failed to read line: {}", e))), // we can skip past things like invalid utf8
- }
+ fn histpath() -> Result<PathBuf> {
+ let user_dirs = UserDirs::new().unwrap();
+ let home_dir = user_dirs.home_dir();
+
+ Ok(home_dir.join(".bash_history"))
+ }
+
+ fn parse(path: impl AsRef<Path>) -> Result<Self> {
+ Self::new(File::open(path)?)
}
}
-impl Iterator for Bash {
+impl<R: Read> Iterator for Bash<R> {
type Item = Result<History>;
fn next(&mut self) -> Option<Self::Item> {
- let line = self.read_line()?;
-
- if let Err(e) = line {
- return Some(Err(e)); // :(
+ self.strbuf.clear();
+ match self.file.read_line(&mut self.strbuf) {
+ Ok(0) => return None,
+ Ok(_) => (),
+ Err(e) => return Some(Err(eyre!("failed to read line: {}", e))), // we can skip past things like invalid utf8
}
- let mut line = line.unwrap();
+ self.loc -= 1;
- while line.ends_with("\\\n") {
- let next_line = self.read_line()?;
-
- if next_line.is_err() {
+ while self.strbuf.ends_with("\\\n") {
+ if self.file.read_line(&mut self.strbuf).is_err() {
+ // There's a chance that the last line of a command has invalid
+ // characters, the only safe thing to do is break :/
+ // usually just invalid utf8 or smth
+ // however, we really need to avoid missing history, so it's
+ // better to have some items that should have been part of
+ // something else, than to miss things. So break.
break;
- }
+ };
- line.push_str(next_line.unwrap().as_str());
+ self.loc -= 1;
}
let time = chrono::Utc::now();
@@ -68,7 +82,7 @@ impl Iterator for Bash {
Some(Ok(History::new(
time,
- line.trim_end().to_string(),
+ self.strbuf.trim_end().to_string(),
String::from("unknown"),
-1,
-1,
@@ -76,4 +90,45 @@ impl Iterator for Bash {
None,
)))
}
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(self.loc))
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::io::Cursor;
+
+ use super::Bash;
+
+ #[test]
+ fn test_parse_file() {
+ let input = r"cargo install atuin
+cargo install atuin; \
+cargo update
+cargo :b̷i̶t̴r̵o̴t̴ ̵i̷s̴ ̷r̶e̵a̸l̷
+";
+
+ let cursor = Cursor::new(input);
+ let mut bash = Bash::new(cursor).unwrap();
+ assert_eq!(bash.loc, 4);
+ assert_eq!(bash.size_hint(), (0, Some(4)));
+
+ assert_eq!(
+ &bash.next().unwrap().unwrap().command,
+ "cargo install atuin"
+ );
+ assert_eq!(
+ &bash.next().unwrap().unwrap().command,
+ "cargo install atuin; \\\ncargo update"
+ );
+ assert_eq!(
+ &bash.next().unwrap().unwrap().command,
+ "cargo :b̷i̶t̴r̵o̴t̴ ̵i̷s̴ ̷r̶e̵a̸l̷"
+ );
+ assert!(bash.next().is_none());
+
+ assert_eq!(bash.size_hint(), (0, Some(0)));
+ }
}