Browse Source

Added cake build scripts

Wiesław Šoltés 9 years ago
parent
commit
1d2be074d6
9 changed files with 1150 additions and 32 deletions
  1. 7 0
      .gitignore
  2. 1 10
      .travis.yml
  3. 7 0
      NuGet.Config
  4. 16 22
      appveyor.yml
  5. 733 0
      build.cake
  6. 193 0
      build.ps1
  7. 103 0
      build.sh
  8. 86 0
      docs/tutorial/nuget.md
  9. 4 0
      docs/tutorial/toc.yml

+ 7 - 0
.gitignore

@@ -152,3 +152,10 @@ $RECYCLE.BIN/
 #################
 *.userprefs
 *.nugetreferenceswitcher
+
+#################
+## Cake
+#################
+tools/
+.nuget
+artifacts/

+ 1 - 10
.travis.yml

@@ -4,17 +4,8 @@ os:
   - osx
 mono:
   - latest
-solution: Avalonia.travis-mono.sln
-before_install:
-  - mkdir -p .nuget
-  - wget -O .nuget/nuget.exe https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
-install:
-  - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y gtk-sharp2 ; fi
-  - mono .nuget/nuget.exe restore Avalonia.sln
-  - mono .nuget/nuget.exe install xunit.runner.console -Version 2.1.0 -OutputDirectory testrunner
 script:
-  - xbuild /p:Platform=Mono /p:Configuration=Release Avalonia.sln
-  - ./tests/run-tests.sh
+  - ./build.sh --target "Travis" --platform "Mono" --configuration "Release"
 notifications:
   email: false
   webhooks:

+ 7 - 0
NuGet.Config

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <clear />
+    <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
+  </packageSources>
+</configuration>

+ 16 - 22
appveyor.yml

@@ -1,31 +1,25 @@
-version: 1.0.{build}
 os: Visual Studio 2015
-before_build:
-- git submodule update --init
-- nuget restore Avalonia.sln
-
+platform:
+- Any CPU
+configuration:
+- Release
 environment:
-  myget_key:
+  NUGET_API_KEY:
+    secure: ADD_SECURE_NUGET_API_KEY_HERE
+  NUGET_API_URL: https://www.nuget.org/api/v2/package
+  MYGET_API_KEY:
     secure: XOgD5bJUKNOS2kDDgb+affS4pDcslxALh+xvvnr1Koy0PjXlhILsBdNhxRe0KcNm
-
+  MYGET_API_URL: https://www.myget.org/F/avalonia-ci/api/v2
 install:
   - if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
   - msiexec /i gtk-sharp-2.12.26.msi /qn /norestart
   - cmd: set PATH=%programfiles(x86)%\GtkSharp\2.12\bin\;%PATH%
-
+before_build:
+- git submodule update --init
+build_script:
+- ps: .\build.ps1 -Target "AppVeyor" -Platform "$env:platform" -Configuration "$env:configuration"
+after_build:
+- .\packages\JetBrains.dotMemoryUnit.2.3.20160517.113140\tools\dotMemoryUnit.exe -targetExecutable="%xunit20%\xunit.console.x86.exe" -returnTargetExitCode  --"tests\Avalonia.LeakTests\bin\Release\Avalonia.LeakTests.dll"
+test: off
 cache:
   - gtk-sharp-2.12.26.msi
-  
-configuration:
-  - Release
-
-after_test:
-- .\packages\JetBrains.dotMemoryUnit.2.1.20150828.125449\tools\dotMemoryUnit.exe -targetExecutable="%xunit20%\xunit.console.x86.exe" -returnTargetExitCode  --"tests\Avalonia.LeakTests\bin\Release\Avalonia.LeakTests.dll"
-- ps: nuget\build-appveyor.ps1
-
-artifacts:
-  - path: nuget\*.nupkg
-
-build:
-  project: Avalonia.sln
-  verbosity: minimal

+ 733 - 0
build.cake

@@ -0,0 +1,733 @@
+///////////////////////////////////////////////////////////////////////////////
+// ADDINS
+///////////////////////////////////////////////////////////////////////////////
+
+#addin "nuget:?package=Polly&version=4.2.0"
+
+///////////////////////////////////////////////////////////////////////////////
+// TOOLS
+///////////////////////////////////////////////////////////////////////////////
+
+#tool "nuget:?package=xunit.runner.console&version=2.1.0"
+
+///////////////////////////////////////////////////////////////////////////////
+// USINGS
+///////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Polly;
+
+///////////////////////////////////////////////////////////////////////////////
+// ARGUMENTS
+///////////////////////////////////////////////////////////////////////////////
+
+var target = Argument("target", "Default");
+var platform = Argument("platform", "Any CPU");
+var configuration = Argument("configuration", "Release");
+
+///////////////////////////////////////////////////////////////////////////////
+// CONFIGURATION
+///////////////////////////////////////////////////////////////////////////////
+
+var MainRepo = "AvaloniaUI/Avalonia";
+var MasterBranch = "master";
+var AssemblyInfoPath = File("./src/Shared/SharedAssemblyInfo.cs");
+var ReleasePlatform = "Any CPU";
+var ReleaseConfiguration = "Release";
+var MSBuildSolution = "./Avalonia.sln";
+var XBuildSolution = "./Avalonia.sln";
+
+///////////////////////////////////////////////////////////////////////////////
+// PARAMETERS
+///////////////////////////////////////////////////////////////////////////////
+
+var isPlatformAnyCPU = StringComparer.OrdinalIgnoreCase.Equals(platform, "Any CPU");
+var isPlatformX86 = StringComparer.OrdinalIgnoreCase.Equals(platform, "x86");
+var isPlatformX64 = StringComparer.OrdinalIgnoreCase.Equals(platform, "x64");
+var isLocalBuild = BuildSystem.IsLocalBuild;
+var isRunningOnUnix = IsRunningOnUnix();
+var isRunningOnWindows = IsRunningOnWindows();
+var isRunningOnAppVeyor = BuildSystem.AppVeyor.IsRunningOnAppVeyor;
+var isPullRequest = BuildSystem.AppVeyor.Environment.PullRequest.IsPullRequest;
+var isMainRepo = StringComparer.OrdinalIgnoreCase.Equals(MainRepo, BuildSystem.AppVeyor.Environment.Repository.Name);
+var isMasterBranch = StringComparer.OrdinalIgnoreCase.Equals(MasterBranch, BuildSystem.AppVeyor.Environment.Repository.Branch);
+var isTagged = BuildSystem.AppVeyor.Environment.Repository.Tag.IsTag 
+               && !string.IsNullOrWhiteSpace(BuildSystem.AppVeyor.Environment.Repository.Tag.Name);
+var isReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, platform) 
+                   && StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, configuration);
+var isMyGetRelease = !isTagged && isReleasable;
+var isNuGetRelease = isTagged && isReleasable;
+
+///////////////////////////////////////////////////////////////////////////////
+// VERSION
+///////////////////////////////////////////////////////////////////////////////
+
+var version = ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion;
+
+if (isRunningOnAppVeyor)
+{
+    if (isTagged)
+    {
+        // Use Tag Name as version
+        version = BuildSystem.AppVeyor.Environment.Repository.Tag.Name;
+    }
+    else
+    {
+        // Use AssemblyVersion with Build as version
+        version += "-build" + EnvironmentVariable("APPVEYOR_BUILD_NUMBER") + "-alpha";
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// DIRECTORIES
+///////////////////////////////////////////////////////////////////////////////
+
+var artifactsDir = (DirectoryPath)Directory("./artifacts");
+var nugetRoot = artifactsDir.Combine("nuget");
+var binRoot = artifactsDir.Combine("bin");
+var zipBinArtifacts = artifactsDir.CombineWithFilePath("Avalonia-" + version + ".zip");
+
+var dirSuffix = configuration;
+var dirSuffixSkia = (isPlatformAnyCPU ? "x86" : platform) + "/" + configuration;
+var dirSuffixIOS = "iPhone" + "/" + configuration;
+
+var buildDirs = 
+    GetDirectories("./src/**/bin/" + dirSuffix) + 
+    GetDirectories("./src/**/obj/" + dirSuffix) + 
+    GetDirectories("./src/Markup/**/bin/" + dirSuffix) + 
+    GetDirectories("./src/Markup/**/obj/" + dirSuffix) + 
+    GetDirectories("./src/Android/**/bin/" + dirSuffix) + 
+    GetDirectories("./src/Android/**/obj/" + dirSuffix) + 
+    GetDirectories("./src/Gtk/**/bin/" + dirSuffix) + 
+    GetDirectories("./src/Gtk/**/obj/" + dirSuffix) + 
+    GetDirectories("./src/iOS/**/bin/" + dirSuffixIOS) + 
+    GetDirectories("./src/iOS/**/obj/" + dirSuffixIOS) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android/bin/" + dirSuffix) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android/obj/" + dirSuffix) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android.TestApp/bin/" + dirSuffix) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Android.TestApp/obj/" + dirSuffix) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Desktop/bin/" + dirSuffixSkia) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.Desktop/obj/" + dirSuffixSkia) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + dirSuffixIOS) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS/obj/" + dirSuffixIOS) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/bin/" + dirSuffixIOS) + 
+    (DirectoryPath)Directory("./src/Skia/Avalonia.Skia.iOS.TestApp/obj/" + dirSuffixIOS) + 
+    GetDirectories("./src/Windows/**/bin/" + dirSuffix) + 
+    GetDirectories("./src/Windows/**/obj/" + dirSuffix) + 
+    GetDirectories("./tests/**/bin/" + dirSuffix) + 
+    GetDirectories("./tests/**/obj/" + dirSuffix) + 
+    GetDirectories("./Samples/**/bin/" + dirSuffix) + 
+    GetDirectories("./Samples/**/obj/" + dirSuffix);
+
+///////////////////////////////////////////////////////////////////////////////
+// NUGET NUSPECS
+///////////////////////////////////////////////////////////////////////////////
+
+var SerilogVersion = "2.1.0";
+var SplatVersion = "1.6.2";
+var SpracheVersion = "2.0.0.52";
+var SystemReactiveVersion = "3.0.0";
+var SkiaSharpVersion = "1.53.0";
+var SharpDXVersion = "3.0.2";
+var SharpDXDirect2D1Version = "3.0.2";
+var SharpDXDXGIVersion = "3.0.2";
+
+var SetNuGetNuspecCommonProperties = new Action<NuGetPackSettings> ((nuspec) => {
+    nuspec.Version = version;
+    nuspec.Authors = new [] { "Avalonia Team" };
+    nuspec.Owners = new [] { "stevenk" };
+    nuspec.LicenseUrl = new Uri("http://opensource.org/licenses/MIT");
+    nuspec.ProjectUrl = new Uri("https://github.com/AvaloniaUI/Avalonia/");
+    nuspec.RequireLicenseAcceptance = false;
+    nuspec.Symbols = false;
+    nuspec.NoPackageAnalysis = true;
+    nuspec.Description = "The Avalonia UI framework";
+    nuspec.Copyright = "Copyright 2015";
+    nuspec.Tags = new [] { "Avalonia" };
+});
+
+var coreLibraries = new string[][]
+{
+    new [] { "./src/", "Avalonia.Animation", ".dll" },
+    new [] { "./src/", "Avalonia.Animation", ".xml" },
+    new [] { "./src/", "Avalonia.Base", ".dll" },
+    new [] { "./src/", "Avalonia.Base", ".xml" },
+    new [] { "./src/", "Avalonia.Controls", ".dll" },
+    new [] { "./src/", "Avalonia.Controls", ".xml" },
+    new [] { "./src/", "Avalonia.DesignerSupport", ".dll" },
+    new [] { "./src/", "Avalonia.DesignerSupport", ".xml" },
+    new [] { "./src/", "Avalonia.Diagnostics", ".dll" },
+    new [] { "./src/", "Avalonia.Diagnostics", ".xml" },
+    new [] { "./src/", "Avalonia.Input", ".dll" },
+    new [] { "./src/", "Avalonia.Input", ".xml" },
+    new [] { "./src/", "Avalonia.Interactivity", ".dll" },
+    new [] { "./src/", "Avalonia.Interactivity", ".xml" },
+    new [] { "./src/", "Avalonia.Layout", ".dll" },
+    new [] { "./src/", "Avalonia.Layout", ".xml" },
+    new [] { "./src/", "Avalonia.Logging.Serilog", ".dll" },
+    new [] { "./src/", "Avalonia.Logging.Serilog", ".xml" },
+    new [] { "./src/", "Avalonia.SceneGraph", ".dll" },
+    new [] { "./src/", "Avalonia.SceneGraph", ".xml" },
+    new [] { "./src/", "Avalonia.Styling", ".dll" },
+    new [] { "./src/", "Avalonia.Styling", ".xml" },
+    new [] { "./src/", "Avalonia.ReactiveUI", ".dll" },
+    new [] { "./src/", "Avalonia.Themes.Default", ".dll" },
+    new [] { "./src/", "Avalonia.Themes.Default", ".xml" },
+    new [] { "./src/Markup/", "Avalonia.Markup", ".dll" },
+    new [] { "./src/Markup/", "Avalonia.Markup", ".xml" },
+    new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".dll" },
+    new [] { "./src/Markup/", "Avalonia.Markup.Xaml", ".xml" }
+};
+
+var coreLibrariesFiles = coreLibraries.Select((lib) => {
+    return (FilePath)File(lib[0] + lib[1] + "/bin/" + dirSuffix + "/" + lib[1] + lib[2]);
+}).ToList();
+
+var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
+    return new NuSpecContent { 
+        Source = file.FullPath, Target = "lib/portable-windows8+net45" 
+    };
+});
+
+var nuspecNuGetSettingsCore = new []
+{
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Serilog", Version = SerilogVersion },
+            new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
+            new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
+            new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion }
+        },
+        Files = coreLibrariesNuSpecContent.ToList(),
+        BasePath = Directory("./"),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.HtmlRenderer
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.HtmlRenderer",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/portable-windows8+net45" }
+        },
+        BasePath = Directory("./src/Avalonia.HtmlRenderer/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    }
+};
+
+var nuspecNuGetSettingsMobile = new []
+{
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Android
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Android",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Skia.Android", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Android.dll", Target = "lib/MonoAndroid10" }
+        },
+        BasePath = Directory("./src/Android/Avalonia.Android/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Skia.Android
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Skia.Android",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Skia.Android.dll", Target = "lib/MonoAndroid10" }
+        },
+        BasePath = Directory("./src/Skia/Avalonia.Skia.Android/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.iOS
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.iOS",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Skia.iOS", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.iOS.dll", Target = "lib/Xamarin.iOS10" }
+        },
+        BasePath = Directory("./src/iOS/Avalonia.iOS/bin/" + dirSuffixIOS),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Skia.iOS
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Skia.iOS",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Skia.iOS.dll", Target = "lib/Xamarin.iOS10" }
+        },
+        BasePath = Directory("./src/Skia/Avalonia.Skia.iOS/bin/" + dirSuffixIOS),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Mobile
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Mobile",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia.Android", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.iOS", Version = version }
+        },
+        Files = new NuSpecContent[]
+        {
+            new NuSpecContent { Source = "licence.md", Target = "" }
+        },
+        BasePath = Directory("./"),
+        OutputDirectory = nugetRoot
+    }
+};
+
+var nuspecNuGetSettingsDesktop = new []
+{
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Win32
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Win32",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Win32.dll", Target = "lib/net45" }
+        },
+        BasePath = Directory("./src/Windows/Avalonia.Win32/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Direct2D1
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Direct2D1",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "SharpDX", Version = SharpDXVersion },
+            new NuSpecDependency() { Id = "SharpDX.Direct2D1", Version = SharpDXDirect2D1Version },
+            new NuSpecDependency() { Id = "SharpDX.DXGI", Version = SharpDXDXGIVersion }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/net45" }
+        },
+        BasePath = Directory("./src/Windows/Avalonia.Direct2D1/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Gtk
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Gtk",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Gtk.dll", Target = "lib/net45" }
+        },
+        BasePath = Directory("./src/Gtk/Avalonia.Gtk/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Cairo
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Cairo",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Cairo.dll", Target = "lib/net45" }
+        },
+        BasePath = Directory("./src/Gtk/Avalonia.Cairo/bin/" + dirSuffix),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Skia.Desktop
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Skia.Desktop",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia", Version = version },
+            new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion }
+        },
+        Files = new []
+        {
+            new NuSpecContent { Source = "Avalonia.Skia.Desktop.dll", Target = "lib/net45" }
+        },
+        BasePath = Directory("./src/Skia/Avalonia.Skia.Desktop/bin/" + dirSuffixSkia),
+        OutputDirectory = nugetRoot
+    },
+    ///////////////////////////////////////////////////////////////////////////////
+    // Avalonia.Desktop
+    ///////////////////////////////////////////////////////////////////////////////
+    new NuGetPackSettings()
+    {
+        Id = "Avalonia.Desktop",
+        Dependencies = new []
+        {
+            new NuSpecDependency() { Id = "Avalonia.Win32", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Gtk", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Cairo", Version = version },
+            new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = version }
+        },
+        Files = new NuSpecContent[]
+        {
+            new NuSpecContent { Source = "licence.md", Target = "" }
+        },
+        BasePath = Directory("./"),
+        OutputDirectory = nugetRoot
+    }
+};
+
+var nuspecNuGetSettings = new List<NuGetPackSettings>();
+
+nuspecNuGetSettings.AddRange(nuspecNuGetSettingsCore);
+nuspecNuGetSettings.AddRange(nuspecNuGetSettingsDesktop);
+nuspecNuGetSettings.AddRange(nuspecNuGetSettingsMobile);
+
+nuspecNuGetSettings.ForEach((nuspec) => SetNuGetNuspecCommonProperties(nuspec));
+
+var nugetPackages = nuspecNuGetSettings.Select(nuspec => {
+    return nuspec.OutputDirectory.CombineWithFilePath(string.Concat(nuspec.Id, ".", nuspec.Version, ".nupkg"));
+}).ToArray();
+
+var binFiles = nuspecNuGetSettings.SelectMany(nuspec => {
+    return nuspec.Files.Select(file => {
+        return ((DirectoryPath)nuspec.BasePath).CombineWithFilePath(file.Source);
+    });
+}).GroupBy(f => f.FullPath).Select(g => g.First());
+
+///////////////////////////////////////////////////////////////////////////////
+// INFORMATION
+///////////////////////////////////////////////////////////////////////////////
+
+Information("Building version {0} of Avalonia ({1}, {2}, {3}) using version {4} of Cake.", 
+    version,
+    platform,
+    configuration,
+    target,
+    typeof(ICakeContext).Assembly.GetName().Version.ToString());
+
+if (isRunningOnAppVeyor)
+{
+    Information("Repository Name: " + BuildSystem.AppVeyor.Environment.Repository.Name);
+    Information("Repository Branch: " + BuildSystem.AppVeyor.Environment.Repository.Branch);
+}
+
+Information("Target: " + target);
+Information("Platform: " + platform);
+Information("Configuration: " + configuration);
+Information("IsLocalBuild: " + isLocalBuild);
+Information("IsRunningOnUnix: " + isRunningOnUnix);
+Information("IsRunningOnWindows: " + isRunningOnWindows);
+Information("IsRunningOnAppVeyor: " + isRunningOnAppVeyor);
+Information("IsPullRequest: " + isPullRequest);
+Information("IsMainRepo: " + isMainRepo);
+Information("IsMasterBranch: " + isMasterBranch);
+Information("IsTagged: " + isTagged);
+Information("IsReleasable: " + isReleasable);
+Information("IsMyGetRelease: " + isMyGetRelease);
+Information("IsNuGetRelease: " + isNuGetRelease);
+
+///////////////////////////////////////////////////////////////////////////////
+// TASKS
+///////////////////////////////////////////////////////////////////////////////
+
+Task("Clean")
+    .Does(() =>
+{
+    CleanDirectories(buildDirs);
+    CleanDirectory(artifactsDir);
+    CleanDirectory(nugetRoot);
+    CleanDirectory(binRoot);
+});
+
+Task("Restore-NuGet-Packages")
+    .IsDependentOn("Clean")
+    .Does(() =>
+{
+    var maxRetryCount = 5;
+    var toolTimeout = 1d;
+    Policy
+        .Handle<Exception>()
+        .Retry(maxRetryCount, (exception, retryCount, context) => {
+            if (retryCount == maxRetryCount)
+            {
+                throw exception;
+            }
+            else
+            {
+                Verbose("{0}", exception);
+                toolTimeout+=0.5;
+            }})
+        .Execute(()=> {
+            if(isRunningOnWindows)
+            {
+                NuGetRestore(MSBuildSolution, new NuGetRestoreSettings {
+                    ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
+                });
+            }
+            else
+            {
+                NuGetRestore(XBuildSolution, new NuGetRestoreSettings {
+                    ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
+                });
+            }
+        });
+});
+
+Task("Build")
+    .IsDependentOn("Restore-NuGet-Packages")
+    .Does(() =>
+{
+    if(isRunningOnWindows)
+    {
+        MSBuild(MSBuildSolution, settings => {
+            settings.SetConfiguration(configuration);
+            settings.WithProperty("Platform", "\"" + platform + "\"");
+            settings.SetVerbosity(Verbosity.Minimal);
+            settings.WithProperty("Windows", "True");
+            settings.UseToolVersion(MSBuildToolVersion.VS2015);
+            settings.SetNodeReuse(false);
+        });
+    }
+    else
+    {
+        XBuild(XBuildSolution, settings => {
+            settings.SetConfiguration(configuration);
+            settings.WithProperty("Platform", "\"" + platform + "\"");
+            settings.SetVerbosity(Verbosity.Minimal);
+        });
+    }
+});
+
+Task("Run-Unit-Tests")
+    .IsDependentOn("Build")
+    .Does(() =>
+{
+    var pattern = "./tests/Avalonia.*.UnitTests/bin/" + dirSuffix + "/Avalonia.*.UnitTests.dll";
+
+    Func<IFileSystemInfo, bool> ExcludeWindowsTests = i => {
+        return !(i.Path.FullPath.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0);
+    };
+
+    var unitTests = isRunningOnWindows ? GetFiles(pattern) : GetFiles(pattern, ExcludeWindowsTests);
+
+    if (isRunningOnWindows)
+    {
+        var windowsTests = GetFiles("./tests/Avalonia.DesignerSupport.Tests/bin/" + dirSuffix + "/*Tests.dll") + 
+                           GetFiles("./tests/Avalonia.LeakTests/bin/" + dirSuffix + "/*Tests.dll") + 
+                           GetFiles("./tests/Avalonia.RenderTests/bin/" + dirSuffix + "/*Tests.dll");
+
+        unitTests += windowsTests;
+    }
+
+    var toolPath = (isPlatformAnyCPU || isPlatformX86) ? 
+        "./tools/xunit.runner.console/tools/xunit.console.x86.exe" :
+        "./tools/xunit.runner.console/tools/xunit.console.exe";
+
+    var settings = new XUnit2Settings 
+    { 
+        ToolPath = toolPath,
+        Parallelism = ParallelismOption.None 
+    };
+
+    if (isRunningOnWindows)
+    {
+        settings.NoAppDomain = false;
+    }
+
+    foreach (var file in unitTests)
+    {
+        Information("Running test " + file.GetFilenameWithoutExtension());
+        XUnit2(file.FullPath, settings);
+    }
+});
+
+Task("Copy-Files")
+    .IsDependentOn("Run-Unit-Tests")
+    .Does(() =>
+{
+    CopyFiles(binFiles, binRoot);
+});
+
+Task("Zip-Files")
+    .IsDependentOn("Copy-Files")
+    .Does(() =>
+{
+    Zip(binRoot, zipBinArtifacts);
+});
+
+Task("Create-NuGet-Packages")
+    .IsDependentOn("Run-Unit-Tests")
+    .Does(() =>
+{
+    foreach(var nuspec in nuspecNuGetSettings)
+    {
+        NuGetPack(nuspec);
+    }
+});
+
+Task("Upload-AppVeyor-Artifacts")
+    .IsDependentOn("Zip-Files")
+    .IsDependentOn("Create-NuGet-Packages")
+    .WithCriteria(() => isRunningOnAppVeyor)
+    .Does(() =>
+{
+    AppVeyor.UploadArtifact(zipBinArtifacts.FullPath);
+
+    foreach(var nupkg in nugetPackages)
+    {
+        AppVeyor.UploadArtifact(nupkg.FullPath);
+    }
+});
+
+Task("Publish-MyGet")
+    .IsDependentOn("Create-NuGet-Packages")
+    .WithCriteria(() => !isLocalBuild)
+    .WithCriteria(() => !isPullRequest)
+    .WithCriteria(() => isMainRepo)
+    .WithCriteria(() => isMasterBranch)
+    .WithCriteria(() => isMyGetRelease)
+    .Does(() =>
+{
+    var apiKey = EnvironmentVariable("MYGET_API_KEY");
+    if(string.IsNullOrEmpty(apiKey)) 
+    {
+        throw new InvalidOperationException("Could not resolve MyGet API key.");
+    }
+
+    var apiUrl = EnvironmentVariable("MYGET_API_URL");
+    if(string.IsNullOrEmpty(apiUrl)) 
+    {
+        throw new InvalidOperationException("Could not resolve MyGet API url.");
+    }
+
+    foreach(var nupkg in nugetPackages)
+    {
+        NuGetPush(nupkg, new NuGetPushSettings {
+            Source = apiUrl,
+            ApiKey = apiKey
+        });
+    }
+})
+.OnError(exception =>
+{
+    Information("Publish-MyGet Task failed, but continuing with next Task...");
+});
+
+Task("Publish-NuGet")
+    .IsDependentOn("Create-NuGet-Packages")
+    .WithCriteria(() => !isLocalBuild)
+    .WithCriteria(() => !isPullRequest)
+    .WithCriteria(() => isMainRepo)
+    .WithCriteria(() => isMasterBranch)
+    .WithCriteria(() => isNuGetRelease)
+    .Does(() =>
+{
+    var apiKey = EnvironmentVariable("NUGET_API_KEY");
+    if(string.IsNullOrEmpty(apiKey)) 
+    {
+        throw new InvalidOperationException("Could not resolve NuGet API key.");
+    }
+
+    var apiUrl = EnvironmentVariable("NUGET_API_URL");
+    if(string.IsNullOrEmpty(apiUrl)) 
+    {
+        throw new InvalidOperationException("Could not resolve NuGet API url.");
+    }
+
+    foreach(var nupkg in nugetPackages)
+    {
+        NuGetPush(nupkg, new NuGetPushSettings {
+            ApiKey = apiKey,
+            Source = apiUrl
+        });
+    }
+})
+.OnError(exception =>
+{
+    Information("Publish-NuGet Task failed, but continuing with next Task...");
+});
+
+///////////////////////////////////////////////////////////////////////////////
+// TARGETS
+///////////////////////////////////////////////////////////////////////////////
+
+Task("Package")
+  .IsDependentOn("Create-NuGet-Packages");
+
+Task("Default")
+  .IsDependentOn("Package");
+
+Task("AppVeyor")
+  .IsDependentOn("Upload-AppVeyor-Artifacts")
+  .IsDependentOn("Publish-MyGet")
+  .IsDependentOn("Publish-NuGet");
+
+Task("Travis")
+  .IsDependentOn("Run-Unit-Tests");
+
+///////////////////////////////////////////////////////////////////////////////
+// EXECUTE
+///////////////////////////////////////////////////////////////////////////////
+
+RunTarget(target);

+ 193 - 0
build.ps1

@@ -0,0 +1,193 @@
+##########################################################################
+# 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 ScriptArgs
+Remaining arguments are added here.
+
+.LINK
+http://cakebuild.net
+
+#>
+
+[CmdletBinding()]
+Param(
+    [string]$Script = "build.cake",
+    [string]$Target = "Default",
+    [ValidateSet("Any CPU", "x86", "x64", "Mono", "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,
+    [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
+    [string[]]$ScriptArgs
+)
+
+[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
+}
+
+$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"
+
+# Should we use mono?
+$UseMono = "";
+if($Mono.IsPresent) {
+    Write-Verbose -Message "Using the Mono based scripting engine."
+    $UseMono = "-mono"
+}
+
+# Should we use the new Roslyn?
+$UseExperimental = "";
+if($Experimental.IsPresent -and !($Mono.IsPresent)) {
+    Write-Verbose -Message "Using experimental version of Roslyn."
+    $UseExperimental = "-experimental"
+}
+
+# Is this a dry run?
+$UseDryRun = "";
+if($WhatIf.IsPresent) {
+    $UseDryRun = "-dryrun"
+}
+
+# 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
+}
+
+# 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."
+    }
+}
+
+# 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
+    }
+}
+
+# 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."
+    }
+}
+
+# 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
+    }
+
+    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"
+}
+
+# Start Cake
+Write-Host "Running build script..."
+Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -platform=`"$Platform`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
+exit $LASTEXITCODE

+ 103 - 0
build.sh

@@ -0,0 +1,103 @@
+#!/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.
+##########################################################################
+
+# 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=
+SHOW_VERSION=false
+SCRIPT_ARGUMENTS=()
+
+# Parse 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 ;;
+        -v|--verbosity) VERBOSITY="$2"; shift ;;
+        -d|--dryrun) DRYRUN="-dryrun" ;;
+        --version) SHOW_VERSION=true ;;
+        --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
+        *) SCRIPT_ARGUMENTS+=("$1") ;;
+    esac
+    shift
+done
+
+# Make sure the tools folder exist.
+if [ ! -d "$TOOLS_DIR" ]; then
+  mkdir "$TOOLS_DIR"
+fi
+
+# 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
+
+# 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
+
+# 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
+
+mono "$NUGET_EXE" install -ExcludeVersion
+if [ $? -ne 0 ]; then
+    echo "Could not restore NuGet packages."
+    exit 1
+fi
+
+$MD5_EXE $PACKAGES_CONFIG | awk '{ print $1 }' >| $PACKAGES_CONFIG_MD5
+
+popd >/dev/null
+
+# Make sure that Cake has been installed.
+if [ ! -f "$CAKE_EXE" ]; then
+    echo "Could not find Cake.exe at '$CAKE_EXE'."
+    exit 1
+fi
+
+# Start Cake
+if $SHOW_VERSION; then
+    exec mono "$CAKE_EXE" -version
+else
+    exec mono "$CAKE_EXE" $SCRIPT -verbosity=$VERBOSITY -platform="$PLATFORM" -configuration="$CONFIGURATION" -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}"
+fi

+ 86 - 0
docs/tutorial/nuget.md

@@ -0,0 +1,86 @@
+# Avalonia NuGet Packages
+
+Avalonia is divided into several `NuGet` packages. 
+
+* The `Avalonia` package contains core portable class libraries.
+* The `Dekstop` and `Mobile` packages contain platform specific windowing and rendering back-ends.
+* The `Avalonia.Desktop` package is intended to be used by the end users targeting multiple desktop platforms (`Windows`, `Linux` and `OSX`).
+* The `Avalonia.iOS` and `Avalonia.Android` packages are intended to be used by the end users targeting specific mobile platforms. 
+* The `Avalonia.Mobile` package is intended to be used by the end users targeting multiple mobile platforms (`Android` and `iOS`).
+
+## Core
+
+* Avalonia (.nupkg)
+  - Avalonia.Animation (.dll)
+  - Avalonia.Base (.dll)
+  - Avalonia.Controls (.dll)
+  - Avalonia.DesignerSupport (.dll)
+  - Avalonia.Diagnostics (.dll)
+  - Avalonia.Input (.dll)
+  - Avalonia.Interactivity (.dll)
+  - Avalonia.Layout (.dll)
+  - Avalonia.Logging.Serilog (.dll)
+  - Avalonia.SceneGraph (.dll)
+  - Avalonia.Styling (.dll)
+  - Avalonia.ReactiveUI (.dll)
+  - Avalonia.Themes.Default (.dll)
+  - Avalonia.Markup (.dll)
+  - Avalonia.Markup.Xaml (.dll)
+  - Serilog (.nupkg)
+  - Splat (.nupkg)
+  - Sprache (.nupkg)
+  - System.Reactive (.nupkg)
+
+* Avalonia.HtmlRenderer (.nupkg)
+  - Avalonia (.nupkg)
+
+## Desktop
+
+* Avalonia.Win32 (.nupkg)
+  - Avalonia.Win32 (.dll)
+  - Avalonia (.nupkg)
+
+* Avalonia.Direct2D1 (.nupkg)
+  - Avalonia.Direct2D1 (.dll)
+  - Avalonia (.nupkg)
+  - SharpDX (.nupkg)
+  - SharpDX.Direct2D1 (.nupkg)
+  - SharpDX.DXGI (.nupkg)
+
+* Avalonia.Gtk (.nupkg)
+  - Avalonia.Gtk (.dll)
+  - Avalonia (.nupkg)
+
+* Avalonia.Cairo (.nupkg)
+  - Avalonia.Cairo (.dll)
+  - Avalonia (.nupkg)
+
+* Avalonia.Skia.Desktop (.nupkg)
+  - Avalonia.Skia.Desktop (.dll)
+  - Avalonia (.nupkg)
+  - SkiaSharp (.nupkg)
+
+* Avalonia.Desktop (.nupkg)
+  - Avalonia.Win32 (.nupkg)
+  - Avalonia.Direct2D1 (.nupkg)
+  - Avalonia.Gtk (.nupkg)
+  - Avalonia.Cairo (.nupkg)
+  - Avalonia.Skia.Desktop (.nupkg)
+
+## Mobile
+
+* Avalonia.Android (.nupkg)
+  - Avalonia.Android (.dll)
+  - Avalonia.Skia.Android (.dll)
+  - Avalonia (.nupkg)
+  - SkiaSharp (.nupkg)
+
+* Avalonia.iOS (.nupkg)
+  - Avalonia.iOS (.dll)
+  - Avalonia.Skia.iOS (.dll)
+  - Avalonia (.nupkg)
+  - SkiaSharp (.nupkg)
+
+* Avalonia.Mobile (.nupkg)
+  - Avalonia.Android (.nupkg)
+  - Avalonia.iOS (.nupkg)

+ 4 - 0
docs/tutorial/toc.yml

@@ -1,2 +1,6 @@
 - name: Getting Started
   href: gettingstarted.md
+- name: Avalonia NuGet Packages
+  href: nuget.md
+- name: Avalonia for WPF Developers
+  href: from-wpf.md