summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md34
-rw-r--r--src/birka-cli.rs24
-rw-r--r--src/database.rs14
3 files changed, 41 insertions, 31 deletions
diff --git a/README.md b/README.md
index 069f8d9..2476df6 100644
--- a/README.md
+++ b/README.md
@@ -26,18 +26,9 @@ the command-line tool enables her to import images en masse with the full
capabilities of the Unix shell at her fingertips. A brief summary of the
command-line interface follows.
-In бирка-тян's tag database, every image is identified by a signed 64-bit
-integer. The command-line tool operates on these internal identifiers, so it is
-often helpful to obtain the identifier for an image in the filesystem.
-
-```sh
-$ birka-cli id_for Cat.jpeg
-2
-```
-
-But, of course, the tag database must be populated with this "Cat.jpeg" before
-this command is to work. Images are introduced to the database with the `add`
-command, which takes zero or more tags.
+Images are introduced to the database with the `add` command, which takes zero
+or more tags following the path of an image. The path is automatically
+canonicalized, so relative names are perfectly acceptable.
```sh
$ birka-cli add Cat.jpeg animal cat cute
@@ -46,13 +37,13 @@ $ birka-cli add Cat.jpeg animal cat cute
Ah, drat. We should have tagged that image with "photograph", too.
```sh
-$ birka-cli add_tags $(birka-cli id_for Cat.jpeg) photograph
+$ birka-cli add_tags Cat.jpeg photograph
```
On second thought, that wasn't a particularly cute picture.
```sh
-$ birka-cli remove_tags $(birka-cli id_for Cat.jpeg) cute
+$ birka-cli remove_tags Cat.jpeg cute
```
Now, let's see all of the photographs in the tag database tagged with
@@ -60,12 +51,19 @@ Now, let's see all of the photographs in the tag database tagged with
```sh
$ birka-cli query photograph
-1,Kww+tPLv/BsbU7M7qqW59ph54v6CSEiUPNpW4XbA0cpoyrrAZsAmT5Ptm30M+hATM71mimoo7PTaS8DEAq57cQ==,/home/jakob/Camera/Cat.jpeg
+/home/jakob/Camera/Cat.jpeg
```
-The `query` command outputs CSV; the first field is the internal identifier you
-would see from `id_for`, the second is a base64-encoded BLAKE2b hash for the
-image, and the third is the absolute path of the image.
+The `query` command outputs a line-separated list of paths to any images
+satisfying the query string. The semantics are similar to that of Danbooru,
+except that the logical disjunction operator ('~') is unsupported. As a
+convenience, the 'query' command can be invoked without a query string, to list
+all paths indexed by the database.
+
+```sh
+$ birka-cli query
+...
+```
### Web-Interface (API)
diff --git a/src/birka-cli.rs b/src/birka-cli.rs
index 703da7d..1e05712 100644
--- a/src/birka-cli.rs
+++ b/src/birka-cli.rs
@@ -51,30 +51,30 @@ fn main() {
std::process::exit(1);
}
let path = Path::new(&args[2]).canonicalize().unwrap();
- let id = tb.add_file(&path, &args[3..].to_vec()).unwrap();
+ tb.add_file(&path, &args[3..].to_vec()).unwrap();
}
"add_tags" => {
if args.len() < 3 {
- eprintln!("usage: {} add_tags ID [TAGS ...]", args[0]);
+ eprintln!("usage: {} add_tags PATH [TAGS ...]", args[0]);
std::process::exit(1);
}
- let id = args[2].parse::<i64>().unwrap();
- tb.tag_file(id, &args[3..].to_vec()).unwrap();
+ let file = tb.file_by_path(&args[2]).unwrap();
+ tb.tag_file(file.id, &args[3..].to_vec()).unwrap();
}
"remove_tags" => {
if args.len() < 3 {
- eprintln!("usage: {} remove_tags ID [TAGS ...]", args[0]);
+ eprintln!("usage: {} remove_tags PATH [TAGS ...]", args[0]);
std::process::exit(1);
}
- let id = args[2].parse::<i64>().unwrap();
- tb.untag_file(id, &args[3..].to_vec()).unwrap();
+ let file = tb.file_by_path(&args[2]).unwrap();
+ tb.untag_file(file.id, &args[3..].to_vec()).unwrap();
}
"query" => {
- if args.len() < 3 {
- eprintln!("usage: {} query QUERY_STRING", args[0]);
- std::process::exit(1);
- }
- let query = database::parse_query(&args[2]).unwrap();
+ let query = if args.len() < 3 {
+ database::parse_query("").unwrap()
+ } else {
+ database::parse_query(&args[2]).unwrap()
+ };
for file in tb.query(&query, None).unwrap() {
println!("{}", file.path);
}
diff --git a/src/database.rs b/src/database.rs
index bd5ae65..4e33fa7 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -264,6 +264,11 @@ impl TagDatabase {
})?)
}
+ /// Return the `File` object for the file at `path`.
+ pub fn file_by_path<T: AsRef<Path>>(&self, path: T) -> Result<File> {
+ self.file_by_id(self.id_for_path(path)?)
+ }
+
/// Return the files in the database satisfying `q` and `k`.
pub fn query(&self, q: &Query, k: Option<Keyset>) -> Result<Vec<File>> {
// Return an empty vector if the query contains tags that aren't in the
@@ -433,7 +438,7 @@ mod tests {
#[test]
fn test_add_file_fail_on_already_indexed() {
let tb = TagDatabase::new_mem().unwrap();
- let img = tb.add_file("test", &vec!["tag1"]).unwrap();
+ tb.add_file("test", &vec!["tag1"]).unwrap();
assert!(tb.add_file("test", &vec!["tag2"]).is_err());
}
@@ -570,6 +575,13 @@ mod tests {
}
#[test]
+ fn test_path_resolution() {
+ let tb = TagDatabase::new_mem().unwrap();
+ let img = tb.add_file("test1", &vec!["tag1", "tag2"]).unwrap();
+ assert_eq!(tb.file_by_path(img.path).unwrap().path, "test1");
+ }
+
+ #[test]
fn top_tags() {
let tb = TagDatabase::new_mem().unwrap();
let ids: Vec<_> = (1..4)