Skip to content

Commit 9f14667

Browse files
committed
fix: auto-repack when source folder contents change
1 parent de41fde commit 9f14667

File tree

6 files changed

+138
-10
lines changed

6 files changed

+138
-10
lines changed

Cargo.lock

Lines changed: 59 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ members = [
1010
]
1111

1212
[workspace.package]
13-
version = "0.21.1"
13+
version = "0.21.2"
1414
edition = "2024"
1515
rust-version = "1.85"
1616
license = "MIT"

crates/fastpack-gui/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ image.workspace = true
2222
rayon.workspace = true
2323
serde_json.workspace = true
2424
walkdir = "2"
25+
notify-debouncer-mini = "0.7"
2526
toml = "0.8"
2627
rfd = "0.15"
2728
ureq = "3"

crates/fastpack-gui/src/app.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::sync::mpsc;
2+
use std::time::Duration;
23

34
use eframe::egui;
45
use fastpack_compress::{
@@ -18,6 +19,8 @@ use fastpack_formats::{
1819
pixijs::PixiJsExporter,
1920
},
2021
};
22+
use notify_debouncer_mini::notify::RecursiveMode;
23+
use notify_debouncer_mini::{DebounceEventResult, new_debouncer};
2124

2225
use crate::{
2326
menu,
@@ -42,6 +45,8 @@ pub struct FastPackApp {
4245
prefs_open: bool,
4346
update_status: UpdateStatus,
4447
update_rx: Option<mpsc::Receiver<UpdateMsg>>,
48+
file_watcher: Option<Box<dyn Send>>,
49+
watch_rx: Option<mpsc::Receiver<DebounceEventResult>>,
4550
}
4651

4752
impl Default for FastPackApp {
@@ -60,6 +65,8 @@ impl Default for FastPackApp {
6065
prefs_open: false,
6166
update_status: UpdateStatus::Idle,
6267
update_rx: None,
68+
file_watcher: None,
69+
watch_rx: None,
6370
};
6471
if app.prefs.auto_check_updates {
6572
let (tx, rx) = mpsc::channel();
@@ -75,6 +82,7 @@ impl eframe::App for FastPackApp {
7582
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
7683
crate::theme::apply(ctx, self.state.dark_mode);
7784
self.poll_worker(ctx);
85+
self.poll_watcher(ctx);
7886
self.handle_pending(ctx);
7987
self.handle_dropped_files(ctx);
8088

@@ -260,9 +268,12 @@ impl FastPackApp {
260268
if std::mem::take(&mut self.state.pending.new_project) {
261269
self.state.new_project(self.prefs.default_config.clone());
262270
self.atlas_textures.clear();
271+
self.file_watcher = None;
272+
self.watch_rx = None;
263273
}
264274
if std::mem::take(&mut self.state.pending.open_project) {
265275
self.do_open_project();
276+
self.state.pending.rebuild_watcher = true;
266277
}
267278
if std::mem::take(&mut self.state.pending.save_project) {
268279
self.do_save_project(false);
@@ -276,6 +287,9 @@ impl FastPackApp {
276287
if std::mem::take(&mut self.state.pending.open_prefs) {
277288
self.prefs_open = true;
278289
}
290+
if std::mem::take(&mut self.state.pending.rebuild_watcher) {
291+
self.rebuild_watcher();
292+
}
279293
}
280294

281295
fn spawn_pack(&mut self, ctx: egui::Context) {
@@ -585,4 +599,62 @@ impl FastPackApp {
585599
}
586600
}
587601
}
602+
603+
fn rebuild_watcher(&mut self) {
604+
self.file_watcher = None;
605+
self.watch_rx = None;
606+
607+
if self.state.project.sources.is_empty() {
608+
return;
609+
}
610+
611+
let (tx, rx) = mpsc::channel::<DebounceEventResult>();
612+
match new_debouncer(Duration::from_millis(500), tx) {
613+
Ok(mut debouncer) => {
614+
let watch_paths: Vec<_> = self
615+
.state
616+
.project
617+
.sources
618+
.iter()
619+
.map(|s| {
620+
if s.path.is_file() {
621+
s.path.parent().unwrap_or(s.path.as_path()).to_path_buf()
622+
} else {
623+
s.path.clone()
624+
}
625+
})
626+
.collect();
627+
let mut errors: Vec<String> = Vec::new();
628+
for path in &watch_paths {
629+
if let Err(e) = debouncer.watcher().watch(path, RecursiveMode::Recursive) {
630+
errors.push(format!("Could not watch {}: {e}", path.display()));
631+
}
632+
}
633+
for err in errors {
634+
self.state.log_warn(err);
635+
}
636+
self.file_watcher = Some(Box::new(debouncer));
637+
self.watch_rx = Some(rx);
638+
}
639+
Err(e) => self
640+
.state
641+
.log_warn(format!("Could not start file watcher: {e}")),
642+
}
643+
}
644+
645+
fn poll_watcher(&mut self, ctx: &egui::Context) {
646+
let Some(rx) = &self.watch_rx else { return };
647+
let mut changed = false;
648+
loop {
649+
match rx.try_recv() {
650+
Ok(Ok(_)) => changed = true,
651+
Ok(Err(_)) | Err(mpsc::TryRecvError::Empty) => break,
652+
Err(mpsc::TryRecvError::Disconnected) => break,
653+
}
654+
}
655+
if changed && !self.state.packing {
656+
self.state.pending.pack = true;
657+
ctx.request_repaint();
658+
}
659+
}
588660
}

crates/fastpack-gui/src/state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ pub struct PendingActions {
118118
pub add_source: bool,
119119
/// Open the preferences window.
120120
pub open_prefs: bool,
121+
/// Rebuild the filesystem watcher to match current sources.
122+
pub rebuild_watcher: bool,
121123
}
122124

123125
/// Playback state for the animation preview window.
@@ -271,6 +273,7 @@ impl AppState {
271273
});
272274
self.dirty = true;
273275
self.pending.pack = true;
276+
self.pending.rebuild_watcher = true;
274277
self.log_info(t!("state.added_source", path = display));
275278
}
276279

@@ -280,6 +283,7 @@ impl AppState {
280283
let removed = self.project.sources.remove(index);
281284
self.dirty = true;
282285
self.pending.pack = true;
286+
self.pending.rebuild_watcher = true;
283287
self.log_info(t!(
284288
"state.removed_source",
285289
path = removed.path.display().to_string()

crates/fastpack/wix/main.wxs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
<Package Name="FastPack"
66
Manufacturer="FastPack"
7-
Version="0.21.1"
7+
Version="0.21.12"
88
UpgradeCode="803B4E26-FC7C-47A0-9B18-E900670ED48A"
99
Scope="perMachine">
1010

0 commit comments

Comments
 (0)