summaryrefslogtreecommitdiff
path: root/src/birka-cli.rs
diff options
context:
space:
mode:
authorJakob L. Kreuze <zerodaysfordays@sdf.org>2020-05-25 14:26:00 -0400
committerJakob L. Kreuze <zerodaysfordays@sdf.org>2020-05-25 18:04:31 -0400
commitc69ed1e0bf7567883445e917414a32f6815addb6 (patch)
tree369c7c24e5f456b2d3d57156d350c48b742c701a /src/birka-cli.rs
parentd59a92b04a398b274fbeda0de6d8e64c718837dd (diff)
Implement initial thumbnail creation.
Diffstat (limited to 'src/birka-cli.rs')
-rw-r--r--src/birka-cli.rs119
1 files changed, 119 insertions, 0 deletions
diff --git a/src/birka-cli.rs b/src/birka-cli.rs
new file mode 100644
index 0000000..d2caba3
--- /dev/null
+++ b/src/birka-cli.rs
@@ -0,0 +1,119 @@
+// Copyright © 2020 Jakob L. Kreuze <zerodaysfordays@sdf.org>
+//
+// This file is part of бирка-тян.
+//
+// бирка-тян is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Affero General Public License as published
+// by the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// бирка-тян is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public
+// License along with бирка-тян. If not, see <http://www.gnu.org/licenses/>.
+
+#[macro_use]
+extern crate anyhow;
+extern crate dirs;
+
+mod database;
+
+use anyhow::Result;
+use blake2::{Blake2b, Digest};
+use database::TagDatabase;
+use std::env;
+use std::io;
+use std::path::Path;
+
+/// Return a base64-encoded BLAKE2b hash identifying the file at `path`.
+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()))
+}
+
+fn main() {
+ 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") {
+ TagDatabase::new(&val)
+ } else if let Some(dir) = dirs::config_dir() {
+ TagDatabase::new(dir.join("birka.db").to_str().unwrap())
+ } else {
+ TagDatabase::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]).canonicalize().unwrap();
+ 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();
+ }
+ }
+ "id_for" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} id_for PATH ", args[0]);
+ std::process::exit(1);
+ }
+ let path = Path::new(&args[2]).canonicalize().unwrap();
+ println!("{}", tb.image_id(&path).unwrap());
+ }
+ "add_tags" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} add_tags ID [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let id = args[2].parse::<i64>().unwrap();
+ for arg in args[3..].iter() {
+ tb.add_tag(arg).unwrap();
+ tb.tag_image(id, arg).unwrap();
+ }
+ }
+ "remove_tags" => {
+ if args.len() < 3 {
+ eprintln!("usage: {} remove_tags ID [TAGS ...]", args[0]);
+ std::process::exit(1);
+ }
+ let id = args[2].parse::<i64>().unwrap();
+ for arg in args[3..].iter() {
+ tb.untag_image(id, arg).unwrap();
+ }
+ }
+ "query" => {
+ let tags = args[2..].iter().map(|s| s.as_str()).collect::<Vec<&str>>();
+ for tag in tags.iter() {
+ if tb.tag_id(tag).is_err() {
+ eprintln!("unknown tag: {}", tag);
+ std::process::exit(1);
+ }
+ }
+ for image in tb.images_by_tags(&tags[..]).unwrap() {
+ println!(
+ "{},{},{}{}",
+ image.id, image.blake2, image.orig_dir, image.filename
+ );
+ }
+ }
+ _ => {
+ eprintln!("Unknown action '{}'", action);
+ std::process::exit(1);
+ }
+ }
+}