diff options
| author | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-06-06 18:58:52 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2020-06-06 18:58:52 -0400 |
| commit | 0f0d4477a4eab8ec0b99c134154ce0fedb4d6400 (patch) | |
| tree | 34b28406cde6489726a65b67bc00e1eea78f018f /src | |
| parent | 52adceb6be36c121d3cfb16e7bf29ec4889dc6ec (diff) | |
Clean up for release.
Diffstat (limited to 'src')
| -rw-r--r-- | src/birka-cli.rs | 10 | ||||
| -rw-r--r-- | src/database.rs | 107 |
2 files changed, 68 insertions, 49 deletions
diff --git a/src/birka-cli.rs b/src/birka-cli.rs index e74fcd7..3fd5420 100644 --- a/src/birka-cli.rs +++ b/src/birka-cli.rs @@ -18,10 +18,12 @@ #[macro_use] extern crate anyhow; extern crate dirs; +#[macro_use] +extern crate rusqlite; mod database; -use database::{hash_file, TagDatabase}; +use database::TagDatabase; use std::env; use std::path::Path; @@ -35,9 +37,9 @@ fn main() { let tb = if let Ok(val) = env::var("TB_PATH") { TagDatabase::new(&val) } else if let Some(dir) = dirs::config_dir() { - TagDatabase::new(dir.join("birka.db").to_str().unwrap()) + TagDatabase::new(&dir.join("birka.db")) } else { - TagDatabase::new(Path::new("/tmp").join("pometka.db").to_str().unwrap()) + TagDatabase::new(&Path::new("/tmp").join("birka.db")) } .unwrap(); @@ -49,7 +51,7 @@ fn main() { std::process::exit(1); } let path = Path::new(&args[2]).canonicalize().unwrap(); - let hash = hash_file(&path).unwrap(); + let hash = database::hash_file(&path).unwrap(); let id = tb.import_image(&path, &hash).unwrap(); for arg in args[3..].iter() { tb.add_tag(arg).unwrap(); diff --git a/src/database.rs b/src/database.rs index b83fc9b..14ff853 100644 --- a/src/database.rs +++ b/src/database.rs @@ -17,25 +17,79 @@ use anyhow::Result; use blake2::{Blake2b, Digest}; -use rusqlite::{params, Connection}; +use rusqlite::Connection; + +use std::convert::AsRef; use std::io; use std::path::Path; -/// A connection to бирка-тян's tag database. +/// A connection to the tag database. #[derive(Debug)] pub struct TagDatabase(Connection); /// Tag query with a sense of "state" for pagination. #[derive(Debug)] pub struct Query<'a> { - pub tags: &'a [&'a str], - pub last_id: Option<i64>, - pub limit: Option<i64>, + tags: &'a [&'a str], + last_id: Option<i64>, + limit: Option<i64>, +} + +impl<'a> Query<'a> { + /// Construct a new query for images tagged with `tags`. + /// + /// When given to the database, this query will return at most `limit` + /// results, if specified, and will return only images newer than `last_id`, + /// if specified. + pub fn new(tags: &'a [&'a str], last_id: Option<i64>, limit: Option<i64>) -> Self { + Query { + tags, + last_id, + limit, + } + } +} + +/// The result of an image query in бирка-тян's tag database. +#[derive(Debug)] +pub struct Image { + pub id: i64, + pub blake2: String, + pub filename: String, + pub orig_dir: String, +} + +/// Return a base64-encoded BLAKE2b hash identifying the file at `path`. +pub fn hash_file(path: &Path) -> Result<String> { + let mut file = std::fs::File::open(path)?; + let mut hasher = Blake2b::new(); + io::copy(&mut file, &mut hasher)?; + Ok(base64::encode(&hasher.result())) +} + +/// Split the path into a tuple containing the parent directory and the filename. +pub fn split_path(path: &Path) -> Result<(String, String)> { + if path.is_dir() { + bail!("`path` does not name a file."); + } + + let file_name = path + .file_name() + .and_then(|os| os.to_str()) + .ok_or(anyhow!("Couldn't parse file name."))?; + + // Convert `path` to a string and strip off the `file_name` we've just + // obtained to yield the name of the parent directory. + let path = path.to_str().ok_or(anyhow!("Couldn't parse path."))?; + let split_index = path.len() - file_name.len(); + let parent_directory = &path[0..split_index]; + + Ok((file_name.to_string(), parent_directory.to_string())) } impl TagDatabase { /// Instantiate a new `TagDatabase` whose backing database is at `path`. - pub fn new(path: &str) -> Result<Self> { + pub fn new<T: AsRef<Path>>(path: &T) -> Result<Self> { let tb = TagDatabase(Connection::open(path)?); tb.initialize_tables()?; Ok(tb) @@ -90,29 +144,9 @@ impl TagDatabase { .query_row(params![tag], |row| Ok(row.get::<_, i64>(0)))??) } - /// Split the path into a tuple containing the parent directory and the filename. - fn split_path(&self, path: &Path) -> Result<(String, String)> { - if path.is_dir() { - bail!("`path` does not name a file."); - } - - let file_name = path - .file_name() - .and_then(|os| os.to_str()) - .ok_or(anyhow!("Couldn't parse file name."))?; - - // Convert `path` to a string and strip off the `file_name` we've just - // obtained to yield the name of the parent directory. - let path = path.to_str().ok_or(anyhow!("Couldn't parse path."))?; - let split_index = path.len() - file_name.len(); - let parent_directory = &path[0..split_index]; - - Ok((file_name.to_string(), parent_directory.to_string())) - } - /// Insert the image at `path` into the data. pub fn import_image(&self, path: &Path, hash: &str) -> Result<i64> { - let (file_name, parent_directory) = self.split_path(path)?; + let (file_name, parent_directory) = split_path(path)?; Ok(self .0 .prepare("INSERT INTO images (blake2, filename, orig_dir) VALUES(?,?,?)")? @@ -121,7 +155,7 @@ impl TagDatabase { /// Return the internal id for the image at `path`. pub fn image_id(&self, path: &Path) -> Result<i64> { - let (file_name, path) = self.split_path(path)?; + let (file_name, path) = split_path(path)?; Ok(self .0 .prepare("SELECT id FROM images WHERE orig_dir = ? AND filename = ?")? @@ -290,23 +324,6 @@ impl TagDatabase { } } -/// The result of an image query in бирка-тян's tag database. -#[derive(Debug)] -pub struct Image { - pub id: i64, - pub blake2: String, - pub filename: String, - pub orig_dir: String, -} - -/// Return a base64-encoded BLAKE2b hash identifying the file at `path`. -pub fn hash_file(path: &Path) -> Result<String> { - let mut file = std::fs::File::open(path)?; - let mut hasher = Blake2b::new(); - io::copy(&mut file, &mut hasher)?; - Ok(base64::encode(&hasher.result())) -} - #[cfg(test)] mod tests { use super::*; |