// Copyright © 2020 Jakob L. Kreuze // // 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 . #[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 { 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 = 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::().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::().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::>(); 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); } } }