-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1349 from johnnyasantoss/fix/1340
Change the way to look for the default MSBuild instance
- Loading branch information
Showing
5 changed files
with
279 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,96 @@ | ||
using Microsoft.Extensions.Logging; | ||
using System.IO; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace OmniSharp.MSBuild.Discovery | ||
{ | ||
internal static class Extensions | ||
{ | ||
public static void RegisterDefaultInstance(this IMSBuildLocator msbuildLocator, ILogger logger) | ||
{ | ||
MSBuildInstance instanceToRegister = null; | ||
var invalidVSFound = false; | ||
var bestInstanceFound = GetBestInstance(msbuildLocator, out var invalidVSFound); | ||
|
||
foreach (var instance in msbuildLocator.GetInstances()) | ||
{ | ||
if (instance.IsInvalidVisualStudio()) | ||
{ | ||
invalidVSFound = true; | ||
} | ||
else | ||
{ | ||
instanceToRegister = instance; | ||
break; | ||
} | ||
} | ||
|
||
|
||
if (instanceToRegister != null) | ||
if (bestInstanceFound != null) | ||
{ | ||
// Did we end up choosing the standalone MSBuild because there was an invalid Visual Studio? | ||
// If so, provide a helpful message to the user. | ||
if (invalidVSFound && instanceToRegister.DiscoveryType == DiscoveryType.StandAlone) | ||
if (invalidVSFound && bestInstanceFound.DiscoveryType == DiscoveryType.StandAlone) | ||
{ | ||
logger.LogWarning(@"It looks like you have Visual Studio 2017 RTM installed. | ||
Try updating Visual Studio 2017 to the most recent release to enable better MSBuild support."); | ||
logger.LogWarning( | ||
@"It looks like you have Visual Studio 2017 RTM installed. | ||
Try updating Visual Studio 2017 to the most recent release to enable better MSBuild support." | ||
); | ||
} | ||
|
||
msbuildLocator.RegisterInstance(instanceToRegister); | ||
msbuildLocator.RegisterInstance(bestInstanceFound); | ||
} | ||
else | ||
{ | ||
logger.LogError("Could not locate MSBuild instance to register with OmniSharp"); | ||
} | ||
} | ||
|
||
public static bool HasDotNetSdksResolvers(this MSBuildInstance instance) | ||
{ | ||
const string dotnetSdkResolver = "Microsoft.DotNet.MSBuildSdkResolver"; | ||
|
||
return File.Exists( | ||
Path.Combine( | ||
instance.MSBuildPath, | ||
"SdkResolvers", | ||
dotnetSdkResolver, | ||
dotnetSdkResolver + ".dll" | ||
) | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Checks if it is MSBuild from Visual Studio 2017 RTM that cannot be used. | ||
/// </summary> | ||
public static bool IsInvalidVisualStudio(this MSBuildInstance instance) | ||
// MSBuild from Visual Studio 2017 RTM cannot be used. | ||
=> instance.Version.Major == 15 | ||
&& instance.Version.Minor == 0 | ||
&& (instance.DiscoveryType == DiscoveryType.DeveloperConsole | ||
|| instance.DiscoveryType == DiscoveryType.VisualStudioSetup); | ||
&& instance.Version.Minor == 0 | ||
&& (instance.DiscoveryType == DiscoveryType.DeveloperConsole | ||
|| instance.DiscoveryType == DiscoveryType.VisualStudioSetup); | ||
|
||
public static MSBuildInstance GetBestInstance(this IMSBuildLocator msbuildLocator, out bool invalidVSFound) | ||
{ | ||
invalidVSFound = false; | ||
MSBuildInstance bestMatchInstance = null; | ||
var bestMatchScore = 0; | ||
|
||
foreach (var instance in msbuildLocator.GetInstances()) | ||
{ | ||
var score = GetInstanceFeatureScore(instance); | ||
|
||
invalidVSFound = invalidVSFound || instance.IsInvalidVisualStudio(); | ||
|
||
if (score > bestMatchScore | ||
|| (score == bestMatchScore && instance.Version.Major > (bestMatchInstance?.Version.Major ?? 0))) | ||
{ | ||
bestMatchInstance = instance; | ||
bestMatchScore = score; | ||
} | ||
} | ||
|
||
return bestMatchInstance; | ||
} | ||
|
||
private static int GetInstanceFeatureScore(MSBuildInstance i) | ||
{ | ||
var score = 0; | ||
|
||
if (i.HasDotNetSdksResolvers()) | ||
score++; | ||
|
||
if (i.IsInvalidVisualStudio()) | ||
return int.MinValue; | ||
else | ||
score++; | ||
|
||
if (i.DiscoveryType == DiscoveryType.StandAlone) | ||
score--; | ||
|
||
return score; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
using System; | ||
using OmniSharp.MSBuild.Discovery; | ||
using TestUtility; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace OmniSharp.MSBuild.Tests | ||
{ | ||
public class MSBuildSelectionTests : AbstractTestFixture | ||
{ | ||
public MSBuildSelectionTests(ITestOutputHelper output) | ||
: base(output) | ||
{ | ||
} | ||
|
||
[Fact] | ||
public void RegisterDefaultInstanceFindsTheBestInstanceAvailable() | ||
{ | ||
var msBuildInstances = new[] | ||
{ | ||
GetInvalidMsBuildInstance(), | ||
// Valid | ||
new MSBuildInstance( | ||
"Test Instance", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("15.1.2.3"), | ||
DiscoveryType.VisualStudioSetup | ||
).AddDotNetCoreToFakeInstance(), | ||
GetStandAloneMSBuildInstance() | ||
}; | ||
|
||
var msbuildLocator = new MSFakeLocator(msBuildInstances); | ||
var logger = LoggerFactory.CreateLogger(nameof(RegisterDefaultInstanceFindsTheBestInstanceAvailable)); | ||
|
||
// test | ||
msbuildLocator.RegisterDefaultInstance(logger); | ||
|
||
Assert.NotNull(msbuildLocator.RegisteredInstance); | ||
Assert.Same(msBuildInstances[1], msbuildLocator.RegisteredInstance); | ||
|
||
// clean up | ||
msbuildLocator.DeleteFakeInstancesFolders(); | ||
} | ||
|
||
[Fact] | ||
public void RegisterDefaultInstanceFindsTheBestInstanceAvailableEvenWithOtherValidInstances() | ||
{ | ||
var msBuildInstances = new[] | ||
{ | ||
new MSBuildInstance( | ||
"Valid Test Instance", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("15.3.2.1"), | ||
DiscoveryType.VisualStudioSetup | ||
), | ||
GetInvalidMsBuildInstance(), | ||
|
||
// Valid + Dotnet Core | ||
new MSBuildInstance( | ||
"Another Valid Test Instance", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("15.1.2.3"), | ||
DiscoveryType.VisualStudioSetup | ||
).AddDotNetCoreToFakeInstance(), | ||
GetStandAloneMSBuildInstance() | ||
}; | ||
|
||
var msbuildLocator = new MSFakeLocator(msBuildInstances); | ||
|
||
var logger = LoggerFactory.CreateLogger( | ||
nameof(RegisterDefaultInstanceFindsTheBestInstanceAvailableEvenWithOtherValidInstances) | ||
); | ||
|
||
// test | ||
msbuildLocator.RegisterDefaultInstance(logger); | ||
|
||
Assert.NotNull(msbuildLocator.RegisteredInstance); | ||
Assert.Same(msBuildInstances[2], msbuildLocator.RegisteredInstance); | ||
|
||
// clean up | ||
msbuildLocator.DeleteFakeInstancesFolders(); | ||
} | ||
|
||
[Fact] | ||
public void RegisterDefaultInstanceStillPrefersTheFirstInstance() | ||
{ | ||
var msBuildInstances = new[] | ||
{ | ||
new MSBuildInstance( | ||
"Test Instance", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("15.1.2.3"), | ||
DiscoveryType.VisualStudioSetup | ||
), | ||
GetStandAloneMSBuildInstance() | ||
}; | ||
|
||
var msbuildLocator = new MSFakeLocator(msBuildInstances); | ||
var logger = LoggerFactory.CreateLogger(nameof(RegisterDefaultInstanceStillPrefersTheFirstInstance)); | ||
|
||
// test | ||
msbuildLocator.RegisterDefaultInstance(logger); | ||
|
||
Assert.NotNull(msbuildLocator.RegisteredInstance); | ||
Assert.Same(msBuildInstances[0], msbuildLocator.RegisteredInstance); | ||
|
||
// clean up | ||
msbuildLocator.DeleteFakeInstancesFolders(); | ||
} | ||
|
||
private static MSBuildInstance GetStandAloneMSBuildInstance() | ||
{ | ||
return new MSBuildInstance( | ||
"Stand Alone :(", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("99.0.0.0"), | ||
DiscoveryType.StandAlone | ||
); | ||
} | ||
|
||
private static MSBuildInstance GetInvalidMsBuildInstance() | ||
{ | ||
return new MSBuildInstance( | ||
"Invalid Instance", | ||
TestIO.GetRandomTempFolderPath(), | ||
Version.Parse("15.0.4.2"), | ||
DiscoveryType.VisualStudioSetup | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.IO; | ||
using OmniSharp.MSBuild.Discovery; | ||
|
||
namespace TestUtility | ||
{ | ||
public class MSFakeLocator : IMSBuildLocator | ||
{ | ||
private readonly ImmutableArray<MSBuildInstance> _instances; | ||
|
||
public MSBuildInstance RegisteredInstance { get; private set; } | ||
|
||
public MSFakeLocator(IEnumerable<MSBuildInstance> instances) | ||
{ | ||
_instances = instances.ToImmutableArray(); | ||
} | ||
|
||
public void RegisterInstance(MSBuildInstance instance) | ||
=> RegisteredInstance = instance; | ||
|
||
public ImmutableArray<MSBuildInstance> GetInstances() | ||
=> _instances; | ||
|
||
public void DeleteFakeInstancesFolders() | ||
{ | ||
foreach (var instance in _instances) | ||
{ | ||
if (Directory.Exists(instance.MSBuildPath)) | ||
Directory.Delete(instance.MSBuildPath, true); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.IO; | ||
|
||
namespace TestUtility | ||
{ | ||
public static class TestIO | ||
{ | ||
public static string GetRandomTempFolderPath() | ||
{ | ||
var path = Path.Combine( | ||
Path.GetTempPath(), | ||
Path.GetRandomFileName() | ||
); | ||
|
||
Directory.CreateDirectory(path); | ||
|
||
return path; | ||
} | ||
|
||
public static void TouchFakeFile(string path) | ||
{ | ||
File.WriteAllText(path, "just testing :)"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters