summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorextrawurst <mail@rusticorn.com>2022-11-21 18:09:08 +0100
committerextrawurst <mail@rusticorn.com>2022-11-21 18:09:08 +0100
commitbbcadcb5d1644c49da7d86187ef9affd33f95da2 (patch)
tree62165144fbdeb5460fd1d0a376fa439b56dee392 /src
parent8cdb02349f8d1a96498ea7fffd9547777a511e04 (diff)
threaded watcher creation and arg for config
new argument `polling` allows to force watcher to use polling instead of file system events. this should address the issue in #1436 and maybe even #1437
Diffstat (limited to 'src')
-rw-r--r--src/args.rs35
-rw-r--r--src/main.rs7
-rw-r--r--src/watcher.rs66
3 files changed, 80 insertions, 28 deletions
diff --git a/src/args.rs b/src/args.rs
index 13621af8..2f58fe07 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -2,8 +2,8 @@ use crate::bug_report;
use anyhow::{anyhow, Result};
use asyncgit::sync::RepoPath;
use clap::{
- crate_authors, crate_description, crate_name, crate_version, Arg,
- Command as ClapApp,
+ crate_authors, crate_description, crate_name, crate_version,
+ value_parser, Arg, Command as ClapApp,
};
use simplelog::{Config, LevelFilter, WriteLogger};
use std::{
@@ -15,6 +15,7 @@ use std::{
pub struct CliArgs {
pub theme: PathBuf,
pub repo_path: RepoPath,
+ pub poll_watcher: bool,
}
pub fn process_cmdline() -> Result<CliArgs> {
@@ -46,17 +47,20 @@ pub fn process_cmdline() -> Result<CliArgs> {
.get_one::<String>("theme")
.map_or_else(|| PathBuf::from("theme.ron"), PathBuf::from);
- if get_app_config_path()?.join(&arg_theme).is_file() {
- Ok(CliArgs {
- theme: get_app_config_path()?.join(arg_theme),
- repo_path,
- })
+ let theme = if get_app_config_path()?.join(&arg_theme).is_file() {
+ get_app_config_path()?.join(arg_theme)
} else {
- Ok(CliArgs {
- theme: get_app_config_path()?.join("theme.ron"),
- repo_path,
- })
- }
+ get_app_config_path()?.join("theme.ron")
+ };
+
+ let arg_poll: bool =
+ *arg_matches.get_one("poll").unwrap_or(&false);
+
+ Ok(CliArgs {
+ theme,
+ poll_watcher: arg_poll,
+ repo_path,
+ })
}
fn app() -> ClapApp {
@@ -91,6 +95,13 @@ fn app() -> ClapApp {
.num_args(0),
)
.arg(
+ Arg::new("poll")
+ .help("Poll folder for changes instead of using file system events. This can be useful if you run into issues with maximum # of file descriptors")
+ .long("polling")
+ .num_args(0)
+ .value_parser(value_parser!(bool)),
+ )
+ .arg(
Arg::new("bugreport")
.help("Generate a bug report")
.long("bugreport"),
diff --git a/src/main.rs b/src/main.rs
index 6563a372..6a45b857 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -150,6 +150,7 @@ fn main() -> Result<()> {
theme,
key_config.clone(),
&input,
+ cliargs.poll_watcher,
&mut terminal,
)?;
@@ -170,13 +171,17 @@ fn run_app(
theme: Theme,
key_config: KeyConfig,
input: &Input,
+ poll_watcher: bool,
terminal: &mut Terminal<CrosstermBackend<io::Stdout>>,
) -> Result<QuitState, anyhow::Error> {
let (tx_git, rx_git) = unbounded();
let (tx_app, rx_app) = unbounded();
let rx_input = input.receiver();
- let watcher = RepoWatcher::new(repo_work_dir(&repo)?.as_str())?;
+ let watcher = RepoWatcher::new(
+ repo_work_dir(&repo)?.as_str(),
+ poll_watcher,
+ );
let rx_watcher = watcher.receiver();
let spinner_ticker = tick(SPINNER_INTERVAL);
diff --git a/src/watcher.rs b/src/watcher.rs
index b2bfe40f..01f99278 100644
--- a/src/watcher.rs
+++ b/src/watcher.rs
@@ -1,8 +1,11 @@
use anyhow::Result;
use crossbeam_channel::{unbounded, Sender};
-use notify::{Error, RecommendedWatcher, RecursiveMode};
+use notify::{
+ Config, Error, PollWatcher, RecommendedWatcher, RecursiveMode,
+ Watcher,
+};
use notify_debouncer_mini::{
- new_debouncer, DebouncedEvent, Debouncer,
+ new_debouncer, new_debouncer_opt, DebouncedEvent,
};
use scopetime::scope_time;
use std::{
@@ -11,22 +14,23 @@ use std::{
pub struct RepoWatcher {
receiver: crossbeam_channel::Receiver<()>,
- #[allow(dead_code)]
- debouncer: Debouncer<RecommendedWatcher>,
}
impl RepoWatcher {
- pub fn new(workdir: &str) -> Result<Self> {
- scope_time!("RepoWatcher::new");
+ pub fn new(workdir: &str, poll: bool) -> Self {
+ log::trace!(
+ "poll watcher: {poll} recommended: {:?}",
+ RecommendedWatcher::kind()
+ );
let (tx, rx) = std::sync::mpsc::channel();
- let mut debouncer =
- new_debouncer(Duration::from_secs(2), None, tx)?;
+ let workdir = workdir.to_string();
- debouncer
- .watcher()
- .watch(Path::new(workdir), RecursiveMode::Recursive)?;
+ thread::spawn(move || {
+ let timeout = Duration::from_secs(2);
+ create_watcher(poll, timeout, tx, &workdir);
+ });
let (out_tx, out_rx) = unbounded();
@@ -37,10 +41,7 @@ impl RepoWatcher {
}
});
- Ok(Self {
- debouncer,
- receiver: out_rx,
- })
+ Self { receiver: out_rx }
}
///
@@ -71,3 +72,38 @@ impl RepoWatcher {
}
}
}
+
+fn create_watcher(
+ poll: bool,
+ timeout: Duration,
+ tx: std::sync::mpsc::Sender<
+ Result<Vec<DebouncedEvent>, Vec<Error>>,
+ >,
+ workdir: &str,
+) {
+ scope_time!("create_watcher");
+
+ if poll {
+ let config = Config::default()
+ .with_poll_interval(Duration::from_secs(2));
+ let mut bouncer = new_debouncer_opt::<_, PollWatcher>(
+ timeout, None, tx, config,
+ )
+ .expect("Watch create error");
+ bouncer
+ .watcher()
+ .watch(Path::new(&workdir), RecursiveMode::Recursive)
+ .expect("Watch error");
+
+ std::mem::forget(bouncer);
+ } else {
+ let mut bouncer = new_debouncer(timeout, None, tx)
+ .expect("Watch create error");
+ bouncer
+ .watcher()
+ .watch(Path::new(&workdir), RecursiveMode::Recursive)
+ .expect("Watch error");
+
+ std::mem::forget(bouncer);
+ };
+}