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

Port fixes for 1.26.2 #1018

Merged
merged 8 commits into from
Nov 10, 2017
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog
All changes to the project will be documented in this file.

## [1.26.2] - 2017-11-09

* Fixed issue with discovering MSBuild under Mono even when it is missing. ([#1011](https://github.com/OmniSharp/omnisharp-roslyn/issues/1011))
* Fixed issue to not use Visual Studio 2017 MSBuild if it is from VS 2017 RTM. ([#1014](https://github.com/OmniSharp/omnisharp-roslyn/issues/1014))

## [1.27.0] - 2017-11-07

* Significant changes made to the MSBuild project system that fix several issues. (PR: [#1003](https://github.com/OmniSharp/omnisharp-roslyn/pull/1003))
Expand Down
190 changes: 190 additions & 0 deletions src/OmniSharp.Abstractions/Utilities/Platform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
using System;
using System.IO;

namespace OmniSharp.Utilities
{
public enum OperatingSystem
{
Unknown,
Windows,
MacOS,
Linux
}

public enum Architecture
{
Unknown,
x86,
x64
}

public sealed class Platform
{
public static Platform Current { get; } = GetCurrentPlatform();

public OperatingSystem OperatingSystem { get; }
public Architecture Architecture { get; }
public Version Version { get; }
public string LinuxDistributionName { get; }

private Platform(
OperatingSystem os = OperatingSystem.Unknown,
Architecture architecture = Architecture.Unknown,
Version version = null,
string linuxDistributionName = null)
{
OperatingSystem = os;
Architecture = architecture;
Version = version ?? new Version(0, 0);
LinuxDistributionName = linuxDistributionName ?? string.Empty;
}

public override string ToString()
=> !string.IsNullOrEmpty(LinuxDistributionName)
? $"{LinuxDistributionName} {Version} ({Architecture})"
: $"{OperatingSystem} {Version} ({Architecture})";

private static Platform GetCurrentPlatform()
{
var os = OperatingSystem.Unknown;
var architecture = Architecture.Unknown;

// Simple check to see if this is Windows. Note: this check is derived from the fact that the
// System.PlatformID enum has six values (https://msdn.microsoft.com/en-us/library/3a8hyw88.aspx)
//
// * Win32 = 0
// * Win32Windows = 1
// * Win32NT = 2
// * WinCE = 3
// * Unix = 4
// * Xbox = 5
// * MacOSX = 6
//
// Essentially, we check to see if this is one of the "windows" values or Xbox. The other values
// can be a little unreliable, so we'll shell out to 'uname' for Linux and macOS.

var platformId = (int)Environment.OSVersion.Platform;
if (platformId <= 3 || platformId == 5)
{
os = OperatingSystem.Windows;

if (Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") == "x86" &&
Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432") == null)
{
architecture = Architecture.x86;
}
else
{
architecture = Architecture.x64;
}
}
else
{
// If this is not Windows, run 'uname' on Bash to get the OS name and architecture.
var output = RunOnBashAndCaptureOutput("uname", "-s -m");
if (string.IsNullOrEmpty(output))
{
return new Platform();
}

var values = output.Split(' ');
var osName = values[0];
var osArch = values[1];

os = osName.Equals("Darwin", StringComparison.OrdinalIgnoreCase)
? OperatingSystem.MacOS
: OperatingSystem.Linux;

if (osArch.Equals("x86", StringComparison.OrdinalIgnoreCase))
{
architecture = Architecture.x86;
}
else if (osArch.Equals("x86_64", StringComparison.OrdinalIgnoreCase))
{
architecture = Architecture.x64;
}
else
{
architecture = Architecture.Unknown;
}
}

switch (os)
{
case OperatingSystem.Windows:
return new Platform(os, architecture, Environment.OSVersion.Version);
case OperatingSystem.MacOS:
return new Platform(os, architecture, GetMacOSVersion());
case OperatingSystem.Linux:
ReadDistroNameAndVersion(out var distroName, out var version);
return new Platform(os, architecture, version, distroName);

default:
throw new NotSupportedException("Could not detect the current platform.");
}
}

private static Version GetMacOSVersion()
{
var versionText = RunOnBashAndCaptureOutput("sw_vers", "-productVersion");
return ParseVersion(versionText);
}

private static void ReadDistroNameAndVersion(out string distroName, out Version version)
{
// Details: https://www.freedesktop.org/software/systemd/man/os-release.html
var lines = File.ReadAllLines("/etc/os-release");

distroName = null;
version = null;

foreach (var line in lines)
{
var equalsIndex = line.IndexOf('=');
if (equalsIndex >= 0)
{
var key = line.Substring(0, equalsIndex).Trim();
var value = line.Substring(equalsIndex + 1).Trim();
value = value.Trim('"');

if (key == "ID")
{
distroName = value;
}
else if (key == "VERSION_ID")
{
version = ParseVersion(value);
}

if (distroName != null && version != null)
{
break;
}
}
}

if (distroName == null)
{
distroName = "Unknown";
}
}

private static Version ParseVersion(string versionText)
{
if (!versionText.Contains("."))
{
versionText += ".0";
}

if (Version.TryParse(versionText, out var version))
{
return version;
}

return null;
}

private static string RunOnBashAndCaptureOutput(string fileName, string arguments)
=> ProcessHelper.RunAndCaptureOutput("/bin/bash", $"-c '{fileName} {arguments}'");
}
}
52 changes: 41 additions & 11 deletions src/OmniSharp.Host/CompositionHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,13 @@ public CompositionHost Build()
var fileSystemWatcher = new ManualFileSystemWatcher();
var metadataHelper = new MetadataHelper(assemblyLoader);

var logger = loggerFactory.CreateLogger<CompositionHostBuilder>();

// We must register an MSBuild instance before composing MEF to ensure that
// our AssemblyResolve event is hooked up first.
var msbuildLocator = _serviceProvider.GetRequiredService<IMSBuildLocator>();
var instances = msbuildLocator.GetInstances();
var instance = instances.FirstOrDefault();
if (instance != null)
{
msbuildLocator.RegisterInstance(instance);
}
else
{
var logger = loggerFactory.CreateLogger<CompositionHostBuilder>();
logger.LogError("Could not locate MSBuild instance to register with OmniSharp");
}

RegisterMSBuildInstance(msbuildLocator, logger);

config = config
.WithProvider(MefValueProvider.From(_serviceProvider))
Expand Down Expand Up @@ -94,6 +87,43 @@ public CompositionHost Build()
return config.CreateContainer();
}

private static void RegisterMSBuildInstance(IMSBuildLocator msbuildLocator, ILogger logger)
{
MSBuildInstance instanceToRegister = null;
var invalidVSFound = false;

foreach (var instance in msbuildLocator.GetInstances())
{
if (instance.IsInvalidVisualStudio())
{
invalidVSFound = true;
}
else
{
instanceToRegister = instance;
break;
}
}


if (instanceToRegister != 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)
{
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);
}
else
{
logger.LogError("Could not locate MSBuild instance to register with OmniSharp");
}
}

private static IEnumerable<Type> SafeGetTypes(Assembly a)
{
try
Expand Down
13 changes: 13 additions & 0 deletions src/OmniSharp.Host/MSBuild/Discovery/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace OmniSharp.MSBuild.Discovery
{
internal static class Extensions
{
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);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ public override ImmutableArray<MSBuildInstance> GetInstances()
return NoInstances;
}

// Look for Microsoft.Build.dll in the tools path. If it isn't there, this is likely a Mono layout on Linux
// where the 'msbuild' package has not been installed.
var microsoftBuildPath = Path.Combine(toolsPath, "Microsoft.Build.dll");
if (!File.Exists(microsoftBuildPath))
{
Logger.LogDebug($"Mono MSBuild could not be used because '{microsoftBuildPath}' does not exist.");

if (Platform.Current.OperatingSystem == Utilities.OperatingSystem.Linux)
{
Logger.LogWarning(@"It looks like you have Mono 5.2.0 or greater installed but MSBuild could not be found.
Try installing MSBuild into Mono (e.g. 'sudo apt-get install msbuild') to enable better MSBuild support.");
}

return NoInstances;
}

var propertyOverrides = ImmutableDictionary.CreateBuilder<string, string>(StringComparer.OrdinalIgnoreCase);

var localMSBuildPath = FindLocalMSBuildDirectory();
Expand Down
6 changes: 4 additions & 2 deletions src/OmniSharp.Http/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
using OmniSharp.Eventing;
using OmniSharp.Http.Middleware;
using OmniSharp.Options;
using OmniSharp.Roslyn;
using OmniSharp.Services;
using OmniSharp.Stdio.Services;
using OmniSharp.Utilities;

namespace OmniSharp.Http
{
Expand Down Expand Up @@ -52,6 +51,7 @@ public void Configure(
{
var workspace = _compositionHost.GetExport<OmniSharpWorkspace>();
var logger = loggerFactory.CreateLogger<Startup>();

loggerFactory.AddConsole((category, level) =>
{
if (HostHelpers.LogFilter(category, level, _environment)) return true;
Expand All @@ -64,6 +64,8 @@ public void Configure(
return false;
});

logger.LogInformation($"Starting OmniSharp on {Platform.Current}");

app.UseRequestLogging();
app.UseExceptionHandler("/error");
app.UseMiddleware<EndpointMiddleware>(_compositionHost);
Expand Down
Loading