-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Change relative path calculation #6311
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
Conversation
|
I assume it's a PR from msbuild into the installer that's failing tests? Can you link it here? |
|
Based on some local testing, I currently believe it needs both this and #6301 to go in for it to work. (I also have a couple local changes.) |
benvillalobos
left a comment
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.
First pass review. Any idea what the perf impact is here?
src/Shared/FileUtilities.cs
Outdated
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.
| return sb.ToString(); | |
| return StringBuilderCache.GetStringAndRelease(sb); |
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.
I was trying to think of that but didn't come up with it. Thanks!
src/Shared/FileUtilities.cs
Outdated
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.
This seems suspicious to me, but I have no evidence off the top of my head 🤔
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.
Seeing if fullPath starts with the current working directory could be another way of determining this, though the current method is faster.
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.
One possible suspicious reason is the (bug) I just found for mac/linux: the path starts with /, which means this will always return false. Now fixed.
ladipro
left a comment
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.
Can you please add details on path patterns where the old code does not work properly? Thank you!
src/Shared/FileUtilities.cs
Outdated
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.
Calling Split with StringSplitOptions.RemoveEmptyEntries should be a faster way of filtering out empty components.
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.
Had to make it char[] because it seems that Split(char, StringSplitOptions) isn't available on .NET Framework. I don't think ifdefs are worth it here. Still a lot nicer than what I had before; thanks!
src/Shared/FileUtilities.cs
Outdated
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.
What guarantees that the string is not just slashes, meaning that the code won't crash with out of bounds access? The split above uses only the primary directory separator char on the current platform and will accept e.g. forward slashes on Windows.
d770c12 to
1d4fea6
Compare
|
The old code threw exceptions if the URI was deemed invalid for some reason. Two such cases that stood out to me: |
ladipro
left a comment
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.
This is
src/Shared/FileUtilities.cs
Outdated
| string fullPath = Path.GetFullPath(path); | ||
|
|
||
| Uri baseUri = new Uri(EnsureTrailingSlash(basePath), UriKind.Absolute); // May throw UriFormatException | ||
| string[] splitBase = fullBase.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); |
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.
The char array is worth caching. And looks like we already do it in Constants.DirectorySeparatorChar!
src/Shared/FileUtilities.cs
Outdated
| sb.Append(splitPath[pathI]).Append(Path.DirectorySeparatorChar); | ||
| pathI++; | ||
| } | ||
| sb.Remove(sb.Length - 1, 1); |
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.
nit: I would expect
| sb.Remove(sb.Length - 1, 1); | |
| sb.Length = sb.Length - 1; |
to be slightly faster and also easier to read.
src/Shared/FileUtilities.cs
Outdated
| while (true) | ||
| { | ||
| if (baseI == splitBase.Length) | ||
| { | ||
| if (pathI == splitPath.Length) | ||
| { | ||
| return "."; | ||
| } | ||
| break; | ||
| } | ||
| else if (pathI == splitPath.Length) | ||
| { | ||
| break; | ||
| } | ||
| else if (splitBase[baseI].Equals(splitPath[pathI], PathComparison)) | ||
| { | ||
| baseI++; | ||
| pathI++; | ||
| } | ||
| else | ||
| { | ||
| break; | ||
| } | ||
| } |
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.
I would find the following much easier to read. As long as it's equivalent, please double-check:
| while (true) | |
| { | |
| if (baseI == splitBase.Length) | |
| { | |
| if (pathI == splitPath.Length) | |
| { | |
| return "."; | |
| } | |
| break; | |
| } | |
| else if (pathI == splitPath.Length) | |
| { | |
| break; | |
| } | |
| else if (splitBase[baseI].Equals(splitPath[pathI], PathComparison)) | |
| { | |
| baseI++; | |
| pathI++; | |
| } | |
| else | |
| { | |
| break; | |
| } | |
| } | |
| while (baseI < splitBase.Length && pathI < splitPath.Length && splitBase[baseI].Equals(splitPath[pathI], PathComparison)) | |
| { | |
| baseI++; | |
| pathI++; | |
| } | |
| if (baseI == splitBase.Length && pathI == splitPath.Length) | |
| { | |
| return "."; | |
| } | |
| } |
src/Shared/FileUtilities.cs
Outdated
| int baseI = 0; | ||
| int pathI = 0; |
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.
nit (last one, promise!): Since the two integers are always incremented together, consider having only one and changing the while (baseI < ... and while (pathI < ... below to for loops. Totally optional, no perf impact, just a matter of subjective taste.
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.
Yep! This PR came out unusually janky, so I appreciate all the refactoring suggestions.
benvillalobos
left a comment
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.
I like where this PR ended up. I did some rough testing to see which was faster and it looks like this version is 👍
| { | ||
| return "."; | ||
| } | ||
| // If the paths have no component in common, the only valid relative path is the full path. |
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.
hyper-nit-9000: newline here.
|
Thanks @benvillalobos for the perf check! |
For some reason, the pre-caching change seems to fail in the installer repo at the build step because of a failing relative path calculation. This version seems to work.