diff --git a/Cargo.lock b/Cargo.lock index 6ffc176..e86c4eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -360,6 +360,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -989,6 +1010,16 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libredox" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +dependencies = [ + "bitflags 2.9.1", + "libc", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1245,7 +1276,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror", + "thiserror 2.0.12", "ucd-trie", ] @@ -1427,6 +1458,17 @@ dependencies = [ "bitflags 2.9.1", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror 1.0.69", +] + [[package]] name = "regex" version = "1.11.1" @@ -1877,13 +1919,33 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", ] [[package]] @@ -2327,6 +2389,7 @@ name = "wikipedia-infobox-analyzer" version = "0.1.0" dependencies = [ "ascii_table", + "dirs-next", "itertools", "mediawiki", "regex", diff --git a/Cargo.toml b/Cargo.toml index 57a4e2e..a1ad818 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ categories = ["command-line-utilities"] [dependencies] regex = "1.11.1" ascii_table = "4.0.7" +dirs-next = "2.0.0" itertools = "0.14.0" mediawiki = "0.3.1" reqwest = { version = "0.12", features = ["blocking"] } diff --git a/src/main.rs b/src/main.rs index 0d9523c..2d094e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,12 @@ -use structopt::StructOpt; use wikipedia_infobox_analyzer::wikipedia_infobox_analyzer::*; +use dirs_next::cache_dir; +use std::collections::HashMap; +use std::fs; +use std::io; +use std::path::PathBuf; +use structopt::StructOpt; + #[derive(StructOpt)] struct Cli { #[structopt(default_value = "Earth", long = "title")] @@ -11,10 +17,88 @@ struct Cli { infobox_template_file: std::path::PathBuf, } +#[derive(Debug)] +struct StorageDisk { + base_path: PathBuf, +} + +impl StorageDisk { + fn new(app_name: &str) -> Self { + // Get OS-specific cache directory, otherwise use a fallback location + let mut path = match cache_dir() { + Some(path) => path, + None => PathBuf::from("./.cache"), + }; + + path.push(app_name); + fs::create_dir_all(&path) + .unwrap_or_else(|_| panic!("Failed to create storage directory: {path:?}")); + + StorageDisk { base_path: path } + } + + #[allow(dead_code)] + fn delete(&self) -> std::io::Result<()> { + fs::remove_dir_all(&self.base_path) + } + + fn store_data(&self, filename: String, data: String) -> std::io::Result<()> { + let file_path = self.base_path.join(filename); + fs::write(file_path, data) + } + + fn read_data(&self, filename: String) -> std::io::Result { + let file_path = self.base_path.join(filename); + fs::read_to_string(file_path) + } +} + +struct Cache { + file_name: String, + storage: StorageDisk, + property_labels: HashMap, +} + +impl Cache { + fn new(file_name: String, storage: StorageDisk) -> std::io::Result { + let mut property_labels: HashMap = HashMap::new(); + + match storage.read_data(file_name.clone()) { + Ok(raw_data) => { + property_labels = serde_json::from_str(&raw_data)?; + } + Err(err) if err.kind() == io::ErrorKind::NotFound => { + println!("No cache found, populating the program cache with wikidata..."); + + property_labels = HashMap::new(); + property_labels.insert("P31".to_string(), "instance of".to_string()); + + let data = serde_json::to_string(&property_labels)?; + storage.store_data(file_name.clone(), data)?; + + println!("Cache populated from wikidata") + } + Err(err) => { + println!("Unknown error occurred, exiting gracefully"); + return Err(err); + } + } + + Ok(Cache { + file_name, + storage, + property_labels, + }) + } +} + fn main() -> Result<(), Box> { - let args = Cli::from_args(); + // Initialize cache and storage + let storage = StorageDisk::new("wikipedia-infobox-analyzer"); + let cache = Cache::new("property_labels.cache".to_string(), storage); // Input to the program + let args = Cli::from_args(); let title = args.wikipedia_article_title; let language = args.wikipedia_language_code; let template = std::fs::read_to_string(&args.infobox_template_file)?;