Skip to content
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

Only consider sdks from before the runtime #106

Merged
merged 23 commits into from
Dec 17, 2020

Conversation

Forgind
Copy link
Member

@Forgind Forgind commented Dec 7, 2020

Fixes #92

This is now based on #79.

if (!int.TryParse(versionMatch.Groups[1].Value, out int major) ||
!int.TryParse(versionMatch.Groups[2].Value, out int minor) ||
!int.TryParse(versionMatch.Groups[3].Value, out int patch))
if (!Version.TryParse(File.ReadAllText(versionPath), out Version version) || version > Environment.Version)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment.Version is a strange beast. It's always 4.0.30319.42000 for .NET 4.6 and higher and for .NET Core 1.0-3.1. Starting with .NET 5.0, it returns a value more like you'd probably expect: dotnet/coreclr#22664.

FORTUNATELY, since this PR is mostly about blocking out 5.0 versions from 3.1 hosts (since people mostly didn't complain about 3.1 versions for 2.1 hosts) this simple call should still work. And keep working into the future for 6.0/7.0 on 5.0 and so on.

@@ -14,7 +14,6 @@ namespace Microsoft.Build.Locator
internal static class DotNetSdkLocationHelper
{
private static readonly Regex DotNetBasePathRegex = new Regex("Base Path:(.*)$", RegexOptions.Multiline);
private static readonly Regex VersionRegex = new Regex(@"^(\d+)\.(\d+)\.(\d+)", RegexOptions.Multiline);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried your new code against a preview SDK? I think the additional complexity here over just using Version.TryParse is to handle a semver version like 6.0.100-alpha.234622.

string parseableVersion = File.ReadAllText(versionPath);
int indexOfHyphen = parseableVersion.IndexOf('-');
parseableVersion = indexOfHyphen >= 0 ? parseableVersion.Substring(0, indexOfHyphen) : parseableVersion;
if (!Version.TryParse(parseableVersion, out Version version) || version > Environment.Version)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we first merge #79 and then move the version filtering to RegisterDefaults? I.e. the default behavior would be to pick the latest SDK not newer than the currently running runtime but the developer can implement their own policy if they choose so? There are legitimate use cases where the developer wants to know about all instances even if they are not compatible with the current process -- they might want to launch MSBuild out-of-proc for example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to get a minimal 5.0 fix out ASAP but I think this is a good way to go long-term.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a change that I think implements this. I tested it with 5.0 and 3.1 runtimes, and they correctly identified 5.0 and 3.1 as the SDKs to use respectively, both ignoring my 2.2 SDK.

@Forgind Forgind marked this pull request as ready for review December 14, 2020 23:00
VisualStudioInstance instance = instances.Where(
inst => inst.Version.Major < Environment.Version.Major || (inst.Version.Major == Environment.Version.Major && inst.Version.Minor <= Environment.Version.Minor)
).FirstOrDefault() ??
instances.FirstOrDefault();
Copy link
Member Author

@Forgind Forgind Dec 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think I should keep this as a fallback? It only ever would return an SDK from after the runtime, but "No instances of MSBuild could be detected" would be misleading. I could also add another error message for "We found MSBuild, but please update the runtime before using it."

Comment on lines 97 to 100
VisualStudioInstance instance = instances.Where(
inst => inst.Version.Major < Environment.Version.Major || (inst.Version.Major == Environment.Version.Major && inst.Version.Minor <= Environment.Version.Minor)
).FirstOrDefault() ??
instances.FirstOrDefault();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this filtering makes sense for the .NET Framework/desktop MSBuild/VS case. Instead, it should be restricted to the .NET Core/5.0 case.

@@ -93,7 +93,11 @@ public static IEnumerable<VisualStudioInstance> QueryVisualStudioInstances()
/// <returns>Instance of Visual Studio found and registered.</returns>
public static VisualStudioInstance RegisterDefaults()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does RegisterDefaults need to change at all? I would expect the change to be entirely in the list returned by GetInstances. I can see from the commit history that you implemented it that way and then changed it, but not why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to implement #106 (comment)

Is that wrong?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Yes, I now think it's not the right design. We could potentially add another overload that takes a bool to "give me everything, I don't care" but I don't think we should filter in RegisterDefaults and I do think we should present only usable instances in the list by default.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted to filtering in DotNetSdkLocationHelper.cs.

Copy link
Member Author

@Forgind Forgind Dec 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little resistant to add an overload for "give me everything" without anyone explicitly asking for it. I'm guessing most people who use MSBuildLocator use it for relatively straightforward purposes, and it would make it a little harder to pull in my unit testing PR when that comes along.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this affect a unit testing PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two reasons: it would add something else I'd probably want to test, and since I'm already planning to add an overload to this, I'd have to split my overload into "give me everything" and "don't give me everything" cases. Not a huge deal, though.

}

if (!int.TryParse(versionMatch.Groups[1].Value, out int major) ||
if (!versionMatch.Success ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the original flow here because the failure conditions are much more obvious in separate ifs:

  1. The version regex didn't match.
  2. We can't parse a version out.
  3. the version doesn't match

Here all together it's hard to see that there are separate failure cases.

Comment on lines 45 to 46
major > Environment.Version.Major ||
(major == Environment.Version.Major && minor > Environment.Version.Minor))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definitely needs a comment! Describe all the things you've learned about why we care about the current runtime version relative to the SDK version, and the SDK policy as we currently understand it.

@@ -93,7 +93,11 @@ public static IEnumerable<VisualStudioInstance> QueryVisualStudioInstances()
/// <returns>Instance of Visual Studio found and registered.</returns>
public static VisualStudioInstance RegisterDefaults()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this affect a unit testing PR?

Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Let's get it out!


// Components of the SDK often have dependencies on the runtime they shipped with, including that several tasks that shipped
// in the .NET 5 SDK rely on the .NET 5.0 runtime. Assuming the runtime that shipped with a particular SDK has the same version,
// this ensures that we don't choose an SDK that doesn't work with the chosen runtime. This is not guaranteed to always work but
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// this ensures that we don't choose an SDK that doesn't work with the chosen runtime. This is not guaranteed to always work but
// this ensures that we don't choose an SDK that doesn't work with the runtime of the current application. This is not guaranteed to always work but

?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Loading net5.0 Assemblies Shouldn't Happen When Running < net5.0
4 participants