diff --git a/.travis.yml b/.travis.yml
index fddd66ab71..075a9b1520 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,55 +4,15 @@ dist: trusty
env:
global:
secure: m2PtYwYOhaK0uFMZ19ZxApZwWZeAIq1dS//jx/5I3txpIWD+TfycQMAWYxycFJ/GJkeVF29P4Zz1uyS2XKKjPJpp2Pds98FNQyDv3OftpLAVa0drsjfhurVlBmSdrV7GH6ncKfvhd+h7KVK5vbZc+NeR4dH7eNvN/jraS//AMJg=
-mono:
- - 4.8.0
+mono: beta
+dotnet: 1.0.4
os:
- linux
- osx
osx_image: xcode7.3
-# Ensure MSBuild is installed
-before_install:
- - |
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
- sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
- echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
- sudo apt-get -qq update
- sudo apt-get install msbuild
- fi
-
- - |
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
- brew update
- brew install jq
- brew install openssl
- ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/
- ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/
- brew list
- fi
-
- - |
- # This is a temporary fix to workaround a problem where Travis picks up a build of Mono on OSX that
- # includes a broken version of MSBuild.
- #
- # See https://github.com/mono/msbuild/commit/cff4013ba3a69f82dc0ae96b3e15af700d8f74ef
- # for the fix this is replicating.
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
- MSBUILD_BIN=/Library/Frameworks/Mono.framework/Versions/4.8.0/lib/mono/msbuild/15.0/bin
-
- if [ ! -d $MSBUILD_BIN ] || [ -f $MSBUILD_BIN/System.Reflection.Metadata.dll ]; then
- echo "WORKAROUND: Time to remove System.Reflection.Metadata.dll workaround"
- else
- echo "WORKAROUND: Copying System.Reflection.Metadata.dll to Mono MSBuild"
- sudo cp $MSBUILD_BIN/Roslyn/System.Reflection.Metadata.dll $MSBUILD_BIN/System.Reflection.Metadata.dll
- fi
- fi
-
- - msbuild /version
-
script:
- - travis_retry ./build.sh --target TravisTestAll
- - ./build.sh --target Travis --archive
+ - ./build.sh --target All --archive
addons:
apt:
diff --git a/BUILD.md b/BUILD.md
index 49fc459ed0..7c21f80a6a 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -6,7 +6,7 @@ In order to build OmniSharp, the [.NET 4.6 targeting pack](http://go.microsoft.c
## macOS
-**Mono 4.8.0** or greater is required. You can install this using the latest [.pkg](http://www.mono-project.com/download/#download-mac) or install it view [Homebrew](https://brew.sh/):
+**Mono 5.2.0** or greater is required. You can install this using the latest [.pkg](http://www.mono-project.com/download/#download-mac) or install it view [Homebrew](https://brew.sh/):
```
brew update
@@ -18,13 +18,7 @@ brew install caskroom/cask/mono-mdk
Because OmniSharp uses the .NET Core SDK as part of the build, not all Linux distros are supported. A good rule of thumb is to check the list [here](https://www.microsoft.com/net/download/linux) to see if your particular distro is supported.
-**Mono 4.8.0** or greater is required. Each distro or derivative has it's own set of instructions for installing Mono which you can find [here](http://www.mono-project.com/download/#download-lin).
-
-In addition, the `msbuild` package must be installed. On Debian, Ubuntu, and derivatives, this can be achieved by first adding the Mono Project GPG signing key and package repository using the instructions [here](http://www.mono-project.com/docs/getting-started/install/linux/#debian-ubuntu-and-derivatives). Then, install msbuild via apt-get.
-
-```
-sudo apt-get install msbuild
-```
+**Mono 5.2.0** or greater is required. Each distro or derivative has it's own set of instructions for installing Mono which you can find [here](http://www.mono-project.com/download/#download-lin).
# Usage
diff --git a/build.cake b/build.cake
index d3c93f8057..a85a9730f8 100644
--- a/build.cake
+++ b/build.cake
@@ -3,6 +3,8 @@
#load "scripts/archiving.cake"
#load "scripts/artifacts.cake"
#load "scripts/msbuild.cake"
+#load "scripts/platform.cake"
+#load "scripts/validation.cake"
using System.ComponentModel;
using System.Net;
@@ -12,15 +14,17 @@ var target = Argument("target", "Default");
var configuration = Argument("configuration", "Release");
var testConfiguration = Argument("test-configuration", "Debug");
var installFolder = Argument("install-path",
- CombinePaths(Environment.GetEnvironmentVariable(IsRunningOnWindows() ? "USERPROFILE" : "HOME"), ".omnisharp", "local"));
+ CombinePaths(Environment.GetEnvironmentVariable(Platform.Current.IsWindows ? "USERPROFILE" : "HOME"), ".omnisharp", "local"));
var requireArchive = HasArgument("archive");
var useGlobalDotNetSdk = HasArgument("use-global-dotnet-sdk");
Log.Context = Context;
-var env = new BuildEnvironment(IsRunningOnWindows(), useGlobalDotNetSdk);
+var env = new BuildEnvironment(useGlobalDotNetSdk);
var buildPlan = BuildPlan.Load(env);
+Information("Current platform: {0}", Platform.Current);
+
///
/// Clean artifacts.
///
@@ -64,7 +68,7 @@ Task("PopulateRuntimes")
.IsDependentOn("BuildEnvironment")
.Does(() =>
{
- if (IsRunningOnWindows() && string.Equals(Environment.GetEnvironmentVariable("APPVEYOR"), "True"))
+ if (Platform.Current.IsWindows && string.Equals(Environment.GetEnvironmentVariable("APPVEYOR"), "True"))
{
buildPlan.SetTargetRids(
"default", // To allow testing the published artifact
@@ -95,34 +99,44 @@ Task("PopulateRuntimes")
void ParseDotNetInfoValues(IEnumerable lines, out string version, out string rid, out string basePath)
{
- var keyValueMap = new Dictionary();
+ version = null;
+ rid = null;
+ basePath = null;
+
foreach (var line in lines)
{
- var index = line.IndexOf(":");
- if (index >= 0)
+ var colonIndex = line.IndexOf(':');
+ if (colonIndex >= 0)
{
- var key = line.Substring(0, index).Trim();
- var value = line.Substring(index + 1).Trim();
+ var name = line.Substring(0, colonIndex).Trim();
+ var value = line.Substring(colonIndex + 1).Trim();
- if (!string.IsNullOrEmpty(key) &&
- !string.IsNullOrEmpty(value))
+ if (string.IsNullOrWhiteSpace(version) && name.Equals("Version", StringComparison.OrdinalIgnoreCase))
+ {
+ version = value;
+ }
+ else if (string.IsNullOrWhiteSpace(rid) && name.Equals("RID", StringComparison.OrdinalIgnoreCase))
+ {
+ rid = value;
+ }
+ else if (string.IsNullOrWhiteSpace(basePath) && name.Equals("Base Path", StringComparison.OrdinalIgnoreCase))
{
- keyValueMap.Add(key, value);
+ basePath = value;
}
}
}
- if (!keyValueMap.TryGetValue("Version", out version))
+ if (string.IsNullOrWhiteSpace(version))
{
throw new Exception("Could not locate Version in 'dotnet --info' output.");
}
- if (!keyValueMap.TryGetValue("RID", out rid))
+ if (string.IsNullOrWhiteSpace(rid))
{
throw new Exception("Could not locate RID in 'dotnet --info' output.");
}
- if (!keyValueMap.TryGetValue("Base Path", out basePath))
+ if (string.IsNullOrWhiteSpace(basePath))
{
throw new Exception("Could not locate Base Path in 'dotnet --info' output.");
}
@@ -144,7 +158,7 @@ void InstallDotNetSdk(BuildEnvironment env, BuildPlan plan, string version, stri
client.DownloadFile(url, scriptFilePath);
}
- if (!IsRunningOnWindows())
+ if (!Platform.Current.IsWindows)
{
Run("chmod", $"+x '{scriptFilePath}'");
}
@@ -166,10 +180,7 @@ void InstallDotNetSdk(BuildEnvironment env, BuildPlan plan, string version, stri
Run(env.ShellCommand, $"{env.ShellArgument} {scriptFilePath} {string.Join(" ", argList)}").ExceptionOnError($"Failed to Install .NET Core SDK {version}");
}
-///
-/// Install/update build environment.
-///
-Task("BuildEnvironment")
+Task("InstallDotNetCoreSdk")
.Does(() =>
{
if (!useGlobalDotNetSdk)
@@ -184,6 +195,9 @@ Task("BuildEnvironment")
version: buildPlan.LegacyDotNetVersion,
installFolder: env.Folders.LegacyDotNetSdk);
+ string DOTNET_CLI_UI_LANGUAGE = "DOTNET_CLI_UI_LANGUAGE";
+ var originalUILanguageValue = Environment.GetEnvironmentVariable(DOTNET_CLI_UI_LANGUAGE);
+ Environment.SetEnvironmentVariable(DOTNET_CLI_UI_LANGUAGE, "en-US");
// Capture 'dotnet --info' output and parse out RID.
var lines = new List();
@@ -196,6 +210,10 @@ Task("BuildEnvironment")
{
throw new Exception("Failed to run 'dotnet --info'");
}
+ finally
+ {
+ Environment.SetEnvironmentVariable(DOTNET_CLI_UI_LANGUAGE, originalUILanguageValue);
+ }
string version, rid, basePath;
ParseDotNetInfoValues(lines, out version, out rid, out basePath);
@@ -214,6 +232,25 @@ Task("BuildEnvironment")
Information(" Base Path: {0}", basePath);
});
+Task("ValidateEnvironment")
+ .Does(() =>
+{
+ if (!Platform.Current.IsWindows)
+ {
+ ValidateMonoVersion(buildPlan);
+ }
+});
+
+///
+/// Install/update build environment.
+///
+Task("BuildEnvironment")
+ .IsDependentOn("ValidateEnvironment")
+ .IsDependentOn("InstallDotNetCoreSdk")
+ .Does(() =>
+{
+});
+
///
/// Restore required NuGet packages.
///
@@ -266,13 +303,13 @@ Task("PrepareTestAssets")
void BuildProject(BuildEnvironment env, string projectName, string projectFilePath, string configuration)
{
- var command = IsRunningOnWindows()
+ var command = Platform.Current.IsWindows
? env.DotNetCommand
: env.ShellCommand;
- var arguments = IsRunningOnWindows()
+ var arguments = Platform.Current.IsWindows
? $"build \"{projectFilePath}\" --configuration {configuration} /v:d"
- : $"{env.ShellArgument} msbuild.{env.ShellScriptFileExtension} \"{projectFilePath}\" /p:Configuration={configuration} /v:d";
+ : $"{env.ShellArgument} msbuild \"{projectFilePath}\" /p:Configuration={configuration} /v:d";
var logFileName = CombinePaths(env.Folders.ArtifactsLogs, $"{projectName}-build.log");
@@ -319,13 +356,6 @@ Task("TestAll")
.IsDependentOn("TestCore")
.Does(() =>{});
-///
-/// Run all tests for Travis CI .NET Desktop and .NET Core
-///
-Task("TravisTestAll")
- .IsDependentOn("Cleanup")
- .IsDependentOn("TestAll");
-
///
/// Run tests for .NET Core (using .NET CLI).
///
@@ -370,7 +400,7 @@ Task("Test")
var logFile = CombinePaths(env.Folders.ArtifactsLogs, $"{testProject}-desktop-result.xml");
var arguments = $"\"{targetPath}\" -parallel none -xml \"{logFile}\" -notrait category=failing";
- if (IsRunningOnWindows())
+ if (Platform.Current.IsWindows)
{
Run(xunitInstancePath, arguments, instanceFolder)
.ExceptionOnError($"Test {testProject} failed for net46");
@@ -380,7 +410,7 @@ Task("Test")
// Copy the Mono-built Microsoft.Build.* binaries to the test folder.
DirectoryHelper.Copy($"{env.Folders.MonoMSBuildLib}", instanceFolder);
- Run("mono", $"\"{xunitInstancePath}\" {arguments}", instanceFolder)
+ Run("mono", $"--assembly-loader=strict \"{xunitInstancePath}\" {arguments}", instanceFolder)
.ExceptionOnError($"Test {testProject} failed for net46");
}
}
@@ -388,7 +418,7 @@ Task("Test")
bool IsNetFrameworkOnUnix(string framework)
{
- return !IsRunningOnWindows()
+ return !Platform.Current.IsWindows
&& !framework.StartsWith("netcore")
&& !framework.StartsWith("netstandard");
}
@@ -469,7 +499,7 @@ Task("OnlyPublish")
var args = GetPublishArguments(projectFileName, rid, framework, configuration, outputFolder);
args = IsNetFrameworkOnUnix(framework)
- ? $"{env.ShellArgument} msbuild.{env.ShellScriptFileExtension} {args}"
+ ? $"{env.ShellArgument} msbuild {args}"
: args;
Information("Publishing {0} for {1}/{2}...", projectName, framework, rid);
@@ -481,7 +511,7 @@ Task("OnlyPublish")
DirectoryHelper.Copy($"{env.Folders.MSBuildBase}-{framework}", CombinePaths(outputFolder, "msbuild"));
// For OSX/Linux net46 builds, copy the MSBuild libraries built for Mono.
- if (!IsRunningOnWindows() && framework == "net46")
+ if (!Platform.Current.IsWindows && framework == "net46")
{
DirectoryHelper.Copy($"{env.Folders.MonoMSBuildLib}", outputFolder);
}
@@ -612,17 +642,6 @@ Task("Local")
.IsDependentOn("LocalPublish")
.IsDependentOn("TestPublished");
-///
-/// Build centered around producing the final artifacts for Travis
-///
-/// The tests are run as a different task "TestAll"
-///
-Task("Travis")
- .IsDependentOn("Cleanup")
- .IsDependentOn("Restore")
- .IsDependentOn("AllPublish")
- .IsDependentOn("TestPublished");
-
///
/// Default Task aliases to Local.
///
diff --git a/build.json b/build.json
index b5116761b0..6876c03480 100644
--- a/build.json
+++ b/build.json
@@ -3,6 +3,7 @@
"DotNetChannel": "preview",
"DotNetVersion": "1.0.4",
"LegacyDotNetVersion": "1.0.0-preview2-1-003177",
+ "RequiredMonoVersion": "5.2.0.196",
"DownloadURL": "https://omnisharpdownload.blob.core.windows.net/ext",
"MSBuildRuntimeForMono": "Microsoft.Build.Runtime.Mono-alpha4.zip",
"MSBuildLibForMono": "Microsoft.Build.Lib.Mono-alpha4.zip",
diff --git a/msbuild.sh b/msbuild.sh
deleted file mode 100755
index 26917a3c6b..0000000000
--- a/msbuild.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-SDK_DIR="$(cd "$(dirname "$0")"/.dotnet/sdk/1.0.4/ && pwd -P)"
-
-echo $SDK_DIR
-
-export MSBuildExtensionsPath=$SDK_DIR/
-export CscToolExe=$SDK_DIR/Roslyn/RunCsc.sh
-export MSBuildSDKsPath=$SDK_DIR/Sdks
-
-msbuild "$@"
\ No newline at end of file
diff --git a/msbuild/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.NuGet.ImportAfter.targets b/msbuild/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.NuGet.ImportAfter.targets
deleted file mode 100644
index 433922aacf..0000000000
--- a/msbuild/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.NuGet.ImportAfter.targets
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- $(MSBuildExtensionsPath)\NuGet.targets
-
-
-
diff --git a/msbuild/15.0/SolutionFile/ImportAfter/Microsoft.NuGet.ImportAfter.targets b/msbuild/15.0/SolutionFile/ImportAfter/Microsoft.NuGet.ImportAfter.targets
deleted file mode 100644
index 433922aacf..0000000000
--- a/msbuild/15.0/SolutionFile/ImportAfter/Microsoft.NuGet.ImportAfter.targets
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- $(MSBuildExtensionsPath)\NuGet.targets
-
-
-
diff --git a/scripts/archiving.cake b/scripts/archiving.cake
index 1e45454ed5..2f97937478 100644
--- a/scripts/archiving.cake
+++ b/scripts/archiving.cake
@@ -1,3 +1,4 @@
+#load "common.cake"
#load "runhelpers.cake"
using System.IO.Compression;
@@ -64,7 +65,7 @@ string GetBuildIdentifier(string runtime, string framework)
void DoArchive(string runtime, string contentFolder, string archiveName)
{
// On all platforms use ZIP for Windows runtimes
- if (runtime.Contains("win") || (runtime.Equals("default") && IsRunningOnWindows()))
+ if (runtime.Contains("win") || (runtime.Equals("default") && Platform.Current.IsWindows))
{
var zipFile = $"{archiveName}.zip";
Zip(contentFolder, zipFile);
@@ -74,7 +75,7 @@ void DoArchive(string runtime, string contentFolder, string archiveName)
{
var tarFile = $"{archiveName}.tar.gz";
// Use 7z to create TAR.GZ on Windows
- if (IsRunningOnWindows())
+ if (Platform.Current.IsWindows)
{
var tempFile = $"{archiveName}.tar";
try
@@ -85,7 +86,7 @@ void DoArchive(string runtime, string contentFolder, string archiveName)
.ExceptionOnError($"Compression failed for {contentFolder} {archiveName}");
System.IO.File.Delete(tempFile);
}
- catch(Win32Exception)
+ catch (Win32Exception)
{
Information("Warning: 7z not available on PATH to pack tar.gz results");
}
diff --git a/scripts/artifacts.cake b/scripts/artifacts.cake
index e368a7c7b6..b7f1216422 100644
--- a/scripts/artifacts.cake
+++ b/scripts/artifacts.cake
@@ -1,57 +1,98 @@
+#load "common.cake"
#load "runhelpers.cake"
+using System.Collections.Generic;
+
///
/// Generate the scripts which target the OmniSharp binaries.
///
/// The root folder where the publised (or installed) binaries are located
void CreateRunScript(string outputRoot, string scriptFolder)
{
- if (IsRunningOnWindows())
- {
- var desktopScript = System.IO.Path.Combine(scriptFolder, "OmniSharp.cmd");
- var coreScript = System.IO.Path.Combine(scriptFolder, "OmniSharp.Core.cmd");
- var omniSharpPath = System.IO.Path.Combine(System.IO.Path.GetFullPath(outputRoot), "{0}", "OmniSharp");
- var content = new string[] {
- "SETLOCAL",
- "",
- $"\"{omniSharpPath}\" %*"
- };
- if (System.IO.File.Exists(desktopScript))
- {
- System.IO.File.Delete(desktopScript);
- }
- content[2] = String.Format(content[2], "net46");
- System.IO.File.WriteAllLines(desktopScript, content);
- if (System.IO.File.Exists(coreScript))
- {
- System.IO.File.Delete(coreScript);
- }
- content[2] = String.Format(content[2], "netcoreapp1.1");
- System.IO.File.WriteAllLines(coreScript, content);
+ CreateScript(outputRoot, scriptFolder, "net46");
+ CreateScript(outputRoot, scriptFolder, "netcoreapp1.1");
+}
+
+private void CreateScript(string outputRoot, string scriptFolder, string framework)
+{
+ var scriptPath = GetScriptPath(scriptFolder, framework);
+ var omniSharpPath = GetOmniSharpPath(outputRoot, framework);
+ var content = GetScriptContent(omniSharpPath, framework);
+
+ if (FileHelper.Exists(scriptPath))
+ {
+ FileHelper.Delete(scriptPath);
+ }
+
+ FileHelper.WriteAllLines(scriptPath, content);
+
+ if (!Platform.Current.IsWindows)
+ {
+ Run("chmod", $"+x \"{scriptPath}\"");
+ }
+}
+
+private string GetScriptPath(string scriptFolder, string framework)
+{
+ var result = CombinePaths(scriptFolder, "OmniSharp");
+
+ if (IsCore(framework))
+ {
+ result += ".Core";
+ }
+
+ if (Platform.Current.IsWindows)
+ {
+ result += ".cmd";
+ }
+
+ return result;
+}
+
+private string GetOmniSharpPath(string outputRoot, string framework)
+{
+ var result = CombinePaths(PathHelper.GetFullPath(outputRoot), framework, "OmniSharp");
+
+ if (!IsCore(framework))
+ {
+ result += ".exe";
+ }
+
+ return result;
+}
+
+private string[] GetScriptContent(string omniSharpPath, string framework)
+{
+ var lines = new List();
+
+ if (Platform.Current.IsWindows)
+ {
+ lines.Add("SETLOCAL");
}
else
{
- var desktopScript = System.IO.Path.Combine(scriptFolder, "OmniSharp");
- var coreScript = System.IO.Path.Combine(scriptFolder, "OmniSharp.Core");
- var omniSharpPath = System.IO.Path.Combine(System.IO.Path.GetFullPath(outputRoot), "{1}", "OmniSharp");
- var content = new string[] {
- "#!/bin/bash",
- "",
- $"{{0}} \"{omniSharpPath}{{2}}\" \"$@\""
- };
- if (System.IO.File.Exists(desktopScript))
- {
- System.IO.File.Delete(desktopScript);
- }
- content[2] = String.Format(content[2], "mono", "net46", ".exe");
- System.IO.File.WriteAllLines(desktopScript, content);
- Run("chmod", $"+x \"{desktopScript}\"");
- if (System.IO.File.Exists(coreScript))
- {
- System.IO.File.Delete(coreScript);
- }
- content[2] = String.Format(content[2], "", "netcoreapp1.1", "");
- System.IO.File.WriteAllLines(coreScript, content);
- Run("chmod", $"+x \"{desktopScript}\"");
+ lines.Add("#!/bin/bash");
}
+
+ lines.Add("");
+
+ var arguments = Platform.Current.IsWindows
+ ? "%*"
+ : "\"$@\"";
+
+ if (IsCore(framework) || Platform.Current.IsWindows)
+ {
+ lines.Add($"\"{omniSharpPath}\" {arguments}");
+ }
+ else // !isCore && !Platform.Current.IsWindows, i.e. Mono
+ {
+ lines.Add($"mono --assembly-loader=strict \"{omniSharpPath}\" {arguments}");
+ }
+
+ return lines.ToArray();
+}
+
+private bool IsCore(string framework)
+{
+ return framework.StartsWith("netcoreapp");
}
\ No newline at end of file
diff --git a/scripts/common.cake b/scripts/common.cake
index aaeecf4f5a..0ed077f1c1 100644
--- a/scripts/common.cake
+++ b/scripts/common.cake
@@ -1,5 +1,7 @@
#addin "Newtonsoft.Json"
+#load "platform.cake"
+
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -27,6 +29,12 @@ public static class FileHelper
Log.Debug(Verbosity.Diagnostic, "Delete file: {0}.", path);
System.IO.File.Delete(path);
}
+
+ public static bool Exists(string path) =>
+ System.IO.File.Exists(path);
+
+ public static void WriteAllLines(string path, string[] contents) =>
+ System.IO.File.WriteAllLines(path, contents);
}
public static class DirectoryHelper
@@ -92,7 +100,7 @@ public static class PathHelper
System.IO.Path.GetFileName(path);
public static string GetFullPath(string path) =>
- System.IO.Path.Combine(path);
+ System.IO.Path.GetFullPath(path);
}
string CombinePaths(params string[] paths)
@@ -156,7 +164,7 @@ public class BuildEnvironment
public string ShellArgument { get; }
public string ShellScriptFileExtension { get; }
- public BuildEnvironment(bool isWindows, bool useGlobalDotNetSdk)
+ public BuildEnvironment(bool useGlobalDotNetSdk)
{
this.WorkingDirectory = PathHelper.GetFullPath(
System.IO.Directory.GetCurrentDirectory());
@@ -168,9 +176,9 @@ public class BuildEnvironment
this.LegacyDotNetCommand = PathHelper.Combine(this.Folders.LegacyDotNetSdk, "dotnet");
- this.ShellCommand = isWindows ? "powershell" : "bash";
- this.ShellArgument = isWindows ? "-NoProfile /Command" : "-C";
- this.ShellScriptFileExtension = isWindows ? "ps1" : "sh";
+ this.ShellCommand = Platform.Current.IsWindows ? "powershell" : "bash";
+ this.ShellArgument = Platform.Current.IsWindows ? "-NoProfile /Command" : "-C";
+ this.ShellScriptFileExtension = Platform.Current.IsWindows ? "ps1" : "sh";
}
}
@@ -183,6 +191,7 @@ public class BuildPlan
public string DotNetChannel { get; set; }
public string DotNetVersion { get; set; }
public string LegacyDotNetVersion { get; set; }
+ public string RequiredMonoVersion { get; set; }
public string DownloadURL { get; set; }
public string MSBuildRuntimeForMono { get; set; }
public string MSBuildLibForMono { get; set; }
diff --git a/scripts/msbuild.cake b/scripts/msbuild.cake
index 33007148f0..70d1e83326 100644
--- a/scripts/msbuild.cake
+++ b/scripts/msbuild.cake
@@ -5,7 +5,7 @@ using System.Net;
void SetupMSBuild(BuildEnvironment env, BuildPlan plan)
{
- if (!IsRunningOnWindows())
+ if (!Platform.Current.IsWindows)
{
AcquireMonoMSBuild(env, plan);
}
@@ -46,7 +46,7 @@ private void SetupMSBuildForFramework(BuildEnvironment env, string framework)
DirectoryHelper.Delete(msbuildFolder, recursive: true);
}
- if (!IsRunningOnWindows() && framework == "net46")
+ if (!Platform.Current.IsWindows && framework == "net46")
{
Information("Copying Mono MSBuild runtime for {0}...", framework);
DirectoryHelper.Copy(env.Folders.MonoMSBuildRuntime, msbuildFolder);
diff --git a/scripts/platform.cake b/scripts/platform.cake
new file mode 100644
index 0000000000..f07405e4cd
--- /dev/null
+++ b/scripts/platform.cake
@@ -0,0 +1,100 @@
+using System;
+using System.Diagnostics;
+
+public sealed class Platform
+{
+ public static Platform Current { get; } = GetCurrentPlatform();
+
+ private readonly string _os;
+ private readonly string _architecture;
+
+ public bool IsWindows => _os == "Windows";
+ public bool IsMacOS => _os == "macOS";
+ public bool IsLinux => _os == "Linux";
+
+ public bool Is32Bit => _architecture == "x86";
+ public bool Is64Bit => _architecture == "x64";
+
+ private Platform(string os, string architecture)
+ {
+ _os = os;
+ _architecture = architecture;
+ }
+
+ public override string ToString() => $"{_os} ({_architecture})";
+
+ private static Platform GetCurrentPlatform()
+ {
+ string os, architecture;
+
+ // Simple check to see if this is Windows.
+ var platformId = (int)Environment.OSVersion.Platform;
+ if (platformId <= 3 || platformId == 5)
+ {
+ os = "Windows";
+
+ if (Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE") == "x86" &&
+ Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432") == null)
+ {
+ architecture = "x86";
+ }
+ else
+ {
+ architecture = "x64";
+ }
+ }
+ else
+ {
+ // If this is not Windows, run 'uname' to get the OS name and architecture.
+ var output = RunAndCaptureOutput("uname", "-s -m");
+ var values = output.Split(' ');
+ var osName = values[0];
+ var osArch = values[1];
+
+ os = osName.Equals("Darwin", StringComparison.OrdinalIgnoreCase)
+ ? "MacOS"
+ : "Linux";
+
+ if (osArch.Equals("x86", StringComparison.OrdinalIgnoreCase))
+ {
+ architecture = "x86";
+ }
+ else if (osArch.Equals("x86_64", StringComparison.OrdinalIgnoreCase))
+ {
+ architecture = "x64";
+ }
+ else
+ {
+ throw new Exception($"Unexpected architecture: {osArch}");
+ }
+ }
+
+ return new Platform(os, architecture);
+ }
+
+ private static string RunAndCaptureOutput(string fileName, string arguments, string workingDirectory = null)
+ {
+ var startInfo = new ProcessStartInfo(fileName, arguments)
+ {
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ CreateNoWindow = true,
+ UseShellExecute = false,
+ WorkingDirectory = workingDirectory ?? string.Empty,
+ };
+
+ try
+ {
+ var process = Process.Start(startInfo);
+
+ var output = process.StandardOutput.ReadToEnd();
+ process.WaitForExit();
+
+ return output.Trim();
+ }
+ catch (Exception ex)
+ {
+ throw new Exception($"Failed to launch '{fileName}' with args, '{arguments}'", ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/runhelpers.cake b/scripts/runhelpers.cake
index c8f99bc6c2..aacbbf3e96 100644
--- a/scripts/runhelpers.cake
+++ b/scripts/runhelpers.cake
@@ -1,5 +1,8 @@
+#load "platform.cake"
+
using System.Collections.Generic;
using System.Diagnostics;
+using System.Text;
///
/// Class encompassing the optional settings for running processes.
@@ -172,6 +175,21 @@ ExitStatus Run(string command, string arguments, RunOptions runOptions)
}
}
+string RunAndCaptureOutput(string command, string arguments, string workingDirectory = null)
+{
+ var output = new List();
+ Run(command, arguments, new RunOptions(workingDirectory, output))
+ .ExceptionOnError($"Failed to run '{command}' with arguments, '{arguments}'.");
+
+ var builder = new StringBuilder();
+ foreach (var line in output)
+ {
+ builder.AppendLine(line);
+ }
+
+ return builder.ToString().Trim();
+}
+
///
/// Run tool with the given arguments
///
@@ -211,7 +229,7 @@ private void KillProcessTree(Process process)
{
// Child processes are not killed on Windows by default
// Use TASKKILL to kill the process hierarchy rooted in the process
- if (IsRunningOnWindows())
+ if (Platform.Current.IsWindows)
{
StartProcess($"TASKKILL",
new ProcessSettings
diff --git a/scripts/validation.cake b/scripts/validation.cake
new file mode 100644
index 0000000000..1996c0fe32
--- /dev/null
+++ b/scripts/validation.cake
@@ -0,0 +1,63 @@
+#load "common.cake"
+#load "runhelpers.cake"
+
+void ValidateMonoVersion(BuildPlan plan)
+{
+ if (Platform.Current.IsWindows)
+ {
+ return;
+ }
+
+ // We require a minimum version of Mono for building on macOS/Linux. The version is specified in
+ // 'RequiredMonoVersion' of build.json.
+
+ var monoVersionOutput = new List();
+ Run("mono", "--version", new RunOptions(output: monoVersionOutput))
+ .ExceptionOnError($"Could not launch 'mono'. Please ensure that Mono {plan.RequiredMonoVersion} or later is installed and on the path.");
+
+ var ErrorMessage = $"Could not detect Mono version. Please ensure that Mono {plan.RequiredMonoVersion} or later is installed and on the path.";
+
+ if (monoVersionOutput.Count == 0)
+ {
+ throw new Exception(ErrorMessage);
+ }
+
+ var monoVersionText = monoVersionOutput[0];
+
+ if (string.IsNullOrWhiteSpace(monoVersionText))
+ {
+ throw new Exception(ErrorMessage);
+ }
+
+ // The first line of Mono's '--version' output looks like so:
+ //
+ // Mono JIT compiler version 5.2.0.196 (2017-02/5077205 Thu May 18 16:11:37 EDT 2017)
+ //
+ // Our approach at parsing out the version number is to search for the open parenthesis,
+ // and then grab the word before that.
+
+ var openParenIndex = monoVersionText.IndexOf("(");
+ if (openParenIndex < 0)
+ {
+ throw new Exception(ErrorMessage);
+ }
+
+ monoVersionText = monoVersionText.Substring(0, openParenIndex).Trim();
+
+ var lastSpaceIndex = monoVersionText.LastIndexOf(" ");
+ if (lastSpaceIndex < 0)
+ {
+ throw new Exception(ErrorMessage);
+ }
+
+ monoVersionText = monoVersionText.Substring(lastSpaceIndex).Trim();
+
+ var monoVersion = new System.Version(monoVersionText);
+
+ if (monoVersion < new System.Version(plan.RequiredMonoVersion))
+ {
+ throw new Exception($"Detected Mono {monoVersion}, but a version >= {plan.RequiredMonoVersion} is required.");
+ }
+
+ Information("Detected Mono version {0}", monoVersion);
+}
\ No newline at end of file