summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob L. Kreuze <zerodaysfordays@sdf.org>2020-05-21 19:56:05 -0400
committerJakob L. Kreuze <zerodaysfordays@sdf.org>2020-05-21 19:56:05 -0400
commitb21b1238401f75e6bf7503ba8d42decdeeb10708 (patch)
tree6ebc07b8513ff68be15a4a0b635363a97095eb47
parent6c8066dd171bd22a03e371dcfa06851fa1366e27 (diff)
Implement an initial command-line interface.
TODO: - Tabulate `query` output: show internal id, blake2, etc. - `remove` command. - `add_tags` command. - `remove_tags` command.
-rw-r--r--Cargo.lock135
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs69
3 files changed, 194 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5bb4da3..9aca2b6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -7,6 +7,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
+
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+
+[[package]]
+name = "base64"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
+
+[[package]]
name = "base64"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -31,12 +55,46 @@ dependencies = [
]
[[package]]
+name = "blake2b_simd"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "constant_time_eq",
+]
+
+[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -56,6 +114,28 @@ dependencies = [
]
[[package]]
+name = "dirs"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
+dependencies = [
+ "cfg-if",
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -77,6 +157,23 @@ dependencies = [
]
[[package]]
+name = "getrandom"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
name = "libc"
version = "0.2.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -126,12 +223,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
[[package]]
+name = "redox_syscall"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+
+[[package]]
+name = "redox_users"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431"
+dependencies = [
+ "getrandom",
+ "redox_syscall",
+ "rust-argon2",
+]
+
+[[package]]
name = "roru"
version = "0.1.0"
dependencies = [
"anyhow",
- "base64",
+ "base64 0.12.1",
"blake2",
+ "dirs",
"rusqlite",
]
@@ -151,6 +266,18 @@ dependencies = [
]
[[package]]
+name = "rust-argon2"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017"
+dependencies = [
+ "base64 0.11.0",
+ "blake2b_simd",
+ "constant_time_eq",
+ "crossbeam-utils",
+]
+
+[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -179,6 +306,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168"
[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 2da0665..e939dda 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,6 +11,7 @@ license = "AGPL-3.0+"
anyhow = "1.0.31"
base64 = "0.12.1"
blake2 = "0.8"
+dirs = "2.0.2"
[dependencies.rusqlite]
version = "0.21.0"
diff --git a/src/main.rs b/src/main.rs
index 4b3fcc1..db43ea9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,10 +17,12 @@
#[macro_use]
extern crate anyhow;
+extern crate dirs;
use anyhow::Result;
use blake2::{Blake2b, Digest};
use rusqlite::{params, Connection};
+use std::env;
use std::io;
use std::path::Path;
@@ -167,7 +169,10 @@ impl TagBase {
/// Return the intersection of the sets of images matching each of `tags`.
fn images_by_tags(&self, tags: &[&str]) -> Result<Vec<Image>> {
- let ids = tags.iter().map(|tag| self.tag_id(tag));
+ let ids: Vec<i64> = tags
+ .iter()
+ .filter_map(|tag| self.tag_id(tag).ok())
+ .collect();
let mut tags = Vec::from(tags);
tags.dedup();
@@ -181,16 +186,16 @@ impl TagBase {
ON images.id = mapping.image",
)
} else {
- (1..tags.len() + 1)
- .zip(tags)
+ (1..ids.len() + 1)
+ .zip(ids)
.map(|pair| {
- let (n, tag) = pair;
+ let (n, id) = pair;
format!(
"INNER JOIN mapping as m{n}
ON images.id = m{n}.image
AND {id} = m{n}.tag",
n = n,
- id = tag
+ id = id
)
})
.collect::<Vec<String>>()
@@ -314,9 +319,53 @@ mod tests {
}
fn main() {
- let tb = TagBase::new("/tmp/test.db").unwrap();
- let path = Path::new("/home/jakob/Sync/06fc9ae71549eb4d.jpeg");
- let hash = hash_file(path).unwrap();
- tb.import_image(path, &hash).unwrap();
- println!("{:?}", tb);
+ let args: Vec<String> = env::args().collect();
+ if args.len() < 2 {
+ eprintln!("usage: {} ACTION [ARGS ...]", args[0]);
+ std::process::exit(1);
+ }
+
+ let tb = if let Ok(val) = env::var("TB_PATH") {
+ TagBase::new(&val)
+ } else {
+ if let Some(dir) = dirs::config_dir() {
+ TagBase::new(dir.join("pometka.db").to_str().unwrap())
+ } else {
+ TagBase::new(Path::new("/tmp").join("pometka.db").to_str().unwrap())
+ }
+ }
+ .unwrap();
+
+ let action = &args[1];
+ match action.to_lowercase().as_str() {
+ "add" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} add PATH [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let path = Path::new(&args[2]);
+ let hash = hash_file(path).unwrap();
+ let id = tb.import_image(path, &hash).unwrap();
+ for arg in args[3..].iter() {
+ tb.add_tag(arg).unwrap();
+ tb.tag_image(id, arg).unwrap();
+ }
+ }
+ "query" => {
+ let tags = args[2..].iter().map(|s| s.as_str()).collect::<Vec<&str>>();
+ for tag in tags.iter() {
+ if let Err(_) = tb.tag_id(tag) {
+ eprintln!("unknown tag: {}", tag);
+ std::process::exit(1);
+ }
+ }
+ for image in tb.images_by_tags(&tags[..]).unwrap() {
+ println!("{}/{}", image.orig_dir, image.filename);
+ }
+ }
+ _ => {
+ eprintln!("Unknown action '{}'", action);
+ std::process::exit(1);
+ }
+ }
}