Normalise root path in file_watcher (#12102)
# Objective
- I hit an issue using the `file_watcher` feature to hot reload assets
for my game. The change in this PR allows me to now hot reload assets.
- The issue stemmed from my project being a multi crate workspace
project structured like so:
```
└── my_game
├── my_game_core
│ ├── src
│ └── assets
├── my_game_editor
│ └── src/main.rs
└── my_game
└── src/main.rs
```
- `my_game_core` is a crate that holds all my game logic and assets
- `my_game` is the crate that creates the binary for my game (depends on
the game logic and assets in `my_game_core`)
- `my_game_editor` is an editor tool for my game (it also depends on the
game logic and assets in `my_game_core`)
Whilst running `my_game` and `my_game_editor` from cargo during
development I would use `AssetPlugin` like so:
```rust
default_plugins.set(AssetPlugin {
watch_for_changes_override: Some(true),
file_path: "../my_game_core/assets".to_string(),
..Default::default()
})
```
This works fine; bevy picks up the assets. However on saving an asset I
would get the following panic from `file_watcher`. It wouldn't kill the
app, but I wouldn't see the asset hot reload:
```
thread 'notify-rs debouncer loop' panicked at /Users/ian/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_asset-0.12.1/src/io/file/file_watcher.rs:48:58:
called `Result::unwrap()` on an `Err` value: StripPrefixError(())
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
## Solution
- The solution is to collapse dot segments in the root asset path
`FileWatcher` is using
- There was already bevy code to do this in `AssetPath`, so I extracted
that code so it could be reused in `FileWatcher`
This commit is contained in:
parent
bc2ddce432
commit
14042b1e34
@ -1,4 +1,5 @@
|
||||
use crate::io::{AssetSourceEvent, AssetWatcher};
|
||||
use crate::path::normalize_path;
|
||||
use bevy_log::error;
|
||||
use bevy_utils::Duration;
|
||||
use crossbeam_channel::Sender;
|
||||
@ -28,7 +29,7 @@ impl FileWatcher {
|
||||
sender: Sender<AssetSourceEvent>,
|
||||
debounce_wait_time: Duration,
|
||||
) -> Result<Self, notify::Error> {
|
||||
let root = super::get_base_path().join(root);
|
||||
let root = normalize_path(super::get_base_path().join(root).as_path());
|
||||
let watcher = new_asset_event_debouncer(
|
||||
root.clone(),
|
||||
debounce_wait_time,
|
||||
|
||||
@ -431,34 +431,13 @@ impl<'a> AssetPath<'a> {
|
||||
_ => rpath,
|
||||
};
|
||||
|
||||
let mut result_path = PathBuf::new();
|
||||
if !is_absolute && source.is_none() {
|
||||
for elt in base_path.iter() {
|
||||
if elt == "." {
|
||||
// Skip
|
||||
} else if elt == ".." {
|
||||
if !result_path.pop() {
|
||||
// Preserve ".." if insufficient matches (per RFC 1808).
|
||||
result_path.push(elt);
|
||||
}
|
||||
} else {
|
||||
result_path.push(elt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for elt in rpath.iter() {
|
||||
if elt == "." {
|
||||
// Skip
|
||||
} else if elt == ".." {
|
||||
if !result_path.pop() {
|
||||
// Preserve ".." if insufficient matches (per RFC 1808).
|
||||
result_path.push(elt);
|
||||
}
|
||||
} else {
|
||||
result_path.push(elt);
|
||||
}
|
||||
}
|
||||
let mut result_path = if !is_absolute && source.is_none() {
|
||||
base_path
|
||||
} else {
|
||||
PathBuf::new()
|
||||
};
|
||||
result_path.push(rpath);
|
||||
result_path = normalize_path(result_path.as_path());
|
||||
|
||||
Ok(AssetPath {
|
||||
source: match source {
|
||||
@ -723,6 +702,25 @@ impl FromReflect for AssetPath<'static> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Normalizes the path by collapsing all occurrences of '.' and '..' dot-segments where possible
|
||||
/// as per [RFC 1808](https://datatracker.ietf.org/doc/html/rfc1808)
|
||||
pub(crate) fn normalize_path(path: &Path) -> PathBuf {
|
||||
let mut result_path = PathBuf::new();
|
||||
for elt in path.iter() {
|
||||
if elt == "." {
|
||||
// Skip
|
||||
} else if elt == ".." {
|
||||
if !result_path.pop() {
|
||||
// Preserve ".." if insufficient matches (per RFC 1808).
|
||||
result_path.push(elt);
|
||||
}
|
||||
} else {
|
||||
result_path.push(elt);
|
||||
}
|
||||
}
|
||||
result_path
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::AssetPath;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user