Browse Source

Switched build to Nuke

Nikita Tsukanov 6 years ago
parent
commit
f8d3046cb5
14 changed files with 723 additions and 607 deletions
  1. 0 0
      .nuke
  2. 1 1
      .travis.yml
  3. 6 0
      Avalonia.sln
  4. 1 1
      appveyor.yml
  5. 12 13
      azure-pipelines.yml
  6. 0 312
      build.cake
  7. 47 179
      build.ps1
  8. 53 86
      build.sh
  9. 0 15
      cake.config
  10. 278 0
      nukebuild/Build.cs
  11. 186 0
      nukebuild/BuildParameters.cs
  12. 80 0
      nukebuild/Shims.cs
  13. 35 0
      nukebuild/_build.csproj
  14. 24 0
      nukebuild/_build.csproj.DotSettings

+ 0 - 0
.nuke


+ 1 - 1
.travis.yml

@@ -13,7 +13,7 @@ dotnet: 2.1.200
 script:
   - sudo apt-get update
   - sudo apt-get install castxml
-  - ./build.sh --target "Travis" --configuration "Release"
+  - ./build.sh --target "CiTravis" --configuration "Release"
 notifications:
   email: false
   webhooks:

+ 6 - 0
Avalonia.sln

@@ -191,6 +191,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Desktop", "src\Ava
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Build.Tasks", "src\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj", "{BF28998D-072C-439A-AFBB-2FE5021241E0}"
 EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "nukebuild\_build.csproj", "{3F00BC43-5095-477F-93D8-E65B08179A00}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -216,6 +218,10 @@ Global
 		Release|iPhoneSimulator = Release|iPhoneSimulator
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3F00BC43-5095-477F-93D8-E65B08179A00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3F00BC43-5095-477F-93D8-E65B08179A00}.Release|Any CPU.Build.0 = Release|Any CPU
 		{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{B09B78D8-9B26-48B0-9149-D64A2F120F3F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU

+ 1 - 1
appveyor.yml

@@ -14,7 +14,7 @@ init:
 before_build:
 - git submodule update --init
 build_script:
-- ps: .\build.ps1 -Target "AppVeyor" -Configuration "$env:configuration"
+- ps: .\build.ps1 --target "CiAppVeyor" --configuration "$env:configuration"
 
 test: off
 artifacts:

+ 12 - 13
azure-pipelines.yml

@@ -11,19 +11,18 @@ jobs:
         sudo apt-get install castxml
 
   - task: CmdLine@2
-    displayName: 'Install Cake'
+    displayName: 'Install Nuke'
     inputs:
       script: |
-        dotnet tool install -g Cake.Tool --version 0.30.0
-  
+         dotnet tool install --global Nuke.GlobalTool --version 0.12.3
   - task: CmdLine@2
-    displayName: 'Run Cake'
+    displayName: 'Run Nuke'
     inputs:
       script: |
         export PATH="$PATH:$HOME/.dotnet/tools"
         dotnet --info
         printenv
-        dotnet cake build.cake -target="Azure-Linux" -configuration="Release"
+        nuke --target="CiAzureLinux" --configuration="Release"
 
   - task: PublishTestResults@2
     inputs:
@@ -55,13 +54,13 @@ jobs:
       script: brew install castxml
 
   - task: CmdLine@2
-    displayName: 'Install Cake'
+    displayName: 'Install Nuke'
     inputs:
       script: |
-        dotnet tool install -g Cake.Tool --version 0.30.0
+       dotnet tool install --global Nuke.GlobalTool --version 0.12.3 
 
   - task: CmdLine@2
-    displayName: 'Run Cake'
+    displayName: 'Run Nuke'
     inputs:
       script: |
         export COREHOST_TRACE=0
@@ -72,7 +71,7 @@ jobs:
         export PATH="$PATH:$HOME/.dotnet/tools"
         dotnet --info
         printenv
-        dotnet cake build.cake -target="Azure-OSX" -configuration="Release"
+        nuke --target="CiAzureOSX" --configuration="Release"
 
   - task: PublishTestResults@2
     inputs:
@@ -97,17 +96,17 @@ jobs:
     vmImage: 'vs2017-win2016'
   steps:
   - task: CmdLine@2
-    displayName: 'Install Cake'
+    displayName: 'Install Nuke'
     inputs:
       script: |
-        dotnet tool install -g Cake.Tool --version 0.30.0
+       dotnet tool install --global Nuke.GlobalTool --version 0.12.3 
 
   - task: CmdLine@2
-    displayName: 'Run Cake'
+    displayName: 'Run Nuke'
     inputs:
       script: |
         set PATH=%PATH%;%USERPROFILE%\.dotnet\tools
-        dotnet cake build.cake -target="Azure-Windows" -configuration="Release"
+        nuke --target="CiAzureWindows" --configuration="Release"
       
   - task: PublishTestResults@2
     inputs:

+ 0 - 312
build.cake

@@ -1,312 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-// TOOLS
-///////////////////////////////////////////////////////////////////////////////
-
-#tool "nuget:?package=NuGet.CommandLine&version=4.7.1"
-#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2018.2.3"
-#tool "nuget:?package=xunit.runner.console&version=2.3.1"
-#tool "nuget:?package=JetBrains.dotMemoryUnit&version=3.0.20171219.105559"
-
-///////////////////////////////////////////////////////////////////////////////
-// USINGS
-///////////////////////////////////////////////////////////////////////////////
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-
-///////////////////////////////////////////////////////////////////////////////
-// SCRIPTS
-///////////////////////////////////////////////////////////////////////////////
-
-#load "./parameters.cake"
-
-///////////////////////////////////////////////////////////////////////////////
-// SETUP
-///////////////////////////////////////////////////////////////////////////////
-
-Setup<Parameters>(context =>
-{
-    var parameters = new Parameters(context);
-
-    Information("Building version {0} of Avalonia ({1}) using version {2} of Cake.", 
-        parameters.Version,
-        parameters.Configuration,
-        typeof(ICakeContext).Assembly.GetName().Version.ToString());
-
-    if (parameters.IsRunningOnAppVeyor)
-    {
-        Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name);
-        Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch);
-    }
-    Information("Target:" + context.TargetTask.Name);
-    Information("Configuration: " + parameters.Configuration);
-    Information("IsLocalBuild: " + parameters.IsLocalBuild);
-    Information("IsRunningOnUnix: " + parameters.IsRunningOnUnix);
-    Information("IsRunningOnWindows: " + parameters.IsRunningOnWindows);
-    Information("IsRunningOnAppVeyor: " + parameters.IsRunningOnAppVeyor);
-    Information("IsRunnongOnAzure:" + parameters.IsRunningOnAzure);
-    Information("IsPullRequest: " + parameters.IsPullRequest);
-    Information("IsMainRepo: " + parameters.IsMainRepo);
-    Information("IsMasterBranch: " + parameters.IsMasterBranch);
-    Information("IsReleaseBranch: " + parameters.IsReleaseBranch);
-    Information("IsTagged: " + parameters.IsTagged);
-    Information("IsReleasable: " + parameters.IsReleasable);
-    Information("IsMyGetRelease: " + parameters.IsMyGetRelease);
-    Information("IsNuGetRelease: " + parameters.IsNuGetRelease);
-
-    return parameters;
-});
-
-///////////////////////////////////////////////////////////////////////////////
-// TEARDOWN
-///////////////////////////////////////////////////////////////////////////////
-
-Teardown<Parameters>((context, buildContext) =>
-{
-    Information("Finished running tasks.");
-});
-
-///////////////////////////////////////////////////////////////////////////////
-// TASKS
-///////////////////////////////////////////////////////////////////////////////
-
-Task("Clean-Impl")
-    .Does<Parameters>(data =>
-{
-    CleanDirectories(data.BuildDirs);
-    CleanDirectory(data.ArtifactsDir);
-    CleanDirectory(data.NugetRoot);
-    CleanDirectory(data.ZipRoot);
-    CleanDirectory(data.TestResultsRoot);
-});
-
-void DotNetCoreBuild(Parameters parameters)
-{
-    var settings = new DotNetCoreBuildSettings 
-    {
-        Configuration = parameters.Configuration,
-        MSBuildSettings = new DotNetCoreMSBuildSettings
-        {
-            Properties =
-            {
-                { "PackageVersion", new [] { parameters.Version } }
-            }
-        }
-    };
-
-    DotNetCoreBuild(parameters.MSBuildSolution, settings);
-}
-
-Task("Build-Impl")
-    .Does<Parameters>(data =>
-{
-    if(data.IsRunningOnWindows)
-    {
-        MSBuild(data.MSBuildSolution, settings => {
-            settings.SetConfiguration(data.Configuration);
-            settings.SetVerbosity(Verbosity.Minimal);
-            settings.WithProperty("iOSRoslynPathHackRequired", "true");
-            settings.WithProperty("PackageVersion", data.Version);
-            settings.UseToolVersion(MSBuildToolVersion.VS2017);
-            settings.WithRestore();
-        });
-    }
-    else
-    {
-        DotNetCoreBuild(data);
-    }
-});
-
-void RunCoreTest(string project, Parameters parameters, bool coreOnly = false)
-{
-    if(!project.EndsWith(".csproj"))
-        project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj");
-    Information("Running tests from " + project);
-    var frameworks = new List<string>(){"netcoreapp2.0"};
-    foreach(var fw in frameworks)
-    {
-        if(!fw.StartsWith("netcoreapp") && coreOnly)
-            continue;
-        Information("Running for " + fw);
-        
-        var settings = new DotNetCoreTestSettings {
-            Configuration = parameters.Configuration,
-            Framework = fw,
-            NoBuild = true,
-            NoRestore = true
-        };
-
-        if (parameters.PublishTestResults)
-        {
-            settings.Logger = "trx";
-            settings.ResultsDirectory = parameters.TestResultsRoot;
-        }
-
-        DotNetCoreTest(project, settings);
-    }
-}
-
-Task("Run-Unit-Tests-Impl")
-    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
-    .Does<Parameters>(data =>
-{
-    RunCoreTest("./tests/Avalonia.Base.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Controls.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Input.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Layout.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Markup.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Styling.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.Skia.UnitTests", data, false);
-    RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", data, false);
-    if (data.IsRunningOnWindows)
-    {
-        RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data, false);
-    }
-});
-
-Task("Run-Designer-Tests-Impl")
-    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
-    .Does<Parameters>(data =>
-{
-    RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", data, false);
-});
-
-Task("Run-Render-Tests-Impl")
-    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
-    .WithCriteria<Parameters>((context, data) => data.IsRunningOnWindows)
-    .Does<Parameters>(data =>
-{
-    RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", data, true);
-    RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", data, true);
-});
-
-Task("Run-Leak-Tests-Impl")
-    .WithCriteria<Parameters>((context, data) => !data.SkipTests)
-    .WithCriteria<Parameters>((context, data) => data.IsRunningOnWindows)
-    .Does(() =>
-{
-    var dotMemoryUnit = Context.Tools.Resolve("dotMemoryUnit.exe");
-    var leakTestsExitCode = StartProcess(dotMemoryUnit, new ProcessSettings
-    {
-        Arguments = new ProcessArgumentBuilder()
-            .Append(Context.Tools.Resolve("xunit.console.x86.exe").FullPath)
-            .Append("--propagate-exit-code")
-            .Append("--")
-            .Append("tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"),
-        Timeout = 120000
-    });
-
-    if (leakTestsExitCode != 0)
-    {
-        throw new Exception("Leak Tests failed");
-    }
-});
-
-Task("Zip-Files-Impl")
-    .Does<Parameters>(data =>
-{
-    Zip(data.BinRoot, data.ZipCoreArtifacts);
-
-    Zip(data.NugetRoot, data.ZipNuGetArtifacts);
-
-    Zip(data.ZipSourceControlCatalogDesktopDirs, 
-        data.ZipTargetControlCatalogDesktopDirs, 
-        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") + 
-        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") + 
-        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") + 
-        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") + 
-        GetFiles(data.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
-});
-
-void DotNetCorePack(Parameters parameters)
-{
-    var settings = new DotNetCorePackSettings 
-    {
-        Configuration = parameters.Configuration,
-        MSBuildSettings = new DotNetCoreMSBuildSettings
-        {
-            Properties =
-            {
-                { "PackageVersion", new [] { parameters.Version } }
-            }
-        }
-    };
-
-    DotNetCorePack(parameters.MSBuildSolution, settings);
-}
-
-Task("Create-NuGet-Packages-Impl")
-    .Does<Parameters>(data =>
-{
-    if(data.IsRunningOnWindows)
-    {
-        MSBuild(data.MSBuildSolution, settings => {
-            settings.SetConfiguration(data.Configuration);
-            settings.SetVerbosity(Verbosity.Minimal);
-            settings.WithProperty("iOSRoslynPathHackRequired", "true");
-            settings.WithProperty("PackageVersion", data.Version);
-            settings.UseToolVersion(MSBuildToolVersion.VS2017);
-            settings.WithRestore();
-            settings.WithTarget("Pack");
-        });
-    }
-    else
-    {
-        DotNetCorePack(data);
-    }
-});
-
-///////////////////////////////////////////////////////////////////////////////
-// TARGETS
-///////////////////////////////////////////////////////////////////////////////
-
-Task("Build")
-    .IsDependentOn("Clean-Impl")
-    .IsDependentOn("Build-Impl");
-
-Task("Run-Tests")
-    .IsDependentOn("Build")
-    .IsDependentOn("Run-Unit-Tests-Impl")
-    .IsDependentOn("Run-Render-Tests-Impl")
-    .IsDependentOn("Run-Designer-Tests-Impl")
-    .IsDependentOn("Run-Leak-Tests-Impl");
-
-Task("Package")
-    .IsDependentOn("Run-Tests")
-    .IsDependentOn("Create-NuGet-Packages-Impl");
-
-Task("AppVeyor")
-  .IsDependentOn("Package")
-  .IsDependentOn("Zip-Files-Impl");
-
-Task("Travis")
-  .IsDependentOn("Run-Tests");
-
-Task("Azure-Linux")
-  .IsDependentOn("Run-Tests");
-
-Task("Azure-OSX")
-  .IsDependentOn("Package")
-  .IsDependentOn("Zip-Files-Impl");
-
-Task("Azure-Windows")
-  .IsDependentOn("Package")
-  .IsDependentOn("Zip-Files-Impl");
-
-///////////////////////////////////////////////////////////////////////////////
-// EXECUTE
-///////////////////////////////////////////////////////////////////////////////
-
-var target = Context.Argument("target", "Default");
-
-if (target == "Default")
-{
-    target = Context.IsRunningOnWindows() ? "Package" : "Run-Tests";
-}
-
-RunTarget(target);

+ 47 - 179
build.ps1

@@ -1,201 +1,69 @@
-##########################################################################
-# This is the Cake bootstrapper script for PowerShell.
-# This file was downloaded from https://github.com/cake-build/resources
-# Feel free to change this file to fit your needs.
-##########################################################################
-
-<#
-
-.SYNOPSIS
-This is a Powershell script to bootstrap a Cake build.
-
-.DESCRIPTION
-This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
-and execute your Cake build script with the parameters you provide.
-
-.PARAMETER Script
-The build script to execute.
-.PARAMETER Target
-The build script target to run.
-.PARAMETER Platform
-The build platform to use.
-.PARAMETER Configuration
-The build configuration to use.
-.PARAMETER Verbosity
-Specifies the amount of information to be displayed.
-.PARAMETER Experimental
-Tells Cake to use the latest Roslyn release.
-.PARAMETER WhatIf
-Performs a dry run of the build script.
-No tasks will be executed.
-.PARAMETER Mono
-Tells Cake to use the Mono scripting engine.
-.PARAMETER SkipToolPackageRestore
-Skips restoring of packages.
-.PARAMETER SkipTests
-Skips unit tests
-.PARAMETER ScriptArgs
-Remaining arguments are added here.
-
-.LINK
-http://cakebuild.net
-
-#>
-
 [CmdletBinding()]
 Param(
-    [string]$Script = "build.cake",
-    [string]$Target = "Default",
-    [ValidateSet("Any CPU", "x86", "x64", "NetCoreOnly", "iPhone")]
-    [string]$Platform = "Any CPU",
-    [ValidateSet("Release", "Debug")]
-    [string]$Configuration = "Release",
-    [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
-    [string]$Verbosity = "Verbose",
-    [switch]$Experimental,
-    [Alias("DryRun","Noop")]
-    [switch]$WhatIf,
-    [switch]$Mono,
-    [switch]$SkipToolPackageRestore,
+    #[switch]$CustomParam,
     [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
-    [string[]]$ScriptArgs
+    [string[]]$BuildArguments
 )
 
-[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
-function MD5HashFile([string] $filePath)
-{
-    if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
-    {
-        return $null
-    }
-
-    [System.IO.Stream] $file = $null;
-    [System.Security.Cryptography.MD5] $md5 = $null;
-    try
-    {
-        $md5 = [System.Security.Cryptography.MD5]::Create()
-        $file = [System.IO.File]::OpenRead($filePath)
-        return [System.BitConverter]::ToString($md5.ComputeHash($file))
-    }
-    finally
-    {
-        if ($file -ne $null)
-        {
-            $file.Dispose()
-        }
-    }
-}
-
-Write-Host "Preparing to run build script..."
-
-if(!$PSScriptRoot){
-    $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
-}
+Write-Output "Windows PowerShell $($Host.Version)"
 
-$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
-$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
-$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
-$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
-$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
-$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
+Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 }
+$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
 
-# Should we use mono?
-$UseMono = "";
-if($Mono.IsPresent) {
-    Write-Verbose -Message "Using the Mono based scripting engine."
-    $UseMono = "-mono"
-}
+###########################################################################
+# CONFIGURATION
+###########################################################################
 
-# Should we use the new Roslyn?
-$UseExperimental = "";
-if($Experimental.IsPresent -and !($Mono.IsPresent)) {
-    Write-Verbose -Message "Using experimental version of Roslyn."
-    $UseExperimental = "-experimental"
-}
+$BuildProjectFile = "$PSScriptRoot\nukebuild\_build.csproj"
+$TempDirectory = "$PSScriptRoot\\.tmp"
 
-# Is this a dry run?
-$UseDryRun = "";
-if($WhatIf.IsPresent) {
-    $UseDryRun = "-dryrun"
-}
+$DotNetGlobalFile = "$PSScriptRoot\\global.json"
+$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1"
+$DotNetChannel = "Current"
 
-# Is this a dry run?
-$UseSkipTests = "";
-if($SkipTests.IsPresent) {
-    $UseSkipTests = "-skip-tests"
-}
+$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
+$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
+$env:NUGET_XMLDOC_MODE = "skip"
 
-# Make sure tools folder exists
-if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
-    Write-Verbose -Message "Creating tools directory..."
-    New-Item -Path $TOOLS_DIR -Type directory | out-null
-}
+###########################################################################
+# EXECUTION
+###########################################################################
 
-# Make sure that packages.config exist.
-if (!(Test-Path $PACKAGES_CONFIG)) {
-    Write-Verbose -Message "Downloading packages.config..."
-    try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
-        Throw "Could not download packages.config."
-    }
+function ExecSafe([scriptblock] $cmd) {
+    & $cmd
+    if ($LASTEXITCODE) { exit $LASTEXITCODE }
 }
 
-# Try find NuGet.exe in path if not exists
-if (!(Test-Path $NUGET_EXE)) {
-    Write-Verbose -Message "Trying to find nuget.exe in PATH..."
-    $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) }
-    $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
-    if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
-        Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
-        $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
+# If global.json exists, load expected version
+if (Test-Path $DotNetGlobalFile) {
+    $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
+    if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
+        $DotNetVersion = $DotNetGlobal.sdk.version
     }
 }
 
-# Try download NuGet.exe if not exists
-if (!(Test-Path $NUGET_EXE)) {
-    Write-Verbose -Message "Downloading NuGet.exe..."
-    try {
-        (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
-    } catch {
-        Throw "Could not download NuGet.exe."
-    }
+# If dotnet is installed locally, and expected version is not set or installation matches the expected version
+if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -ne $null -and `
+     (!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
+    $env:DOTNET_EXE = (Get-Command "dotnet").Path
 }
-
-# Save nuget.exe path to environment to be available to child processed
-$ENV:NUGET_EXE = $NUGET_EXE
-
-# Restore tools from NuGet?
-if(-Not $SkipToolPackageRestore.IsPresent) {
-    Push-Location
-    Set-Location $TOOLS_DIR
-
-    # Check for changes in packages.config and remove installed tools if true.
-    [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
-    if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
-      ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
-        Write-Verbose -Message "Missing or changed package.config hash..."
-        Remove-Item * -Recurse -Exclude packages.config,nuget.exe
+else {
+    $DotNetDirectory = "$TempDirectory\dotnet-win"
+    $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
+
+    # Download install script
+    $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
+    md -force $TempDirectory > $null
+    (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
+
+    # Install by channel or version
+    if (!(Test-Path variable:DotNetVersion)) {
+        ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
+    } else {
+        ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
     }
-
-    Write-Verbose -Message "Restoring tools from NuGet..."
-    $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
-
-    if ($LASTEXITCODE -ne 0) {
-        Throw "An error occured while restoring NuGet tools."
-    }
-    else
-    {
-        $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
-    }
-    Write-Verbose -Message ($NuGetOutput | out-string)
-    Pop-Location
 }
 
-# Make sure that Cake has been installed.
-if (!(Test-Path $CAKE_EXE)) {
-    Throw "Could not find Cake.exe at $CAKE_EXE"
-}
+Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
 
-# Start Cake
-Write-Host "Running build script..."
-Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -platform=`"$Platform`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseSkipTests $UseMono $UseDryRun $UseExperimental $ScriptArgs"
-exit $LASTEXITCODE
+ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile -- $BuildArguments }

+ 53 - 86
build.sh

@@ -1,105 +1,72 @@
 #!/usr/bin/env bash
 
-##########################################################################
-# This is the Cake bootstrapper script for Linux and OS X.
-# This file was downloaded from https://github.com/cake-build/resources
-# Feel free to change this file to fit your needs.
-##########################################################################
+echo $(bash --version 2>&1 | head -n 1)
 
-# Define directories.
-SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
-TOOLS_DIR=$SCRIPT_DIR/tools
-NUGET_EXE=$TOOLS_DIR/nuget.exe
-CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe
-PACKAGES_CONFIG=$TOOLS_DIR/packages.config
-PACKAGES_CONFIG_MD5=$TOOLS_DIR/packages.config.md5sum
-
-# Define md5sum or md5 depending on Linux/OSX
-MD5_EXE=
-if [[ "$(uname -s)" == "Darwin" ]]; then
-    MD5_EXE="md5 -r"
-else
-    MD5_EXE="md5sum"
-fi
-
-# Define default arguments.
-SCRIPT="build.cake"
-TARGET="Default"
-CONFIGURATION="Release"
-PLATFORM="Any CPU"
-VERBOSITY="verbose"
-DRYRUN=
-SKIP_TESTS=
-SHOW_VERSION=false
-SCRIPT_ARGUMENTS=()
-
-# Parse arguments.
+#CUSTOMPARAM=0
+BUILD_ARGUMENTS=()
 for i in "$@"; do
-    case $1 in
-        -s|--script) SCRIPT="$2"; shift ;;
-        -t|--target) TARGET="$2"; shift ;;
-        -p|--platform) PLATFORM="$2"; shift ;;
-        -c|--configuration) CONFIGURATION="$2"; shift ;;
-        --skip-tests) SKIP_TESTS="-skip-tests"; shift ;;
-        -v|--verbosity) VERBOSITY="$2"; shift ;;
-        -d|--dryrun) DRYRUN="-dryrun" ;;
-        --version) SHOW_VERSION=true ;;
-        --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
-        *) SCRIPT_ARGUMENTS+=("$1") ;;
+    case $(echo $1 | awk '{print tolower($0)}') in
+        # -custom-param) CUSTOMPARAM=1;;
+        *) BUILD_ARGUMENTS+=("$1") ;;
     esac
     shift
 done
 
-# Make sure the tools folder exist.
-if [ ! -d "$TOOLS_DIR" ]; then
-  mkdir "$TOOLS_DIR"
-fi
+set -eo pipefail
+SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
 
-# Make sure that packages.config exist.
-if [ ! -f "$TOOLS_DIR/packages.config" ]; then
-    echo "Downloading packages.config..."
-    curl -Lsfo "$TOOLS_DIR/packages.config" http://cakebuild.net/download/bootstrapper/packages
-    if [ $? -ne 0 ]; then
-        echo "An error occured while downloading packages.config."
-        exit 1
-    fi
-fi
+###########################################################################
+# CONFIGURATION
+###########################################################################
 
-# Download NuGet if it does not exist.
-if [ ! -f "$NUGET_EXE" ]; then
-    echo "Downloading NuGet..."
-    curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
-    if [ $? -ne 0 ]; then
-        echo "An error occured while downloading nuget.exe."
-        exit 1
-    fi
-fi
+BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj"
+TEMP_DIRECTORY="$SCRIPT_DIR//.tmp"
 
-# Restore tools from NuGet.
-pushd "$TOOLS_DIR" >/dev/null
-if [ ! -f $PACKAGES_CONFIG_MD5 ] || [ "$( cat $PACKAGES_CONFIG_MD5 | sed 's/\r$//' )" != "$( $MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' )" ]; then
-    find . -type d ! -name . | xargs rm -rf
-fi
+DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
+DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh"
+DOTNET_CHANNEL="Current"
 
-mono "$NUGET_EXE" install -ExcludeVersion
-if [ $? -ne 0 ]; then
-    echo "Could not restore NuGet packages."
-    exit 1
-fi
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+export NUGET_XMLDOC_MODE="skip"
 
-$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
+###########################################################################
+# EXECUTION
+###########################################################################
 
-popd >/dev/null
+function FirstJsonValue {
+    perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2}
+}
 
-# Make sure that Cake has been installed.
-if [ ! -f "$CAKE_EXE" ]; then
-    echo "Could not find Cake.exe at '$CAKE_EXE'."
-    exit 1
+# If global.json exists, load expected version
+if [ -f "$DOTNET_GLOBAL_FILE" ]; then
+    DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE"))
+    if [ "$DOTNET_VERSION" == ""  ]; then
+        unset DOTNET_VERSION
+    fi
 fi
 
-# Start Cake
-if $SHOW_VERSION; then
-    exec mono "$CAKE_EXE" -version
+# If dotnet is installed locally, and expected version is not set or installation matches the expected version
+if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then
+    export DOTNET_EXE="$(command -v dotnet)"
 else
-    exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -platform="$PLATFORM" -configuration="$CONFIGURATION" -target=$TARGET $DRYRUN $SKIP_TESTS "${SCRIPT_ARGUMENTS[@]}"
+    DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
+    export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
+    
+    # Download install script
+    DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
+    mkdir -p "$TEMP_DIRECTORY"
+    curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
+    chmod +x "$DOTNET_INSTALL_FILE"
+    
+    # Install by channel or version
+    if [ -z ${DOTNET_VERSION+x} ]; then
+        "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
+    else
+        "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
+    fi
 fi
+
+echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
+
+"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}

+ 0 - 15
cake.config

@@ -1,15 +0,0 @@
-; This is the default configuration file for Cake.
-; This file was downloaded from https://github.com/cake-build/resources
-
-[Nuget]
-Source=https://api.nuget.org/v3/index.json
-UseInProcessClient=true
-LoadDependencies=false
-
-[Paths]
-Tools=./tools
-Addins=./tools/Addins
-Modules=./tools/Modules
-
-[Settings]
-SkipVerification=false

+ 278 - 0
nukebuild/Build.cs

@@ -0,0 +1,278 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Nuke.Common;
+using Nuke.Common.Git;
+using Nuke.Common.ProjectModel;
+using Nuke.Common.Tooling;
+using Nuke.Common.Tools.DotNet;
+using Nuke.Common.Tools.MSBuild;
+using Nuke.Common.Utilities;
+using static Nuke.Common.EnvironmentInfo;
+using static Nuke.Common.IO.FileSystemTasks;
+using static Nuke.Common.IO.PathConstruction;
+using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
+using static Nuke.Common.Tools.DotNet.DotNetTasks;
+using static Nuke.Common.Tools.Xunit.XunitTasks;
+
+
+/*
+ Before editing this file, install support plugin for your IDE,
+ running and debugging a particular target (optionally without deps) would be way easier
+ ReSharper/Rider - https://plugins.jetbrains.com/plugin/10803-nuke-support
+ VSCode - https://marketplace.visualstudio.com/items?itemName=nuke.support
+ 
+ */
+
+partial class Build : NukeBuild
+{   
+    BuildParameters Parameters { get; set; }
+    protected override void OnBuildInitialized()
+    {
+        Parameters = new BuildParameters(this);
+        Information("Building version {0} of Avalonia ({1}) using version {2} of Nuke.", 
+            Parameters.Version,
+            Parameters.Configuration,
+            typeof(NukeBuild).Assembly.GetName().Version.ToString());
+
+        if (Parameters.IsLocalBuild)
+        {
+            Information("Repository Name: " + Parameters.RepositoryName);
+            Information("Repository Branch: " + Parameters.RepositoryBranch);
+        }
+        Information("Configuration: " + Parameters.Configuration);
+        Information("IsLocalBuild: " + Parameters.IsLocalBuild);
+        Information("IsRunningOnUnix: " + Parameters.IsRunningOnUnix);
+        Information("IsRunningOnWindows: " + Parameters.IsRunningOnWindows);
+        Information("IsRunningOnAppVeyor: " + Parameters.IsRunningOnAppVeyor);
+        Information("IsRunnongOnAzure:" + Parameters.IsRunningOnAzure);
+        Information("IsPullRequest: " + Parameters.IsPullRequest);
+        Information("IsMainRepo: " + Parameters.IsMainRepo);
+        Information("IsMasterBranch: " + Parameters.IsMasterBranch);
+        Information("IsReleaseBranch: " + Parameters.IsReleaseBranch);
+        Information("IsTagged: " + Parameters.IsTagged);
+        Information("IsReleasable: " + Parameters.IsReleasable);
+        Information("IsMyGetRelease: " + Parameters.IsMyGetRelease);
+        Information("IsNuGetRelease: " + Parameters.IsNuGetRelease);
+    }
+
+    Target Clean => _ => _.Executes(() =>
+    {
+        var data = Parameters;
+        DeleteDirectories(data.BuildDirs);
+        EnsureCleanDirectories(data.BuildDirs);
+        EnsureCleanDirectory(data.ArtifactsDir);
+        EnsureCleanDirectory(data.NugetRoot);
+        EnsureCleanDirectory(data.ZipRoot);
+        EnsureCleanDirectory(data.TestResultsRoot);
+    });
+
+
+    Target Compile => _ => _
+        .DependsOn(Clean)
+        .Executes(() =>
+        {
+            var data = Parameters;
+            if (data.IsRunningOnWindows)
+                MSBuild(data.MSBuildSolution, c => c
+                    .SetConfiguration(data.Configuration)
+                    .SetVerbosity(MSBuildVerbosity.Minimal)
+                    .AddProperty("PackageVersion", Parameters.Version)
+                    .AddProperty("iOSRoslynPathHackRequired", "true")
+                    .SetToolsVersion(MSBuildToolsVersion._15_0)
+                    .AddTargets("Restore", "Build")
+                );
+
+            else
+                DotNetBuild(Parameters.MSBuildSolution, c => c
+                    .AddProperty("PackageVersion", Parameters.Version)
+                    .SetConfiguration(Parameters.Configuration)
+                );
+        });
+    
+    void RunCoreTest(string project, bool coreOnly = false)
+    {
+        if(!project.EndsWith(".csproj"))
+            project = System.IO.Path.Combine(project, System.IO.Path.GetFileName(project)+".csproj");
+        Information("Running tests from " + project);
+        var frameworks = new List<string>(){"netcoreapp2.0"};
+        foreach(var fw in frameworks)
+        {
+            if(!fw.StartsWith("netcoreapp") && coreOnly)
+                continue;
+            Information("Running for " + fw);
+            DotNetTest(c =>
+            {
+                c = c
+                    .SetProjectFile(project)
+                    .SetConfiguration(Parameters.Configuration)
+                    .SetFramework(fw)
+                    .EnableNoBuild()
+                    .EnableNoRestore();
+                // NOTE: I can see that we could maybe add another extension method "Switch" or "If" to make this more  convenient
+                if (Parameters.PublishTestResults)
+                    c = c.SetLogger("trx").SetResultsDirectory(Parameters.TestResultsRoot);
+                return c;
+            });
+        }
+    }
+
+    Target RunCoreLibsTests => _ => _
+        .OnlyWhen(() => !Parameters.SkipTests)
+        .DependsOn(Compile)
+        .Executes(() =>
+        {
+            
+            RunCoreTest("./tests/Avalonia.Base.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Controls.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Input.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Layout.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Markup.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Styling.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Visuals.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.Skia.UnitTests", false);
+            RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", false);
+
+        });
+
+    Target RunRenderTests => _ => _
+        .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
+        .DependsOn(Compile)
+        .Executes(() =>
+        {
+            RunCoreTest("./tests/Avalonia.Skia.RenderTests/Avalonia.Skia.RenderTests.csproj", true);
+            RunCoreTest("./tests/Avalonia.Direct2D1.RenderTests/Avalonia.Direct2D1.RenderTests.csproj", true);
+        });
+    
+    Target RunDesignerTests => _ => _
+        .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
+        .DependsOn(Compile)
+        .Executes(() =>
+        {
+            RunCoreTest("./tests/Avalonia.DesignerSupport.Tests", false);
+        });
+
+    [PackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe")] readonly Tool DotMemoryUnit;
+
+    Target RunLeakTests => _ => _
+        .OnlyWhen(() => !Parameters.SkipTests && Parameters.IsRunningOnWindows)
+        .DependsOn(Compile)
+        .Executes(() =>
+        {
+
+            var dotMemoryUnitPath =
+                ToolPathResolver.GetPackageExecutable("JetBrains.dotMemoryUnit", "dotMemoryUnit.exe");
+            var xunitRunnerPath =
+                ToolPathResolver.GetPackageExecutable("xunit.runner.console", "xunit.console.x86.exe");
+            var args = new[]
+            {
+                Path.GetFullPath(xunitRunnerPath),
+                "--propagate-exit-code",
+                "--",
+                "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll"
+            };
+            var cargs = string.Join(" ", args.Select(a => '"' + a + '"'));
+
+            var proc = Process.Start(new ProcessStartInfo(dotMemoryUnitPath, cargs)
+            {
+                UseShellExecute = false
+            });
+
+            if (!proc.WaitForExit(120000))
+            {
+                proc.Kill();
+                throw new Exception("Leak tests timed out");
+            }
+
+            var leakTestsExitCode = proc.ExitCode;
+            
+            if (leakTestsExitCode != 0)
+            {
+                throw new Exception("Leak Tests failed");
+            }
+            
+
+            var testAssembly = "tests\\Avalonia.LeakTests\\bin\\Release\\net461\\Avalonia.LeakTests.dll";
+            DotMemoryUnit(
+                $"{XunitPath.DoubleQuoteIfNeeded()} --propagate-exit-code -- {testAssembly}",
+                timeout: 120_000);
+        });
+
+    Target ZipFiles => _ => _
+        .After(CreateNugetPackages, Compile, RunCoreLibsTests, Package)    
+        .Executes(() =>
+        {
+            var data = Parameters;
+            Zip(data.ZipCoreArtifacts, data.BinRoot);
+
+            Zip(data.ZipNuGetArtifacts, data.NugetRoot);
+
+            Zip(data.ZipTargetControlCatalogDesktopDir,
+                GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dll").Concat(
+                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.config")).Concat(
+                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.so")).Concat(
+                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.dylib")).Concat(
+                    GlobFiles(data.ZipSourceControlCatalogDesktopDir, "*.exe")));
+        });
+
+    Target CreateNugetPackages => _ => _
+        .DependsOn(Compile)
+        .After(RunTests)
+        .Executes(() =>
+        {
+            if (Parameters.IsRunningOnWindows)
+
+                MSBuild(Parameters.MSBuildSolution, c => c
+                    .SetConfiguration(Parameters.Configuration)
+                    .SetVerbosity(MSBuildVerbosity.Minimal)
+                    .AddProperty("PackageVersion", Parameters.Version)
+                    .AddProperty("iOSRoslynPathHackRequired", "true")
+                    .SetToolsVersion(MSBuildToolsVersion._15_0)
+                    .AddTargets("Restore", "Pack"));
+            else
+                DotNetPack(Parameters.MSBuildSolution, c =>
+                    c.SetConfiguration(Parameters.Configuration)
+                        .AddProperty("PackageVersion", Parameters.Version));
+        });
+    
+    Target RunTests => _ => _
+        .DependsOn(RunCoreLibsTests)
+        .DependsOn(RunRenderTests)
+        .DependsOn(RunDesignerTests)
+        .DependsOn(RunLeakTests);
+    
+    Target Package => _ => _
+        .DependsOn(RunTests)
+        .DependsOn(CreateNugetPackages);
+    
+    Target CiAppVeyor => _ => _
+        .DependsOn(Package)
+        .DependsOn(ZipFiles);
+    
+    Target CiTravis => _ => _
+        .DependsOn(RunTests);
+    
+    Target CiAsuzeLinux => _ => _
+        .DependsOn(RunTests);
+    
+    Target CiAsuzeOSX => _ => _
+        .DependsOn(Package)
+        .DependsOn(ZipFiles);
+    
+    Target CiAsuzeWindows => _ => _
+        .DependsOn(Package)
+        .DependsOn(ZipFiles);
+
+    
+    public static int Main() =>
+        RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+            ? Execute<Build>(x => x.Package)
+            : Execute<Build>(x => x.RunTests);
+
+}

+ 186 - 0
nukebuild/BuildParameters.cs

@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Xml.Linq;
+using Nuke.Common;
+using Nuke.Common.BuildServers;
+using Nuke.Common.Execution;
+using Nuke.Common.IO;
+using static Nuke.Common.IO.FileSystemTasks;
+using static Nuke.Common.IO.PathConstruction;
+using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
+
+public partial class Build
+{
+    [Parameter("configuration")]
+    public string NukeArgConfiguration { get; set; }
+    
+    [Parameter("skip-tests")]
+    public bool NukeArgSkipTests { get; set; }
+    
+    [Parameter("force-nuget-version")]
+    public string NukeArgForceNugetVersion { get; set; }
+    
+    public class BuildParameters
+    {
+        public string Configuration { get; }
+        public bool SkipTests { get; }
+        public string MainRepo { get; }
+        public string MasterBranch { get; }
+        public string RepositoryName { get; }
+        public string RepositoryBranch { get; }
+        public string ReleaseConfiguration { get; }
+        public string ReleaseBranchPrefix { get; }
+        public string MSBuildSolution { get; }
+        public bool IsLocalBuild { get; }
+        public bool IsRunningOnUnix { get; }
+        public bool IsRunningOnWindows { get; }
+        public bool IsRunningOnAppVeyor { get; }
+        public bool IsRunningOnAzure { get; }
+        public bool IsPullRequest { get; }
+        public bool IsMainRepo { get; }
+        public bool IsMasterBranch { get; }
+        public bool IsReleaseBranch { get; }
+        public bool IsTagged { get; }
+        public bool IsReleasable { get; }
+        public bool IsMyGetRelease { get; }
+        public bool IsNuGetRelease { get; }
+        public bool PublishTestResults { get; }
+        public string Version { get; }
+        public AbsolutePath ArtifactsDir { get; }
+        public AbsolutePath NugetRoot { get; }
+        public AbsolutePath ZipRoot { get; }
+        public AbsolutePath BinRoot { get; }
+        public AbsolutePath TestResultsRoot { get; }
+        public string DirSuffix { get; }
+        public List<string> BuildDirs { get; }
+        public string FileZipSuffix { get; }
+        public AbsolutePath ZipCoreArtifacts { get; }
+        public AbsolutePath ZipNuGetArtifacts { get; }
+        public AbsolutePath ZipSourceControlCatalogDesktopDir { get; }
+        public AbsolutePath ZipTargetControlCatalogDesktopDir { get; }
+
+
+       public BuildParameters(Build b)
+        {
+            var buildSystem = Host;
+            
+
+            // ARGUMENTS
+            Configuration = b.NukeArgConfiguration ?? "Release";
+            SkipTests = b.NukeArgSkipTests;
+
+            // CONFIGURATION
+            MainRepo = "https://github.com/AvaloniaUI/Avalonia";
+            MasterBranch = "refs/heads/master";
+            ReleaseBranchPrefix = "refs/heads/release/";
+            ReleaseConfiguration = "Release";
+            MSBuildSolution = RootDirectory / "dirs.proj";
+
+            // PARAMETERS
+            IsLocalBuild = buildSystem == HostType.Console;
+            IsRunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix ||
+                              Environment.OSVersion.Platform == PlatformID.MacOSX;
+            IsRunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+            IsRunningOnAppVeyor = buildSystem == HostType.AppVeyor;
+            IsRunningOnAzure = buildSystem == HostType.TeamServices ||
+                               Environment.GetEnvironmentVariable("LOGNAME") == "vsts";
+
+            string tagName = null;
+            if (IsRunningOnAppVeyor)
+            {
+                IsPullRequest = AppVeyor.Instance.PullRequestNumber != 0;
+                RepositoryName = Environment.GetEnvironmentVariable("BUILD_REPOSITORY_URI");
+                RepositoryBranch = Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH");
+                
+                IsReleaseBranch =
+                    (Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH") ?? "").StartsWith(ReleaseBranchPrefix,
+                        StringComparison.OrdinalIgnoreCase);
+                IsTagged = AppVeyor.Instance.RepositoryTag
+                           && !string.IsNullOrWhiteSpace(AppVeyor.Instance.RepositoryTagName);
+                
+                tagName = AppVeyor.Instance.RepositoryTagName;
+            }
+            else if (IsRunningOnAzure)
+            {
+                RepositoryName = TeamServices.Instance.RepositoryUri;
+                RepositoryBranch = TeamServices.Instance.SourceBranch;
+                IsPullRequest = TeamServices.Instance.PullRequestId.HasValue;
+                IsMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, TeamServices.Instance.RepositoryUri);
+                
+                // TODO???
+                IsTagged = false;
+                tagName = null;
+            }
+            IsMainRepo =
+                StringComparer.OrdinalIgnoreCase.Equals(MainRepo,
+                    RepositoryName);
+            IsMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch,
+                RepositoryBranch);
+
+            
+            IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
+            IsMyGetRelease = !IsTagged && IsReleasable;
+            IsNuGetRelease = IsMainRepo && IsReleasable && IsReleaseBranch;
+
+            // VERSION
+            Version = b.NukeArgForceNugetVersion ?? GetVersion();
+
+            if (IsRunningOnAppVeyor)
+            {
+                string tagVersion = null;
+                if (IsTagged)
+                {
+                    var tag = tagName;
+                    var nugetReleasePrefix = "nuget-release-";
+                    IsNuGetRelease = IsTagged && IsReleasable && tag.StartsWith(nugetReleasePrefix);
+                    if (IsNuGetRelease)
+                        tagVersion = tag.Substring(nugetReleasePrefix.Length);
+                }
+
+                if (tagVersion != null)
+                {
+                    Version = tagVersion;
+                }
+                else
+                {
+                    // Use AssemblyVersion with Build as version
+                    Version += "-build" + Environment.GetEnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-beta";
+                }
+            }
+            else if (IsRunningOnAzure)
+            {
+                if (!IsNuGetRelease)
+                {
+                    // Use AssemblyVersion with Build as version
+                    Version += "-build" + Environment.GetEnvironmentVariable("BUILD_BUILDID") + "-beta";
+                }
+
+                PublishTestResults = true;
+            }
+
+            // DIRECTORIES
+            ArtifactsDir = RootDirectory / "artifacts";
+            NugetRoot = ArtifactsDir / "nuget";
+            ZipRoot = ArtifactsDir / "zip";
+            BinRoot = ArtifactsDir / "bin";
+            TestResultsRoot = ArtifactsDir / "test-results";
+            BuildDirs = GlobDirectories(RootDirectory, "**bin").Concat(GlobDirectories(RootDirectory, "**obj")).ToList();
+            DirSuffix = Configuration;
+            FileZipSuffix = Version + ".zip";
+            ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix);
+            ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix);
+            ZipSourceControlCatalogDesktopDir =
+                RootDirectory / ("samples/ControlCatalog.Desktop/bin/" + DirSuffix + "/net461");
+            ZipTargetControlCatalogDesktopDir = ZipRoot / ("ControlCatalog.Desktop-" + FileZipSuffix);
+        }
+
+        private static string GetVersion()
+        {
+            var xdoc = XDocument.Load("./build/SharedVersion.props");
+            return xdoc.Descendants().First(x => x.Name.LocalName == "Version").Value;
+        }
+    }
+
+}

+ 80 - 0
nukebuild/Shims.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using Nuke.Common;
+using Nuke.Common.IO;
+
+public partial class Build
+{
+    static void Information(string info)
+    {
+        Logger.Info(info);
+    }
+
+    static void Information(string info, params object[] args)
+    {
+        Logger.Info(info, args);
+    }
+
+    private void Zip(PathConstruction.AbsolutePath target, params string[] paths) => Zip(target, paths.AsEnumerable());
+
+    private void Zip(PathConstruction.AbsolutePath target, IEnumerable<string> paths)
+    {
+        var targetPath = target.ToString();
+        bool finished = false, atLeastOneFileAdded = false;
+        try
+        {
+            using (var targetStream = File.Create(targetPath))
+            using(var archive = new System.IO.Compression.ZipArchive(targetStream, ZipArchiveMode.Create))
+            {
+                void AddFile(string path, string relativePath)
+                {
+                    var e = archive.CreateEntry(relativePath.Replace("\\", "/"), CompressionLevel.Optimal);
+                    using (var entryStream = e.Open())
+                    using (var fileStream = File.OpenRead(path))
+                        fileStream.CopyTo(entryStream);
+                    atLeastOneFileAdded = true;
+                }
+                
+                foreach (var path in paths)
+                {
+                    
+                    if (Directory.Exists(path))
+                    {
+                        var dirInfo = new DirectoryInfo(path);
+                        var rootPath = Path.GetDirectoryName(dirInfo.FullName);
+                        foreach(var fsEntry in dirInfo.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
+                        {
+                            if (fsEntry is FileInfo)
+                            {
+                                var relPath = Path.GetRelativePath(rootPath, fsEntry.FullName);
+                                AddFile(fsEntry.FullName, relPath);
+                            }
+                        }
+                    }
+                    else if(File.Exists(path))
+                    {
+                        var name = Path.GetFileName(path);
+                        AddFile(path, name);
+                    }
+                }
+            }
+
+            finished = true;
+        }
+        finally 
+        {
+            try
+            {
+                if (!finished || !atLeastOneFileAdded)
+                    File.Delete(targetPath);
+            }
+            catch
+            {
+                //Ignore
+            }
+        }
+    }
+}

+ 35 - 0
nukebuild/_build.csproj

@@ -0,0 +1,35 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.0</TargetFramework>
+    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+    <RootNamespace></RootNamespace>
+    <IsPackable>False</IsPackable>
+    <NoWarn>CS0649;CS0169</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Nuke.Common" Version="0.12.3" />
+    <PackageReference Include="xunit.runner.console" Version="2.3.1" />
+    <PackageReference Include="JetBrains.dotMemoryUnit" Version="3.0.20171219.105559" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <NukeMetadata Include="**\*.json" Exclude="bin\**;obj\**" />
+    <NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
+    <None Remove="*.csproj.DotSettings;*.ref.*.txt" />
+    
+    <!-- Common build related files -->
+    <None Include="..\build.ps1" />
+    <None Include="..\build.sh" />
+    <None Include="..\.nuke" />     
+    <None Include="..\global.json" Condition="Exists('..\global.json')" />
+    <None Include="..\nuget.config" Condition="Exists('..\nuget.config')" />
+    <None Include="..\Jenkinsfile" Condition="Exists('..\Jenkinsfile')" />
+    <None Include="..\appveyor.yml" Condition="Exists('..\appveyor.yml')" />
+    <None Include="..\.travis.yml" Condition="Exists('..\.travis.yml')" />
+    <None Include="..\GitVersion.yml" Condition="Exists('..\GitVersion.yml')" />
+  </ItemGroup>
+
+</Project>

+ 24 - 0
nukebuild/_build.csproj.DotSettings

@@ -0,0 +1,24 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:Boolean x:Key="/Default/CodeInspection/ImplicitNullability/EnableFields/@EntryValue">False</s:Boolean>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_INTERNAL_MODIFIER/@EntryValue">Implicit</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue">Implicit</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">0</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
+	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_USER_LINEBREAKS/@EntryValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_INVOCATION_LPAR/@EntryValue">False</s:Boolean>
+	<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_ATTRIBUTE_LENGTH_FOR_SAME_LINE/@EntryValue">120</s:Int64>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">IF_OWNER_IS_SINGLE_LINE</s:String>
+	<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">WRAP_IF_LONG</s:String>
+	<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
+	<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>