-
Notifications
You must be signed in to change notification settings - Fork 758
Fix SourceLink parsing to support both wildcard and exact path mappings #2355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1726,15 +1726,36 @@ internal bool GetUrlForFilePathUsingSourceLink(string buildTimeFilePath, out str | |
|
|
||
| if (_sourceLinkMapping != null) | ||
| { | ||
| foreach (Tuple<string, string> map in _sourceLinkMapping) | ||
| // First, try to find an exact match for the buildTimeFilePath (non-wildcard entries) | ||
| foreach (Tuple<string, string, bool> map in _sourceLinkMapping) | ||
| { | ||
| string path = map.Item1; | ||
| string urlReplacement = map.Item2; | ||
| string urlTemplate = map.Item2; | ||
| bool isWildcard = map.Item3; | ||
|
|
||
| if (buildTimeFilePath.StartsWith(path, StringComparison.OrdinalIgnoreCase)) | ||
| if (!isWildcard && buildTimeFilePath.Equals(path, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| // Exact match found - this is a direct file mapping without wildcards | ||
| relativeFilePath = ""; | ||
| url = urlTemplate; // Use the URL as-is for exact matches | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| // If no exact match, try prefix matching (wildcard patterns only) | ||
| // Per spec rule 2: only paths that had a wildcard (*) should be used for prefix matching | ||
| foreach (Tuple<string, string, bool> map in _sourceLinkMapping) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. COMMENT: It's at least a little weird to swing through these twice and operate on disjoint sets. I get there's a simplicity to looking through once for the "exact match" and once for the others. Is this something that can be simplified in the data structure so this code isn't so weird? Some example approaches:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is possible, but I'm not sure it's worth it. The set size is usually quite small and so it's likely more complex to the change the data structure to iterate through them one less time. |
||
| { | ||
| string path = map.Item1; | ||
| string urlTemplate = map.Item2; | ||
| bool isWildcard = map.Item3; | ||
|
|
||
| // Only use wildcard patterns for prefix matching | ||
| if (isWildcard && buildTimeFilePath.StartsWith(path, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| // Prefix match - extract the relative path and substitute into URL | ||
| relativeFilePath = buildTimeFilePath.Substring(path.Length, buildTimeFilePath.Length - path.Length).Replace('\\', '/'); | ||
| url = urlReplacement.Replace("*", string.Join("/", relativeFilePath.Split('/').Select(Uri.EscapeDataString))); | ||
| url = urlTemplate.Replace("*", string.Join("/", relativeFilePath.Split('/').Select(Uri.EscapeDataString))); | ||
| return true; | ||
| } | ||
| } | ||
|
|
@@ -1746,11 +1767,12 @@ internal bool GetUrlForFilePathUsingSourceLink(string buildTimeFilePath, out str | |
| } | ||
|
|
||
| /// <summary> | ||
| /// Parses SourceLink information and returns a list of filepath -> url Prefix tuples. | ||
| /// Parses SourceLink information and returns a list of (filepath, url, isWildcard) tuples. | ||
| /// Supports both wildcard patterns ("path\\*" -> "url/*") and exact path mappings ("path\\file.h" -> "url"). | ||
| /// </summary> | ||
| private List<Tuple<string, string>> ParseSourceLinkJson(IEnumerable<string> sourceLinkContents) | ||
| private List<Tuple<string, string, bool>> ParseSourceLinkJson(IEnumerable<string> sourceLinkContents) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. QUESTION: Is this a good opportunity to move to ValueTuple (and the built-in syntax for them that supports names?) |
||
| { | ||
| List<Tuple<string, string>> ret = null; | ||
| List<Tuple<string, string, bool>> ret = null; | ||
| foreach (string sourceLinkJson in sourceLinkContents) | ||
| { | ||
| // TODO this is not right for corner cases (e.g. file paths with " or , } in them) | ||
|
|
@@ -1760,24 +1782,26 @@ private List<Tuple<string, string>> ParseSourceLinkJson(IEnumerable<string> sour | |
| string mappings = m.Groups[1].Value; | ||
| while (!string.IsNullOrWhiteSpace(mappings)) | ||
| { | ||
| m = Regex.Match(m.Groups[1].Value, "^\\s*\"(.*?)\"\\s*:\\s*\"(.*?)\"\\s*,?(.*)", RegexOptions.Singleline); | ||
| m = Regex.Match(mappings, "^\\s*\"(.*?)\"\\s*:\\s*\"(.*?)\"\\s*,?(.*)", RegexOptions.Singleline); | ||
| if (m.Success) | ||
| { | ||
| if (ret == null) | ||
| { | ||
| ret = new List<Tuple<string, string>>(); | ||
| ret = new List<Tuple<string, string, bool>>(); | ||
| } | ||
|
|
||
| string pathSpec = m.Groups[1].Value.Replace("\\\\", "\\"); | ||
| if (pathSpec.EndsWith("*")) | ||
| { | ||
| pathSpec = pathSpec.Substring(0, pathSpec.Length - 1); // Remove the * | ||
| ret.Add(new Tuple<string, string>(pathSpec, m.Groups[2].Value)); | ||
| } | ||
| else | ||
| string urlSpec = m.Groups[2].Value; | ||
| bool isWildcard = pathSpec.EndsWith("*"); | ||
|
|
||
| // Support both wildcard patterns and exact path mappings | ||
| if (isWildcard) | ||
| { | ||
| _log.WriteLine("Warning: {0} does not end in *, skipping this mapping.", pathSpec); | ||
| // Wildcard pattern: remove the * from the path | ||
| pathSpec = pathSpec.Substring(0, pathSpec.Length - 1); | ||
| } | ||
| // Add the mapping with wildcard flag | ||
| ret.Add(new Tuple<string, string, bool>(pathSpec, urlSpec, isWildcard)); | ||
|
|
||
| mappings = m.Groups[3].Value; | ||
| } | ||
|
|
@@ -1799,7 +1823,7 @@ private List<Tuple<string, string>> ParseSourceLinkJson(IEnumerable<string> sour | |
|
|
||
| private string _pdbPath; | ||
| private SymbolReader _reader; | ||
| private List<Tuple<string, string>> _sourceLinkMapping; // Used by SourceLink to map build paths to URLs (see GetUrlForFilePath) | ||
| private List<Tuple<string, string, bool>> _sourceLinkMapping; // Used by SourceLink to map build paths to URLs (path, url, isWildcard) | ||
| private bool _sourceLinkMappingInited; // Lazy init flag. | ||
| #endregion | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SUGGESTION: deconstruct these in the foreach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same below.