diff --git a/.appveyor.yml b/.appveyor.yml
deleted file mode 100644
index 9df1571da9..0000000000
--- a/.appveyor.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-init:
- - git config --global core.autocrlf true
-branches:
- only:
- - master
- - /^release\/.*/
- - dev
- - /^(.*\/)?ci-.*$/
-install:
- - git submodule update --init --recursive
-skip_commits:
- message: /.*\[auto-updated:.*/
-build_script:
- - ps: .\run.ps1 default-build /t:CheckUniverse
-clone_depth: 1
-environment:
- global:
- DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- DOTNET_CLI_TELEMETRY_OPTOUT: 1
-test: off
-deploy: off
-os: Visual Studio 2017
diff --git a/.azure/pipelines/ci-official.yml b/.azure/pipelines/ci-official.yml
new file mode 100644
index 0000000000..50c32dca7b
--- /dev/null
+++ b/.azure/pipelines/ci-official.yml
@@ -0,0 +1,225 @@
+trigger:
+ branches:
+ include:
+ - master
+ - release/*
+ exclude:
+ - release/2.0
+
+phases:
+- phase: Windows
+ queue:
+ name: DotNetCore-Windows
+ timeoutInMinutes: 120
+ matrix:
+ Release:
+ BuildConfiguration: Release
+ variables:
+ CI: true
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+
+ # This variable is required by MicroBuildSigningPlugin to determine permissions for codesigning.
+ TeamName: AspNetCore
+
+ # SignType = { test, real }
+ # This is prefixed underscore because variables automatically become environment variables (and therefore MSBuild properties),
+ # and this one was causing issues in MSBuild projects which use the $(SignType) MSbuild prop.
+ _SignType: real
+
+ steps:
+ - task: NodeTool@0
+ displayName: Install Node 10.x
+ inputs:
+ versionSpec: 10.x
+ - task: MicroBuildSigningPlugin@1
+ displayName: Install MicroBuild plugin
+ condition: and(succeeded(), in(variables['_SignType'], 'test', 'real'))
+ inputs:
+ signType: $(_SignType)
+ zipSources: false
+ # TODO: configure build.cmd to build both x64 and x86 in one invocation
+ - script: build.cmd -ci /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:Build /t:BuildSharedFx /p:SharedFxRID=win-x64 /t:BuildFallbackArchive
+ displayName: Build NuGet packages and win-x64 runtime
+ - script: build.cmd -ci /p:SkipTests=true /p:Configuration=$(BuildConfiguration) /p:BuildNumber=$(Build.BuildNumber) /t:BuildSharedFx /p:SharedFxRID=win-x86
+ displayName: Build win-x86 runtime
+ - powershell: >
+ src/Installers/Windows/clone_and_build_ancm.ps1
+ -GitCredential '$(dn-bot-devdiv-build-rw-code-rw)'
+ -Config $(BuildConfiguration)
+ -BuildNumber $(Build.BuildNumber)
+ -SignType $(_SignType)
+ displayName: Build ANCM installers
+ # TODO: configure harvesting to run as a part of build.cmd so we don't need a hard-coded version here.
+ - powershell: >
+ src/Installers/Windows/build.ps1
+ -x64 artifacts/runtime/aspnetcore-runtime-internal-2.1.6-servicing-$(Build.BuildNumber)-win-x64.zip
+ -x86 artifacts/runtime/aspnetcore-runtime-internal-2.1.6-servicing-$(Build.BuildNumber)-win-x86.zip
+ -Config $(BuildConfiguration)
+ -BuildNumber $(Build.BuildNumber)
+ -SignType $(_SignType)
+ displayName: Build Windows installers
+ - task: PublishTestResults@2
+ displayName: Publish test results
+ condition: always()
+ inputs:
+ testRunner: vstest
+ testResultsFiles: 'artifacts/logs/**/*.trx'
+ - task: PublishBuildArtifacts@1
+ displayName: Upload artifacts
+ condition: eq(variables['system.pullrequest.isfork'], false)
+ inputs:
+ pathtoPublish: ./artifacts/
+ artifactName: artifacts-Windows-Release
+ artifactType: Container
+ # Detect OSS Components in use in the product. Only needs to run on one OS in the matrix.
+ - task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
+ displayName: 'Component Detection'
+ inputs:
+ # This funky GUID represents the product "ASP.NET and EF Core"
+ governanceProduct: 'c641993b-8380-e811-80c3-0004ffb4789e'
+ snapshotForceEnabled: true
+ - task: MicroBuildCleanup@1
+ displayName: Cleanup MicroBuild tasks
+ condition: always()
+
+- phase: macOS
+ dependsOn: Windows
+ queue:
+ name: Hosted macOS Preview
+ matrix:
+ Release:
+ BuildConfiguration: Release
+ variables:
+ CI: true
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download artifacts
+ inputs:
+ artifactName: artifacts-Windows-Release
+ downloadPath: $(Build.SourcesDirectory)/.deps
+ itemPattern: '**/*.nupkg'
+ # Workaround https://github.com/Microsoft/vsts-tasks/issues/6739
+ - task: CopyFiles@2
+ displayName: Copy package assets to correct folder
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/.deps/artifacts-Windows-Release
+ targetFolder: $(Build.SourcesDirectory)/.deps
+ - script: >
+ ./build.sh
+ --ci
+ /t:Prepare
+ /t:Restore
+ /t:GeneratePropsFiles
+ /t:BuildSharedFx
+ /p:SharedFxRID=osx-x64
+ /p:BuildNumber=$(Build.BuildNumber)
+ displayName: Build osx-x64 runtime
+ - task: PublishTestResults@2
+ displayName: Publish test results
+ condition: always()
+ inputs:
+ testRunner: vstest
+ testResultsFiles: 'artifacts/logs/**/*.trx'
+ - task: PublishBuildArtifacts@1
+ displayName: Upload artifacts
+ condition: eq(variables['system.pullrequest.isfork'], false)
+ inputs:
+ pathtoPublish: ./artifacts/
+ artifactName: artifacts-macOS-Release
+ artifactType: Container
+
+- phase: Linux
+ dependsOn:
+ - Windows
+ - macOS
+ queue:
+ name: DotNetCore-Linux
+ matrix:
+ Release:
+ BuildConfiguration: Release
+ variables:
+ CI: true
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download artifacts
+ inputs:
+ artifactName: artifacts-Windows-Release
+ downloadPath: $(Build.SourcesDirectory)/.deps
+ itemPattern: '**/*.nupkg'
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Windows artifacts
+ inputs:
+ artifactName: artifacts-Windows-Release
+ downloadPath: $(Build.SourcesDirectory)/.r
+ itemPattern: '**/aspnetcore-runtime-*'
+ - task: DownloadBuildArtifacts@0
+ displayName: Download macOS artifacts
+ inputs:
+ artifactName: artifacts-macOS-Release
+ downloadPath: $(Build.SourcesDirectory)/.r
+ itemPattern: '**/aspnetcore-runtime-*'
+ # Workaround https://github.com/Microsoft/vsts-tasks/issues/6739
+ - task: CopyFiles@2
+ displayName: Copy package assets to correct folder
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/.deps/artifacts-Windows-Release
+ targetFolder: $(Build.SourcesDirectory)/.deps
+ # TODO: Make the cumulative zips build in their own step
+ - task: CopyFiles@2
+ displayName: Copy package assets to correct folder
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/.r/artifacts-Windows-Release
+ targetFolder: $(Build.SourcesDirectory)/artifacts/
+ - task: CopyFiles@2
+ displayName: Copy package assets to correct folder
+ inputs:
+ sourceFolder: $(Build.SourcesDirectory)/.r/artifacts-macOS-Release
+ targetFolder: $(Build.SourcesDirectory)/artifacts/
+ - script: >
+ ./build.sh
+ --ci
+ /t:Prepare
+ /t:Restore
+ /t:GeneratePropsFiles
+ /t:BuildSharedFx
+ /p:SharedFxRID=linux-x64
+ /p:BuildNumber=$(Build.BuildNumber)
+ displayName: Build linux-x64 runtime
+ - script: >
+ ./build.sh
+ --ci
+ /t:BuildSharedFx
+ /p:SharedFxRID=linux-arm
+ /p:BuildNumber=$(Build.BuildNumber)
+ displayName: Build linux-arm runtime
+ - script: >
+ ./dockerbuild.sh
+ alpine
+ /t:Prepare
+ /t:GeneratePropsFiles
+ /t:BuildSharedFx
+ /p:SharedFxRID=linux-musl-x64
+ /p:BuildNumber=$(Build.BuildNumber)
+ displayName: Build linux-musl-x64 runtime
+ # TODO: configure installers to run in one build.sh invocation
+ - script: >
+ ./build.sh
+ --ci
+ /t:BuildInstallers
+ /p:_SharedFxSourceDir=$(Build.SourcesDirectory)/artifacts/runtime/
+ displayName: Build linux installers
+ - task: PublishTestResults@2
+ displayName: Publish test results
+ condition: always()
+ inputs:
+ testRunner: vstest
+ testResultsFiles: 'artifacts/logs/**/*.trx'
+ - task: PublishBuildArtifacts@1
+ displayName: Upload artifacts
+ condition: eq(variables['system.pullrequest.isfork'], false)
+ inputs:
+ pathtoPublish: ./artifacts/
+ artifactName: artifacts-Linux-Release
+ artifactType: Container
diff --git a/.gitignore b/.gitignore
index 19ef7b5771..9f2e95e1d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
-bin
-obj
+bin/
+obj/
.vs/
*.suo
*.user
@@ -11,11 +11,9 @@ _ReSharper.*
*.psess
*.binlog
*.log
-packages
-target
-artifacts
+artifacts/
StyleCop.Cache
-node_modules
+node_modules/
*.snk
.nuget
.r
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index ffb7a95841..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-language: csharp
-sudo: false
-dist: trusty
-env:
- global:
- - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
- - DOTNET_CLI_TELEMETRY_OPTOUT: 1
-mono: none
-addons:
- apt:
- packages:
- - libunwind8
-branches:
- only:
- - master
- - /^release\/.*/
- - dev
- - /^(.*\/)?ci-.*$/
-script:
- - ./build.sh -t:CheckUniverse
diff --git a/Directory.Build.props b/Directory.Build.props
index 153d8f33f9..4316633c71 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,10 +1,26 @@
-
+
+
+ Microsoft ASP.NET Core
+ $(MSBuildThisFileDirectory)
+ https://github.com/aspnet/Universe
+ git
+ $(MSBuildThisFileDirectory)eng\AspNetCore.snk
+ true
+ true
+
+
- $(MSBuildThisFileDirectory)
+ $(RepositoryRoot)artifacts\
+ $(ArtifactsDir)obj\
+ $(ArtifactsDir)$(Configuration)\
+ $(ArtifactsConfigurationDir)bin\
+ $(ArtifactsConfigurationDir)packages\
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 692f3a81da..755d556547 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -1,6 +1,9 @@
+ $(MicrosoftNETCoreApp20PackageVersion)
$(MicrosoftNETCoreApp21PackageVersion)
$(NETStandardLibrary20PackageVersion)
+
+
diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES
new file mode 100644
index 0000000000..a6470f40de
--- /dev/null
+++ b/THIRD-PARTY-NOTICES
@@ -0,0 +1,37 @@
+.NET Core uses third-party libraries or other resources that may be
+distributed under licenses different than the .NET Core software.
+
+In the event that we accidentally failed to list a required notice, please
+bring it to our attention. Post an issue or email us:
+
+ dotnet@microsoft.com
+
+The attached notices are provided for information only.
+
+License notice for dotnet-deb-tool
+------------------------------------
+
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/build/SharedFx.props b/build/SharedFx.props
index 7d2ccaf754..ee9deb9c6e 100644
--- a/build/SharedFx.props
+++ b/build/SharedFx.props
@@ -4,11 +4,10 @@
<_WorkRoot>$(RepositoryRoot).w\
<_WorkLayoutDir>$(_WorkRoot).l\
<_WorkOutputDir>$(_WorkRoot).o\
- <_MetapackageSrcRoot>$(RepositoryRoot)src\
+ <_MetapackageSrcRoot>$(RepositoryRoot)src\Packages\
<_TemplatesDir>$(MSBuildThisFileDirectory)tools\templates\
<_DockerDir>$(MSBuildThisFileDirectory)tools\docker\
<_PackagingDir>$(MSBuildThisFileDirectory)tools\packaging\
- <_DebToolDir>$(MSBuildThisFileDirectory)tools\dotnet-deb-tool-consumer\
<_SharedFxSourceDir>$(RepositoryRoot).deps\Signed\SharedFx\
<_InstallerSourceDir>$(RepositoryRoot).deps\Installers\
<_SymbolsSourceDir>$(RepositoryRoot).deps\symbols\
@@ -17,6 +16,8 @@
:
%3B
+ .tar.gz
+ .zip
lib
.so
diff --git a/build/SharedFx.targets b/build/SharedFx.targets
index 7cbdb99c5c..7b3592d650 100644
--- a/build/SharedFx.targets
+++ b/build/SharedFx.targets
@@ -1,5 +1,4 @@
-
@@ -8,9 +7,9 @@
- <_MetapackageProject Include="$(RepositoryRoot)src\Microsoft.AspNetCore.All\Microsoft.AspNetCore.All.csproj" />
- <_MetapackageProject Include="$(RepositoryRoot)src\Microsoft.AspNetCore.App\Microsoft.AspNetCore.App.csproj" />
- <_MetapackageProject Include="$(RepositoryRoot)src\Microsoft.AspNetCore.Analyzers\Microsoft.AspNetCore.Analyzers.csproj" />
+ <_MetapackageProject Include="$(RepositoryRoot)src\Packages\Microsoft.AspNetCore.All\Microsoft.AspNetCore.All.csproj" />
+ <_MetapackageProject Include="$(RepositoryRoot)src\Packages\Microsoft.AspNetCore.App\Microsoft.AspNetCore.App.csproj" />
+ <_MetapackageProject Include="$(RepositoryRoot)src\Packages\Microsoft.AspNetCore.Analyzers\Microsoft.AspNetCore.Analyzers.csproj" />
$(_MetapackageSrcRoot)$(MetapackageName)\
- $(_WorkRoot)$(MetapackageName)\
+ $(_WorkRoot)pkg\$(MetapackageName)\
$(CommonProps);Configuration=$(Configuration)
$(CommonProps);DotNetRestoreSourcePropsPath=$(GeneratedRestoreSourcesPropsPath)
@@ -48,7 +47,7 @@
@@ -109,7 +108,7 @@
BuildInParallel="false" />
-
+
true
false
@@ -165,12 +164,12 @@
Properties="$(RestoreProps);_Target=Restore;RestoreForce=true" />
-
+
- SharedFxWorkDirectory=$(AppSharedFxWorkDirectory)
+ RepositoryCommit=$(RepositoryCommit);SharedFxWorkDirectory=$(AppSharedFxWorkDirectory)
$(AppSharedFxProps);RuntimeFrameworkVersion=$(MicrosoftNETCoreApp21PackageVersion)
$(AppSharedFxProps);SharedFxPackage=Microsoft.AspNetCore.App
- SharedFxWorkDirectory=$(AllSharedFxWorkDirectory)
+ RepositoryCommit=$(RepositoryCommit);SharedFxWorkDirectory=$(AllSharedFxWorkDirectory)
$(AllSharedFxProps);RuntimeFrameworkVersion=$(MicrosoftNETCoreApp21PackageVersion)
$(AllSharedFxProps);SharedFxPackage=Microsoft.AspNetCore.All
$(AllSharedFxProps);SharedFxDep=Microsoft.AspNetCore.App
@@ -178,7 +177,7 @@
-
+
@@ -186,9 +185,9 @@
-
+
-
+
@@ -515,8 +514,10 @@
-
-
+
+
-
-
+
+ $(RepositoryRoot)src/Installers/Debian/build.sh
+
-
+
diff --git a/build/common.props b/build/common.props
deleted file mode 100644
index b34f91a0b1..0000000000
--- a/build/common.props
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Microsoft ASP.NET Core
- https://github.com/aspnet/Universe
- git
- false
- ..\..\build\Key.snk
- true
- true
- true
-
-
-
diff --git a/build/repo.targets b/build/repo.targets
index bba113bb1c..26f42adaed 100644
--- a/build/repo.targets
+++ b/build/repo.targets
@@ -205,8 +205,8 @@
Condition="'$(KOREBUILD_REPOSITORY_INCLUDE)' != '' AND '$(KOREBUILD_REPOSITORY_EXCLUDE)' != ''" />
-
-
+
+
diff --git a/build/submodules.props b/build/submodules.props
index 6ce4b071a5..2a0bf13984 100644
--- a/build/submodules.props
+++ b/build/submodules.props
@@ -22,10 +22,12 @@
-->
ProductChangesOnly
+
false
ProductChangesOnly
+
diff --git a/build/tools/dotnet-deb-tool-consumer/dotnet-deb-tool-consumer.csproj b/build/tools/dotnet-deb-tool-consumer/dotnet-deb-tool-consumer.csproj
deleted file mode 100644
index d2fa226fc4..0000000000
--- a/build/tools/dotnet-deb-tool-consumer/dotnet-deb-tool-consumer.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- netcoreapp2.0
- $(RestoreSources);https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json
- true
-
-
-
-
-
-
-
diff --git a/build/Key.snk b/eng/AspNetCore.snk
similarity index 100%
rename from build/Key.snk
rename to eng/AspNetCore.snk
diff --git a/eng/targets/MicroBuild.Plugin.props b/eng/targets/MicroBuild.Plugin.props
new file mode 100644
index 0000000000..0101904811
--- /dev/null
+++ b/eng/targets/MicroBuild.Plugin.props
@@ -0,0 +1,12 @@
+
+
+
+
+ $(MicroBuildOverridePluginDirectory)
+
+
+ $(NuGetPackageRoot)
+ $(NUGET_PACKAGES)
+ $(USERPROFILE)\.nuget\packages
+
+
diff --git a/eng/targets/Wix.Common.props b/eng/targets/Wix.Common.props
new file mode 100644
index 0000000000..d958514aba
--- /dev/null
+++ b/eng/targets/Wix.Common.props
@@ -0,0 +1,32 @@
+
+
+
+
+ 2.0
+ 3.11
+ 3.11.1
+
+
+
+
+ net461
+ $(BaseIntermediateOutputPath)
+ $(MSBuildProjectDir)\obj\
+ $(MSBuildExtensionsPath)\..\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets
+
+
+
+
+
+
+
+
+
+ true
+ $(WixExtDir)dark.exe
+
+
+
+
+
+
diff --git a/eng/targets/Wix.Common.targets b/eng/targets/Wix.Common.targets
new file mode 100644
index 0000000000..4b07606e19
--- /dev/null
+++ b/eng/targets/Wix.Common.targets
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+ Microsoft400
+
+
+ Microsoft400
+
+
+ Microsoft400
+
+
+ Microsoft400
+
+
+
+
+
+
+
+
+
+ yes
+ $(OutputName.Replace('-', '_')).cab
+ $(ProductName)
+
+ $(DefineConstants);Debug
+ $(DefineConstants);EmbedCab=$(EmbedCab)
+ $(DefineConstants);Cabinet=$(Cabinet)
+
+
+
+ en-US
+ $(Culture)
+ $(Platform)
+ $(Platform)
+ $(OutputPath)
+ $(DefineConstants);BinPath=$(OutputPath)$(Culture)\
+ $(WixVariables);$(DefineConstants)
+
+
+
+
+
+
+
+
diff --git a/scripts/common.psm1 b/scripts/common.psm1
index 4e43dc35fb..9a4900258c 100644
--- a/scripts/common.psm1
+++ b/scripts/common.psm1
@@ -1,4 +1,6 @@
$ErrorActionPreference = 'Stop'
+# Update the default TLS support to 1.2
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
function Assert-Git {
if (!(Get-Command git -ErrorAction Ignore)) {
@@ -7,19 +9,31 @@ function Assert-Git {
}
}
-function Invoke-Block([scriptblock]$cmd) {
- $cmd | Out-String | Write-Verbose
- & $cmd
+function Invoke-Block([scriptblock]$cmd, [string]$WorkingDir = $null) {
+ if ($WorkingDir) {
+ Push-Location $WorkingDir
+ }
- # Need to check both of these cases for errors as they represent different items
- # - $?: did the powershell script block throw an error
- # - $lastexitcode: did a windows command executed by the script block end in error
- if ((-not $?) -or ($lastexitcode -ne 0)) {
- if ($error -ne $null)
- {
- Write-Warning $error[0]
+ try {
+
+ $cmd | Out-String | Write-Verbose
+ & $cmd
+
+ # Need to check both of these cases for errors as they represent different items
+ # - $?: did the powershell script block throw an error
+ # - $lastexitcode: did a windows command executed by the script block end in error
+ if ((-not $?) -or ($lastexitcode -ne 0)) {
+ if ($error -ne $null)
+ {
+ Write-Warning $error[0]
+ }
+ throw "Command failed to execute: $cmd"
+ }
+ }
+ finally {
+ if ($WorkingDir) {
+ Pop-Location
}
- throw "Command failed to execute: $cmd"
}
}
@@ -230,3 +244,72 @@ function UpdateVersions([hashtable]$variables, [xml]$dependencies, [string]$deps
return $updatedVars
}
+
+function Get-MSBuildPath {
+ param(
+ [switch]$Prerelease,
+ [string[]]$Requires
+ )
+
+ $vsInstallDir = $null
+ if ($env:VSINSTALLDIR -and (Test-Path $env:VSINSTALLDIR)) {
+ $vsInstallDir = $env:VSINSTALLDIR
+ Write-Verbose "Using VSINSTALLDIR=$vsInstallDir"
+ }
+ else {
+ $vswhere = "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe"
+ Write-Verbose "Using vswhere.exe from $vswhere"
+
+ if (-not (Test-Path $vswhere)) {
+ Write-Error "Missing prerequisite: could not find vswhere"
+ }
+
+ [string[]] $vswhereArgs = @()
+
+ if ($Prerelease) {
+ $vswhereArgs += '-prerelease'
+ }
+
+ if ($Requires) {
+ foreach ($r in $Requires) {
+ $vswhereArgs += '-requires', $r
+ }
+ }
+
+ $installs = & $vswhere -format json -version '[15.0, 16.0)' -latest -products * @vswhereArgs | ConvertFrom-Json
+ if (!$installs) {
+ Write-Error "Missing prerequisite: could not find any installations of Visual Studio"
+ }
+
+ $vs = $installs | Select-Object -First 1
+ $vsInstallDir = $vs.installationPath
+ Write-Host "Using $($vs.displayName)"
+ }
+
+ $msbuild = Join-Path $vsInstallDir 'MSBuild/15.0/bin/msbuild.exe'
+ if (!(Test-Path $msbuild)) {
+ Write-Error "Missing prerequisite: could not find msbuild.exe"
+ }
+ return $msbuild
+}
+
+function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) {
+ if ($RemotePath -notlike 'http*') {
+ Copy-Item $RemotePath $LocalPath
+ return
+ }
+
+ $retries = 10
+ while ($retries -gt 0) {
+ $retries -= 1
+ try {
+ Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath
+ return
+ }
+ catch {
+ Write-Verbose "Request failed. $retries retries remaining"
+ }
+ }
+
+ Write-Error "Download failed: '$RemotePath'."
+}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
deleted file mode 100644
index 34fdc31455..0000000000
--- a/src/Directory.Build.props
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/Installers/Debian/build.sh b/src/Installers/Debian/build.sh
new file mode 100755
index 0000000000..6bd678c8ef
--- /dev/null
+++ b/src/Installers/Debian/build.sh
@@ -0,0 +1,272 @@
+#!/usr/bin/env bash
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+set -e
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+## Load Functions ##
+source $SCRIPT_DIR/scripts/debian_build_lib.sh
+
+## Debian Package Creation Functions ##
+execute(){
+ if ! parse_args_and_set_env_vars "$@"; then
+ exit 1
+ fi
+
+ # Exit if required validation fails
+ if ! validate_inputs; then
+ exit 1
+ fi
+
+ parse_config_and_set_env_vars
+ clean_or_create_build_dirs
+ package_all
+ generate_all
+ create_source_tarball
+
+ # Actually Build Package Files
+ (cd ${PACKAGE_SOURCE_DIR}; debuild -us -uc)
+
+ copy_files_to_output
+}
+
+parse_args_and_set_env_vars(){
+ OPTIND=1 # Reset in case getopts has been used previously in the shell.
+
+ while getopts ":n:v:i:o:h" opt; do
+ case $opt in
+ n)
+ export PACKAGE_NAME="$OPTARG"
+ ;;
+ v)
+ export PACKAGE_VERSION="$OPTARG"
+ ;;
+ i)
+ export INPUT_DIR="$OPTARG"
+ ;;
+ o)
+ export OUTPUT_DIR="$OPTARG"
+ ;;
+ h)
+ print_help
+ return 1
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ return 1
+ ;;
+ :)
+ echo "Option -$OPTARG requires an argument." >&2
+ return 1
+ ;;
+ esac
+ done
+
+ # Special Input Directories + Paths
+ ABSOLUTE_PLACEMENT_DIR="${INPUT_DIR}/\$"
+ PACKAGE_ROOT_PLACEMENT_DIR="${INPUT_DIR}/package_root"
+ CONFIG="$INPUT_DIR/debian_config.json"
+
+ return 0
+}
+
+print_help(){
+ echo "Usage: package_tool [-i ] [-o ]
+ [-n ] [-v ] [-h]
+
+ REQUIRED:
+ -i : Input directory conforming to package_tool conventions and debian_config.json
+ -o : Output directory for debian package and other artifacts
+
+ OPTIONAL:
+ -n : name of created package, will override value in debian_config.json
+ -v : version of created package, will override value in debian_config.json
+ -h: Show this message
+
+ NOTES:
+ See Readme for more information on package_tool conventions and debian_config.json format
+ https://github.com/dotnet/cli/tree/master/packaging/debian/package_tool
+ "
+}
+
+validate_inputs(){
+ local ret=0
+ if [[ -z "$INPUT_DIR" ]]; then
+ echo "ERROR: -i Not Specified"
+ ret=1
+ fi
+
+ if [[ -z "$OUTPUT_DIR" ]]; then
+ echo "ERROR: -o Not Specified."
+ ret=1
+ fi
+
+ if [[ ! -d "$PACKAGE_ROOT_PLACEMENT_DIR" ]]; then
+ echo "ERROR: package_root directory does not exist"
+ echo $PACKAGE_ROOT_PLACEMENT_DIR
+ ret=1
+ fi
+
+ if [[ ! -f "$CONFIG" ]]; then
+ echo "ERROR: debian_config.json file does not exist"
+ echo $CONFIG
+ ret=1
+ fi
+
+ return $ret
+}
+
+parse_config_and_set_env_vars(){
+ extract_base_cmd="python $SCRIPT_DIR/scripts/extract_json_value.py"
+
+ # Arguments Take Precedence over Config
+ [ -z "$PACKAGE_VERSION" ] && PACKAGE_VERSION="$($extract_base_cmd $CONFIG "release.package_version")"
+ [ -z "$PACKAGE_NAME" ] && PACKAGE_NAME="$($extract_base_cmd $CONFIG "package_name")"
+
+ # Inputs
+ INPUT_SAMPLES_DIR="$INPUT_DIR/samples"
+ INPUT_DOCS_DIR="$INPUT_DIR/docs"
+ DOCS_JSON_PATH="$INPUT_DIR/docs.json"
+
+ PACKAGE_SOURCE_DIR="${OUTPUT_DIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}"
+
+ if ! INSTALL_ROOT="$($extract_base_cmd $CONFIG "install_root")"; then
+ INSTALL_ROOT="/usr/share/$PACKAGE_NAME"
+ fi
+
+ DEBIAN_DIR="${PACKAGE_SOURCE_DIR}/debian"
+ DOCS_DIR="${PACKAGE_SOURCE_DIR}/docs"
+}
+
+clean_or_create_build_dirs(){
+ rm -rf ${PACKAGE_SOURCE_DIR}
+ mkdir -p $DEBIAN_DIR
+}
+
+package_all(){
+ package_static_files
+ package_package_root_placement
+ package_absolute_placement
+ package_samples
+ package_docs
+ package_install_scripts
+}
+
+generate_all(){
+ generate_config_templates
+ generate_manpages
+ generate_manpage_manifest
+ generate_sample_manifest
+ write_debian_install_file
+}
+
+create_source_tarball(){
+ rm -f ${OUTPUT_DIR}/${PACKAGE_NAME}_${PACKAGE_VERSION}.orig.tar.gz
+ tar -cvzf ${OUTPUT_DIR}/${PACKAGE_NAME}_${PACKAGE_VERSION}.orig.tar.gz -C $PACKAGE_SOURCE_DIR .
+}
+
+copy_files_to_output(){
+ # .deb, .dsc, etc.. Already in output dir
+ # Copy Test files
+
+ cp $SCRIPT_DIR/test/integration_tests/test_package.bats $OUTPUT_DIR
+}
+
+## Packaging Functions ##
+package_static_files(){
+ cp -a $SCRIPT_DIR/package_files/debian/* ${PACKAGE_SOURCE_DIR}/debian
+}
+
+package_package_root_placement(){
+ add_dir_to_install ${PACKAGE_ROOT_PLACEMENT_DIR} ""
+}
+
+package_absolute_placement(){
+ if [[ -d "$ABSOLUTE_PLACEMENT_DIR" ]]; then
+ abs_in_package_dir="\$"
+
+ add_dir_to_install ${ABSOLUTE_PLACEMENT_DIR} $abs_in_package_dir
+
+ # Get List of all files in directory tree, relative to ABSOLUTE_PLACEMENT_DIR
+ abs_files=( $(_get_files_in_dir_tree $ABSOLUTE_PLACEMENT_DIR) )
+
+ # For each file add a a system placement
+ for abs_file in ${abs_files[@]}
+ do
+ parent_dir=$(dirname $abs_file)
+ filename=$(basename $abs_file)
+
+ add_system_file_placement "$abs_in_package_dir/$abs_file" "/$parent_dir"
+ done
+ fi
+}
+
+package_samples(){
+ if [[ -d "$INPUT_SAMPLES_DIR" ]]; then
+ cp -a $INPUT_SAMPLES_DIR/. $PACKAGE_SOURCE_DIR
+ fi
+}
+
+package_docs(){
+ if [[ -d "$INPUT_DOCS_DIR" ]]; then
+ mkdir -p $DOCS_DIR
+ cp -a $INPUT_DOCS_DIR/. $DOCS_DIR
+ fi
+}
+
+package_install_scripts(){
+ # copy scripts for the package's control section like preinst, postint, etc
+ if [[ -d "$INPUT_DIR/debian" ]]; then
+ cp -a "$INPUT_DIR/debian/." $DEBIAN_DIR
+ fi
+}
+
+## Generation Functions ##
+generate_config_templates(){
+ python ${SCRIPT_DIR}/scripts/config_template_generator.py $CONFIG $SCRIPT_DIR/templates/debian $DEBIAN_DIR $PACKAGE_NAME $PACKAGE_VERSION
+}
+
+generate_manpages(){
+ if [[ -f "$DOCS_JSON_PATH" ]]; then
+ mkdir -p $DOCS_DIR
+
+ # Generate the manpages from json spec
+ python ${SCRIPT_DIR}/scripts/manpage_generator.py ${DOCS_JSON_PATH} ${DOCS_DIR}
+ fi
+}
+
+generate_manpage_manifest(){
+ # Get a list of files generated relative to $DOCS_DIR
+ generated_manpages=( $(_get_files_in_dir_tree $DOCS_DIR) )
+
+ # Get path relative to $PACKAGE_SOURCE_DIR to prepend to each filename
+ # This syntax is bash substring removal
+ docs_rel_path=${DOCS_DIR#${PACKAGE_SOURCE_DIR}/}
+
+ # Remove any existing manifest
+ rm -f ${DEBIAN_DIR}/${PACKAGE_NAME}.manpages
+
+ for manpage in ${generated_manpages[@]}
+ do
+ echo "${docs_rel_path}/${manpage}" >> "${DEBIAN_DIR}/${PACKAGE_NAME}.manpages"
+ done
+}
+
+generate_sample_manifest(){
+ if [[ -d "$INPUT_SAMPLES_DIR" ]]; then
+ generated_manpages=( $(_get_files_in_dir_tree $INPUT_SAMPLES_DIR) )
+
+ rm -f sample_manifest
+ for sample in ${samples[@]}
+ do
+ echo "$sample" >> "${DEBIAN_DIR}/${PACKAGE_NAME}.examples"
+ done
+ else
+ echo "Provide a 'samples' directory in INPUT_DIR to package samples"
+ fi
+}
+
+execute "$@"
diff --git a/src/Installers/Debian/package_files/debian/compat b/src/Installers/Debian/package_files/debian/compat
new file mode 100755
index 0000000000..ec635144f6
--- /dev/null
+++ b/src/Installers/Debian/package_files/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/src/Installers/Debian/package_files/debian/source/format b/src/Installers/Debian/package_files/debian/source/format
new file mode 100755
index 0000000000..163aaf8d82
--- /dev/null
+++ b/src/Installers/Debian/package_files/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/src/Installers/Debian/scripts/config_template_generator.py b/src/Installers/Debian/scripts/config_template_generator.py
new file mode 100755
index 0000000000..86f19df461
--- /dev/null
+++ b/src/Installers/Debian/scripts/config_template_generator.py
@@ -0,0 +1,267 @@
+#!/usr/bin/python
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# Parses debian_config.json and generates appropriate templates
+# Where optional defaults exist, they are defined in the template_dict
+# of the appropriate generation function
+
+import os
+import sys
+import json
+import datetime
+
+FILE_CHANGELOG = 'changelog'
+FILE_CONTROL = 'control'
+FILE_COPYRIGHT = 'copyright'
+FILE_SYMLINK_FORMAT = '{package_name}.links'
+FILE_RULES = 'rules'
+
+PACKAGE_ROOT_FORMAT = "usr/share/{package_name}"
+CHANGELOG_DATE_FORMAT = "%a, %d %b %Y %H:%M:%S %z"
+
+# UTC Timezone for Changelog date
+class UTC(datetime.tzinfo):
+ def utcoffset(self, dt):
+ return datetime.timedelta(0)
+
+ def tzname(self, dt):
+ return "UTC"
+
+ def dst(self, dt):
+ return datetime.timedelta(0)
+
+# Generation Functions
+def generate_and_write_all(config_data, template_dir, output_dir, package_name=None, package_version=None):
+ try:
+ changelog_contents = generate_changelog(
+ config_data,
+ template_dir,
+ package_name=package_name,
+ package_version=package_version)
+
+ control_contents = generate_control(config_data, template_dir, package_name=package_name)
+ copyright_contents = generate_copyright(config_data, template_dir)
+ symlink_contents = generate_symlinks(config_data, package_name=package_name)
+ rules_contents = generate_rules(config_data, template_dir)
+ except Exception as exc:
+ print exc
+ help_and_exit("Error: Generation Failed, check your config file.")
+
+ write_file(changelog_contents, output_dir, FILE_CHANGELOG)
+ write_file(control_contents, output_dir, FILE_CONTROL)
+ write_file(copyright_contents, output_dir, FILE_COPYRIGHT)
+ write_file(rules_contents, output_dir, FILE_RULES)
+
+ # Symlink File is optional
+ if symlink_contents:
+ symlink_filename = get_symlink_filename(config_data, package_name=package_name)
+ write_file(symlink_contents, output_dir, symlink_filename)
+
+ return
+
+def generate_rules(config_data, template_dir):
+ template = get_template(template_dir, FILE_RULES)
+
+ ignored_dependency_packages = config_data.get("debian_ignored_dependencies", None)
+ override_text = ""
+
+ if ignored_dependency_packages != None:
+ override_text = "override_dh_shlibdeps:\n\tdh_shlibdeps --dpkg-shlibdeps-params=\""
+
+ for package in ignored_dependency_packages:
+ override_text += "-x{0} ".format(package)
+
+ override_text += "\""
+
+ return template.format(overrides=override_text)
+
+def generate_changelog(config_data, template_dir, package_version=None, package_name=None):
+ template = get_template(template_dir, FILE_CHANGELOG)
+
+ release_data = config_data["release"]
+
+ # Allow for Version Override
+ config_package_version = release_data["package_version"]
+ package_version = package_version or config_package_version
+
+ template_dict = dict(\
+ PACKAGE_VERSION=package_version,
+ PACKAGE_REVISION=release_data["package_revision"],
+ CHANGELOG_MESSAGE=release_data["changelog_message"],
+ URGENCY=release_data.get("urgency", "low"),
+
+ PACKAGE_NAME=package_name or config_data["package_name"],
+ MAINTAINER_NAME=config_data["maintainer_name"],
+ MAINTAINER_EMAIL=config_data["maintainer_email"],
+ DATE=datetime.datetime.now(UTC()).strftime(CHANGELOG_DATE_FORMAT)
+ )
+
+ contents = template.format(**template_dict)
+
+ return contents
+
+def generate_control(config_data, template_dir, package_name=None):
+ template = get_template(template_dir, FILE_CONTROL)
+
+ dependency_data = config_data.get("debian_dependencies", None)
+ dependency_str = get_dependendent_packages_string(dependency_data)
+
+ conflict_data = config_data.get("package_conflicts", [])
+ conflict_str = ', '.join(conflict_data)
+
+ # Default to empty dict, so we don't explode on nested optional values
+ control_data = config_data.get("control", dict())
+
+ template_dict = dict(\
+ SHORT_DESCRIPTION=config_data["short_description"],
+ LONG_DESCRIPTION=config_data["long_description"],
+ HOMEPAGE=config_data.get("homepage", ""),
+
+ SECTION=control_data.get("section", "misc"),
+ PRIORITY=control_data.get("priority", "low"),
+ ARCH=control_data.get("architecture", "all"),
+
+ DEPENDENT_PACKAGES=dependency_str,
+ CONFLICT_PACKAGES=conflict_str,
+
+ PACKAGE_NAME=package_name or config_data["package_name"],
+ MAINTAINER_NAME=config_data["maintainer_name"],
+ MAINTAINER_EMAIL=config_data["maintainer_email"]
+ )
+
+ contents = template.format(**template_dict)
+
+ return contents
+
+def generate_copyright(config_data, template_dir):
+ template = get_template(template_dir, FILE_COPYRIGHT)
+
+ license_data = config_data["license"]
+
+ template_dict = dict(\
+ COPYRIGHT_TEXT=config_data["copyright"],
+ LICENSE_NAME=license_data["type"],
+ LICENSE_TEXT=license_data["full_text"]
+ )
+
+ contents = template.format(**template_dict)
+
+ return contents
+
+def generate_symlinks(config_data, package_name=None):
+ symlink_entries = []
+ package_root_path = get_package_root(config_data, package_name=package_name)
+
+ symlink_data = config_data.get("symlinks", dict())
+
+ for package_rel_path, symlink_path in symlink_data.iteritems():
+
+ package_abs_path = os.path.join(package_root_path, package_rel_path)
+
+ symlink_entries.append( '%s %s' % (package_abs_path, symlink_path) )
+
+ return '\n'.join(symlink_entries)
+
+# Helper Functions
+def get_package_root(config_data, package_name=None):
+ config_install_root = config_data.get("install_root", None)
+ package_name = package_name or config_data["package_name"]
+
+ return config_install_root or PACKAGE_ROOT_FORMAT.format(package_name=package_name)
+
+def get_symlink_filename(config_data, package_name=None):
+ package_name = package_name or config_data["package_name"]
+ return FILE_SYMLINK_FORMAT.format(package_name=package_name)
+
+def get_dependendent_packages_string(debian_dependency_data):
+ if debian_dependency_data is None:
+ return ""
+
+ dependencies = []
+
+ for debian_package_name in debian_dependency_data:
+ dep_str = debian_package_name
+
+ if debian_dependency_data[debian_package_name].get("package_version", None):
+ debian_package_version = debian_dependency_data[debian_package_name].get("package_version")
+
+ dep_str += " (>= %s)" % debian_package_version
+
+ dependencies.append(dep_str)
+
+ # Leading Comma is important here
+ return ', ' + ', '.join(dependencies)
+
+
+def load_json(json_path):
+ json_data = None
+ with open(json_path, 'r') as json_file:
+ json_data = json.load(json_file)
+
+ return json_data
+
+def get_template(template_dir, name):
+ path = os.path.join(template_dir, name)
+ template_contents = None
+
+ with open(path, 'r') as template_file:
+ template_contents = template_file.read()
+
+ return template_contents
+
+def write_file(contents, output_dir, name):
+ path = os.path.join(output_dir, name)
+
+ with open(path, 'w') as out_file:
+ out_file.write(contents)
+
+ return
+
+# Tool Functions
+def help_and_exit(msg):
+ print msg
+ sys.exit(1)
+
+def print_usage():
+ print "Usage: config_template_generator.py [config file path] [template directory path] [output directory] (package name) (package version)"
+
+def parse_and_validate_args():
+ if len(sys.argv) < 4:
+ print_usage()
+ help_and_exit("Error: Invalid Arguments")
+
+ config_path = sys.argv[1]
+ template_dir = sys.argv[2]
+ output_dir = sys.argv[3]
+ name_override = None
+ version_override = None
+
+ if len(sys.argv) >= 5:
+ name_override = sys.argv[4]
+
+ if len(sys.argv) >= 6:
+ version_override = sys.argv[5]
+
+ if not os.path.isfile(config_path):
+ help_and_exit("Error: Invalid config file path")
+
+ if not os.path.isdir(template_dir):
+ help_and_exit("Error: Invalid template directory path")
+
+ if not os.path.isdir(output_dir):
+ help_and_exit("Error: Invalid output directory path")
+
+ return (config_path, template_dir, output_dir, name_override, version_override)
+
+def execute():
+ config_path, template_dir, output_dir, name_override, version_override = parse_and_validate_args()
+
+ config_data = load_json(config_path)
+
+ generate_and_write_all(config_data, template_dir, output_dir, package_name = name_override, package_version=version_override)
+
+if __name__ == "__main__":
+ execute()
diff --git a/src/Installers/Debian/scripts/debian_build_lib.sh b/src/Installers/Debian/scripts/debian_build_lib.sh
new file mode 100755
index 0000000000..8aa53420f9
--- /dev/null
+++ b/src/Installers/Debian/scripts/debian_build_lib.sh
@@ -0,0 +1,170 @@
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# This file is not intended to be executed directly
+# Import these functions using source
+#
+# Relies on these environment variables:
+# PACKAGE_SOURCE_DIR :: Package Source Staging Directory
+# INSTALL_ROOT :: Absolute path of package installation root
+
+# write_debian_install_file
+# Summary: Writes the contents of the "install_placement" array to the debian/install
+# This array is populated by calls to the "add_system_file_placement" function
+# Usage: write_debian_install_file
+write_debian_install_file(){
+ # Remove any existing install file, we need to overwrite it
+ rm -f ${PACKAGE_SOURCE_DIR}/debian/install
+
+ for i in "${install_placement[@]}"
+ do
+ echo "${i}" >> "${PACKAGE_SOURCE_DIR}/debian/install"
+ done
+}
+
+# add_system_file_placement
+# Summary: Registers a file placement on the filesystem from the package by populating the "install_placement" array
+# Usage: add_system_file_placement {local path of file in package} {absolute path of directory to place file in}
+add_system_file_placement(){
+ #Initialize placement_index variable
+ if [[ -z "$placement_index" ]]; then
+ placement_index=0
+ fi
+
+ install_placement[${placement_index}]="${1} ${2}"
+ placement_index=$((${placement_index}+1))
+}
+
+# add_system_dir_placement
+# Summary: Registers a directory placement on the post-installation package from an in-package path
+add_system_dir_placement(){
+
+ in_package_dir=$1
+ abs_installation_dir=$2
+
+ dir_files=( $(_get_files_in_dir_tree $PACKAGE_SOURCE_DIR/$in_package_dir) )
+
+ # If in_package_dir isn't empty include a slash
+ if [ ! -z "$in_package_dir" ]; then
+ in_package_dir="${in_package_dir}/"
+ fi
+
+ for rel_filepath in ${dir_files[@]}
+ do
+ local parent_path=$(dirname $rel_filepath)
+
+ # If there is no parent, parent_path = "."
+ if [[ "$parent_path" == "." ]]; then
+ add_system_file_placement "${in_package_dir}${rel_filepath}" "${abs_installation_dir}"
+ else
+ add_system_file_placement "${in_package_dir}${rel_filepath}" "${abs_installation_dir}/${parent_path}"
+ fi
+
+ done
+}
+
+# add_file_to_install
+# Summary: Adds a file from the local filesystem to the package and installs it rooted at INSTALL_ROOT
+# Usage: add_install_file {relative path to local file} {relative path to INSTALL_ROOT to place file}
+add_file_to_install(){
+ copy_from_file=$1
+ rel_install_path=$2
+
+ local filename=$(basename $copy_from_file)
+ local parent_dir=$(dirname $copy_from_file)
+
+ # Create Relative Copy From Path
+ rel_copy_from_file=${copy_from_file#$parent_dir/}
+
+ # Delete any existing file and ensure path exists
+ rm -f ./${PACKAGE_SOURCE_DIR}/${rel_install_path}/${filename}
+ mkdir -p ./${PACKAGE_SOURCE_DIR}/${rel_install_path}
+
+ dir_files=( "$rel_copy_from_file" )
+
+ _copy_files_to_package $parent_dir $rel_install_path "${dir_files[@]}"
+
+ add_system_file_placement "${rel_install_path}/${filename}" "${INSTALL_ROOT}/$rel_install_path"
+}
+
+# add_dir_to_install
+# Summary: Adds contents of a directory on the local filesystem to the package and installs them rooted at INSTALL_ROOT
+# Note: Does not install the directory passed, only its contents
+# Usage: add_dir_to_install {relative path of directory to copy} {relative path to INSTALL_ROOT to place directory tree}
+add_dir_to_install(){
+
+ copy_from_dir=$1
+ rel_install_path=$2
+
+ # Delete and Create any existing directory
+ mkdir -p ${PACKAGE_SOURCE_DIR}/${rel_install_path}
+
+ dir_files=( $(_get_files_in_dir_tree $copy_from_dir) )
+
+ _copy_files_to_package "$copy_from_dir" "$rel_install_path" "${dir_files[@]}"
+
+ for file in "${dir_files[@]}"
+ do
+ file_rel_dir="$(dirname $file)"
+ add_system_file_placement "${rel_install_path}/${file}" "${INSTALL_ROOT}/$rel_install_path/${file_rel_dir}"
+ done
+}
+
+# Usage: _copy_files_to_package {local files root directory} {relative directory in package to copy to} "${filepath_array[@]}"
+# Note: The specific syntax on the parameter shows how to pass an array
+_copy_files_to_package(){
+ local_root_dir=$1
+ package_dest_dir=$2
+
+ # Consume the remaining input as an array
+ shift; shift;
+ rel_filepath_list=( $@ )
+
+ for rel_filepath in ${rel_filepath_list[@]}
+ do
+ local parent_dir=$(dirname $rel_filepath)
+ local filename=$(basename $rel_filepath)
+
+ mkdir -p ${PACKAGE_SOURCE_DIR}/${package_dest_dir}/${parent_dir}
+
+ # Ignore $parent_dir if it there isn't one
+ if [[ "$parent_dir" == "." ]]; then
+ cp "${local_root_dir}/${rel_filepath}" "${PACKAGE_SOURCE_DIR}/${package_dest_dir}"
+ else
+ cp "${local_root_dir}/${rel_filepath}" "${PACKAGE_SOURCE_DIR}/${package_dest_dir}/${parent_dir}"
+ fi
+
+ done
+}
+
+# Usage: _get_files_in_dir_tree {path of directory}
+_get_files_in_dir_tree(){
+
+ root_dir=$1
+
+ # Use Globstar expansion to enumerate all directories and files in the tree
+ shopt -s globstar
+ shopt -s dotglob
+ dir_tree_list=( "${root_dir}/"** )
+
+ # Build a new array with only the Files contained in $dir_tree_list
+ local index=0
+ for file_path in "${dir_tree_list[@]}"
+ do
+ if [ -f $file_path ]; then
+ dir_tree_file_list[${index}]=$file_path
+ index=$(($index+1))
+ fi
+ done
+
+ # Remove $root_dir prefix from each path in dir_tree_file_list
+ # This is confusing syntax, so here's a reference link (Substring Removal)
+ # http://wiki.bash-hackers.org/syntax/pe
+ dir_tree_file_list=( "${dir_tree_file_list[@]#${root_dir}/}" )
+
+ # Echo is the return mechanism
+ echo "${dir_tree_file_list[@]}"
+}
+
diff --git a/src/Installers/Debian/scripts/extract_json_value.py b/src/Installers/Debian/scripts/extract_json_value.py
new file mode 100755
index 0000000000..c7d290bf1f
--- /dev/null
+++ b/src/Installers/Debian/scripts/extract_json_value.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# Extract Json Value
+#
+# Very simple tool to ease extracting json values from the cmd line.
+import os
+import sys
+import json
+
+def print_usage():
+ print """
+ Usage: extract_json_value.py [json file path] [key of value to extract]
+ For nested keys, use . separator
+ """
+
+def help_and_exit(msg=None):
+ print msg
+ print_usage()
+ sys.exit(1)
+
+def parse_and_validate_args():
+
+ if len(sys.argv) < 3:
+ help_and_exit(msg="Error: Invalid Args")
+
+ json_path = sys.argv[1]
+ json_key = sys.argv[2]
+
+ if not os.path.isfile(json_path):
+ help_and_exit("Error: Invalid json file path")
+
+ return json_path, json_key
+
+def extract_key(json_path, json_key):
+ json_data = None
+
+ with open(json_path, 'r') as json_file:
+ json_data = json.load(json_file)
+
+ nested_keys = json_key.split('.')
+ json_context = json_data
+
+ for key in nested_keys:
+ json_context = json_context.get(key, None)
+
+ if json_context is None:
+ help_and_exit("Error: Invalid json key")
+
+ return str(json_context)
+
+def execute():
+ json_path, json_key = parse_and_validate_args()
+
+ value = extract_key(json_path, json_key)
+
+ return value
+
+if __name__ == "__main__":
+ print execute()
+
diff --git a/src/Installers/Debian/scripts/manpage_generator.py b/src/Installers/Debian/scripts/manpage_generator.py
new file mode 100755
index 0000000000..3ba7afb8a6
--- /dev/null
+++ b/src/Installers/Debian/scripts/manpage_generator.py
@@ -0,0 +1,303 @@
+#!/usr/bin/python
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# manpage_generator
+# Converts top level docs.json format command info to
+# nroff manpage format. Done in python for easy json parsing.
+#
+# Usage: argv[1] = path to docs.json; argv[2] = output path
+
+import sys
+import os
+import json
+import datetime
+
+SECTION_SEPARATOR = "\n.P \n"
+MANPAGE_EXTENSION = ".1"
+
+# For now this is a magic number
+# See https://www.debian.org/doc/manuals/maint-guide/dother.en.html#manpage
+SECTION_NUMBER = 1
+
+def generate_man_pages(doc_path, output_dir):
+
+ with open(doc_path) as doc_file:
+ doc_json = None
+ try:
+ doc_json = json.load(doc_file)
+ except:
+ raise Exception("Failed to load json file. Check formatting.")
+
+ tools = doc_json.get("tools", None)
+
+ if tools is None:
+ raise Exception("No tool sections in doc.json")
+
+ for tool_name in tools:
+ tool_data = tools[tool_name]
+
+ man_page_content = generate_man_page(tool_name, tool_data)
+ man_page_path = get_output_path(tool_name, output_dir)
+
+ write_man_page(man_page_path, man_page_content)
+
+def get_output_path(toolname, output_dir):
+ out_filename = toolname + MANPAGE_EXTENSION
+
+ return os.path.join(output_dir, out_filename)
+
+def write_man_page(path, content):
+ with open(path, 'w') as man_file:
+ man_file.write(content)
+
+ #Build Fails without a final newline
+ man_file.write('\n')
+
+def generate_man_page(tool_name, tool_data):
+
+ sections = [
+ generate_header_section(tool_name, tool_data),
+ generate_name_section(tool_name, tool_data),
+ generate_synopsis_section(tool_name, tool_data),
+ generate_description_section(tool_name, tool_data),
+ generate_options_section(tool_name, tool_data),
+ generate_author_section(tool_name, tool_data),
+ generate_copyright_section(tool_name, tool_data)
+ ]
+
+ return SECTION_SEPARATOR.join(sections)
+
+def generate_header_section(tool_name, tool_data):#
+ roff_text_builder = []
+
+ header_format = ".TH {program_name} {section_number} {center_footer} {left_footer} {center_header}"
+
+ today = datetime.date.today()
+ today_string = today.strftime("%B %d, %Y")
+
+ format_args = {
+ "program_name" : tool_name,
+ "section_number" : SECTION_NUMBER,
+ "center_footer" : "", # Omitted
+ "left_footer" : "", # Omitted
+ "center_header" : "" # Omitted
+ }
+
+ roff_text_builder.append(header_format.format(**format_args))
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_name_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH NAME")
+
+ tool_short_description = tool_data.get("short_description", "")
+ name_format = ".B {program_name} - {short_description}"
+
+ name_format_args = {
+ "program_name": tool_name,
+ "short_description" : tool_short_description
+ }
+
+ roff_text_builder.append(name_format.format(**name_format_args))
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_synopsis_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH SYNOPSIS")
+
+ synopsis_format = '.B {program_name} {command_name} \n.RI {options} " "\n.I "{argument_list_name}"'
+
+ tool_commands = tool_data.get("commands", [])
+ for command_name in tool_commands:
+ command_data = tool_commands[command_name]
+
+ # Default options to empty list so the loop doesn't blow up
+ options = command_data.get("options", [])
+ argument_list = command_data.get("argumentlist", None)
+
+ # Construct Option Strings
+ option_string_list = []
+ argument_list_name = ""
+
+ for option_name in options:
+ option_data = options[option_name]
+
+ specifier_short = option_data.get("short", None)
+ specifier_long = option_data.get("long", None)
+ parameter = option_data.get("parameter", None)
+
+ option_string = _option_string_helper(specifier_short, specifier_long, parameter)
+
+ option_string_list.append(option_string)
+
+ # Populate Argument List Name
+ if argument_list:
+ argument_list_name = argument_list.get("name", "")
+
+ cmd_format_args = {
+ 'program_name' : tool_name,
+ 'command_name' : command_name,
+ 'options' : '" "'.join(option_string_list),
+ 'argument_list_name' : argument_list_name
+ }
+
+ cmd_string = synopsis_format.format(**cmd_format_args)
+
+ roff_text_builder.append(cmd_string)
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_description_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH DESCRIPTION")
+
+ # Tool Description
+ long_description = tool_data.get("long_description", "")
+ roff_text_builder.append(".PP {0}".format(long_description))
+
+ # Command Descriptions
+ cmd_description_format = ".B {program_name} {command_name}\n{command_description}"
+
+ tool_commands = tool_data.get("commands", [])
+ for command_name in tool_commands:
+ command_data = tool_commands[command_name]
+
+ command_description = command_data.get("description", "")
+
+ format_args = {
+ "program_name" : tool_name,
+ "command_name" : command_name,
+ "command_description" : command_description
+ }
+
+ cmd_string = cmd_description_format.format(**format_args)
+
+ roff_text_builder.append(cmd_string)
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_options_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH OPTIONS")
+
+ options_format = '.TP\n.B {option_specifiers}\n{option_description}'
+
+ tool_commands = tool_data.get("commands", [])
+ for command_name in tool_commands:
+ command_data = tool_commands[command_name]
+
+ # Default to empty list so the loop doesn't blow up
+ options = command_data.get("options", [])
+
+ for option_name in options:
+ option_data = options[option_name]
+
+ specifier_short = option_data.get("short", None)
+ specifier_long = option_data.get("long", None)
+ parameter = option_data.get("parameter", None)
+ description = option_data.get("description", "")
+
+ option_specifiers_string = _option_string_helper(specifier_short,
+ specifier_long,
+ parameter,
+ include_brackets = False,
+ delimiter=' ", " ')
+
+ format_args = {
+ "option_specifiers": option_specifiers_string,
+ "option_description" : description
+ }
+
+ roff_text_builder.append(options_format.format(**format_args))
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_author_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH AUTHOR")
+
+ author_format = '.B "{author_name}" " " \n.RI ( "{author_email}" )'
+
+ author_name = tool_data.get("author", "")
+ author_email = tool_data.get("author_email", "")
+
+ format_args = {
+ "author_name" : author_name,
+ "author_email" : author_email
+ }
+
+ roff_text_builder.append(author_format.format(**format_args))
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def generate_copyright_section(tool_name, tool_data):#
+ roff_text_builder = []
+ roff_text_builder.append(".SH COPYRIGHT")
+
+ copyright_data = tool_data.get("copyright")
+
+ roff_text_builder.append('.B "{0}"'.format(copyright_data))
+
+ return SECTION_SEPARATOR.join(roff_text_builder)
+
+def _option_string_helper(specifier_short, specifier_long, parameter, include_brackets = True, delimiter = " | "):
+ option_string = ""
+
+ if include_brackets:
+ option_string = " [ "
+
+ if specifier_short:
+ option_string += ' "{0}" '.format(specifier_short)
+
+ if specifier_short and specifier_long:
+ option_string += delimiter
+
+ if specifier_long:
+ option_string += ' "{0}" '.format(specifier_long)
+
+ if parameter:
+ option_string += ' " " '
+ option_string += ' "{0}" '.format(parameter)
+
+ if include_brackets:
+ option_string += " ] "
+
+ return option_string
+
+
+def print_usage():
+ print "Usage: argv[1] = path to docs.json; argv[2] = output path"
+ print "Example: manpage_generator.py ../docs.json ./dotnet-1.0/debian"
+
+def parse_args():
+ doc_path = sys.argv[1]
+ output_dir = sys.argv[2]
+
+ return (doc_path, output_dir)
+
+def validate_args(doc_path, output_dir):
+ if not os.path.isfile(doc_path):
+ raise Exception("Docs.json path is not valid.")
+
+ if not os.path.isdir(output_dir):
+ raise Exception("Output Directory Path is not valid.")
+
+def execute_command_line():
+ try:
+ doc_path, output_dir = parse_args()
+
+ validate_args(doc_path, output_dir)
+
+ generate_man_pages(doc_path, output_dir)
+
+ except Exception as exc:
+ print "Error: ", exc
+ print_usage()
+
+if __name__ == "__main__":
+ execute_command_line()
diff --git a/src/Installers/Debian/setup/build_setup.sh b/src/Installers/Debian/setup/build_setup.sh
new file mode 100755
index 0000000000..269aff50ef
--- /dev/null
+++ b/src/Installers/Debian/setup/build_setup.sh
@@ -0,0 +1,20 @@
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+install_dependencies(){
+ # Add LLdb 3.6 package source
+ echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.6 main" | tee /etc/apt/sources.list.d/llvm.list
+ wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
+
+ #Install Deps
+ apt-get update
+ apt-get install -y debhelper build-essential devscripts git liblttng-ust-dev lldb-3.6-dev
+}
+
+setup(){
+ install_dependencies
+}
+
+setup
\ No newline at end of file
diff --git a/src/Installers/Debian/setup/test_setup.sh b/src/Installers/Debian/setup/test_setup.sh
new file mode 100755
index 0000000000..47442fd603
--- /dev/null
+++ b/src/Installers/Debian/setup/test_setup.sh
@@ -0,0 +1,27 @@
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+install_dependencies(){
+ # Add LLdb 3.6 package source
+ echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.6 main" | tee /etc/apt/sources.list.d/llvm.list
+ wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | apt-key add -
+
+ #Install Deps
+ apt-get update
+ apt-get install -y debhelper build-essential devscripts git liblttng-ust-dev lldb-3.6-dev
+}
+
+install_bats(){
+ git clone https://github.com/sstephenson/bats.git
+ cd bats
+ ./install.sh /usr/local
+}
+
+setup(){
+ install_dependencies
+ install_bats
+}
+
+setup
\ No newline at end of file
diff --git a/src/Installers/Debian/templates/debian/changelog b/src/Installers/Debian/templates/debian/changelog
new file mode 100755
index 0000000000..8eccaab397
--- /dev/null
+++ b/src/Installers/Debian/templates/debian/changelog
@@ -0,0 +1,5 @@
+{PACKAGE_NAME} ({PACKAGE_VERSION}-{PACKAGE_REVISION}) unstable; urgency={URGENCY}
+
+ * {CHANGELOG_MESSAGE}
+
+ -- {MAINTAINER_NAME} <{MAINTAINER_EMAIL}> {DATE}
diff --git a/src/Installers/Debian/templates/debian/control b/src/Installers/Debian/templates/debian/control
new file mode 100755
index 0000000000..49fb2b994a
--- /dev/null
+++ b/src/Installers/Debian/templates/debian/control
@@ -0,0 +1,19 @@
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+Source: {PACKAGE_NAME}
+Maintainer: {MAINTAINER_NAME} <{MAINTAINER_EMAIL}>
+Section: {SECTION}
+Priority: {PRIORITY}
+Standards-Version: 3.9.2
+Build-Depends: debhelper (>=9)
+Homepage: {HOMEPAGE}
+
+Package: {PACKAGE_NAME}
+Architecture: {ARCH}
+Depends: ${{shlibs:Depends}}, ${{misc:Depends}}{DEPENDENT_PACKAGES}
+Conflicts: {CONFLICT_PACKAGES}
+Description: {SHORT_DESCRIPTION}
+ {LONG_DESCRIPTION}
diff --git a/src/Installers/Debian/templates/debian/copyright b/src/Installers/Debian/templates/debian/copyright
new file mode 100755
index 0000000000..1fe22df1b7
--- /dev/null
+++ b/src/Installers/Debian/templates/debian/copyright
@@ -0,0 +1,10 @@
+Comment: Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files: *
+Copyright: {COPYRIGHT_TEXT}
+License: {LICENSE_NAME}
+
+License: {LICENSE_NAME}
+ {LICENSE_TEXT}
\ No newline at end of file
diff --git a/src/Installers/Debian/templates/debian/rules b/src/Installers/Debian/templates/debian/rules
new file mode 100755
index 0000000000..103057ac7a
--- /dev/null
+++ b/src/Installers/Debian/templates/debian/rules
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+{overrides}
+
+%:
+ dh $@
+
diff --git a/src/Installers/Debian/test.sh b/src/Installers/Debian/test.sh
new file mode 100755
index 0000000000..9adde436f4
--- /dev/null
+++ b/src/Installers/Debian/test.sh
@@ -0,0 +1,41 @@
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+current_user=$(whoami)
+if [ $current_user != "root" ]; then
+ echo "test.sh requires superuser privileges to run"
+ exit 1
+fi
+
+run_unit_tests(){
+ bats $DIR/test/unit_tests/test_debian_build_lib.bats
+ bats $DIR/test/unit_tests/test_scripts.bats
+}
+
+run_integration_tests(){
+ input_dir=$DIR/test/test_assets/test_package_layout
+ output_dir=$DIR/bin
+
+ # Create output dir
+ mkdir -p $output_dir
+
+ # Build the actual package
+ $DIR/package_tool -i $input_dir -o $output_dir
+
+ # Integration Test Entrypoint placed by package_tool
+ bats $output_dir/test_package.bats
+
+ # Cleanup output dir
+ rm -rf $DIR/test/test_assets/test_package_output
+}
+
+run_all(){
+ run_unit_tests
+ run_integration_tests
+}
+
+run_all
diff --git a/src/Installers/Debian/test/integration_tests/test_package.bats b/src/Installers/Debian/test/integration_tests/test_package.bats
new file mode 100755
index 0000000000..8f4c750538
--- /dev/null
+++ b/src/Installers/Debian/test/integration_tests/test_package.bats
@@ -0,0 +1,80 @@
+#!/bin/bash
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+# This script is used to test the debian package after it's creation.
+# The package tool will drop it next to the .deb file it creates.
+# Environment Variables:
+# LAST_VERSION_URL: Url for last version .deb (to test upgrades) [required for upgrade test]
+
+#Ensure running with superuser privileges
+current_user=$(whoami)
+if [ $current_user != "root" ]; then
+ echo "WARNING: test_package.bats requires superuser privileges to run, trying sudo..."
+ SUDO_PREFIX="sudo"
+fi
+
+setup(){
+ DIR="$BATS_TEST_DIRNAME"
+
+ PACKAGE_FILENAME="$(ls $DIR | grep .deb -m 1)"
+ PACKAGE_PATH="$DIR/*.deb"
+
+ # Get Package name from package path,
+ PACKAGE_NAME=${PACKAGE_FILENAME%%_*}
+}
+
+install_package(){
+ $SUDO_PREFIX dpkg -i $PACKAGE_PATH
+}
+
+remove_package(){
+ $SUDO_PREFIX dpkg -r $PACKAGE_NAME
+}
+
+purge_package(){
+ $SUDO_PREFIX dpkg -P $PACKAGE_NAME
+}
+
+install_last_version(){
+ $SUDO_PREFIX dpkg -i "$DIR/last_version.deb"
+}
+
+download_and_install_last_version(){
+ curl "$LAST_VERSION_URL" -o "$DIR/last_version.deb"
+
+ install_last_version
+}
+
+delete_last_version(){
+ rm -f "$DIR/last_version.deb"
+}
+
+teardown(){
+ delete_last_version
+}
+
+@test "package install + removal test" {
+ install_package
+ remove_package
+}
+
+@test "package install + purge test" {
+ install_package
+ purge_package
+}
+
+# Ultimate Package Test
+# https://www.debian.org/doc/manuals/maint-guide/checkit.en.html#pmaintscripts
+@test "package install + upgrade + purge + install + remove + install + purge test" {
+ if [ ! -z "$LAST_VERSION_URL" ]; then
+ download_and_install_last_version
+ install_package
+ purge_package
+ install_package
+ remove_package
+ install_package
+ purge_package
+ fi
+}
diff --git a/src/Installers/Debian/test/test_assets/lkgtestman.1 b/src/Installers/Debian/test/test_assets/lkgtestman.1
new file mode 100755
index 0000000000..57915b0a61
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/lkgtestman.1
@@ -0,0 +1,99 @@
+.TH tool1 1
+.P
+.SH NAME
+.P
+.B tool1 - A tool to Vestibulum lacinia arcu eget nulla.
+.P
+.SH SYNOPSIS
+.P
+.B tool1 noOptionsCommand
+.RI " "
+.I "argument list stuff"
+.P
+.B tool1 noArgumentListFullOptions
+.RI [ "-t" | "--target" " " "TARGET" ] " " [ "--noshortparam" ] " " [ "-l" ] " " [ "-p" | "--noparam" ] " " [ "-n" " " "NOLONG" ] " " [ "--noshort" " " "NOSHORT" ] " " [ "-a" | "--another" " " "ANOTHER" ] " "
+.I ""
+.P
+.B tool1 fullcommand1
+.RI [ "-t" | "--target" " " "TARGET" ] " " [ "--noshortparam" ] " " [ "-l" ] " " [ "-p" | "--noparam" ] " " [ "-n" " " "NOLONG" ] " " [ "--noshort" " " "NOSHORT" ] " " [ "-a" | "--another" " " "ANOTHER" ] " "
+.I "argument list stuff"
+.P
+.SH DESCRIPTION
+.P
+.PP Tool1 is a really great Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh.
+.P
+.B tool1 noOptionsCommand
+builds a native executable from specified source files
+.P
+.B tool1 noArgumentListFullOptions
+builds a native executable from specified source files
+.P
+.B tool1 fullcommand1
+builds a native executable from specified source files
+.P
+.SH OPTIONS
+.P
+.TP
+.B "-t" ", " "--target" " " "TARGET"
+Specifies target binary output type. EXE or DLL
+.P
+.TP
+.B "--noshortparam"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-l"
+Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet
+.P
+.TP
+.B "-p" ", " "--noparam"
+Specifies noparam metus vitae pharetra auctor, sem
+.P
+.TP
+.B "-n" " " "NOLONG"
+Specifies nolong Nunc feugiat mi a tellus consequat
+.P
+.TP
+.B "--noshort" " " "NOSHORT"
+Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt
+.P
+.TP
+.B "-a" ", " "--another" " " "ANOTHER"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-t" ", " "--target" " " "TARGET"
+Specifies target binary output type. EXE or DLL
+.P
+.TP
+.B "--noshortparam"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-l"
+Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet
+.P
+.TP
+.B "-p" ", " "--noparam"
+Specifies noparam metus vitae pharetra auctor, sem
+.P
+.TP
+.B "-n" " " "NOLONG"
+Specifies nolong Nunc feugiat mi a tellus consequat
+.P
+.TP
+.B "--noshort" " " "NOSHORT"
+Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt
+.P
+.TP
+.B "-a" ", " "--another" " " "ANOTHER"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.SH AUTHOR
+.P
+.B "Test Author" " "
+.RI ( "testing@testing.com" )
+.P
+.SH COPYRIGHT
+.P
+.B "This is the copyright of tool1."
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/debian_config.json b/src/Installers/Debian/test/test_assets/test_package_layout/debian_config.json
new file mode 100755
index 0000000000..db873c7162
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/debian_config.json
@@ -0,0 +1,40 @@
+{
+ "maintainer_name":"Microsoft",
+ "maintainer_email": "optimus@service.microsoft.com",
+
+ "package_name": "packagetooltest",
+
+ "short_description": "This is a test package",
+ "long_description": "This is a longer description of the test package",
+ "homepage": "http://testpackage.com",
+
+ "release":{
+ "package_version":"0.1",
+ "package_revision":"1",
+ "urgency" : "low",
+ "changelog_message" : "some stuff here"
+ },
+
+ "control": {
+ "priority":"standard",
+ "section":"devel",
+ "architecture":"any"
+ },
+
+ "copyright": "2015 Microsoft",
+ "license": {
+ "type": "some_license",
+ "full_text": "full license text here"
+ },
+
+ "debian_dependencies" : {
+ "curl": {
+ "package_version" : "0.5.3"
+ },
+ "python":{}
+ },
+
+ "symlinks": {
+ "path_relative_to_package_root/test_exe.sh" : "usr/bin/test_exe.sh"
+ }
+}
\ No newline at end of file
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/docs.json b/src/Installers/Debian/test/test_assets/test_package_layout/docs.json
new file mode 100755
index 0000000000..e35fdb3bfd
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/docs.json
@@ -0,0 +1,108 @@
+{
+ "tools": {
+ "tool1": {
+ "copyright": "This is the copyright of tool1.",
+ "license" : "This is the license of tool1",
+ "author":"Test Author",
+ "author_email":"testing@testing.com",
+ "short_description":"A tool to Vestibulum lacinia arcu eget nulla.",
+ "long_description":"Tool1 is a really great Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. ",
+ "commands": {
+ "fullcommand1":{
+ "description":"builds a native executable from specified source files",
+ "options" : {
+ "target": {
+ "short": "-t",
+ "long":"--target",
+ "description":"Specifies target binary output type. EXE or DLL",
+ "parameter":"TARGET"
+ },
+ "target2": {
+ "short": "-a",
+ "long":"--another",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra",
+ "parameter":"ANOTHER"
+ },
+ "noshort": {
+ "long":"--noshort",
+ "description":"Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt",
+ "parameter":"NOSHORT"
+ },
+ "nolong": {
+ "short": "-n",
+ "description":"Specifies nolong Nunc feugiat mi a tellus consequat ",
+ "parameter":"NOLONG"
+ },
+ "noparam": {
+ "short": "-p",
+ "long":"--noparam",
+ "description":"Specifies noparam metus vitae pharetra auctor, sem"
+ },
+ "noParamNoShort": {
+ "long":"--noshortparam",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra"
+ },
+ "noParamNoLong": {
+ "short": "-l",
+ "description":"Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet"
+ }
+ },
+ "argumentlist" : {
+ "name":"argument list stuff",
+ "description":"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;"
+ }
+
+ },
+ "noOptionsCommand":{
+ "description":"builds a native executable from specified source files",
+ "argumentlist" : {
+ "name":"argument list stuff",
+ "description":"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;"
+ }
+
+ },
+ "noArgumentListFullOptions":{
+ "description":"builds a native executable from specified source files",
+ "options" : {
+ "target": {
+ "short": "-t",
+ "long":"--target",
+ "description":"Specifies target binary output type. EXE or DLL",
+ "parameter":"TARGET"
+ },
+ "target2": {
+ "short": "-a",
+ "long":"--another",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra",
+ "parameter":"ANOTHER"
+ },
+ "noshort": {
+ "long":"--noshort",
+ "description":"Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt",
+ "parameter":"NOSHORT"
+ },
+ "nolong": {
+ "short": "-n",
+ "description":"Specifies nolong Nunc feugiat mi a tellus consequat ",
+ "parameter":"NOLONG"
+ },
+ "noparam": {
+ "short": "-p",
+ "long":"--noparam",
+ "description":"Specifies noparam metus vitae pharetra auctor, sem"
+ },
+ "noParamNoShort": {
+ "long":"--noshortparam",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra"
+ },
+ "noParamNoLong": {
+ "short": "-l",
+ "description":"Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet"
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/docs/testdocs.1 b/src/Installers/Debian/test/test_assets/test_package_layout/docs/testdocs.1
new file mode 100755
index 0000000000..57915b0a61
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/docs/testdocs.1
@@ -0,0 +1,99 @@
+.TH tool1 1
+.P
+.SH NAME
+.P
+.B tool1 - A tool to Vestibulum lacinia arcu eget nulla.
+.P
+.SH SYNOPSIS
+.P
+.B tool1 noOptionsCommand
+.RI " "
+.I "argument list stuff"
+.P
+.B tool1 noArgumentListFullOptions
+.RI [ "-t" | "--target" " " "TARGET" ] " " [ "--noshortparam" ] " " [ "-l" ] " " [ "-p" | "--noparam" ] " " [ "-n" " " "NOLONG" ] " " [ "--noshort" " " "NOSHORT" ] " " [ "-a" | "--another" " " "ANOTHER" ] " "
+.I ""
+.P
+.B tool1 fullcommand1
+.RI [ "-t" | "--target" " " "TARGET" ] " " [ "--noshortparam" ] " " [ "-l" ] " " [ "-p" | "--noparam" ] " " [ "-n" " " "NOLONG" ] " " [ "--noshort" " " "NOSHORT" ] " " [ "-a" | "--another" " " "ANOTHER" ] " "
+.I "argument list stuff"
+.P
+.SH DESCRIPTION
+.P
+.PP Tool1 is a really great Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh.
+.P
+.B tool1 noOptionsCommand
+builds a native executable from specified source files
+.P
+.B tool1 noArgumentListFullOptions
+builds a native executable from specified source files
+.P
+.B tool1 fullcommand1
+builds a native executable from specified source files
+.P
+.SH OPTIONS
+.P
+.TP
+.B "-t" ", " "--target" " " "TARGET"
+Specifies target binary output type. EXE or DLL
+.P
+.TP
+.B "--noshortparam"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-l"
+Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet
+.P
+.TP
+.B "-p" ", " "--noparam"
+Specifies noparam metus vitae pharetra auctor, sem
+.P
+.TP
+.B "-n" " " "NOLONG"
+Specifies nolong Nunc feugiat mi a tellus consequat
+.P
+.TP
+.B "--noshort" " " "NOSHORT"
+Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt
+.P
+.TP
+.B "-a" ", " "--another" " " "ANOTHER"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-t" ", " "--target" " " "TARGET"
+Specifies target binary output type. EXE or DLL
+.P
+.TP
+.B "--noshortparam"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.TP
+.B "-l"
+Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet
+.P
+.TP
+.B "-p" ", " "--noparam"
+Specifies noparam metus vitae pharetra auctor, sem
+.P
+.TP
+.B "-n" " " "NOLONG"
+Specifies nolong Nunc feugiat mi a tellus consequat
+.P
+.TP
+.B "--noshort" " " "NOSHORT"
+Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt
+.P
+.TP
+.B "-a" ", " "--another" " " "ANOTHER"
+Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra
+.P
+.SH AUTHOR
+.P
+.B "Test Author" " "
+.RI ( "testing@testing.com" )
+.P
+.SH COPYRIGHT
+.P
+.B "This is the copyright of tool1."
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/package_root/path_relative_to_package_root/test_exe.sh b/src/Installers/Debian/test/test_assets/test_package_layout/package_root/path_relative_to_package_root/test_exe.sh
new file mode 100755
index 0000000000..370bc40f3a
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/package_root/path_relative_to_package_root/test_exe.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# Resolve symlinks until we have the parent dir of the actual file
+SOURCE="${BASH_SOURCE[0]}"
+while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
+ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+ SOURCE="$(readlink "$SOURCE")"
+ [[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
+done
+DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
+
+# This is how tools should be called
+exec bash $DIR/../test_called.sh
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/package_root/test_called.sh b/src/Installers/Debian/test/test_assets/test_package_layout/package_root/test_called.sh
new file mode 100755
index 0000000000..e14e427cf6
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/package_root/test_called.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+echo "script called"
diff --git a/src/Installers/Debian/test/test_assets/test_package_layout/samples/testsample.cs b/src/Installers/Debian/test/test_assets/test_package_layout/samples/testsample.cs
new file mode 100755
index 0000000000..4f7432b480
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/test_package_layout/samples/testsample.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+
+public class Program {
+
+ public static void Main(){
+ System.Console.WriteLine("Hello World");
+ }
+
+}
\ No newline at end of file
diff --git a/src/Installers/Debian/test/test_assets/testdocs.json b/src/Installers/Debian/test/test_assets/testdocs.json
new file mode 100755
index 0000000000..e35fdb3bfd
--- /dev/null
+++ b/src/Installers/Debian/test/test_assets/testdocs.json
@@ -0,0 +1,108 @@
+{
+ "tools": {
+ "tool1": {
+ "copyright": "This is the copyright of tool1.",
+ "license" : "This is the license of tool1",
+ "author":"Test Author",
+ "author_email":"testing@testing.com",
+ "short_description":"A tool to Vestibulum lacinia arcu eget nulla.",
+ "long_description":"Tool1 is a really great Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. ",
+ "commands": {
+ "fullcommand1":{
+ "description":"builds a native executable from specified source files",
+ "options" : {
+ "target": {
+ "short": "-t",
+ "long":"--target",
+ "description":"Specifies target binary output type. EXE or DLL",
+ "parameter":"TARGET"
+ },
+ "target2": {
+ "short": "-a",
+ "long":"--another",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra",
+ "parameter":"ANOTHER"
+ },
+ "noshort": {
+ "long":"--noshort",
+ "description":"Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt",
+ "parameter":"NOSHORT"
+ },
+ "nolong": {
+ "short": "-n",
+ "description":"Specifies nolong Nunc feugiat mi a tellus consequat ",
+ "parameter":"NOLONG"
+ },
+ "noparam": {
+ "short": "-p",
+ "long":"--noparam",
+ "description":"Specifies noparam metus vitae pharetra auctor, sem"
+ },
+ "noParamNoShort": {
+ "long":"--noshortparam",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra"
+ },
+ "noParamNoLong": {
+ "short": "-l",
+ "description":"Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet"
+ }
+ },
+ "argumentlist" : {
+ "name":"argument list stuff",
+ "description":"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;"
+ }
+
+ },
+ "noOptionsCommand":{
+ "description":"builds a native executable from specified source files",
+ "argumentlist" : {
+ "name":"argument list stuff",
+ "description":"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;"
+ }
+
+ },
+ "noArgumentListFullOptions":{
+ "description":"builds a native executable from specified source files",
+ "options" : {
+ "target": {
+ "short": "-t",
+ "long":"--target",
+ "description":"Specifies target binary output type. EXE or DLL",
+ "parameter":"TARGET"
+ },
+ "target2": {
+ "short": "-a",
+ "long":"--another",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra",
+ "parameter":"ANOTHER"
+ },
+ "noshort": {
+ "long":"--noshort",
+ "description":"Specifies noshortNam nec ante. Sed lacinia, urna non tincidunt",
+ "parameter":"NOSHORT"
+ },
+ "nolong": {
+ "short": "-n",
+ "description":"Specifies nolong Nunc feugiat mi a tellus consequat ",
+ "parameter":"NOLONG"
+ },
+ "noparam": {
+ "short": "-p",
+ "long":"--noparam",
+ "description":"Specifies noparam metus vitae pharetra auctor, sem"
+ },
+ "noParamNoShort": {
+ "long":"--noshortparam",
+ "description":"Specifies another aptent taciti sociosqu ad litora torquent per conubia nostra"
+ },
+ "noParamNoLong": {
+ "short": "-l",
+ "description":"Specifies noparam nolong congue elementum. Morbi in ipsum sit amet pede facilisis laoreet"
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/src/Installers/Debian/test/unit_tests/test_debian_build_lib.bats b/src/Installers/Debian/test/unit_tests/test_debian_build_lib.bats
new file mode 100755
index 0000000000..193868f835
--- /dev/null
+++ b/src/Installers/Debian/test/unit_tests/test_debian_build_lib.bats
@@ -0,0 +1,279 @@
+#!/usr/bin/env bats
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# Tests for debian_build_lib.sh
+
+setup(){
+ DIR="$BATS_TEST_DIRNAME"
+ PACKAGIFY_DIR="$(readlink -f $DIR/../../)"
+
+ PACKAGE_DIR="$BATS_TMPDIR/test-package"
+ PACKAGE_SOURCE_DIR="$BATS_TMPDIR/test-source-package"
+ INSTALL_ROOT="test-install-root"
+
+ # # Create Mock Package Directory
+ mkdir -p $PACKAGE_SOURCE_DIR/debian
+ mkdir $PACKAGE_DIR
+
+ source $PACKAGIFY_DIR/scripts/debian_build_lib.sh
+
+}
+
+teardown(){
+ # Remove Mock Package Directory
+ rm -r $PACKAGE_DIR
+ rm -r $PACKAGE_SOURCE_DIR
+}
+
+@test "add_system_file_placement populates placement array" {
+
+ add_system_file_placement "testfile0" "testdir0"
+ add_system_file_placement "testfile1" "testdir1"
+
+ [ $placement_index -eq "2" ]
+ [ "${install_placement[0]}" = "testfile0 testdir0" ]
+ [ "${install_placement[1]}" = "testfile1 testdir1" ]
+}
+
+@test "add_system_dir_placement adds files in dir to placement array" {
+ test_package_rel_dir="test-dir"
+ abs_test_path="/abs/test/path"
+
+ mkdir $PACKAGE_SOURCE_DIR/$test_package_rel_dir
+ echo "file0 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file0
+ echo "file1 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file1
+ echo "file2 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file2
+
+ add_system_dir_placement $test_package_rel_dir $abs_test_path
+
+ rm -r $PACKAGE_SOURCE_DIR/$test_package_rel_dir
+
+ [ "$placement_index" -eq 3 ]
+ [ "${install_placement[0]}" = "$test_package_rel_dir/file0 $abs_test_path" ]
+ [ "${install_placement[1]}" = "$test_package_rel_dir/file1 $abs_test_path" ]
+ [ "${install_placement[2]}" = "$test_package_rel_dir/file2 $abs_test_path" ]
+}
+
+@test "add_system_dir_placement adds all files in subdir to placement array" {
+ test_package_rel_dir="test-dir"
+ test_package_rel_subdir="test-subdir"
+ abs_test_path="/abs/test/path"
+
+ mkdir -p $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir
+ echo "file0 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file0
+ echo "file1 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file1
+ echo "file2 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file2
+
+ add_system_dir_placement $test_package_rel_dir $abs_test_path
+
+ rm -r $PACKAGE_SOURCE_DIR/$test_package_rel_dir
+
+ [ "$placement_index" -eq "3" ]
+ [ "${install_placement[0]}" = "$test_package_rel_dir/$test_package_rel_subdir/file0 $abs_test_path/$test_package_rel_subdir" ]
+ [ "${install_placement[1]}" = "$test_package_rel_dir/$test_package_rel_subdir/file1 $abs_test_path/$test_package_rel_subdir" ]
+ [ "${install_placement[2]}" = "$test_package_rel_dir/$test_package_rel_subdir/file2 $abs_test_path/$test_package_rel_subdir" ]
+}
+
+@test "add_system_dir_placement adds all files in subdir and dir to placement array" {
+ test_package_rel_dir="test-dir"
+ test_package_rel_subdir="test-subdir"
+ abs_test_path="/abs/test/path"
+
+ mkdir -p $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir
+ echo "file0 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file0
+ echo "file1 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file1
+ echo "file2 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/file2
+ echo "file3 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file3
+ echo "file4 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file4
+ echo "file5 contents" > $PACKAGE_SOURCE_DIR/$test_package_rel_dir/$test_package_rel_subdir/file5
+
+ add_system_dir_placement $test_package_rel_dir $abs_test_path
+
+ rm -r $PACKAGE_SOURCE_DIR/$test_package_rel_dir
+
+ [ "$placement_index" -eq "6" ]
+ [ "${install_placement[0]}" = "$test_package_rel_dir/file0 $abs_test_path" ]
+ [ "${install_placement[1]}" = "$test_package_rel_dir/file1 $abs_test_path" ]
+ [ "${install_placement[2]}" = "$test_package_rel_dir/file2 $abs_test_path" ]
+ [ "${install_placement[3]}" = "$test_package_rel_dir/$test_package_rel_subdir/file3 $abs_test_path/$test_package_rel_subdir" ]
+ [ "${install_placement[4]}" = "$test_package_rel_dir/$test_package_rel_subdir/file4 $abs_test_path/$test_package_rel_subdir" ]
+ [ "${install_placement[5]}" = "$test_package_rel_dir/$test_package_rel_subdir/file5 $abs_test_path/$test_package_rel_subdir" ]
+}
+
+@test "write_debian_install_file writes to debian/install" {
+ add_system_file_placement "somefile" "/some/abs/path"
+ write_debian_install_file
+
+ [ -f "$PACKAGE_SOURCE_DIR/debian/install" ]
+ [ "$(cat $PACKAGE_SOURCE_DIR/debian/install)" = "somefile /some/abs/path" ]
+}
+
+@test "add_file_to_install adds file to package_dest_dir" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ local_subdir="the/path/should/not/matter"
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir -p $local_test_dir/$local_subdir
+ echo "file0 contents" > $local_test_dir/$local_subdir/file0
+ echo "file1 contents" > $local_test_dir/$local_subdir/file1
+ echo "file2 contents" > $local_test_dir/$local_subdir/file2
+
+ add_file_to_install "$local_test_dir/$local_subdir/file0" "$package_test_dir"
+ add_file_to_install "$local_test_dir/$local_subdir/file1" "$package_test_dir"
+ add_file_to_install "$local_test_dir/$local_subdir/file2" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file0" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file1" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file2" ]
+}
+
+@test "add_file_to_install added files written to install file after write_debian_install_file" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ local_subdir="the/path/should/not/matter"
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir -p $local_test_dir/$local_subdir
+ echo "file0 contents" > $local_test_dir/$local_subdir/file0
+
+ add_file_to_install "$local_test_dir/$local_subdir/file0" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ ! -e $PACKAGE_SOURCE_DIR/debian/install ]
+ write_debian_install_file
+ [ -f $PACKAGE_SOURCE_DIR/debian/install ]
+ [ "$(cat $PACKAGE_SOURCE_DIR/debian/install)" = "$package_test_dir/file0 $INSTALL_ROOT/$package_test_dir" ]
+}
+
+@test "add_dir_to_install adds files in dir to package_dest_dir" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir $local_test_dir
+ echo "file0 contents" > $local_test_dir/file0
+ echo "file1 contents" > $local_test_dir/file1
+ echo "file2 contents" > $local_test_dir/file2
+
+ add_dir_to_install "$local_test_dir" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file0" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file1" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file2" ]
+}
+
+@test "add_dir_to_install adds files in subdirectory tree to package_dest_dir" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ local_test_subdir="local-subdir"
+
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir -p $local_test_dir/$local_test_subdir
+ echo "file0 contents" > $local_test_dir/$local_test_subdir/file0
+ echo "file1 contents" > $local_test_dir/$local_test_subdir/file1
+ echo "file2 contents" > $local_test_dir/$local_test_subdir/file2
+
+ add_dir_to_install "$local_test_dir" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file0" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file1" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file2" ]
+}
+
+@test "add_dir_to_install adds files in directory and subdirectory tree to package_dest_dir" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ local_test_subdir="local-subdir"
+
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir -p $local_test_dir/$local_test_subdir
+
+ echo "file0 contents" > $local_test_dir/file0
+ echo "file1 contents" > $local_test_dir/file1
+ echo "file2 contents" > $local_test_dir/file2
+ echo "file3 contents" > $local_test_dir/$local_test_subdir/file3
+ echo "file4 contents" > $local_test_dir/$local_test_subdir/file4
+ echo "file5 contents" > $local_test_dir/$local_test_subdir/file5
+
+ add_dir_to_install "$local_test_dir" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file0" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file1" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/file2" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file3" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file4" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$package_test_dir/$local_test_subdir/file5" ]
+}
+
+@test "add_dir_to_install added files written to install file after write_debian_install_file" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ package_test_dir="package-dir"
+
+ mkdir $PACKAGE_SOURCE_DIR/$package_test_dir
+ mkdir -p $local_test_dir
+
+ echo "file0 contents" > $local_test_dir/file0
+
+ add_dir_to_install "$local_test_dir" "$package_test_dir"
+
+ rm -r $local_test_dir
+
+ [ ! -e $PACKAGE_SOURCE_DIR/debian/install ]
+ write_debian_install_file
+ [ -f $PACKAGE_SOURCE_DIR/debian/install ]
+ [ "$(cat $PACKAGE_SOURCE_DIR/debian/install)" = "$package_test_dir/file0 $INSTALL_ROOT/$package_test_dir" ]
+}
+
+@test "add_dir_to_install with empty dest dir outputs to PACKAGE_SOURCE_DIR" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ mkdir -p $local_test_dir
+
+ echo "file0 contents" > $local_test_dir/file0
+
+ add_dir_to_install "$local_test_dir" ""
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/file0" ]
+}
+
+
+@test "add_dir_to_install with empty dest dir adds files in directory and subdirectory tree to $PACKAGE_SOURCE_DIR" {
+ local_test_dir="$BATS_TMPDIR/local-dir"
+ local_test_subdir="local-subdir"
+
+ mkdir -p $local_test_dir/$local_test_subdir
+
+ echo "file0 contents" > $local_test_dir/file0
+ echo "file1 contents" > $local_test_dir/file1
+ echo "file2 contents" > $local_test_dir/file2
+ echo "file3 contents" > $local_test_dir/$local_test_subdir/file3
+ echo "file4 contents" > $local_test_dir/$local_test_subdir/file4
+ echo "file5 contents" > $local_test_dir/$local_test_subdir/file5
+
+ add_dir_to_install "$local_test_dir" ""
+
+ rm -r $local_test_dir
+
+ [ -f "$PACKAGE_SOURCE_DIR/file0" ]
+ [ -f "$PACKAGE_SOURCE_DIR/file1" ]
+ [ -f "$PACKAGE_SOURCE_DIR/file2" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$local_test_subdir/file3" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$local_test_subdir/file4" ]
+ [ -f "$PACKAGE_SOURCE_DIR/$local_test_subdir/file5" ]
+}
diff --git a/src/Installers/Debian/test/unit_tests/test_scripts.bats b/src/Installers/Debian/test/unit_tests/test_scripts.bats
new file mode 100755
index 0000000000..9d23b0b126
--- /dev/null
+++ b/src/Installers/Debian/test/unit_tests/test_scripts.bats
@@ -0,0 +1,28 @@
+#!/usr/bin/env bats
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+
+# Tests for debian_build_lib.sh
+
+setup(){
+ DIR="$BATS_TEST_DIRNAME"
+ PACKAGIFY_DIR="$(readlink -f $DIR/../../)"
+}
+
+@test "manpage generation is identical to lkg file" {
+ # Output is file "tool1.1"
+ # LKG file is "lkgtestman.1"
+ python $PACKAGIFY_DIR/scripts/manpage_generator.py $PACKAGIFY_DIR/test/test_assets/testdocs.json $PACKAGIFY_DIR/test/test_assets
+
+ # Test Output existence
+ [ -f $PACKAGIFY_DIR/test/test_assets/tool1.1 ]
+
+ # Test Output matches LKG
+ # If this is failing double check line ending style
+ [ -z "$(diff "$PACKAGIFY_DIR/test/test_assets/tool1.1" "$PACKAGIFY_DIR/test/test_assets/lkgtestman.1")" ]
+
+ # Cleanup
+ rm $PACKAGIFY_DIR/test/test_assets/tool1.1
+}
\ No newline at end of file
diff --git a/src/Installers/Windows/.gitignore b/src/Installers/Windows/.gitignore
new file mode 100644
index 0000000000..fe67cac916
--- /dev/null
+++ b/src/Installers/Windows/.gitignore
@@ -0,0 +1 @@
+ancm/
diff --git a/src/Installers/Windows/Directory.Build.props b/src/Installers/Windows/Directory.Build.props
new file mode 100644
index 0000000000..096863e245
--- /dev/null
+++ b/src/Installers/Windows/Directory.Build.props
@@ -0,0 +1,20 @@
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(MSBuildThisFileDirectory)..\..\..\'))
+ $(RepositoryRoot)artifacts/
+ $(RootOutputPath)bin/$(Configuration)/$(MSBuildProjectName)/
+ $(BaseOutputPath)
+ $(RootOutputPath)obj/$(MSBuildProjectName)/
+ $(BaseIntermediateOutputPath)$(Configuration)/
+ $(IntermediateOutputPath)$(Platform)/
+
+ aspnetcore-runtime
+
+ $(RuntimeInstallerBaseName)-internal
+
+
+
+
+
+
diff --git a/src/Installers/Windows/Directory.Build.targets b/src/Installers/Windows/Directory.Build.targets
new file mode 100644
index 0000000000..8dc63cace9
--- /dev/null
+++ b/src/Installers/Windows/Directory.Build.targets
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFramework/DependencyProvider.wxs b/src/Installers/Windows/SharedFramework/DependencyProvider.wxs
new file mode 100644
index 0000000000..d62c3dfe7d
--- /dev/null
+++ b/src/Installers/Windows/SharedFramework/DependencyProvider.wxs
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Installers/Windows/SharedFramework/Product.props b/src/Installers/Windows/SharedFramework/Product.props
new file mode 100644
index 0000000000..a6a29c3f80
--- /dev/null
+++ b/src/Installers/Windows/SharedFramework/Product.props
@@ -0,0 +1,11 @@
+
+
+ Microsoft ASP.NET Core Shared Framework
+ Microsoft ASP.NET Core $(PackageBrandingVersion) Shared Framework ($(Platform))
+ AspNetCore.SharedFramework
+
+ $(DefineConstants);ProductName=$(ProductName)
+ $(DefineConstants);ProductNameShort=$(ProductNameShort)
+ $(DefineConstants);ProductNameFolder=$(ProductNameFolder)
+
+
diff --git a/src/Installers/Windows/SharedFramework/Product.wxs b/src/Installers/Windows/SharedFramework/Product.wxs
new file mode 100644
index 0000000000..c97b12e5c4
--- /dev/null
+++ b/src/Installers/Windows/SharedFramework/Product.wxs
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFramework/SharedFramework.wixproj b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj
new file mode 100644
index 0000000000..5dd1ce6809
--- /dev/null
+++ b/src/Installers/Windows/SharedFramework/SharedFramework.wixproj
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+ AspNetCoreSharedFramework
+ $(RuntimeInstallerBaseName)-$(PackageVersion)-win-$(Platform)
+ Package
+ no
+ sfx_$(Platform).cab
+ C681D730-4505-42C6-9E6C-87F757C4FB32
+ true
+ 5150;5151
+ true
+ $(SharedFrameworkHarvestRootPath)\$(Platform)\
+ $(DefineConstants);AspNetCoreSharedFrameworkSource=$(HarvestSource)
+ $(SharedFrameworkNamespaceGuid)
+
+
+
+
+ $(WixExtDir)\WixDependencyExtension.dll
+ WixDependencyExtension
+
+
+ $(WixExtDir)\WixNetFxExtension.dll
+ WixNetFxExtension
+
+
+ $(WixExtDir)\WixUtilExtension.dll
+ WixUtilExtension
+
+
+ $(WixExtDir)\WixUIExtension.dll
+ WixUIExtension
+
+
+
+
+
+ true
+ CG_AspNetCoreSharedFramework
+ DotNetFolder
+ var.AspNetCoreSharedFrameworkSource
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFramework/Strings.wxl b/src/Installers/Windows/SharedFramework/Strings.wxl
new file mode 100644
index 0000000000..ffac28752f
--- /dev/null
+++ b/src/Installers/Windows/SharedFramework/Strings.wxl
@@ -0,0 +1,5 @@
+
+
+ ASP.NET Core Shared Framework
+ ASP.NET Core Shared Framework
+
\ No newline at end of file
diff --git a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
new file mode 100644
index 0000000000..2ca506b46e
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Installers/Windows/SharedFrameworkBundle/DotNetLogo.bmp b/src/Installers/Windows/SharedFrameworkBundle/DotNetLogo.bmp
new file mode 100644
index 0000000000..f652d049e8
Binary files /dev/null and b/src/Installers/Windows/SharedFrameworkBundle/DotNetLogo.bmp differ
diff --git a/src/Installers/Windows/SharedFrameworkBundle/Product.props b/src/Installers/Windows/SharedFrameworkBundle/Product.props
new file mode 100644
index 0000000000..a77dc7a3df
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkBundle/Product.props
@@ -0,0 +1,31 @@
+
+
+ Microsoft ASP.NET Core $(PackageBrandingVersion)
+
+
+
+ Shared Framework
+ $(BundleNameShort) - $(BundleNameSub)
+ $(BundleName) ($(Platform))
+ Microsoft Corporation
+ dd_AspNetCoreSharedFramework_
+
+
+ Microsoft
+ .NET Core
+ Microsoft ASP.NET Core $(PackageBrandingVersion) Shared Framework
+ $(BundleNameFull)
+
+
+
+ $(DefineConstants);BundleName=$(BundleName)
+ $(DefineConstants);BundleNameFull=$(BundleNameFull)
+ $(DefineConstants);BundleNameShort=$(BundleNameShort)
+ $(DefineConstants);BundleNameSub=$(BundleNameSub)
+ $(DefineConstants);BundleManufacturer=$(BundleManufacturer)
+ $(DefineConstants);BundleLogPrefix=$(BundleLogPrefix)
+ $(DefineConstants);BundleRegManufacturer=$(BundleRegManufacturer)
+ $(DefineConstants);BundleRegFamily=$(BundleRegFamily)
+ $(DefineConstants);BundleRegName=$(BundleRegName)
+
+
diff --git a/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
new file mode 100644
index 0000000000..e4d3697989
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+ AspNetCoreSharedFrameworkBundle
+ Bundle
+ $(RuntimeInstallerBaseName)-$(PackageVersion)-win-$(Platform)
+ $(SharedFrameworkNamespaceGuid)
+ D6C54D8B-043F-4877-B751-60E7390F9EC6
+
+
+
+
+ $(WixExtDir)\WixDependencyExtension.dll
+ WixDependencyExtension
+
+
+ $(WixExtDir)\WixBalExtension.dll
+ WixBalExtension
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFrameworkBundle/thm.wxl b/src/Installers/Windows/SharedFrameworkBundle/thm.wxl
new file mode 100644
index 0000000000..bb88e23d9e
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkBundle/thm.wxl
@@ -0,0 +1,61 @@
+
+
+ [BundleNameFull] Setup
+ [BundleNameShort]
+ [BundleNameSub]
+
+ Setup will install [WixBundleName] on your computer. Click install to continue, options to set the install directory or Close to exit.
+ Version [WixBundleVersion]
+ Are you sure you want to cancel?
+ Previous version
+
+ /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
+ creates a complete local copy of the bundle in directory. Install is the default.
+
+/passive | /quiet - displays minimal UI with no prompts or displays no UI and
+ no prompts. By default UI and all prompts are displayed.
+
+/norestart - suppress any attempts to restart. By default UI will prompt before restart.
+/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.
+ &Close
+ [WixBundleName] <a href="#">license terms</a>.
+ I &agree to the license terms and conditions
+ &Options
+ &Install
+ &Close
+
+ Install location:
+ &Browse
+ &OK
+ &Cancel
+
+ Processing:
+ Initializing...
+ &Cancel
+
+ &Repair
+ &Uninstall
+ &Close
+
+
+
+
+ &Launch
+ You must restart your computer before you can use the software.
+ &Restart
+ &Close
+
+
+
+
+ One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.
+ You must restart your computer to complete the rollback of the software.
+ &Restart
+ &Close
+
+ The following applications are using files that need to be updated:
+ Close the &applications and attempt to restart them.
+ &Do not close applications. A reboot will be required.
+ &OK
+ &Cancel
+
\ No newline at end of file
diff --git a/src/Installers/Windows/SharedFrameworkBundle/thm.xml b/src/Installers/Windows/SharedFrameworkBundle/thm.xml
new file mode 100644
index 0000000000..f9323a366f
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkBundle/thm.xml
@@ -0,0 +1,80 @@
+
+
+ #(loc.Caption)
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+
+
+ #(loc.Title)
+ #(loc.SubTitle)
+
+
+ #(loc.HelpHeader)
+ #(loc.HelpText)
+
+
+
+ Welcome to the #(loc.Caption).
+ [WixBundleName] <a href="https://go.microsoft.com/fwlink/?LinkId=320539">license terms</a> and <a href="https://go.microsoft.com/fwlink/?LinkId=786378">privacy statement</a>.
+ #(loc.InstallAcceptCheckbox)
+
+
+
+
+
+ #(loc.OptionsHeader)
+ #(loc.OptionsLocationLabel)
+
+
+
+
+
+
+ #(loc.FilesInUseHeader)
+ #(loc.FilesInUseLabel)
+
+
+
+
+
+
+
+
+
+ #(loc.ProgressHeader)
+ #(loc.ProgressLabel)
+ #(loc.OverallProgressPackageText)
+
+
+
+
+ #(loc.ModifyHeader)
+
+
+
+
+
+ #(loc.SuccessHeader)
+ #(loc.SuccessInstallHeader)
+ #(loc.SuccessRepairHeader)
+ #(loc.SuccessUninstallHeader)
+
+ #(loc.SuccessRestartText)
+
+
+
+
+ #(loc.FailureHeader)
+ #(loc.FailureInstallHeader)
+ #(loc.FailureUninstallHeader)
+ #(loc.FailureRepairHeader)
+ #(loc.FailureHyperlinkLogText)
+
+ #(loc.FailureRestartText)
+
+
+
+
\ No newline at end of file
diff --git a/src/Installers/Windows/SharedFrameworkLib/Library.wxs b/src/Installers/Windows/SharedFrameworkLib/Library.wxs
new file mode 100644
index 0000000000..e3a367a7e4
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkLib/Library.wxs
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFrameworkLib/SharedFrameworkLib.wixproj b/src/Installers/Windows/SharedFrameworkLib/SharedFrameworkLib.wixproj
new file mode 100644
index 0000000000..672ca7de66
--- /dev/null
+++ b/src/Installers/Windows/SharedFrameworkLib/SharedFrameworkLib.wixproj
@@ -0,0 +1,27 @@
+
+
+
+
+
+ AspNetCoreSharedFrameworkLib$(Platform)
+ $(WixlibBaseFileName)-$(PackageVersion)-win-$(Platform)
+ Library
+ true
+ $(SharedFrameworkNamespaceGuid)
+ 5244BC49-2568-4701-80A6-EAB8950AB5FA
+
+
+
+ $(DefineConstants);Debug
+
+
+
+
+
+ $(WixExtDir)\WixBalExtension.dll
+ WixBalExtension
+
+
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs
new file mode 100644
index 0000000000..367daa45ed
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/ANCM.wxs
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs b/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs
new file mode 100644
index 0000000000..96f43c5515
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs b/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs
new file mode 100644
index 0000000000..5f017547dd
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/DotNetCore.wxs
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/DotNetLogo.bmp b/src/Installers/Windows/WindowsHostingBundle/DotNetLogo.bmp
new file mode 100644
index 0000000000..f652d049e8
Binary files /dev/null and b/src/Installers/Windows/WindowsHostingBundle/DotNetLogo.bmp differ
diff --git a/src/Installers/Windows/WindowsHostingBundle/Product.props b/src/Installers/Windows/WindowsHostingBundle/Product.props
new file mode 100644
index 0000000000..64492e50c9
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/Product.props
@@ -0,0 +1,31 @@
+
+
+ Microsoft .NET Core $(PackageBrandingVersion)
+
+
+
+ Windows Server Hosting
+ $(BundleNameShort) - $(BundleNameSub)
+ $(BundleName) ($(Platform))
+ Microsoft Corporation
+ dd_DotNetCoreWinSvrHosting
+
+
+ Microsoft
+ .NET Core
+ Microsoft .NET Core $(PackageBrandingVersion) - Windows Server Hosting
+ $(BundleNameFull)
+
+
+
+ $(DefineConstants);BundleName=$(BundleName)
+ $(DefineConstants);BundleNameFull=$(BundleNameFull)
+ $(DefineConstants);BundleNameShort=$(BundleNameShort)
+ $(DefineConstants);BundleNameSub=$(BundleNameSub)
+ $(DefineConstants);BundleManufacturer=$(BundleManufacturer)
+ $(DefineConstants);BundleLogPrefix=$(BundleLogPrefix)
+ $(DefineConstants);BundleRegManufacturer=$(BundleRegManufacturer)
+ $(DefineConstants);BundleRegFamily=$(BundleRegFamily)
+ $(DefineConstants);BundleRegName=$(BundleRegName)
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/Product.targets b/src/Installers/Windows/WindowsHostingBundle/Product.targets
new file mode 100644
index 0000000000..038dd250ff
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/Product.targets
@@ -0,0 +1,90 @@
+
+
+ $(IntermediateOutputPath)d\
+ $(BaseIntermediateOutputPath)
+ $(DefineConstants);DepsPath=$(DepsPath)
+
+
+
+
+
+ x64
+ DotNetRedistLtsInstallerx64
+ $(MicrosoftNETCoreAppPackageVersion)
+
+
+ x86
+ DotNetRedistLtsInstallerx86
+ $(MicrosoftNETCoreAppPackageVersion)
+
+
+
+
+
+ https://dotnetcli.azureedge.net/dotnet/
+ $(DotNetAssetRootUrl)/
+
+
+
+
+ dotnet-runtime-$(MicrosoftNETCoreAppPackageVersion)-win-x64.exe
+
+
+ dotnet-runtime-$(MicrosoftNETCoreAppPackageVersion)-win-x86.exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DotNetRedistLtsInstallerProductVersion%(Platforms.Identity)
+ DotNetRedistLtsInstallerProductCode%(Platforms.Identity)
+ DotNetRedistLtsInstallerUpgradeCode%(Platforms.Identity)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);DotNetRedistLtsInstallerx64=$(DotNetRedistLtsInstallerx64)
+ $(DefineConstants);DotNetRedistLtsInstallerProductVersionx64=$(DotNetRedistLtsInstallerProductVersionx64)
+ $(DefineConstants);DotNetRedistLtsInstallerProductCodex64=$(DotNetRedistLtsInstallerProductCodex64)
+ $(DefineConstants);DotNetRedistLtsInstallerUpgradeCodex64=$(DotNetRedistLtsInstallerUpgradeCodex64)
+ $(DefineConstants);DotNetRedistLtsInstallerx86=$(DotNetRedistLtsInstallerx86)
+ $(DefineConstants);DotNetRedistLtsInstallerProductVersionx86=$(DotNetRedistLtsInstallerProductVersionx86)
+ $(DefineConstants);DotNetRedistLtsInstallerProductCodex86=$(DotNetRedistLtsInstallerProductCodex86)
+ $(DefineConstants);DotNetRedistLtsInstallerUpgradeCodex86=$(DotNetRedistLtsInstallerUpgradeCodex86)
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/Strings.wxl b/src/Installers/Windows/WindowsHostingBundle/Strings.wxl
new file mode 100644
index 0000000000..069fdd7451
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/Strings.wxl
@@ -0,0 +1,10 @@
+
+
+ Some features that were selected requires .NET 4.5.1. Please install .NET 4.5.1, then install this product again.
+ This product requires IIS 7.5. Please install IIS, then install this product again.
+ This product requires Visual Studio 2015 Update 2 or later. Please install Visual Studio 2015 Update 2 or later, then install this product again.
+ This product requires Visual Studio 2015 Update 3 or later. Please install Visual Studio 2015 Update 3 or later, then install this product again.
+ Setup has detected that Visual Studio 2015 Update 3 may not be completely installed. Please repair Visual Studio 2015 Update 3, then install this product again.
+ This product requires the Web Developer Tools feature in Visual Studio 2015. Please enable the feature by going to Programs and Features in Windows, then modify Visual Studio 2015.
+ This product requires Visual Studio 2015 or Visual Studio Express 2015 for Web to be installed. Please install the missing product, then install this product again.
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj
new file mode 100644
index 0000000000..70d2362433
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+ WindowsServerHostingBundle
+ dotnet-hosting-$(PackageVersion)-win
+ 6F1B115C-1903-40CB-837D-7961AB610F4E
+ Bundle
+ x86
+
+
+ $(HostingBundleNamespaceGuid)
+
+
+
+
+
+
+ $(WixExtDir)\WixUtilExtension.dll
+ WixUtilExtension
+
+
+ $(WixExtDir)\WixDependencyExtension.dll
+ WixDependencyExtension
+
+
+ $(WixExtDir)\WixBalExtension.dll
+ WixBalExtension
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/thm.wxl b/src/Installers/Windows/WindowsHostingBundle/thm.wxl
new file mode 100644
index 0000000000..87ae937c7d
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/thm.wxl
@@ -0,0 +1,61 @@
+
+
+ [WixBundleName] Setup
+ [BundleNameShort]
+ [BundleNameSub]
+
+ Setup will install [WixBundleName] on your computer. Click install to continue, options to set the install directory or Close to exit.
+ Version [WixBundleVersion]
+ Are you sure you want to cancel?
+ Previous version
+
+ /install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
+ creates a complete local copy of the bundle in directory. Install is the default.
+
+/passive | /quiet - displays minimal UI with no prompts or displays no UI and
+ no prompts. By default UI and all prompts are displayed.
+
+/norestart - suppress any attempts to restart. By default UI will prompt before restart.
+/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.
+ &Close
+ [WixBundleName] <a href="#">license terms</a>.
+ I &agree to the license terms and conditions
+ &Options
+ &Install
+ &Close
+
+ Install location:
+ &Browse
+ &OK
+ &Cancel
+
+ Processing:
+ Initializing...
+ &Cancel
+
+ &Repair
+ &Uninstall
+ &Close
+
+
+
+
+ &Launch
+ You must restart your computer before you can use the software.
+ &Restart
+ &Close
+
+
+
+
+ One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.
+ You must restart your computer to complete the rollback of the software.
+ &Restart
+ &Close
+
+ The following applications are using files that need to be updated:
+ Close the &applications and attempt to restart them.
+ &Do not close applications. A reboot will be required.
+ &OK
+ &Cancel
+
\ No newline at end of file
diff --git a/src/Installers/Windows/WindowsHostingBundle/thm.xml b/src/Installers/Windows/WindowsHostingBundle/thm.xml
new file mode 100644
index 0000000000..8ca4905b72
--- /dev/null
+++ b/src/Installers/Windows/WindowsHostingBundle/thm.xml
@@ -0,0 +1,84 @@
+
+
+ #(loc.Caption)
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+ Segoe UI
+
+
+ #(loc.Title)
+ #(loc.SubTitle)
+
+
+ #(loc.HelpHeader)
+ #(loc.HelpText)
+
+
+
+ Welcome to the #(loc.Caption).
+ Please restart IIS after the installation completes. You can find additional information <a href="https://go.microsoft.com/fwlink/?LinkId=798277">here</a>.
+ IIS is not enabled on this machine. If you intend to run ASP.NET Core applications with IIS, you must install IIS before running this installer. You can find additional information <a href="https://go.microsoft.com/fwlink/?LinkId=798277">here</a>.
+ [WixBundleName] <a href="https://go.microsoft.com/fwlink/?LinkId=320539">license terms</a> and <a href="https://go.microsoft.com/fwlink/?LinkId=786378">privacy statement</a>.
+ #(loc.InstallAcceptCheckbox)
+
+
+
+
+
+ #(loc.OptionsHeader)
+ #(loc.OptionsLocationLabel)
+
+
+
+
+
+
+ #(loc.FilesInUseHeader)
+ #(loc.FilesInUseLabel)
+
+
+
+
+
+
+
+
+
+ #(loc.ProgressHeader)
+ #(loc.ProgressLabel)
+ #(loc.OverallProgressPackageText)
+
+
+
+
+ #(loc.ModifyHeader)
+ Please restart IIS after the installation completes. You can find additional information <a href="https://go.microsoft.com/fwlink/?LinkId=798277">here</a>.
+ IIS is not enabled on this machine. If you intend to run ASP.NET Core applications with IIS, you must install IIS before running this installer. You can find additional information <a href="https://go.microsoft.com/fwlink/?LinkId=798277">here</a>.
+
+
+
+
+
+ #(loc.SuccessHeader)
+ #(loc.SuccessInstallHeader)
+ #(loc.SuccessRepairHeader)
+ #(loc.SuccessUninstallHeader)
+
+ #(loc.SuccessRestartText)
+
+
+
+
+ #(loc.FailureHeader)
+ #(loc.FailureInstallHeader)
+ #(loc.FailureUninstallHeader)
+ #(loc.FailureRepairHeader)
+ #(loc.FailureHyperlinkLogText)
+
+ #(loc.FailureRestartText)
+
+
+
+
\ No newline at end of file
diff --git a/src/Installers/Windows/WindowsInstallers.proj b/src/Installers/Windows/WindowsInstallers.proj
new file mode 100644
index 0000000000..bf0011cca0
--- /dev/null
+++ b/src/Installers/Windows/WindowsInstallers.proj
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Installers/Windows/Wix.props b/src/Installers/Windows/Wix.props
new file mode 100644
index 0000000000..61c4ca9f6c
--- /dev/null
+++ b/src/Installers/Windows/Wix.props
@@ -0,0 +1,38 @@
+
+
+
+ $(AspNetCoreMajorVersion).$(AspNetCoreMinorVersion).$(AspNetCorePatchVersion).0
+
+ Release
+ x64
+ ENU
+ en-US
+ $(RootOutputPath)bin/$(Configuration)/installers/
+ $(BaseOutputPath)
+
+
+
+
+ -fv
+ ICE61
+ 1033
+
+
+
+ false
+
+
+ E1FD1271-E0F0-4B8B-B4BE-01F2EBA58F4E
+ C43D5520-11B3-4D62-B6FE-5D6840B04101
+
+
+
+ $(DefineConstants);files=$(MSBuildThisFileDirectory)files
+ $(DefineConstants);Version=$(Version)
+ $(DefineConstants);Culture=$(Cultures)
+ $(DefineConstants);MajorVersion=$(AspNetCoreMajorVersion)
+ $(DefineConstants);MinorVersion=$(AspNetCoreMinorVersion)
+ $(DefineConstants);PackageVersion=$(PackageVersion)
+
+
+
diff --git a/src/Installers/Windows/Wix.targets b/src/Installers/Windows/Wix.targets
new file mode 100644
index 0000000000..a40275cd06
--- /dev/null
+++ b/src/Installers/Windows/Wix.targets
@@ -0,0 +1,42 @@
+
+
+ $(ProductName)
+ Microsoft.$(ProductNameShort)_$(Platform)_$(Lang),v$(PackageVersion)
+ $(DefineConstants);DepProviderKey=$(DepProviderKey)
+
+
+
+ $(Version);$(Platform)
+ $(GuidInputs);$(BuildNumber)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);ProductCode=$(ProductCode);UpgradeCode=$(UpgradeCode)
+
+
+
+
+
+
+
+
+
+
+
+
+ $(DefineConstants);BundleProviderKey=$(BundleProviderKey);BundleUpgradeCode=$(BundleUpgradeCode)
+
+
+
diff --git a/src/Installers/Windows/build.ps1 b/src/Installers/Windows/build.ps1
new file mode 100644
index 0000000000..c6493b84c2
--- /dev/null
+++ b/src/Installers/Windows/build.ps1
@@ -0,0 +1,98 @@
+#
+# This script requires internal-only access to the code which generates ANCM installers.
+#
+
+#requires -version 5
+[cmdletbinding()]
+param(
+ [string]$Configuration = 'Debug',
+ [Parameter(Mandatory = $true)]
+ [Alias("x86")]
+ [string]$Runtime86Zip,
+ [Parameter(Mandatory = $true)]
+ [Alias("x64")]
+ [string]$Runtime64Zip,
+ [string]$BuildNumber = 't000',
+ [string]$SignType = '',
+ [string]$PackageVersionPropsUrl = $null,
+ [string]$AccessTokenSuffix = $null,
+ [string]$AssetRootUrl = $null,
+ [switch]$clean
+)
+
+$ErrorActionPreference = 'Stop'
+$repoRoot = Resolve-Path "$PSScriptRoot/../../../"
+Import-Module -Scope Local "$repoRoot/scripts/common.psm1" -Force
+$msbuild = Get-MSBuildPath -Prerelease -requires 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64'
+
+$harvestRoot = "$repoRoot/obj/sfx/"
+if ($clean) {
+ Remove-Item -Recurse -Force $harvestRoot -ErrorAction Ignore | Out-Null
+}
+
+New-Item "$harvestRoot/x86", "$harvestRoot/x64" -ItemType Directory -ErrorAction Ignore | Out-Null
+
+if (-not (Test-Path "$harvestRoot/x86/shared/")) {
+ Expand-Archive $Runtime86Zip -DestinationPath "$harvestRoot/x86"
+}
+
+if (-not (Test-Path "$harvestRoot/x64/shared/")) {
+ Expand-Archive $Runtime64Zip -DestinationPath "$harvestRoot/x64"
+}
+
+Push-Location $PSScriptRoot
+try {
+ Invoke-Block { & $msbuild `
+ tasks/InstallerTasks.csproj `
+ -nologo `
+ -m `
+ -v:m `
+ -nodeReuse:false `
+ -restore `
+ -t:Build `
+ "-p:Configuration=$Configuration"
+ }
+
+ [string[]] $msbuildArgs = @()
+
+ if ($clean) {
+ $msbuildArgs += '-t:Clean'
+ }
+
+ if ($AssetRootUrl) {
+ $msbuildArgs += "-p:DotNetAssetRootUrl=$AssetRootUrl"
+ }
+
+ if ($AccessTokenSuffix) {
+ $msbuildArgs += "-p:DotNetAccessTokenSuffix=$AccessTokenSuffix"
+ }
+
+ if ($PackageVersionPropsUrl) {
+ $IntermediateDir = Join-Path $PSScriptRoot 'obj'
+ $PropsFilePath = Join-Path $IntermediateDir 'external-dependencies.props'
+ New-Item -ItemType Directory $IntermediateDir -ErrorAction Ignore | Out-Null
+ Get-RemoteFile "${PackageVersionPropsUrl}${AccessTokenSuffix}" $PropsFilePath
+ $msbuildArgs += "-p:DotNetPackageVersionPropsPath=$PropsFilePath"
+ }
+
+ $msbuildArgs += '-t:Build'
+
+ Invoke-Block { & $msbuild `
+ WindowsInstallers.proj `
+ -restore `
+ -nologo `
+ -m `
+ -v:m `
+ -nodeReuse:false `
+ -clp:Summary `
+ "-p:SharedFrameworkHarvestRootPath=$repoRoot/obj/sfx/" `
+ "-p:Configuration=$Configuration" `
+ "-p:BuildNumber=$BuildNumber" `
+ "-p:SignType=$SignType" `
+ "-bl:$repoRoot/artifacts/logs/installers.msbuild.binlog" `
+ @msbuildArgs
+ }
+}
+finally {
+ Pop-Location
+}
diff --git a/src/Installers/Windows/clone_and_build_ancm.ps1 b/src/Installers/Windows/clone_and_build_ancm.ps1
new file mode 100644
index 0000000000..cc76a869d9
--- /dev/null
+++ b/src/Installers/Windows/clone_and_build_ancm.ps1
@@ -0,0 +1,105 @@
+#
+# This builds installers for AspNetCoreModule.
+# This script requires internal-only access to the code which generates ANCM installers.
+#
+#requires -version 5
+[cmdletbinding()]
+param(
+ [string]$GitCredential,
+ [string]$Configuration = 'Release',
+ [string]$BuildNumber = 't000',
+ [string]$AncmSourceBranch = 'release/2.1',
+ [string]$SignType = ''
+)
+
+$ErrorActionPreference = 'Stop'
+
+$repoRoot = Resolve-Path "$PSScriptRoot/../../../"
+
+Import-Module -Scope Local "$repoRoot/scripts/common.psm1" -Force
+
+$msbuild = Get-MSBuildPath -Prerelease -requires 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64'
+
+# get wix
+[version] $wixVer = '3.11.1'
+$wixToolSetRoot = "$repoRoot/obj/tools/wix/$wixVer/"
+$downloadFile = "$wixToolSetRoot/wix-binaries.zip"
+if (-not (Test-Path $downloadFile)) {
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+ $downloadUrl = "https://github.com/wixtoolset/wix3/releases/download/wix$($wixVer.Major)$($wixVer.Minor)$($wixVer.Build)rtm/wix$($wixVer.Major)$($wixVer.Minor)-binaries.zip"
+ Write-Host "Downloading fix $wixVer from $downloadUrl"
+ New-Item -Type Directory $wixToolSetRoot -ErrorAction Ignore | Out-Null
+ Invoke-WebRequest -UseBasicParsing -Uri $downloadUrl -OutFile $downloadFile
+ Expand-Archive $downloadFile -DestinationPath $wixToolSetRoot
+}
+
+# get nuget.exe
+$nuget = "$repoRoot/obj/tools/nuget.exe"
+if (-not (Test-Path $nuget)) {
+ Invoke-WebRequest -UseBasicParsing -Uri 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' -OutFile $nuget
+}
+
+Push-Location $PSScriptRoot
+
+try {
+ if ($GitCredential) {
+ # Disable prompts for passwords
+ $env:GIT_TERMINAL_PROMPT = 0
+ }
+
+ if (-not (Test-Path ancm/)) {
+ Invoke-Block {
+ & git clone "https://${GitCredential}@devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/AspNetCoreModule-Setup" `
+ --branch $AncmSourceBranch `
+ --recursive `
+ ancm/
+ }
+ }
+
+ Invoke-Block -WorkingDir ancm/ {
+ & git submodule update --init --recursive
+ }
+
+ Invoke-Block -WorkingDir ancm/ {
+ New-Item .deps -ItemType Directory -ErrorAction Ignore | Out-Null
+ Copy-Item "$repoRoot/obj/dependencies.g.props" .deps/dependencies.g.props
+ & $msbuild artifactfetcher/artifactfetcher.csproj `
+ '-t:Restore' `
+ "-p:RestoreAdditionalProjectSources=$repoRoot/artifacts/build"
+ }
+
+ Invoke-Block -WorkingDir ancm/ {
+ & $nuget restore ANCM-Setup.sln
+ }
+
+ Invoke-Block -WorkingDir ancm/IIS-Common/lib/ {
+ & $nuget restore packages.config
+ }
+
+ Invoke-Block { & $msbuild `
+ ancm/Setup.msbuild `
+ -m `
+ -v:m `
+ -nodeReuse:false `
+ -clp:Summary `
+ "-t:BuildCustomAction;Build" `
+ "-p:WixToolPath=$wixToolSetRoot" `
+ "-p:WixTargetsPath=$wixToolSetRoot\Wix.targets" `
+ "-p:WixTasksPath=$wixToolSetRoot\wixtasks.dll" `
+ "-p:WixNativeCATargetsPath=$wixToolSetRoot\sdk\wix.nativeca.targets" `
+ "-p:Configuration=$Configuration" `
+ "-p:BuildNumber=$BuildNumber" `
+ "-p:SignType=$SignType" `
+ "-bl:$repoRoot/artifacts/logs/ancn.msbuild.binlog"
+ }
+
+ $outputPath = "$repoRoot/artifacts/bin/$Configuration/installers/en-US/"
+ New-Item $outputPath -ItemType Directory -ErrorAction Ignore | Out-Null
+ Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV1/$Configuration/x64/en-us/*" $outputPath
+ Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV1/$Configuration/x86/en-us/*" $outputPath
+ Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV2/$Configuration/x64/en-us/*" $outputPath
+ Copy-Item -Recurse "ancm/bin/AspNetCoreModuleV2/$Configuration/x86/en-us/*" $outputPath
+}
+finally {
+ Pop-Location
+}
diff --git a/src/Installers/Windows/files/eula.rtf b/src/Installers/Windows/files/eula.rtf
new file mode 100644
index 0000000000..70fb842c6c
--- /dev/null
+++ b/src/Installers/Windows/files/eula.rtf
@@ -0,0 +1,113 @@
+{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\deflangfe1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Tahoma;}{\f1\froman\fprq2\fcharset0 Times New Roman;}{\f2\fswiss\fprq2\fcharset0 Calibri;}{\f3\fnil\fcharset2 Symbol;}}
+{\colortbl ;\red31\green73\blue125;\red0\green0\blue255;}
+{\*\listtable
+{\list\listhybrid
+{\listlevel\levelnfc0\leveljc0\levelstartat1{\leveltext\'02\'00.;}{\levelnumbers\'01;}\jclisttab\tx360}
+{\listlevel\levelnfc4\leveljc0\levelstartat1{\leveltext\'02\'01.;}{\levelnumbers\'01;}\jclisttab\tx363}
+{\listlevel\levelnfc2\leveljc0\levelstartat1{\leveltext\'02\'02.;}{\levelnumbers\'01;}\jclisttab\tx720}\listid1 }
+{\list\listhybrid
+{\listlevel\levelnfc0\leveljc0\levelstartat1{\leveltext\'02\'00.;}{\levelnumbers\'01;}\jclisttab\tx363}
+{\listlevel\levelnfc4\leveljc0\levelstartat1{\leveltext\'02\'01.;}{\levelnumbers\'01;}\jclisttab\tx363}\listid2 }}
+{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}}
+{\*\generator Riched20 6.3.9600}{\*\mmathPr\mnaryLim0\mdispDef1\mwrapIndent1440 }\viewkind4\uc1
+\pard\nowidctlpar\sb120\sa120\b\f0\fs24 MICROSOFT SOFTWARE LICENSE TERMS\par
+
+\pard\brdrb\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120 MICROSOFT .NET LIBRARY \par
+
+\pard\nowidctlpar\sb120\sa120\fs19 These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above, which includes the media on which you received it, if any. The terms also apply to any Microsoft\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent363{\pntxtb\'B7}}\nowidctlpar\fi-363\li720\sb120\sa120\b0 updates,\par
+{\pntext\f3\'B7\tab}supplements,\par
+{\pntext\f3\'B7\tab}Internet-based services, and\par
+{\pntext\f3\'B7\tab}support services\par
+
+\pard\nowidctlpar\sb120\sa120\b for this software, unless other terms accompany those items. If so, those terms apply.\par
+BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE.\par
+
+\pard\brdrt\brdrs\brdrw10\brsp20 \nowidctlpar\sb120\sa120 IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE PERPETUAL RIGHTS BELOW.\par
+
+\pard
+{\listtext\f0 1.\tab}\jclisttab\tx360\ls1\nowidctlpar\fi-357\li357\sb120\sa120 INSTALLATION AND USE RIGHTS. \par
+
+\pard
+{\listtext\f0 a.\tab}\jclisttab\tx363\ls1\ilvl1\nowidctlpar\fi-363\li720\sb120\sa120 Installation and Use.\b0\fs20 You may install and use any number of copies of the software to design, develop and test your programs.\par
+{\listtext\f0 b.\tab}\b\fs19 Third Party Programs.\b0\fs20 The software may include third party programs that Microsoft, not the third party, licenses to you under this agreement. Notices, if any, for the third party program are included for your information only.\b\fs19\par
+
+\pard
+{\listtext\f0 2.\tab}\jclisttab\tx360\ls1\nowidctlpar\fi-357\li357\sb120\sa120\fs20 ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS.\par
+
+\pard
+{\listtext\f0 a.\tab}\jclisttab\tx363\ls1\ilvl1\nowidctlpar\fi-363\li720\sb120\sa120 DISTRIBUTABLE CODE.\~ \b0 The software is comprised of Distributable Code. \f1\ldblquote\f0 Distributable Code\f1\rdblquote\f0 is code that you are permitted to distribute in programs you develop if you comply with the terms below.\b\par
+
+\pard
+{\listtext\f0 i.\tab}\jclisttab\tx720\ls1\ilvl2\nowidctlpar\fi-357\li1077\sb120\sa120\tx1077 Right to Use and Distribute. \par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent360{\pntxtb\'B7}}\nowidctlpar\fi-357\li1434\sb120\sa120\b0 You may copy and distribute the object code form of the software.\par
+{\pntext\f3\'B7\tab}Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs.\par
+
+\pard\nowidctlpar\fi-357\li1077\sb120\sa120\tx1077\b ii.\tab Distribution Requirements.\b0 \b For any Distributable Code you distribute, you must\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent360{\pntxtb\'B7}}\nowidctlpar\fi-357\li1434\sb120\sa120\b0 add significant primary functionality to it in your programs;\par
+{\pntext\f3\'B7\tab}require distributors and external end users to agree to terms that protect it at least as much as this agreement;\par
+{\pntext\f3\'B7\tab}display your valid copyright notice on your programs; and\par
+{\pntext\f3\'B7\tab}indemnify, defend, and hold harmless Microsoft from any claims, including attorneys\rquote fees, related to the distribution or use of your programs.\par
+
+\pard\nowidctlpar\fi-357\li1077\sb120\sa120\tx1077\b iii.\tab Distribution Restrictions.\b0 \b You may not\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent360{\pntxtb\'B7}}\nowidctlpar\fi-357\li1434\sb120\sa120\b0 alter any copyright, trademark or patent notice in the Distributable Code;\par
+{\pntext\f3\'B7\tab}use Microsoft\rquote s trademarks in your programs\rquote names or in a way that suggests your programs come from or are endorsed by Microsoft;\par
+{\pntext\f3\'B7\tab}include Distributable Code in malicious, deceptive or unlawful programs; or\par
+{\pntext\f3\'B7\tab}modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent360{\pntxtb\'B7}}\nowidctlpar\fi-358\li1792\sb120\sa120 the code be disclosed or distributed in source code form; or\cf1\f2\par
+{\pntext\f3\'B7\tab}\cf0\f0 others have the right to modify it.\cf1\f2\par
+
+\pard\nowidctlpar\fi-357\li357\sb120\sa120\cf0\b\f0 3.\tab\fs19 SCOPE OF LICENSE. \b0 The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent363{\pntxtb\'B7}}\nowidctlpar\fi-363\li720\sb120\sa120 work around any technical limitations in the software;\par
+{\pntext\f3\'B7\tab}reverse engineer, decompile or disassemble the software, except and only to the extent that applicable law expressly permits, despite this limitation;\par
+{\pntext\f3\'B7\tab}publish the software for others to copy;\par
+{\pntext\f3\'B7\tab}rent, lease or lend the software;\par
+{\pntext\f3\'B7\tab}transfer the software or this agreement to any third party; or\par
+{\pntext\f3\'B7\tab}use the software for commercial software hosting services.\par
+
+\pard\nowidctlpar\fi-357\li357\sb120\sa120\b\fs20 4.\tab\fs19 BACKUP COPY. \b0 You may make one backup copy of the software. You may use it only to reinstall the software.\par
+\b\fs20 5.\tab\fs19 DOCUMENTATION. \b0 Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes.\par
+\b\fs20 6.\tab\fs19 EXPORT RESTRICTIONS. \b0 The software is subject to United States export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the software. These laws include restrictions on destinations, end users and end use. For additional information, see {\fs20{\field{\*\fldinst{HYPERLINK www.microsoft.com/exporting }}{\fldrslt{www.microsoft.com/exporting\ul0\cf0}}}}\f0\fs19 .\fs20\par
+\b 7.\tab\fs19 SUPPORT SERVICES. \b0 Because this software is \ldblquote as is,\rdblquote we may not provide support services for it.\par
+\b\fs20 8.\tab\fs19 ENTIRE AGREEMENT. \b0 This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.\par
+\b\fs20 9.\tab\fs19 APPLICABLE LAW.\par
+
+\pard
+{\listtext\f0 a.\tab}\jclisttab\tx363\ls2\ilvl1\nowidctlpar\fi-363\li720\sb120\sa120 United States. \b0 If you acquired the software in the United States, Washington state law governs the interpretation of this agreement and applies to claims for breach of it, regardless of conflict of laws principles. The laws of the state where you live govern all other claims, including claims under state consumer protection laws, unfair competition laws, and in tort.\par
+{\listtext\f0 b.\tab}\b Outside the United States. If you acquired the software in any other country, the laws of that country apply.\par
+
+\pard
+{\pntext\f0 1.\tab}{\*\pn\pnlvlbody\pnf0\pnindent360\pnstart1\pndec{\pntxta.}}
+\nowidctlpar\fi-357\li357\sb120\sa120 LEGAL EFFECT. \b0 This agreement describes certain legal rights. You may have other rights under the laws of your country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your country if the laws of your country do not permit it to do so.\par
+{\pntext\f0 2.\tab}\b DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED \ldblquote AS-IS.\rdblquote YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS OR STATUTORY GUARANTEES UNDER YOUR LOCAL LAWS WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.\par
+
+\pard\nowidctlpar\li357\sb120\sa120 FOR AUSTRALIA \endash YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS.\par
+
+\pard\nowidctlpar\fi-357\li357\sb120\sa120\fs20 12.\tab\fs19 LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.\par
+
+\pard\nowidctlpar\li357\sb120\sa120\b0 This limitation applies to\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent363{\pntxtb\'B7}}\nowidctlpar\fi-363\li720\sb120\sa120 anything related to the software, services, content (including code) on third party Internet sites, or third party programs; and\par
+{\pntext\f3\'B7\tab}claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.\par
+
+\pard\nowidctlpar\sb120\sa120 It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.\par
+\lang9 Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French.\par
+Remarque : Ce logiciel \'e9tant distribu\'e9 au Qu\'e9bec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en fran\'e7ais.\par
+\b\lang1033 EXON\'c9RATION DE GARANTIE. \b0 Le logiciel vis\'e9 par une licence est offert \'ab tel quel \'bb. Toute utilisation de ce logiciel est \'e0 votre seule risque et p\'e9ril. Microsoft n\rquote accorde aucune autre garantie expresse. Vous pouvez b\'e9n\'e9ficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualit\'e9 marchande, d\rquote ad\'e9quation \'e0 un usage particulier et d\rquote absence de contrefa\'e7on sont exclues.\par
+\b LIMITATION DES DOMMAGES-INT\'c9R\'caTS ET EXCLUSION DE RESPONSABILIT\'c9 POUR LES DOMMAGES. \b0 Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement \'e0 hauteur de 5,00 $ US. Vous ne pouvez pr\'e9tendre \'e0 aucune indemnisation pour les autres dommages, y compris les dommages sp\'e9ciaux, indirects ou accessoires et pertes de b\'e9n\'e9fices.\par
+\lang9 Cette limitation concerne :\par
+
+\pard{\pntext\f3\'B7\tab}{\*\pn\pnlvlblt\pnf3\pnindent360{\pntxtb\'B7}}\nowidctlpar\li720\sb120\sa120 tout ce qui est reli\'e9 au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et\par
+{\pntext\f3\'B7\tab}les r\'e9clamations au titre de violation de contrat ou de garantie, ou au titre de responsabilit\'e9 stricte, de n\'e9gligence ou d\rquote une autre faute dans la limite autoris\'e9e par la loi en vigueur.\par
+
+\pard\nowidctlpar\sb120\sa120 Elle s\rquote applique \'e9galement, m\'eame si Microsoft connaissait ou devrait conna\'eetre l\rquote\'e9ventualit\'e9 d\rquote un tel dommage. Si votre pays n\rquote autorise pas l\rquote exclusion ou la limitation de responsabilit\'e9 pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l\rquote exclusion ci-dessus ne s\rquote appliquera pas \'e0 votre \'e9gard.\par
+\b\lang1033 EFFET JURIDIQUE. \b0 Le pr\'e9sent contrat d\'e9crit certains droits juridiques. Vous pourriez avoir d\rquote autres droits pr\'e9vus par les lois de votre pays. Le pr\'e9sent contrat ne modifie pas les droits que vous conf\'e8rent les lois de votre pays si celles-ci ne le permettent pas.\par
+\b\fs20\lang1036\par
+}
+
\ No newline at end of file
diff --git a/src/Installers/Windows/tasks/GenerateGuid.cs b/src/Installers/Windows/tasks/GenerateGuid.cs
new file mode 100644
index 0000000000..f6e8039864
--- /dev/null
+++ b/src/Installers/Windows/tasks/GenerateGuid.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace RepoTasks
+{
+ public class GenerateGuid : Task
+ {
+ [Output]
+ public string Guid { get; private set; }
+
+ [Required]
+ public string NamespaceGuid { get; set; }
+
+ [Required]
+ public ITaskItem[] Values { get; set; }
+
+ public override bool Execute()
+ {
+ try
+ {
+ var value = string.Join(",", Values.Select(o => o.ItemSpec).ToArray()).ToLowerInvariant();
+
+ Guid = Uuid.Create(new Guid(NamespaceGuid), value).ToString();
+ }
+ catch (Exception e)
+ {
+ Log.LogErrorFromException(e);
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/Installers/Windows/tasks/GetMsiProperty.cs b/src/Installers/Windows/tasks/GetMsiProperty.cs
new file mode 100644
index 0000000000..90f3cd3d24
--- /dev/null
+++ b/src/Installers/Windows/tasks/GetMsiProperty.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.Deployment.WindowsInstaller.Package;
+
+namespace RepoTasks
+{
+ public class GetMsiProperty : Task
+ {
+ [Required]
+ public string InstallPackage { get; set; }
+
+ [Required]
+ public string Property { get; set; }
+
+ [Output]
+ public string Value { get; set; }
+
+ public override bool Execute()
+ {
+ try
+ {
+ using (var package = new InstallPackage(InstallPackage, 0))
+ {
+ Value = package.Property[Property];
+ }
+ }
+ catch (Exception exception)
+ {
+ Log.LogErrorFromException(exception);
+ }
+ return !Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/Installers/Windows/tasks/InstallerTasks.csproj b/src/Installers/Windows/tasks/InstallerTasks.csproj
new file mode 100644
index 0000000000..a6d3ce18f1
--- /dev/null
+++ b/src/Installers/Windows/tasks/InstallerTasks.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net461
+ false
+ false
+
+
+
+
+
+
+
+
+
+ $(WiXSdkPath)\Microsoft.Deployment.WindowsInstaller.dll
+
+
+ $(WiXSdkPath)\Microsoft.Deployment.WindowsInstaller.Package.dll
+
+
+
+
diff --git a/src/Installers/Windows/tasks/Uuid.cs b/src/Installers/Windows/tasks/Uuid.cs
new file mode 100644
index 0000000000..8083117d38
--- /dev/null
+++ b/src/Installers/Windows/tasks/Uuid.cs
@@ -0,0 +1,79 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace RepoTasks
+{
+ ///
+ /// Implementation of RFC 4122 - A Universally Unique Identifier (UUID) URN Namespace.
+ ///
+ internal sealed class Uuid
+ {
+ ///
+ /// Generates a version 3 UUID given a namespace UUID and name. This is based on the algorithm described in
+ /// RFC 4122 (http://www.apps.ietf.org/rfc/rfc4122.html), section 4.3.
+ ///
+ ///
+ ///
+ ///
+ public static Guid Create(Guid namespaceId, string name)
+ {
+ // 1. Convert the name to a canonical sequence of octets (as defined by the standards or conventions of its name space); put the name space ID in network byte order.
+ byte[] namespaceBytes = namespaceId.ToByteArray();
+ // Octet 0-3
+ int timeLow = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(namespaceBytes, 0));
+ // Octet 4-5
+ short timeMid = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(namespaceBytes, 4));
+ // Octet 6-7
+ short timeHiVersion = IPAddress.HostToNetworkOrder(BitConverter.ToInt16(namespaceBytes, 6));
+
+ // 2. Compute the hash of the namespace ID concatenated with the name
+ byte[] nameBytes = Encoding.Unicode.GetBytes(name);
+ byte[] hashBuffer = new byte[namespaceBytes.Length + nameBytes.Length];
+
+ Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, hashBuffer, 0, 4);
+ Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, hashBuffer, 4, 2);
+ Buffer.BlockCopy(BitConverter.GetBytes(timeHiVersion), 0, hashBuffer, 6, 2);
+ Buffer.BlockCopy(namespaceBytes, 8, hashBuffer, 8, 8);
+ Buffer.BlockCopy(nameBytes, 0, hashBuffer, 16, nameBytes.Length);
+ byte[] hash;
+
+ using (SHA256 sha256 = new SHA256Managed())
+ {
+ hash = sha256.ComputeHash(hashBuffer);
+ }
+
+ Array.Resize(ref hash, 16);
+
+ // 3. Set octets zero through 3 of the time_low field to octets zero through 3 of the hash.
+ timeLow = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(hash, 0));
+ Buffer.BlockCopy(BitConverter.GetBytes(timeLow), 0, hash, 0, 4);
+
+ // 4. Set octets zero and one of the time_mid field to octets 4 and 5 of the hash.
+ timeMid = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(hash, 4));
+ Buffer.BlockCopy(BitConverter.GetBytes(timeMid), 0, hash, 4, 2);
+
+ // 5. Set octets zero and one of the time_hi_and_version field to octets 6 and 7 of the hash.
+ timeHiVersion = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(hash, 6));
+
+ // 6. Set the four most significant bits (bits 12 through 15) of the time_hi_and_version field to the appropriate 4-bit version number from Section 4.1.3.
+ timeHiVersion = (short)((timeHiVersion & 0x0fff) | 0x3000);
+ Buffer.BlockCopy(BitConverter.GetBytes(timeHiVersion), 0, hash, 6, 2);
+
+ // 7. Set the clock_seq_hi_and_reserved field to octet 8 of the hash.
+ // 8. Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively.
+ hash[8] = (byte)((hash[8] & 0x3f) | 0x80);
+
+ // Steps 9-11 are essentially no-ops, but provided for completion sake
+ // 9. Set the clock_seq_low field to octet 9 of the hash.
+ // 10. Set octets zero through five of the node field to octets 10 through 15 of the hash.
+ // 11. Convert the resulting UUID to local byte order.
+
+ return new Guid(hash);
+ }
+ }
+}
diff --git a/src/Packages/Directory.Build.props b/src/Packages/Directory.Build.props
new file mode 100644
index 0000000000..b917f91a06
--- /dev/null
+++ b/src/Packages/Directory.Build.props
@@ -0,0 +1,11 @@
+
+
+
+
+ false
+
+
+
+
+
+
diff --git a/src/Directory.Build.targets b/src/Packages/Directory.Build.targets
similarity index 100%
rename from src/Directory.Build.targets
rename to src/Packages/Directory.Build.targets
diff --git a/src/Microsoft.AspNetCore.All/Microsoft.AspNetCore.All.csproj b/src/Packages/Microsoft.AspNetCore.All/Microsoft.AspNetCore.All.csproj
similarity index 100%
rename from src/Microsoft.AspNetCore.All/Microsoft.AspNetCore.All.csproj
rename to src/Packages/Microsoft.AspNetCore.All/Microsoft.AspNetCore.All.csproj
diff --git a/src/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.props b/src/Packages/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.props
similarity index 100%
rename from src/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.props
rename to src/Packages/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.props
diff --git a/src/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.targets b/src/Packages/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.targets
similarity index 100%
rename from src/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.targets
rename to src/Packages/Microsoft.AspNetCore.All/build/netcoreapp2.1/Microsoft.AspNetCore.All.targets
diff --git a/src/Microsoft.AspNetCore.All/lib/netcoreapp2.1/_._ b/src/Packages/Microsoft.AspNetCore.All/lib/netcoreapp2.1/_._
similarity index 100%
rename from src/Microsoft.AspNetCore.All/lib/netcoreapp2.1/_._
rename to src/Packages/Microsoft.AspNetCore.All/lib/netcoreapp2.1/_._
diff --git a/src/Microsoft.AspNetCore.Analyzers/Microsoft.AspNetCore.Analyzers.csproj b/src/Packages/Microsoft.AspNetCore.Analyzers/Microsoft.AspNetCore.Analyzers.csproj
similarity index 100%
rename from src/Microsoft.AspNetCore.Analyzers/Microsoft.AspNetCore.Analyzers.csproj
rename to src/Packages/Microsoft.AspNetCore.Analyzers/Microsoft.AspNetCore.Analyzers.csproj
diff --git a/src/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj b/src/Packages/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
similarity index 100%
rename from src/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
rename to src/Packages/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj
diff --git a/src/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.props b/src/Packages/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.props
similarity index 100%
rename from src/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.props
rename to src/Packages/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.props
diff --git a/src/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.targets b/src/Packages/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.targets
similarity index 100%
rename from src/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.targets
rename to src/Packages/Microsoft.AspNetCore.App/build/netcoreapp2.1/Microsoft.AspNetCore.App.targets
diff --git a/src/Microsoft.AspNetCore.App/lib/netcoreapp2.1/_._ b/src/Packages/Microsoft.AspNetCore.App/lib/netcoreapp2.1/_._
similarity index 100%
rename from src/Microsoft.AspNetCore.App/lib/netcoreapp2.1/_._
rename to src/Packages/Microsoft.AspNetCore.App/lib/netcoreapp2.1/_._