From 6ad0def9c4ac3d4e85ad8b7247ca270ff07b45b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E6=89=8B=E6=8E=89=E5=8C=85=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=B8=88?= Date: Wed, 3 Jul 2024 21:31:21 +0800 Subject: [PATCH] fix: handle Windows path correctly (#555) We need to make truncate_registry_path can handle Windows path as well. Because tokio-console can connect to any server from different platforms, so we use the same path separator to have the same experience. --- tokio-console/src/state/mod.rs | 79 +++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/tokio-console/src/state/mod.rs b/tokio-console/src/state/mod.rs index d40dac014..4b9928a8f 100644 --- a/tokio-console/src/state/mod.rs +++ b/tokio-console/src/state/mod.rs @@ -504,6 +504,20 @@ impl Attribute { } } +// A naive way to determine if a path is a Windows path. +// If the path has a drive letter and more backslashes than forward slashes, it's a Windows path. +fn is_windows_path(path: &str) -> bool { + use once_cell::sync::OnceCell; + use regex::Regex; + + static REGEX: OnceCell = OnceCell::new(); + let regex = REGEX.get_or_init(|| Regex::new(r"^[a-zA-Z]:\\").expect("failed to compile regex")); + let has_drive_letter = regex.is_match(path); + let slash_count = path.chars().filter(|&c| c == '/').count(); + let backslash_count = path.chars().filter(|&c| c == '\\').count(); + has_drive_letter && backslash_count > slash_count +} + fn truncate_registry_path(s: String) -> String { use once_cell::sync::OnceCell; use regex::Regex; @@ -511,15 +525,21 @@ fn truncate_registry_path(s: String) -> String { static REGEX: OnceCell = OnceCell::new(); let regex = REGEX.get_or_init(|| { - Regex::new(r".*/\.cargo(/registry/src/[^/]*/|/git/checkouts/)") + Regex::new(r".*[/\\]\.cargo[/\\](registry[/\\]src[/\\][^/\\]*[/\\]|git[/\\]checkouts[/\\])") .expect("failed to compile regex") }); - return match regex.replace(&s, "/") { + let rep = if is_windows_path(&s) { + "\\" + } else { + "/" + }; + + match regex.replace(&s, rep) { Cow::Owned(s) => s, // String was not modified, return the original. - Cow::Borrowed(_) => s.to_string(), - }; + Cow::Borrowed(_) => s, + } } fn format_location(loc: Option) -> String { @@ -586,30 +606,69 @@ mod tests { #[test] fn test_format_location_macos() { // macOS style paths. - let location4 = proto::Location { + let location1 = proto::Location { file: Some("/Users/user/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.0.1/src/lib.rs".to_string()), ..Default::default() }; - let location5 = proto::Location { + let location2 = proto::Location { file: Some("/Users/user/.cargo/git/checkouts/tokio-1.0.1/src/lib.rs".to_string()), ..Default::default() }; - let location6 = proto::Location { + let location3 = proto::Location { file: Some("/Users/user/projects/tokio-1.0.1/src/lib.rs".to_string()), ..Default::default() }; assert_eq!( - format_location(Some(location4)), + format_location(Some(location1)), "/tokio-1.0.1/src/lib.rs" ); assert_eq!( - format_location(Some(location5)), + format_location(Some(location2)), "/tokio-1.0.1/src/lib.rs" ); assert_eq!( - format_location(Some(location6)), + format_location(Some(location3)), "/Users/user/projects/tokio-1.0.1/src/lib.rs" ); } + + #[test] + fn test_format_location_windows() { + // Windows style paths. + let location1 = proto::Location { + file: Some( + "C:\\Users\\user\\.cargo\\registry\\src\\github.com-1ecc6299db9ec823\\tokio-1.0.1\\src\\lib.rs" + .to_string(), + ), + ..Default::default() + }; + + let location2 = proto::Location { + file: Some( + "C:\\Users\\user\\.cargo\\git\\checkouts\\tokio-1.0.1\\src\\lib.rs".to_string(), + ), + ..Default::default() + }; + + let location3 = proto::Location { + file: Some("C:\\Users\\user\\projects\\tokio-1.0.1\\src\\lib.rs".to_string()), + ..Default::default() + }; + + assert_eq!( + format_location(Some(location1)), + "\\tokio-1.0.1\\src\\lib.rs" + ); + + assert_eq!( + format_location(Some(location2)), + "\\tokio-1.0.1\\src\\lib.rs" + ); + + assert_eq!( + format_location(Some(location3)), + "C:\\Users\\user\\projects\\tokio-1.0.1\\src\\lib.rs" + ); + } }