diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 115 |
1 files changed, 56 insertions, 59 deletions
@@ -6,56 +6,56 @@ use std::{ #[derive(Debug)] pub enum NormalizeError { EmptyInput, - InputOutsideFileSystemRoot, - PathHasMultipleInternalPrefix, + EscapesFilesystemRoot, + InvalidMultiplePrefix, } pub struct Normalizer { root: PathBuf, - origin: PathBuf, + origin_base: PathBuf, } impl Normalizer { - pub fn new(root: &Path, origin: &Path) -> std::io::Result<Self> { + pub fn new(root: &Path, origin_base: &Path) -> std::io::Result<Self> { let cwd = env::current_dir()?; - Ok(Self::new_with_cwd(root, origin, &cwd)) + Ok(Self::new_with_cwd(root, origin_base, &cwd)) } - fn new_with_cwd(root: &Path, origin: &Path, cwd: &Path) -> Self { + fn new_with_cwd(root: &Path, origin_base: &Path, cwd: &Path) -> Self { Self { root: absolutize(root, cwd), - origin: absolutize(origin, cwd), + origin_base: absolutize(origin_base, cwd), } } - pub fn normalize_path(&self, input: &Path) -> Result<PathBuf, NormalizeError> { + pub fn normalize(&self, input: &Path) -> Result<PathBuf, NormalizeError> { if input.as_os_str().is_empty() { return Err(NormalizeError::EmptyInput); } - let input = absolutize(input, &self.origin); - let normalized_input = normalize_lexically(&input)?; - Ok(normalize_to_root(normalized_input, &self.root)) + let input = absolutize(input, &self.origin_base); + let normalized_input = normalize_components(&input)?; + Ok(make_relative_to_root(normalized_input, &self.root)) } } -fn absolutize(path: &Path, absolute_prefix: &Path) -> PathBuf { +fn absolutize(path: &Path, base: &Path) -> PathBuf { if path.is_absolute() { path.to_path_buf() } else { - absolute_prefix.join(path) + base.join(path) } } /// # Invariant /// `path` must be an absolute path. /// Violations indicate a bug in the caller. -fn normalize_lexically(path: &Path) -> Result<PathBuf, NormalizeError> { +fn normalize_components(path: &Path) -> Result<PathBuf, NormalizeError> { debug_assert!( path.is_absolute(), "Input must be an absolute path: {:?}", path ); - let mut lexical = PathBuf::new(); + let mut normalized = PathBuf::new(); let mut iter = path.components().peekable(); // Find the root, if any, and add it to the lexical path. @@ -63,21 +63,21 @@ fn normalize_lexically(path: &Path) -> Result<PathBuf, NormalizeError> { // `components` splits it into two: (Prefix, RootDir). let root = match iter.peek() { Some(p @ Component::RootDir) => { - lexical.push(p); + normalized.push(p); iter.next(); - lexical.as_os_str().len() + normalized.as_os_str().len() } Some(Component::Prefix(prefix)) => { - lexical.push(prefix.as_os_str()); + normalized.push(prefix.as_os_str()); iter.next(); if let Some(p @ Component::RootDir) = iter.peek() { - lexical.push(p); + normalized.push(p); iter.next(); } - lexical.as_os_str().len() + normalized.as_os_str().len() } _ => unreachable!( - "normalize_lexically received a non-absolute path: {:?}", + "normalize_components received a non-absolute path: {:?}", path ), }; @@ -85,26 +85,26 @@ fn normalize_lexically(path: &Path) -> Result<PathBuf, NormalizeError> { for component in iter { match component { Component::RootDir => unreachable!(), - Component::Prefix(_) => return Err(NormalizeError::PathHasMultipleInternalPrefix), + Component::Prefix(_) => return Err(NormalizeError::InvalidMultiplePrefix), Component::CurDir => continue, Component::ParentDir => { // It's an error if ParentDir causes us to go above the "root". - if lexical.as_os_str().len() == root { - return Err(NormalizeError::InputOutsideFileSystemRoot); + if normalized.as_os_str().len() == root { + return Err(NormalizeError::EscapesFilesystemRoot); } else { - lexical.pop(); + normalized.pop(); } } - Component::Normal(path) => lexical.push(path), + Component::Normal(path) => normalized.push(path), } } - Ok(lexical) + Ok(normalized) } /// # Invariant /// `target` and `root` must be an absolute paths. /// Violations indicate a bug in the caller. -fn normalize_to_root(target: PathBuf, mut root: &Path) -> PathBuf { +fn make_relative_to_root(target: PathBuf, mut root: &Path) -> PathBuf { debug_assert!( target.is_absolute(), "Target must be an absolute path: {:?}", @@ -115,13 +115,13 @@ fn normalize_to_root(target: PathBuf, mut root: &Path) -> PathBuf { "Root must be an absolute path: {:?}", root ); - let mut prefix = PathBuf::new(); + let mut upward = PathBuf::new(); loop { if let Ok(suffix) = target.strip_prefix(root) { - return prefix.join(suffix); + return upward.join(suffix); } if let Some(new_root) = root.parent() { - prefix.push(".."); + upward.push(".."); root = new_root; } else { return target; @@ -139,7 +139,7 @@ mod tests { fn empty_path_returns_error() { let fake_cwd = Path::new("/sandbox"); let normalizer = Normalizer::new_with_cwd(Path::new(""), Path::new(""), fake_cwd); - let result = normalizer.normalize_path(Path::new("")); + let result = normalizer.normalize(Path::new("")); assert!(matches!(result, Err(NormalizeError::EmptyInput))); } @@ -147,7 +147,7 @@ mod tests { fn plain_filename_with_root_at_cwd_returns_filename() { let fake_cwd = Path::new("/sandbox"); let normalizer = Normalizer::new_with_cwd(Path::new(""), Path::new(""), fake_cwd); - let result = normalizer.normalize_path(Path::new("main.rs")); + let result = normalizer.normalize(Path::new("main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("main.rs")); } @@ -156,9 +156,9 @@ mod tests { fn relative_path_from_origin_is_resolved() { let fake_cwd = Path::new("/sandbox"); let root = Path::new(""); - let origin_dir = Path::new("src"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("../main.rs")); + let origin_base = Path::new("src"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("../main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("main.rs")); } @@ -167,9 +167,9 @@ mod tests { fn path_is_made_relative_to_root() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("/project"); - let origin_dir = Path::new("/project/src"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("main.rs")); + let origin_base = Path::new("/project/src"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("src/main.rs")); } @@ -178,9 +178,9 @@ mod tests { fn path_is_made_relative_to_root_from_outside() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("/project"); - let origin_dir = Path::new("/outside"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("main.rs")); + let origin_base = Path::new("/outside"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("../outside/main.rs")); } @@ -189,9 +189,9 @@ mod tests { fn path_is_made_relative_to_root_even_if_root_dir_is_relative() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("project"); - let origin_dir = Path::new("/sandbox/outside"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("main.rs")); + let origin_base = Path::new("/sandbox/outside"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("../outside/main.rs")); } @@ -200,20 +200,20 @@ mod tests { fn absolute_inputs_work() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("project"); - let origin_dir = Path::new("/sandbox/outside"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("/sandbox/main.rs")); + let origin_base = Path::new("/sandbox/outside"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("/sandbox/main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("../main.rs")); } #[test] - fn path_is_made_relative_to_root_even_if_origin_dir_is_relative() { + fn path_is_made_relative_to_root_even_if_origin_base_is_relative() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("/sandbox/project"); - let origin_dir = Path::new("outside"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("main.rs")); + let origin_base = Path::new("outside"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("main.rs")); assert!(result.is_ok()); assert_eq!(result.unwrap(), Path::new("../outside/main.rs")); } @@ -222,12 +222,9 @@ mod tests { fn input_cannot_go_above_root() { let fake_cwd = Path::new("/sandbox"); let root = Path::new("project"); - let origin_dir = Path::new("outside"); - let normalizer = Normalizer::new_with_cwd(root, origin_dir, fake_cwd); - let result = normalizer.normalize_path(Path::new("../../../main.rs")); - assert!(matches!( - result, - Err(NormalizeError::InputOutsideFileSystemRoot) - )); + let origin_base = Path::new("outside"); + let normalizer = Normalizer::new_with_cwd(root, origin_base, fake_cwd); + let result = normalizer.normalize(Path::new("../../../main.rs")); + assert!(matches!(result, Err(NormalizeError::EscapesFilesystemRoot))); } } |
