diff --git a/CHANGELOG.md b/CHANGELOG.md index 848efdf..78fe598 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - fixed - Fix throttling for fetched bookmarks - Fix `Cache::exists` + - Fix clean up for `Ctrl+C` shortcut - changed - Rename subcommand from `update` to `sync` - Rename flag from `--all` to `--replace` for `bogrep fetch` diff --git a/src/bookmark_reader/target_reader_writer.rs b/src/bookmark_reader/target_reader_writer.rs index fe82975..6625163 100644 --- a/src/bookmark_reader/target_reader_writer.rs +++ b/src/bookmark_reader/target_reader_writer.rs @@ -5,7 +5,7 @@ use std::{ path::{Path, PathBuf}, }; -/// A helper struct to read from and write to target files. +/// A helper to read from and write to a target file. pub struct TargetReaderWriter { reader: File, reader_path: PathBuf, diff --git a/src/cmd/add.rs b/src/cmd/add.rs index ec78f8d..38d5d9c 100644 --- a/src/cmd/add.rs +++ b/src/cmd/add.rs @@ -9,7 +9,11 @@ use anyhow::anyhow; use chrono::Utc; use log::debug; -pub async fn add(config: Config, args: AddArgs) -> Result<(), anyhow::Error> { +pub async fn add( + config: Config, + args: AddArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); let urls = utils::parse_urls(&args.urls)?; @@ -26,10 +30,6 @@ pub async fn add(config: Config, args: AddArgs) -> Result<(), anyhow::Error> { )?; let client_config = ClientConfig::new(&config.settings); let cache_mode = CacheMode::new(&None, &config.settings.cache_mode); - let target_reader_writer = TargetReaderWriter::new( - &config.target_bookmark_file, - &config.target_bookmark_lock_file, - )?; let cache = Cache::new(&config.cache_path, cache_mode); let client = Client::new(&client_config)?; let mut bookmark_manager = BookmarkManager::default(); @@ -45,7 +45,5 @@ pub async fn add(config: Config, args: AddArgs) -> Result<(), anyhow::Error> { ) .await?; - target_reader_writer.close()?; - Ok(()) } diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index ba6fb7a..5e14130 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -1,15 +1,19 @@ use crate::{ - args::CleanArgs, bookmark_reader::ReadTarget, cache::CacheMode, utils, Cache, Caching, Config, - TargetBookmarks, + args::CleanArgs, bookmark_reader::ReadTarget, cache::CacheMode, Cache, Caching, Config, + TargetBookmarks, TargetReaderWriter, }; use log::debug; /// Clean up cache for removed bookmarks. -pub async fn clean(config: &Config, args: &CleanArgs) -> Result<(), anyhow::Error> { +pub async fn clean( + config: &Config, + args: &CleanArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); let mut target_bookmarks = TargetBookmarks::default(); - let mut target_reader = utils::open_file_in_read_mode(&config.target_bookmark_file)?; + let mut target_reader = target_reader_writer.reader(); target_reader.read(&mut target_bookmarks)?; let cache_mode = CacheMode::new(&args.mode, &config.settings.cache_mode); let cache = Cache::new(&config.cache_path, cache_mode); diff --git a/src/cmd/fetch.rs b/src/cmd/fetch.rs index c5d6ec3..2b17592 100644 --- a/src/cmd/fetch.rs +++ b/src/cmd/fetch.rs @@ -9,7 +9,11 @@ use chrono::Utc; use log::debug; /// Fetch and cache bookmarks. -pub async fn fetch(config: &Config, args: &FetchArgs) -> Result<(), anyhow::Error> { +pub async fn fetch( + config: &Config, + args: &FetchArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); if args.dry_run { @@ -21,11 +25,6 @@ pub async fn fetch(config: &Config, args: &FetchArgs) -> Result<(), anyhow::Erro let client_config = ClientConfig::new(&config.settings); let client = Client::new(&client_config)?; let mut source_readers = []; - let target_reader_writer = TargetReaderWriter::new( - &config.target_bookmark_file, - &config.target_bookmark_lock_file, - )?; - let now = Utc::now(); let run_mode = if args.dry_run { RunMode::DryRun @@ -55,7 +54,5 @@ pub async fn fetch(config: &Config, args: &FetchArgs) -> Result<(), anyhow::Erro ) .await?; - target_reader_writer.close()?; - Ok(()) } diff --git a/src/cmd/import.rs b/src/cmd/import.rs index 7ac2462..afe5885 100644 --- a/src/cmd/import.rs +++ b/src/cmd/import.rs @@ -12,7 +12,11 @@ use std::io::Write; /// Import bookmarks from the configured source files and store unique bookmarks /// in cache. -pub async fn import(config: Config, args: ImportArgs) -> Result<(), anyhow::Error> { +pub async fn import( + config: Config, + args: ImportArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); if args.dry_run { @@ -44,10 +48,6 @@ pub async fn import(config: Config, args: ImportArgs) -> Result<(), anyhow::Erro .iter() .map(SourceReader::init) .collect::, anyhow::Error>>()?; - let target_reader_writer = TargetReaderWriter::new( - &config.target_bookmark_file, - &config.target_bookmark_lock_file, - )?; let now = Utc::now(); let run_mode = if args.dry_run { @@ -73,7 +73,5 @@ pub async fn import(config: Config, args: ImportArgs) -> Result<(), anyhow::Erro ) .await?; - target_reader_writer.close()?; - Ok(()) } diff --git a/src/cmd/remove.rs b/src/cmd/remove.rs index 23be04e..32fbb36 100644 --- a/src/cmd/remove.rs +++ b/src/cmd/remove.rs @@ -9,7 +9,11 @@ use anyhow::anyhow; use chrono::Utc; use log::debug; -pub async fn remove(config: Config, args: RemoveArgs) -> Result<(), anyhow::Error> { +pub async fn remove( + config: Config, + args: RemoveArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); let urls = utils::parse_urls(&args.urls)?; @@ -19,10 +23,6 @@ pub async fn remove(config: Config, args: RemoveArgs) -> Result<(), anyhow::Erro } let now = Utc::now(); - let target_reader_writer = TargetReaderWriter::new( - &config.target_bookmark_file, - &config.target_bookmark_lock_file, - )?; let service_config = ServiceConfig::new( RunMode::RemoveUrls(urls.clone()), &[], @@ -45,7 +45,5 @@ pub async fn remove(config: Config, args: RemoveArgs) -> Result<(), anyhow::Erro ) .await?; - target_reader_writer.close()?; - Ok(()) } diff --git a/src/cmd/search.rs b/src/cmd/search.rs index 443a449..d0a3939 100644 --- a/src/cmd/search.rs +++ b/src/cmd/search.rs @@ -1,6 +1,6 @@ use crate::{ - bookmark_reader::ReadTarget, cache::CacheMode, utils, Args, Cache, Caching, Config, - TargetBookmarks, + bookmark_reader::ReadTarget, cache::CacheMode, Args, Cache, Caching, Config, TargetBookmarks, + TargetReaderWriter, }; use anyhow::anyhow; use colored::Colorize; @@ -14,14 +14,19 @@ use std::{ /// Maximum number of characters per line displayed in the search result. const MAX_COLUMNS: usize = 1000; -pub fn search(pattern: &str, config: &Config, args: &Args) -> Result<(), anyhow::Error> { +pub fn search( + pattern: &str, + config: &Config, + args: &Args, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{:?}", pattern); let cache_mode = CacheMode::new(&args.mode, &config.settings.cache_mode); let cache = Cache::new(&config.cache_path, cache_mode); let mut target_bookmarks = TargetBookmarks::default(); - let mut target_reader = utils::open_file_in_read_mode(&config.target_bookmark_file)?; + let mut target_reader = target_reader_writer.reader(); target_reader.read(&mut target_bookmarks)?; if target_bookmarks.is_empty() { diff --git a/src/cmd/sync.rs b/src/cmd/sync.rs index eddce11..fc56b7d 100644 --- a/src/cmd/sync.rs +++ b/src/cmd/sync.rs @@ -11,7 +11,11 @@ use log::debug; /// Import the diff of source and target bookmarks. Fetch and cache websites for /// new bookmarks; delete cache for removed bookmarks. -pub async fn sync(config: &Config, args: &SyncArgs) -> Result<(), anyhow::Error> { +pub async fn sync( + config: &Config, + args: &SyncArgs, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { debug!("{args:?}"); if args.dry_run { @@ -29,10 +33,6 @@ pub async fn sync(config: &Config, args: &SyncArgs) -> Result<(), anyhow::Error> .iter() .map(SourceReader::init) .collect::, anyhow::Error>>()?; - let target_reader_writer = TargetReaderWriter::new( - &config.target_bookmark_file, - &config.target_bookmark_lock_file, - )?; let now = Utc::now(); let run_mode = if args.dry_run { RunMode::DryRun @@ -57,7 +57,5 @@ pub async fn sync(config: &Config, args: &SyncArgs) -> Result<(), anyhow::Error> ) .await?; - target_reader_writer.close()?; - Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 5dac606..cdbdacf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ pub mod utils; pub use args::{Args, ConfigArgs, FetchArgs, Subcommands}; pub use bookmark_reader::{ - ChromiumReader, FirefoxReader, ReadBookmark, SafariReader, SimpleReader, + ChromiumReader, FirefoxReader, ReadBookmark, SafariReader, SimpleReader, TargetReaderWriter, }; pub use bookmarks::{ Action, BookmarkManager, BookmarkService, JsonBookmark, JsonBookmarks, RunMode, ServiceConfig, diff --git a/src/main.rs b/src/main.rs index 83c6175..92e70da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ use anyhow::anyhow; -use bogrep::{cmd, Args, Config, Logger, Subcommands}; +use bogrep::{cmd, Args, Config, Logger, Subcommands, TargetReaderWriter}; use clap::Parser; -use std::fs; use tokio::signal; #[tokio::main] @@ -9,40 +8,46 @@ async fn main() -> Result<(), anyhow::Error> { let args = Args::parse(); Logger::init(args.verbose); let config = Config::init()?; - let target_bookmark_lock_file = config.target_bookmark_lock_file.clone(); + let target_reader_writer = TargetReaderWriter::new( + &config.target_bookmark_file, + &config.target_bookmark_lock_file, + )?; tokio::select! { _ = signal::ctrl_c() => { - // Clean up lock file when aborting. - // TODO: finish writing to `bookmarks.json` - if target_bookmark_lock_file.exists() { - if let Err(err) = fs::remove_file(target_bookmark_lock_file) { - eprintln!("Can't remove lock file: {err:?}") - } + // Clean up when aborting. + if let Err(err) = target_reader_writer.close() { + eprintln!("Can't finish clean up: {err:?}"); } + println!("Aborting ..."); Ok(()) }, - res = run_app(args, config) => { + res = run_app(args, config, &target_reader_writer) => { + target_reader_writer.close()?; res } } } -async fn run_app(args: Args, config: Config) -> Result<(), anyhow::Error> { +async fn run_app( + args: Args, + config: Config, + target_reader_writer: &TargetReaderWriter, +) -> Result<(), anyhow::Error> { if let Some(subcommands) = args.subcommands { match subcommands { Subcommands::Config(args) => cmd::configure(config, args)?, - Subcommands::Import(args) => cmd::import(config, args).await?, - Subcommands::Sync(args) => cmd::sync(&config, &args).await?, - Subcommands::Fetch(args) => cmd::fetch(&config, &args).await?, - Subcommands::Clean(args) => cmd::clean(&config, &args).await?, - Subcommands::Add(args) => cmd::add(config, args).await?, - Subcommands::Remove(args) => cmd::remove(config, args).await?, + Subcommands::Import(args) => cmd::import(config, args, target_reader_writer).await?, + Subcommands::Sync(args) => cmd::sync(&config, &args, target_reader_writer).await?, + Subcommands::Fetch(args) => cmd::fetch(&config, &args, target_reader_writer).await?, + Subcommands::Clean(args) => cmd::clean(&config, &args, target_reader_writer).await?, + Subcommands::Add(args) => cmd::add(config, args, target_reader_writer).await?, + Subcommands::Remove(args) => cmd::remove(config, args, target_reader_writer).await?, } } else if let Some(pattern) = &args.pattern { - cmd::search(pattern, &config, &args)?; + cmd::search(pattern, &config, &args, target_reader_writer)?; } else { return Err(anyhow!("Missing search pattern: `bogrep `")); }