Skip to content

Commit

Permalink
attempt to normalize windows paths first
Browse files Browse the repository at this point in the history
  • Loading branch information
brady.ouren committed Jan 23, 2025
1 parent 19cfaa1 commit c6d0b7c
Showing 1 changed file with 93 additions and 1 deletion.
94 changes: 93 additions & 1 deletion components/clarinet-files/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ impl FileLocation {
}

pub fn from_url_string(url_string: &str) -> Result<FileLocation, String> {
// Handle Windows-style paths specially
if url_string.contains('\\') || url_string.contains(':') {
let path = PathBuf::from(url_string);
if path.exists() {
return Ok(FileLocation::FileSystem { path });
}
}
let url = Url::from_str(url_string)
.map_err(|e| format!("unable to parse {} as a url\n{:?}", url_string, e))?;

Expand Down Expand Up @@ -129,15 +136,26 @@ impl FileLocation {
path.extend(&path_to_append);
}
FileLocation::Url { url } => {
// Handle Windows paths first
if url.scheme() == "file" && url.path().starts_with("/C:") {
let new_path = url.path().trim_start_matches('/').to_string();
url.set_path(&new_path);
}
let mut paths_segments = url
.path_segments_mut()
.map_err(|_| "unable to mutate url".to_string())?;

// Clear existing empty segments at the end
paths_segments.pop_if_empty();

for component in path_to_append.components() {
let segment = component
.as_os_str()
.to_str()
.ok_or(format!("unable to format component {:?}", component))?;
paths_segments.push(segment);
if !segment.is_empty() {
paths_segments.push(segment);
}
}
}
}
Expand Down Expand Up @@ -411,3 +429,77 @@ pub fn get_manifest_location(path: Option<String>) -> Option<FileLocation> {
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use url::Url;

#[test]
fn test_windows_url_mutation() {
// Windows file URLs typically start with a drive letter
let windows_url = Url::parse("file:///C:/Users/test/project/")
.expect("Failed to parse Windows-style URL");
let mut location = FileLocation::from_url(windows_url);

let result = location.append_path("subdir\\file.txt");
assert!(result.is_ok());
}
#[test]
fn test_valid_url_mutation() {
// Create a regular URL that should work
let valid_url =
Url::parse("file:///home/user/project/").expect("Failed to parse Unix-style URL");

let mut location = FileLocation::from_url(valid_url);

// This should succeed
let result = location.append_path("subdir/file.txt");
assert!(result.is_ok());

if let FileLocation::Url { url } = location {
assert_eq!(url.path(), "/home/user/project/subdir/file.txt");
} else {
panic!("Expected URL variant");
}
}

#[test]
fn test_windows_drive_letter_parsing() {
// Test parsing a Windows-style file URL
let result = FileLocation::from_url_string("file:///C:/Users/test/project");
assert!(result.is_ok(), "Windows file URL should parse");
}

#[test]
fn test_try_parse_windows_paths() {
// Test relative Windows path
let result = FileLocation::try_parse("folder\\file.txt", None);
assert!(
result.is_none(),
"Relative Windows path without hint should return None"
);

// Test absolute Windows path
let result = FileLocation::try_parse("C:\\Users\\test\\file.txt", None);
assert!(result.is_some(), "Absolute Windows path should parse");
}

#[test]
fn test_append_with_windows_separators() {
let mut location = FileLocation::from_path(PathBuf::from("/base/path"));

// Test appending Windows-style path
let result = location.append_path("subdir\\file.txt");
assert!(result.is_ok(), "Should handle Windows separators");

if let FileLocation::FileSystem { path } = &location {
let path_str = path.to_string_lossy();
assert!(
path_str.contains("subdir") && path_str.contains("file.txt"),
"Path should contain appended components"
);
}
}
}

0 comments on commit c6d0b7c

Please sign in to comment.