Watch selected folders and reconcile bounded changes with media freshness guards
This commit is contained in:
1 parent
99748bd99f
commit
657de3de86
22 files changed
+2022
-149
No files matched your search
@@ -1,6 +1,44 @@
|
||||
//! Explicit data-directory isolation for portable use and native release QA.
|
||||
//! Ordinary launches continue to use the operating system's app-data directory.
|
||||
use std::{ffi::OsString, io, path::PathBuf};
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
/// Match canonical watched paths, including Windows verbatim prefixes, even
|
||||
/// before a first-use model or scratch directory exists.
|
||||
pub fn canonical_exclusion(path: &Path) -> io::Result<PathBuf> {
|
||||
if !path.is_absolute() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Excluded directory must be absolute",
|
||||
));
|
||||
}
|
||||
let mut ancestor = path.to_path_buf();
|
||||
let mut suffix = Vec::new();
|
||||
loop {
|
||||
match std::fs::canonicalize(&ancestor) {
|
||||
Ok(mut resolved) => {
|
||||
for part in suffix.iter().rev() {
|
||||
resolved.push(part);
|
||||
}
|
||||
return Ok(resolved);
|
||||
}
|
||||
Err(error) if error.kind() == io::ErrorKind::NotFound => {
|
||||
let name = ancestor.file_name().ok_or(error)?;
|
||||
suffix.push(name.to_os_string());
|
||||
if !ancestor.pop() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
"Excluded directory has no existing ancestor",
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve(default: PathBuf, override_path: Option<OsString>) -> io::Result<PathBuf> {
|
||||
let Some(value) = override_path else {
|
||||
@@ -20,6 +58,23 @@ pub fn resolve(default: PathBuf, override_path: Option<OsString>) -> io::Result<
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing_exclusion_matches_canonical_root_without_creating_directories() {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let missing = root.path().join("Models").join("MediaScratch");
|
||||
let canonical = std::fs::canonicalize(root.path()).unwrap();
|
||||
let exclusion = canonical_exclusion(&missing).unwrap();
|
||||
assert_eq!(exclusion, canonical.join("Models/MediaScratch"));
|
||||
assert!(exclusion.starts_with(&canonical));
|
||||
assert!(!missing.exists());
|
||||
assert_eq!(canonical_exclusion(root.path()).unwrap(), canonical);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relative_exclusion_is_rejected() {
|
||||
assert!(canonical_exclusion(Path::new("relative/cache")).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_directory_isolates_settings_and_index_without_changing_default() {
|
||||
let default = std::env::temp_dir().join("searchi-default");
|
||||
|
||||
Reference in new issue
Block a user