mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 11:09:23 -06:00
64 lines
2.7 KiB
Rust
64 lines
2.7 KiB
Rust
//! Paths stored in a file LightCraft reads but the user did not choose path by path, such as the
|
|
//! originals a Lightroom catalog lists.
|
|
//!
|
|
//! Such a path reaches the file system only through [`resolve`]: a relative path is taken from the
|
|
//! document's folder, and only local files, or files on the network share the document itself is
|
|
//! on, are looked at (see `craft_docpath`). A path that is not followed is handled like a missing
|
|
//! file.
|
|
|
|
use std::fmt;
|
|
use std::path::{Path, PathBuf};
|
|
|
|
pub use craft_docpath::Refused;
|
|
|
|
/// Why a stored path is not followed.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum NotFollowed {
|
|
/// The path is on another computer (other than the document's share), names a device, is a
|
|
/// URL, or is not a usable path.
|
|
Refused(Refused),
|
|
/// The path is not an absolute path on this computer, such as a Windows drive path read on
|
|
/// macOS or Linux.
|
|
NotHere,
|
|
}
|
|
|
|
impl fmt::Display for NotFollowed {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
Self::Refused(r) => r.fmt(f),
|
|
Self::NotHere => f.write_str("the path is not a path on this computer"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::error::Error for NotFollowed {}
|
|
|
|
/// The file to look at for `stored`, a path or `file:` URL stored in the document at `document`,
|
|
/// or why it is not followed. A relative `document` is taken from the working directory, where it
|
|
/// was opened from.
|
|
pub fn resolve(stored: &str, document: Option<&Path>) -> Result<PathBuf, NotFollowed> {
|
|
let document = document.map(|d| if d.is_relative() { std::path::absolute(d).unwrap_or_else(|_| d.to_path_buf()) } else { d.to_path_buf() });
|
|
let path = craft_docpath::resolve(stored, document.as_deref()).map_err(NotFollowed::Refused)?;
|
|
// A path that is still relative would be taken from the working directory, which the
|
|
// document does not choose.
|
|
if path.is_relative() {
|
|
return Err(NotFollowed::NotHere);
|
|
}
|
|
Ok(path)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn relative_paths_are_taken_from_the_document_folder_and_other_computers_are_refused() {
|
|
let doc = std::env::temp_dir().join("lrcat").join("catalog.lrcat");
|
|
assert_eq!(resolve("Photos/a.jpg", Some(&doc)), Ok(std::env::temp_dir().join("lrcat").join("Photos").join("a.jpg")));
|
|
assert_eq!(resolve("a.jpg", None), Err(NotFollowed::NotHere));
|
|
assert_eq!(resolve(r"\\192.0.2.1\share\x.jpg", Some(&doc)), Err(NotFollowed::Refused(Refused::Network)));
|
|
assert_eq!(resolve("file://192.0.2.1/s/x.jpg", Some(&doc)), Err(NotFollowed::Refused(Refused::Network)));
|
|
assert_eq!(resolve(r"\\.\COM1", Some(&doc)), Err(NotFollowed::Refused(Refused::Device)));
|
|
}
|
|
}
|