diff --git a/Cargo.lock b/Cargo.lock index cbde54f..c640a6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,7 +238,7 @@ dependencies = [ [[package]] name = "gibcite" -version = "0.3.0" +version = "0.3.1" dependencies = [ "assert_cmd", "assert_fs", @@ -250,6 +250,7 @@ dependencies = [ "rusqlite", "serde", "serde_json", + "tempfile", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 345f669..e94cd9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "gibcite" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Marek S. Ɓukasiewicz "] description = "Give details of citation from local Zotero database" readme = "README.md" repository = "https://github.com/Maarrk/gibcite" license = "AGPL-3.0-or-later" -license-file = "LICENSE.txt" keywords = ["bibliography", "zotero"] categories = ["command-line-utilities"] @@ -21,6 +20,7 @@ regex = "1" rusqlite = { version = "0.27.0", features = ["backup", "bundled"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +tempfile = "3" [dev-dependencies] assert_cmd = "2.0" diff --git a/src/lib.rs b/src/lib.rs index cfe1893..7e2589d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,11 +3,15 @@ use regex::Regex; use rusqlite::Connection; use serde::Deserialize; use serde_json::Value; -use std::{error::Error, path::PathBuf}; +use std::{error::Error, fs::copy, path::PathBuf}; +use tempfile::{tempdir, TempDir}; pub mod output; -pub fn get_database_path(input: &Option) -> Result, String> { +/// Copies the SQLite database files into a temporary directory +/// +/// This allows to read them while they are locked by Zotero +pub fn get_database_path(input: &Option) -> Result { let path_buf = match input { Some(path) => path.to_owned(), None => { @@ -32,7 +36,23 @@ pub fn get_database_path(input: &Option) -> Result, String )); } - Ok(Box::new(path_buf)) + if let Ok(dir) = tempdir() { + if let Err(err) = copy( + path_buf.join("zotero.sqlite"), + dir.path().join("zotero.sqlite"), + ) { + return Err(format!("copy error: {:?}", err)); + } + if let Err(err) = copy( + path_buf.join("better-bibtex.sqlite"), + dir.path().join("better-bibtex.sqlite"), + ) { + return Err(format!("copy error: {:?}", err)); + } + Ok(dir) + } else { + Err("could not open temporary dir".into()) + } } pub fn count_items(conn: &Connection) -> Result> { diff --git a/src/main.rs b/src/main.rs index f5ecb81..eb5926b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,7 @@ fn main() { } let conn = Connection::open_with_flags( - database_path.join("zotero.sqlite"), + database_path.path().join("zotero.sqlite"), OpenFlags::SQLITE_OPEN_READ_ONLY, ) .unwrap_or_else(|err| { @@ -43,7 +43,7 @@ fn main() { exit(exitcode::UNAVAILABLE); }); let bibtex_conn = Connection::open_with_flags( - database_path.join("better-bibtex.sqlite"), + database_path.path().join("better-bibtex.sqlite"), OpenFlags::SQLITE_OPEN_READ_ONLY, ) .unwrap_or_else(|err| { diff --git a/tests/cli.rs b/tests/cli.rs index 29e3103..72ba2a9 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -71,3 +71,28 @@ fn mock_key() -> Result<(), Box> { Ok(()) } + +#[test] +fn missing_key() -> Result<(), Box> { + let (mut cmd, _dir) = setup_command().unwrap(); + cmd.arg("thisisnotacitationkey"); + + cmd.assert().failure(); + + Ok(()) +} + +#[test] +fn json_output() -> Result<(), Box> { + let (mut cmd, _dir) = setup_command().unwrap(); + cmd.arg("kowalskiSampleTitle2022"); + + let output = cmd.output().unwrap().stdout; + let val: serde_json::Value = serde_json::from_slice(&output).unwrap(); + let object = val[0].as_object().unwrap(); + + assert_eq!("A sample title", object["title"]); + assert_eq!("Abstract for a sample article", object["abstract"]); + + Ok(()) +}