2018-02-13 18:23:53 +01:00
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
2018-09-25 18:53:42 +02:00
2017-07-23 21:29:33 +02:00
$Environment = Get-EnvironmentInformation
2018-09-25 18:53:42 +02:00
$RepoRoot = ( Resolve-Path -Path " $PSScriptRoot /../.. " ) . Path
2017-07-26 17:49:56 +02:00
$packagingStrings = Import-PowerShellDataFile " $PSScriptRoot \packaging.strings.psd1 "
2018-08-31 21:50:51 +02:00
Import-Module " $PSScriptRoot \..\Xml " -ErrorAction Stop -Force
2018-09-17 23:48:23 +02:00
$DebianDistributions = @ ( " ubuntu.14.04 " , " ubuntu.16.04 " , " ubuntu.18.04 " , " debian.8 " , " debian.9 " )
2017-07-26 17:49:56 +02:00
2017-07-23 21:29:33 +02:00
function Start-PSPackage {
[ CmdletBinding ( DefaultParameterSetName = 'Version' , SupportsShouldProcess = $true ) ]
param (
# PowerShell packages use Semantic Versioning http://semver.org/
[ Parameter ( ParameterSetName = " Version " ) ]
[ string ] $Version ,
[ Parameter ( ParameterSetName = " ReleaseTag " ) ]
2017-11-16 01:55:13 +01:00
[ ValidatePattern ( " ^v\d+\.\d+\.\d+(-\w+(\.\d+)?)? $ " ) ]
2017-07-23 21:29:33 +02:00
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ReleaseTag ,
# Package name
[ ValidatePattern ( " ^powershell " ) ]
[ string ] $Name = " powershell " ,
2017-09-07 19:34:40 +02:00
# Ubuntu, CentOS, Fedora, macOS, and Windows packages are supported
2018-09-10 21:47:32 +02:00
[ ValidateSet ( " deb " , " osxpkg " , " rpm " , " msi " , " zip " , " AppImage " , " nupkg " , " tar " , " tar-arm " , 'tar-musl' , 'fxdependent' ) ]
2017-07-23 21:29:33 +02:00
[ string[] ] $Type ,
# Generate windows downlevel package
2017-12-11 22:57:02 +01:00
[ ValidateSet ( " win7-x86 " , " win7-x64 " , " win-arm " , " win-arm64 " ) ]
2017-07-23 21:29:33 +02:00
[ ValidateScript ( { $Environment . IsWindows } ) ]
2017-09-11 21:16:58 +02:00
[ string ] $WindowsRuntime ,
2017-08-01 23:35:50 +02:00
2017-08-09 23:36:23 +02:00
[ Switch ] $Force ,
2018-06-06 19:28:22 +02:00
[ Switch ] $SkipReleaseChecks ,
[ switch ] $NoSudo
2017-07-23 21:29:33 +02:00
)
2017-10-23 21:30:25 +02:00
DynamicParam {
2018-09-10 21:47:32 +02:00
if ( " zip " -eq $Type -or " fxdependent " -eq $Type ) {
2017-12-11 22:57:02 +01:00
# Add a dynamic parameter '-IncludeSymbols' when the specified package type is 'zip' only.
2017-10-23 21:30:25 +02:00
# The '-IncludeSymbols' parameter can be used to indicate that the package should only contain powershell binaries and symbols.
$ParameterAttr = New-Object " System.Management.Automation.ParameterAttribute "
$Attributes = New-Object " System.Collections.ObjectModel.Collection `` 1[System.Attribute] "
$Attributes . Add ( $ParameterAttr ) > $null
$Parameter = New-Object " System.Management.Automation.RuntimeDefinedParameter " -ArgumentList ( " IncludeSymbols " , [ switch ] , $Attributes )
$Dict = New-Object " System.Management.Automation.RuntimeDefinedParameterDictionary "
$Dict . Add ( " IncludeSymbols " , $Parameter ) > $null
return $Dict
}
2017-07-23 21:29:33 +02:00
}
2017-08-29 01:10:03 +02:00
2017-10-23 21:30:25 +02:00
End {
$IncludeSymbols = $null
if ( $PSBoundParameters . ContainsKey ( 'IncludeSymbols' ) ) {
2018-03-08 19:47:20 +01:00
Write-Log 'setting IncludeSymbols'
2017-10-23 21:30:25 +02:00
$IncludeSymbols = $PSBoundParameters [ 'IncludeSymbols' ]
}
2017-08-29 01:10:03 +02:00
2017-10-23 21:30:25 +02:00
# Runtime and Configuration settings required by the package
( $Runtime , $Configuration ) = if ( $WindowsRuntime ) {
$WindowsRuntime , " Release "
2017-11-09 19:48:55 +01:00
} elseif ( $Type -eq " tar-arm " ) {
2017-10-23 21:30:25 +02:00
New-PSOptions -Configuration " Release " -Runtime " Linux-ARM " -WarningAction SilentlyContinue | ForEach-Object { $_ . Runtime , $_ . Configuration }
2018-06-28 00:30:38 +02:00
} elseif ( $Type -eq " tar-musl " ) {
New-PSOptions -Configuration " Release " -Runtime " Linux-musl-x64 " -WarningAction SilentlyContinue | ForEach-Object { $_ . Runtime , $_ . Configuration }
2017-10-23 21:30:25 +02:00
} else {
New-PSOptions -Configuration " Release " -WarningAction SilentlyContinue | ForEach-Object { $_ . Runtime , $_ . Configuration }
}
2017-07-23 21:29:33 +02:00
2018-09-10 21:47:32 +02:00
if ( $Environment . IsWindows ) {
2017-12-11 22:57:02 +01:00
# Runtime will be one of win7-x64, win7-x86, "win-arm" and "win-arm64" on Windows.
2017-10-23 21:30:25 +02:00
# Build the name suffix for universal win-plat packages.
2017-12-11 22:57:02 +01:00
switch ( $Runtime ) {
" win-arm " { $NameSuffix = " win-arm32 " }
" win-arm64 " { $NameSuffix = " win-arm64 " }
default { $NameSuffix = $_ -replace 'win\d+' , 'win' }
}
2017-10-23 21:30:25 +02:00
}
2017-08-01 23:35:50 +02:00
2018-09-10 21:47:32 +02:00
if ( $Type -eq 'fxdependent' ) {
$NameSuffix = " win-fxdependent "
Write-Log " Packaging : ' $Type '; Packaging Configuration: ' $Configuration ' "
} else {
Write-Log " Packaging RID: ' $Runtime '; Packaging Configuration: ' $Configuration ' "
}
2017-08-09 23:36:23 +02:00
2017-10-23 21:30:25 +02:00
$Script:Options = Get-PSOptions
$crossGenCorrect = $false
2017-12-11 22:57:02 +01:00
if ( $Runtime -match " arm " ) {
# crossgen doesn't support arm32/64
2017-10-23 21:30:25 +02:00
$crossGenCorrect = $true
}
2017-12-11 22:57:02 +01:00
elseif ( $Script:Options . CrossGen ) {
2017-10-23 21:30:25 +02:00
$crossGenCorrect = $true
}
2017-11-02 21:52:17 +01:00
$PSModuleRestoreCorrect = $false
# Require PSModuleRestore for packaging without symbols
# But Disallow it when packaging with symbols
if ( ! $IncludeSymbols . IsPresent -and $Script:Options . PSModuleRestore ) {
$PSModuleRestoreCorrect = $true
}
elseif ( $IncludeSymbols . IsPresent -and ! $Script:Options . PSModuleRestore ) {
$PSModuleRestoreCorrect = $true
2017-10-23 21:30:25 +02:00
}
2018-09-10 21:47:32 +02:00
$precheckFailed = if ( $Type -eq 'fxdependent' ) {
## We do not check for runtime and crossgen for framework dependent package.
-not $Script:Options -or ## Start-PSBuild hasn't been executed yet
-not $PSModuleRestoreCorrect -or ## Last build didn't specify '-PSModuleRestore' correctly
$Script:Options . Configuration -ne $Configuration -or ## Last build was with configuration other than 'Release'
$Script:Options . Framework -ne " netcoreapp2.1 " ## Last build wasn't for CoreCLR
} else {
-not $Script:Options -or ## Start-PSBuild hasn't been executed yet
2017-10-23 21:30:25 +02:00
-not $crossGenCorrect -or ## Last build didn't specify '-CrossGen' correctly
2017-12-11 22:57:02 +01:00
-not $PSModuleRestoreCorrect -or ## Last build didn't specify '-PSModuleRestore' correctly
2017-10-23 21:30:25 +02:00
$Script:Options . Runtime -ne $Runtime -or ## Last build wasn't for the required RID
$Script:Options . Configuration -ne $Configuration -or ## Last build was with configuration other than 'Release'
2018-09-10 21:47:32 +02:00
$Script:Options . Framework -ne " netcoreapp2.1 " ## Last build wasn't for CoreCLR
}
# Make sure the most recent build satisfies the package requirement
if ( $precheckFailed ) {
2017-10-23 21:30:25 +02:00
# It's possible that the most recent build doesn't satisfy the package requirement but
# an earlier build does.
# It's also possible that the last build actually satisfies the package requirement but
# then `Start-PSPackage` runs from a new PS session or `build.psm1` was reloaded.
#
# In these cases, the user will be asked to build again even though it's technically not
# necessary. However, we want it that way -- being very explict when generating packages.
# This check serves as a simple gate to ensure that the user knows what he is doing, and
# also ensure `Start-PSPackage` does what the user asks/expects, because once packages
# are generated, it'll be hard to verify if they were built from the correct content.
$params = @ ( '-Clean' )
2018-09-10 21:47:32 +02:00
# CrossGen cannot be done for framework dependent package as it is runtime agnostic.
if ( $Type -ne 'fxdependent' ) {
$params + = '-CrossGen'
}
2017-11-02 21:52:17 +01:00
if ( ! $IncludeSymbols . IsPresent ) {
$params + = '-PSModuleRestore'
2017-10-23 21:30:25 +02:00
}
2017-11-02 21:52:17 +01:00
2018-09-10 21:47:32 +02:00
if ( $Type -eq 'fxdependent' ) {
$params + = '-Runtime' , 'fxdependent'
} else {
$params + = '-Runtime' , $Runtime
}
2017-10-23 21:30:25 +02:00
$params + = '-Configuration' , $Configuration
throw " Please ensure you have run 'Start-PSBuild $params '! "
2017-08-09 23:36:23 +02:00
}
2018-09-10 21:47:32 +02:00
if ( $SkipReleaseChecks . IsPresent ) {
2017-10-23 21:30:25 +02:00
Write-Warning " Skipping release checks. "
}
2018-09-10 21:47:32 +02:00
elseif ( ! $Script:Options . RootInfo . IsValid ) {
2017-10-23 21:30:25 +02:00
throw $Script:Options . RootInfo . Warning
}
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
# If ReleaseTag is specified, use the given tag to calculate Vesrion
if ( $PSCmdlet . ParameterSetName -eq " ReleaseTag " ) {
$Version = $ReleaseTag -Replace '^v'
}
2017-08-16 01:17:45 +02:00
2017-10-23 21:30:25 +02:00
# Use Git tag if not given a version
if ( -not $Version ) {
2018-09-25 18:53:42 +02:00
$Version = ( git - -git -dir = " $RepoRoot /.git " describe ) -Replace '^v'
2017-10-23 21:30:25 +02:00
}
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
$Source = Split-Path -Path $Script:Options . Output -Parent
2017-07-23 21:29:33 +02:00
2018-06-12 19:58:05 +02:00
# Copy the ThirdPartyNotices.txt so it's part of the package
2018-09-25 18:53:42 +02:00
Copy-Item " $RepoRoot /ThirdPartyNotices.txt " -Destination $Source -Force
2018-06-12 19:58:05 +02:00
2017-11-03 22:49:15 +01:00
# If building a symbols package, we add a zip of the parent to publish
2017-10-23 21:30:25 +02:00
if ( $IncludeSymbols . IsPresent )
{
2017-11-02 21:52:17 +01:00
$publishSource = $Source
2017-10-24 06:40:39 +02:00
$buildSource = Split-Path -Path $Source -Parent
2017-10-23 21:30:25 +02:00
$Source = New-TempFolder
2017-11-03 22:49:15 +01:00
$symbolsSource = New-TempFolder
2017-11-09 19:48:55 +01:00
try
2017-11-03 22:49:15 +01:00
{
# Copy files which go into the root package
Get-ChildItem -Path $publishSource | Copy-Item -Destination $Source -Recurse
# files not to include as individual files. These files will be included in the root package
# pwsh.exe is just dotnet.exe renamed by dotnet.exe during the build.
$toExclude = @ (
'hostfxr.dll'
'hostpolicy.dll'
'libhostfxr.so'
'libhostpolicy.so'
'libhostfxr.dylib'
'libhostpolicy.dylib'
'Publish'
'pwsh.exe'
)
# Copy file which go into symbols.zip
Get-ChildItem -Path $buildSource | Where-Object { $toExclude -inotcontains $_ . Name } | Copy-Item -Destination $symbolsSource -Recurse
# Zip symbols.zip to the root package
$zipSource = Join-Path $symbolsSource -ChildPath '*'
$zipPath = Join-Path -Path $Source -ChildPath 'symbols.zip'
2018-05-18 04:04:20 +02:00
Save-PSOptions -PSOptionsPath ( Join-Path -Path $source -ChildPath 'psoptions.json' ) -Options $Script:Options
2017-11-03 22:49:15 +01:00
Compress-Archive -Path $zipSource -DestinationPath $zipPath
}
finally
{
Remove-Item -Path $symbolsSource -Recurse -Force -ErrorAction SilentlyContinue
}
2017-10-23 21:30:25 +02:00
}
2017-07-23 21:29:33 +02:00
2018-03-08 19:47:20 +01:00
Write-Log " Packaging Source: ' $Source ' "
2017-10-23 21:30:25 +02:00
# Decide package output type
if ( -not $Type ) {
$Type = if ( $Environment . IsLinux ) {
if ( $Environment . LinuxInfo . ID -match " ubuntu " ) {
" deb " , " nupkg "
} elseif ( $Environment . IsRedHatFamily ) {
" rpm " , " nupkg "
2018-01-22 23:58:17 +01:00
} elseif ( $Environment . IsSUSEFamily ) {
" rpm " , " nupkg "
2017-10-23 21:30:25 +02:00
} else {
throw " Building packages for $( $Environment . LinuxInfo . PRETTY_NAME ) is unsupported! "
}
} elseif ( $Environment . IsMacOS ) {
" osxpkg " , " nupkg "
} elseif ( $Environment . IsWindows ) {
" msi " , " nupkg "
2017-07-23 21:29:33 +02:00
}
2017-10-23 21:30:25 +02:00
Write-Warning " -Type was not specified, continuing with $Type ! "
2017-07-23 21:29:33 +02:00
}
2018-03-08 19:47:20 +01:00
Write-Log " Packaging Type: $Type "
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
# Add the symbols to the suffix
# if symbols are specified to be included
2018-09-10 21:47:32 +02:00
if ( $IncludeSymbols . IsPresent -and $NameSuffix ) {
2017-10-23 21:30:25 +02:00
$NameSuffix = " symbols- $NameSuffix "
}
elseif ( $IncludeSymbols . IsPresent ) {
$NameSuffix = " symbols "
}
2017-08-09 23:36:23 +02:00
2017-10-23 21:30:25 +02:00
switch ( $Type ) {
" zip " {
$Arguments = @ {
PackageNameSuffix = $NameSuffix
PackageSourcePath = $Source
PackageVersion = $Version
Force = $Force
}
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
if ( $PSCmdlet . ShouldProcess ( " Create Zip Package " ) ) {
New-ZipPackage @Arguments
}
2017-07-23 21:29:33 +02:00
}
2018-09-10 21:47:32 +02:00
" fxdependent " {
if ( $IsWindows ) {
$Arguments = @ {
PackageNameSuffix = $NameSuffix
PackageSourcePath = $Source
PackageVersion = $Version
Force = $Force
}
if ( $PSCmdlet . ShouldProcess ( " Create Zip Package " ) ) {
New-ZipPackage @Arguments
}
} elseif ( $IsLinux ) {
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
PackageNameSuffix = 'fxdependent'
Version = $Version
Force = $Force
}
if ( $PSCmdlet . ShouldProcess ( " Create tar.gz Package " ) ) {
New-TarballPackage @Arguments
}
}
}
2017-10-23 21:30:25 +02:00
" msi " {
$TargetArchitecture = " x64 "
if ( $Runtime -match " -x86 " ) {
$TargetArchitecture = " x86 "
}
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
$Arguments = @ {
ProductNameSuffix = $NameSuffix
ProductSourcePath = $Source
ProductVersion = $Version
2018-09-25 18:53:42 +02:00
AssetsPath = " $RepoRoot \assets "
LicenseFilePath = " $RepoRoot \assets\license.rtf "
2018-01-18 00:34:03 +01:00
# Product Code needs to be unique for every PowerShell version since it is a unique identifier for the particular product release
ProductCode = New-Guid
2017-10-23 21:30:25 +02:00
ProductTargetArchitecture = $TargetArchitecture
Force = $Force
}
2017-07-23 21:29:33 +02:00
2017-10-23 21:30:25 +02:00
if ( $PSCmdlet . ShouldProcess ( " Create MSI Package " ) ) {
New-MSIPackage @Arguments
}
2017-08-09 23:36:23 +02:00
}
2017-10-23 21:30:25 +02:00
" AppImage " {
if ( $IncludeSymbols . IsPresent ) {
throw " AppImage does not support packaging '-IncludeSymbols' "
}
2017-09-25 21:49:43 +02:00
2017-10-23 21:30:25 +02:00
if ( $Environment . IsUbuntu14 ) {
$null = Start-NativeExecution { bash -iex " $PSScriptRoot /../appimage.sh " }
2017-10-24 06:40:39 +02:00
$appImage = Get-Item powershell - * . AppImage
2017-10-23 21:30:25 +02:00
if ( $appImage . Count -gt 1 ) {
throw " Found more than one AppImage package, remove all *.AppImage files and try to create the package again "
}
Rename-Item $appImage . Name $appImage . Name . Replace ( " - " , " - $Version - " )
} else {
Write-Warning " Ignoring AppImage type for non Ubuntu Trusty platform "
2017-07-23 21:29:33 +02:00
}
2017-08-01 23:35:50 +02:00
}
2017-10-23 21:30:25 +02:00
'nupkg' {
$Arguments = @ {
PackageNameSuffix = $NameSuffix
PackageSourcePath = $Source
PackageVersion = $Version
PackageRuntime = $Runtime
PackageConfiguration = $Configuration
Force = $Force
}
2017-08-01 23:35:50 +02:00
2017-10-23 21:30:25 +02:00
if ( $PSCmdlet . ShouldProcess ( " Create NuPkg Package " ) ) {
2018-02-27 00:35:09 +01:00
New-NugetContentPackage @Arguments
2017-10-23 21:30:25 +02:00
}
2017-10-12 22:36:46 +02:00
}
2017-11-09 19:48:55 +01:00
" tar " {
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
}
if ( $PSCmdlet . ShouldProcess ( " Create tar.gz Package " ) ) {
New-TarballPackage @Arguments
}
}
" tar-arm " {
2017-10-23 21:30:25 +02:00
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
2017-11-09 19:48:55 +01:00
Architecture = " arm32 "
2017-10-23 21:30:25 +02:00
}
2017-10-12 22:36:46 +02:00
2017-10-23 21:30:25 +02:00
if ( $PSCmdlet . ShouldProcess ( " Create tar.gz Package " ) ) {
New-TarballPackage @Arguments
}
2017-10-12 22:36:46 +02:00
}
2018-06-28 00:30:38 +02:00
" tar-musl " {
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
Architecture = " musl-x64 "
}
if ( $PSCmdlet . ShouldProcess ( " Create tar.gz Package " ) ) {
New-TarballPackage @Arguments
}
}
2017-10-23 21:30:25 +02:00
'deb' {
$Arguments = @ {
Type = 'deb'
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
2018-06-06 19:28:22 +02:00
NoSudo = $NoSudo
2017-10-23 21:30:25 +02:00
}
foreach ( $Distro in $Script:DebianDistributions ) {
$Arguments [ " Distribution " ] = $Distro
if ( $PSCmdlet . ShouldProcess ( " Create DEB Package for $Distro " ) ) {
New-UnixPackage @Arguments
}
}
2017-10-03 23:29:43 +02:00
}
2017-10-23 21:30:25 +02:00
default {
$Arguments = @ {
Type = $_
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
2018-06-06 19:28:22 +02:00
NoSudo = $NoSudo
2017-10-23 21:30:25 +02:00
}
if ( $PSCmdlet . ShouldProcess ( " Create $_ Package " ) ) {
2017-10-12 22:36:46 +02:00
New-UnixPackage @Arguments
}
2017-10-03 23:29:43 +02:00
}
}
2017-07-23 21:29:33 +02:00
2018-09-10 21:47:32 +02:00
if ( $IncludeSymbols . IsPresent )
2017-10-23 21:30:25 +02:00
{
# Source is a temporary folder when -IncludeSymbols is present. So, we should remove it.
Remove-Item -Path $Source -Recurse -Force -ErrorAction SilentlyContinue
2017-07-23 21:29:33 +02:00
}
}
}
2017-10-12 22:36:46 +02:00
function New-TarballPackage {
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ Parameter ( Mandatory ) ]
[ string ] $PackageSourcePath ,
# Must start with 'powershell' but may have any suffix
[ Parameter ( Mandatory ) ]
[ ValidatePattern ( " ^powershell " ) ]
2017-11-09 19:48:55 +01:00
[ string ] $Name ,
2017-10-12 22:36:46 +02:00
2018-09-10 21:47:32 +02:00
# Suffix of the Name
[ string ] $PackageNameSuffix ,
2017-10-12 22:36:46 +02:00
[ Parameter ( Mandatory ) ]
2017-11-09 19:48:55 +01:00
[ string ] $Version ,
[ Parameter ( ) ]
[ string ] $Architecture = " x64 " ,
2017-10-12 22:36:46 +02:00
[ switch ] $Force
)
2018-09-10 21:47:32 +02:00
if ( $PackageNameSuffix ) {
$packageName = " $Name - $Version -{0}- $Architecture - $PackageNameSuffix .tar.gz "
} else {
$packageName = " $Name - $Version -{0}- $Architecture .tar.gz "
}
2017-10-12 22:36:46 +02:00
if ( $Environment . IsWindows ) {
throw " Must be on Linux or macOS to build 'tar.gz' packages! "
} elseif ( $Environment . IsLinux ) {
$packageName = $packageName -f " linux "
} elseif ( $Environment . IsMacOS ) {
$packageName = $packageName -f " osx "
}
$packagePath = Join-Path -Path $PWD -ChildPath $packageName
Write-Verbose " Create package $packageName "
Write-Verbose " Package destination path: $packagePath "
if ( Test-Path -Path $packagePath ) {
if ( $Force -or $PSCmdlet . ShouldProcess ( " Overwrite existing package file " ) ) {
Write-Verbose " Overwrite existing package file at $packagePath " -Verbose
Remove-Item -Path $packagePath -Force -ErrorAction Stop -Confirm: $false
}
}
if ( Get-Command -Name tar -CommandType Application -ErrorAction Ignore ) {
if ( $Force -or $PSCmdlet . ShouldProcess ( " Create tarball package " ) ) {
$options = " -czf "
if ( $PSBoundParameters . ContainsKey ( 'Verbose' ) -and $PSBoundParameters [ 'Verbose' ] . IsPresent ) {
# Use the verbose mode '-v' if '-Verbose' is specified
$options = " -czvf "
}
try {
Push-Location -Path $PackageSourcePath
tar $options $packagePath .
} finally {
Pop-Location
}
if ( Test-Path -Path $packagePath ) {
2018-03-08 19:47:20 +01:00
Write-Log " You can find the tarball package at $packagePath "
2017-10-12 22:36:46 +02:00
return $packagePath
} else {
throw " Failed to create $packageName "
}
}
} else {
throw " Failed to create the package because the application 'tar' cannot be found "
}
}
2017-10-23 21:30:25 +02:00
function New-TempFolder
{
$tempPath = [ System.IO.Path ] :: GetTempPath ( )
$tempFolder = Join-Path -Path $tempPath -ChildPath ( [ System.IO.Path ] :: GetRandomFileName ( ) )
2018-09-10 21:47:32 +02:00
if ( ! ( Test-Path -Path $tempFolder ) )
2017-10-23 21:30:25 +02:00
{
$null = New-Item -Path $tempFolder -ItemType Directory
}
return $tempFolder
}
2017-12-07 00:51:33 +01:00
2017-11-13 19:10:51 +01:00
function New-PSSignedBuildZip
{
param (
[ Parameter ( Mandatory ) ]
[ string ] $BuildPath ,
[ Parameter ( Mandatory ) ]
[ string ] $SignedFilesPath ,
[ Parameter ( Mandatory ) ]
[ string ] $DestinationFolder ,
[ parameter ( HelpMessage = 'VSTS variable to set for path to zip' ) ]
[ string ] $VstsVariableName
)
# Replace unsigned binaries with signed
$signedFilesFilter = Join-Path -Path $signedFilesPath -ChildPath '*'
2017-12-07 00:51:33 +01:00
Get-ChildItem -path $signedFilesFilter -Recurse -File | Select-Object -ExpandProperty FullName | Foreach-Object -Process {
2018-06-06 22:05:10 +02:00
$relativePath = $_ . ToLowerInvariant ( ) . Replace ( $signedFilesPath . ToLowerInvariant ( ) , '' )
2017-11-13 19:10:51 +01:00
$destination = Join-Path -Path $buildPath -ChildPath $relativePath
2018-03-08 19:47:20 +01:00
Write-Log " replacing $destination with $_ "
2017-11-13 19:10:51 +01:00
Copy-Item -Path $_ -Destination $destination -force
}
2017-12-07 00:51:33 +01:00
# Remove '$signedFilesPath' now that signed binaries are copied
if ( Test-Path $signedFilesPath )
2017-11-28 02:26:51 +01:00
{
2017-12-07 00:51:33 +01:00
Remove-Item -Recurse -Force -Path $signedFilesPath
2017-11-28 02:26:51 +01:00
}
2017-11-13 19:10:51 +01:00
$name = split-path -Path $BuildPath -Leaf
$zipLocationPath = Join-Path -Path $DestinationFolder -ChildPath " $name -signed.zip "
Compress-Archive -Path $BuildPath \ * -DestinationPath $zipLocationPath
if ( $VstsVariableName )
{
# set VSTS variable with path to package files
2018-03-08 19:47:20 +01:00
Write-Log " Setting $VstsVariableName to $zipLocationPath "
2017-11-13 19:10:51 +01:00
Write-Host " ##vso[task.setvariable variable= $VstsVariableName ] $zipLocationPath "
}
2017-11-16 01:55:13 +01:00
else
2017-11-13 19:10:51 +01:00
{
return $zipLocationPath
}
}
function Expand-PSSignedBuild
{
param (
[ Parameter ( Mandatory ) ]
2018-09-10 21:47:32 +02:00
[ string ] $BuildZip ,
[ Switch ] $SkipPwshExeCheck
2017-11-13 19:10:51 +01:00
)
$psModulePath = Split-Path -path $PSScriptRoot
2017-12-07 00:51:33 +01:00
# Expand signed build
2017-11-13 19:10:51 +01:00
$buildPath = Join-Path -path $psModulePath -childpath 'ExpandedBuild'
2017-11-14 19:30:17 +01:00
$null = New-Item -path $buildPath -itemtype Directory -force
2017-11-13 19:10:51 +01:00
Expand-Archive -path $BuildZip -destinationpath $buildPath -Force
2017-12-07 00:51:33 +01:00
# Remove the zip file that contains only those files from the parent folder of 'publish'.
# That zip file is used for compliance scan.
2017-11-14 19:30:17 +01:00
Remove-Item -Path ( Join-Path -Path $buildPath -ChildPath '*.zip' ) -Recurse
2017-11-13 19:10:51 +01:00
2018-09-10 21:47:32 +02:00
if ( $SkipPwshExeCheck )
{
$windowsExecutablePath = ( Join-Path $buildPath -ChildPath 'pwsh.dll' )
}
else
{
$windowsExecutablePath = ( Join-Path $buildPath -ChildPath 'pwsh.exe' )
}
2017-11-13 19:10:51 +01:00
Restore-PSModuleToBuild -PublishPath $buildPath
2018-03-10 18:51:23 +01:00
$psOptionsPath = Join-Path $buildPath -ChildPath 'psoptions.json'
2018-05-18 04:04:20 +02:00
Restore-PSOptions -PSOptionsPath $psOptionsPath -Remove
2018-03-10 18:51:23 +01:00
2018-05-18 04:04:20 +02:00
$options = Get-PSOptions
2018-03-10 18:51:23 +01:00
2017-11-14 19:30:17 +01:00
$options . PSModuleRestore = $true
2017-11-13 19:10:51 +01:00
2018-09-10 21:47:32 +02:00
if ( Test-Path -Path $windowsExecutablePath )
2017-11-13 19:10:51 +01:00
{
$options . Output = $windowsExecutablePath
}
else
{
throw 'Could not find pwsh'
}
Set-PSOptions -Options $options
}
2017-10-23 21:30:25 +02:00
2017-07-23 21:29:33 +02:00
function New-UnixPackage {
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ Parameter ( Mandatory ) ]
[ ValidateSet ( " deb " , " osxpkg " , " rpm " ) ]
[ string ] $Type ,
[ Parameter ( Mandatory ) ]
[ string ] $PackageSourcePath ,
# Must start with 'powershell' but may have any suffix
[ Parameter ( Mandatory ) ]
[ ValidatePattern ( " ^powershell " ) ]
[ string ] $Name ,
[ Parameter ( Mandatory ) ]
[ string ] $Version ,
2017-10-03 23:29:43 +02:00
# Package iteration version (rarely changed)
# This is a string because strings are appended to it
[ string ] $Iteration = " 1 " ,
2017-08-01 23:35:50 +02:00
[ Switch ]
2018-06-06 19:28:22 +02:00
$Force ,
[ switch ]
$NoSudo
2017-07-23 21:29:33 +02:00
)
2017-10-03 23:29:43 +02:00
DynamicParam {
if ( $Type -eq " deb " ) {
# Add a dynamic parameter '-Distribution' when the specified package type is 'deb'.
# The '-Distribution' parameter can be used to indicate which Debian distro this pacakge is targeting.
$ParameterAttr = New-Object " System.Management.Automation.ParameterAttribute "
$ValidateSetAttr = New-Object " System.Management.Automation.ValidateSetAttribute " -ArgumentList $Script:DebianDistributions
$Attributes = New-Object " System.Collections.ObjectModel.Collection `` 1[System.Attribute] "
$Attributes . Add ( $ParameterAttr ) > $null
$Attributes . Add ( $ValidateSetAttr ) > $null
$Parameter = New-Object " System.Management.Automation.RuntimeDefinedParameter " -ArgumentList ( " Distribution " , [ string ] , $Attributes )
$Dict = New-Object " System.Management.Automation.RuntimeDefinedParameterDictionary "
$Dict . Add ( " Distribution " , $Parameter ) > $null
return $Dict
2017-07-23 21:29:33 +02:00
}
}
2017-10-03 23:29:43 +02:00
End {
2018-06-06 19:28:22 +02:00
# This allows sudo install to be optional; needed when running in containers / as root
# Note that when it is null, Invoke-Expression (but not &) must be used to interpolate properly
$sudo = if ( ! $NoSudo ) { " sudo " }
2017-10-03 23:29:43 +02:00
# Validate platform
$ErrorMessage = " Must be on {0} to build ' $Type ' packages! "
switch ( $Type ) {
" deb " {
2018-03-07 20:45:21 +01:00
$packageVersion = Get-LinuxPackageSemanticVersion -Version $Version
2017-10-03 23:29:43 +02:00
if ( ! $Environment . IsUbuntu -and ! $Environment . IsDebian ) {
throw ( $ErrorMessage -f " Ubuntu or Debian " )
2017-07-23 21:29:33 +02:00
}
2017-10-03 23:29:43 +02:00
if ( $PSBoundParameters . ContainsKey ( 'Distribution' ) ) {
$DebDistro = $PSBoundParameters [ 'Distribution' ]
} elseif ( $Environment . IsUbuntu14 ) {
$DebDistro = " ubuntu.14.04 "
} elseif ( $Environment . IsUbuntu16 ) {
$DebDistro = " ubuntu.16.04 "
2018-05-07 21:30:58 +02:00
} elseif ( $Environment . IsUbuntu18 ) {
$DebDistro = " ubuntu.18.04 "
2017-10-03 23:29:43 +02:00
} elseif ( $Environment . IsDebian8 ) {
$DebDistro = " debian.8 "
} elseif ( $Environment . IsDebian9 ) {
$DebDistro = " debian.9 "
} else {
throw " The current Debian distribution is not supported. "
2017-07-23 21:29:33 +02:00
}
2017-10-03 23:29:43 +02:00
# iteration is "debian_revision"
# usage of this to differentiate distributions is allowed by non-standard
$Iteration + = " . $DebDistro "
}
" rpm " {
2018-03-07 20:45:21 +01:00
$packageVersion = Get-LinuxPackageSemanticVersion -Version $Version
2018-01-22 23:58:17 +01:00
if ( ! $Environment . IsRedHatFamily -and ! $Environment . IsSUSEFamily ) {
throw ( $ErrorMessage -f " Redhat or SUSE Family " )
2017-10-03 23:29:43 +02:00
}
}
" osxpkg " {
2018-03-07 20:45:21 +01:00
$packageVersion = $Version
2017-10-03 23:29:43 +02:00
if ( ! $Environment . IsMacOS ) {
throw ( $ErrorMessage -f " macOS " )
}
}
2017-07-23 21:29:33 +02:00
}
2018-06-05 21:51:47 +02:00
# Determine if the version is a preview version
2018-06-06 19:28:22 +02:00
$IsPreview = Test-IsPreview -Version $Version
2018-06-05 21:51:47 +02:00
# Preview versions have preview in the name
2018-06-14 19:01:09 +02:00
$Name = if ( $IsPreview ) { " powershell-preview " } else { " powershell " }
2018-06-05 21:51:47 +02:00
2017-12-08 19:55:34 +01:00
# Verify dependencies are installed and in the path
2017-12-07 19:48:00 +01:00
Test-Dependencies
2017-07-23 21:29:33 +02:00
2017-10-03 23:29:43 +02:00
$Description = $packagingStrings . Description
2017-07-23 21:29:33 +02:00
2018-06-05 21:51:47 +02:00
# Break the version down into its components, we are interested in the major version
$VersionMatch = [ regex ] :: Match ( $Version , '(\d+)(?:.(\d+)(?:.(\d+)(?:-preview(?:.(\d+))?)?)?)?' )
$MajorVersion = $VersionMatch . Groups [ 1 ] . Value
# Suffix is used for side-by-side preview/release package installation
$Suffix = if ( $IsPreview ) { $MajorVersion + " -preview " } else { $MajorVersion }
2017-07-23 21:29:33 +02:00
2017-10-03 23:29:43 +02:00
# Setup staging directory so we don't change the original source directory
$Staging = " $PSScriptRoot /staging "
if ( $pscmdlet . ShouldProcess ( " Create staging folder " ) ) {
2017-10-18 02:25:11 +02:00
New-StagingFolder -StagingPath $Staging
2017-10-03 23:29:43 +02:00
}
2017-07-23 21:29:33 +02:00
2017-10-03 23:29:43 +02:00
# Follow the Filesystem Hierarchy Standard for Linux and macOS
$Destination = if ( $Environment . IsLinux ) {
" /opt/microsoft/powershell/ $Suffix "
} elseif ( $Environment . IsMacOS ) {
" /usr/local/microsoft/powershell/ $Suffix "
2017-07-23 21:29:33 +02:00
}
2017-10-03 23:29:43 +02:00
# Destination for symlink to powershell executable
$Link = if ( $Environment . IsLinux ) {
2018-06-05 21:51:47 +02:00
if ( $IsPreview ) { " /usr/bin/pwsh-preview " } else { " /usr/bin/pwsh " }
2017-10-03 23:29:43 +02:00
} elseif ( $Environment . IsMacOS ) {
2018-06-05 21:51:47 +02:00
if ( $IsPreview ) { " /usr/local/bin/pwsh-preview " } else { " /usr/local/bin/pwsh " }
2017-07-23 21:29:33 +02:00
}
2017-12-07 19:48:00 +01:00
$linkSource = " /tmp/pwsh "
2017-07-23 21:29:33 +02:00
2018-09-10 21:47:32 +02:00
if ( $pscmdlet . ShouldProcess ( " Create package file system " ) )
2017-10-03 23:29:43 +02:00
{
2018-06-09 01:31:38 +02:00
# refers to executable, does not vary by channel
2017-12-07 19:48:00 +01:00
New-Item -Force -ItemType SymbolicLink -Path $linkSource -Target " $Destination /pwsh " > $null
2017-07-23 21:29:33 +02:00
2017-12-07 19:48:00 +01:00
# Generate After Install and After Remove scripts
2018-06-09 01:31:38 +02:00
$AfterScriptInfo = New-AfterScripts -Link $Link
2017-10-03 23:29:43 +02:00
# there is a weird bug in fpm
# if the target of the powershell symlink exists, `fpm` aborts
# with a `utime` error on macOS.
# so we move it to make symlink broken
2018-06-09 01:31:38 +02:00
# refers to executable, does not vary by channel
2017-10-18 02:25:11 +02:00
$symlink_dest = " $Destination /pwsh "
2017-10-03 23:29:43 +02:00
$hack_dest = " ./_fpm_symlink_hack_powershell "
if ( $Environment . IsMacOS ) {
if ( Test-Path $symlink_dest ) {
Write-Warning " Move $symlink_dest to $hack_dest (fpm utime bug) "
2018-06-06 19:28:22 +02:00
Start-NativeExecution ( [ ScriptBlock ] :: Create ( " $sudo mv $symlink_dest $hack_dest " ) )
2017-10-03 23:29:43 +02:00
}
2017-07-23 21:29:33 +02:00
}
2017-12-07 19:48:00 +01:00
# Generate gzip of man file
2018-06-09 01:31:38 +02:00
$ManGzipInfo = New-ManGzip -IsPreview: $IsPreview
2017-07-23 21:29:33 +02:00
2017-10-03 23:29:43 +02:00
# Change permissions for packaging
Start-NativeExecution {
find $Staging -type d | xargs chmod 755
find $Staging -type f | xargs chmod 644
2017-12-07 19:48:00 +01:00
chmod 644 $ManGzipInfo . GzipFile
2018-06-09 01:31:38 +02:00
# refers to executable, does not vary by channel
chmod 755 " $Staging /pwsh " #only the executable file should be granted the execution permission
2017-10-03 23:29:43 +02:00
}
2017-07-23 21:29:33 +02:00
}
2017-11-06 19:44:20 +01:00
# Add macOS powershell launcher
2018-09-10 21:47:32 +02:00
if ( $Type -eq " osxpkg " )
2017-11-06 19:44:20 +01:00
{
2018-09-10 21:47:32 +02:00
if ( $pscmdlet . ShouldProcess ( " Add macOS launch application " ) )
2017-12-07 19:48:00 +01:00
{
# Generate launcher app folder
2017-12-08 19:55:34 +01:00
$AppsFolder = New-MacOSLauncher -Version $Version
2017-11-06 19:44:20 +01:00
}
}
2017-12-07 19:48:00 +01:00
$packageDependenciesParams = @ { }
2018-09-10 21:47:32 +02:00
if ( $DebDistro )
2017-12-07 19:48:00 +01:00
{
$packageDependenciesParams [ 'Distribution' ] = $DebDistro
}
# Setup package dependencies
$Dependencies = @ ( Get-PackageDependencies @packageDependenciesParams )
$Arguments = Get-FpmArguments `
-Name $Name `
2018-03-07 20:45:21 +01:00
-Version $packageVersion `
2017-12-07 19:48:00 +01:00
-Iteration $Iteration `
-Description $Description `
-Type $Type `
-Dependencies $Dependencies `
-AfterInstallScript $AfterScriptInfo . AfterInstallScript `
-AfterRemoveScript $AfterScriptInfo . AfterRemoveScript `
-Staging $Staging `
-Destination $Destination `
-ManGzipFile $ManGzipInfo . GzipFile `
-ManDestination $ManGzipInfo . ManFile `
-LinkSource $LinkSource `
2017-12-08 19:55:34 +01:00
-LinkDestination $Link `
-AppsFolder $AppsFolder `
-ErrorAction Stop
2017-12-07 19:48:00 +01:00
2017-10-03 23:29:43 +02:00
# Build package
try {
2018-09-10 21:47:32 +02:00
if ( $pscmdlet . ShouldProcess ( " Create $type package " ) ) {
2017-10-03 23:29:43 +02:00
$Output = Start-NativeExecution { fpm $Arguments }
}
} finally {
if ( $Environment . IsMacOS ) {
2018-09-10 21:47:32 +02:00
if ( $pscmdlet . ShouldProcess ( " Cleanup macOS launcher " ) )
2017-11-06 19:44:20 +01:00
{
2017-12-07 19:48:00 +01:00
Clear-MacOSLauncher
2017-11-06 19:44:20 +01:00
}
2017-10-03 23:29:43 +02:00
# this is continuation of a fpm hack for a weird bug
if ( Test-Path $hack_dest ) {
Write-Warning " Move $hack_dest to $symlink_dest (fpm utime bug) "
2018-06-06 19:28:22 +02:00
Start-NativeExecution ( [ ScriptBlock ] :: Create ( " $sudo mv $hack_dest $symlink_dest " ) )
2017-10-03 23:29:43 +02:00
}
}
2017-12-07 19:48:00 +01:00
if ( $AfterScriptInfo . AfterInstallScript ) {
2017-12-08 19:55:34 +01:00
Remove-Item -erroraction 'silentlycontinue' $AfterScriptInfo . AfterInstallScript -Force
2017-10-03 23:29:43 +02:00
}
2017-12-07 19:48:00 +01:00
if ( $AfterScriptInfo . AfterRemoveScript ) {
2017-12-08 19:55:34 +01:00
Remove-Item -erroraction 'silentlycontinue' $AfterScriptInfo . AfterRemoveScript -Force
2017-10-03 23:29:43 +02:00
}
2017-12-07 19:48:00 +01:00
Remove-Item -Path $ManGzipInfo . GzipFile -Force -ErrorAction SilentlyContinue
2017-07-23 21:29:33 +02:00
}
2017-10-03 23:29:43 +02:00
# Magic to get path output
$createdPackage = Get-Item ( Join-Path $PWD ( ( $Output [ -1 ] -split " :path=> " ) [ -1 ] -replace '["{}]' ) )
2017-07-23 21:29:33 +02:00
2017-10-03 23:29:43 +02:00
if ( $Environment . IsMacOS ) {
2017-12-08 19:55:34 +01:00
if ( $pscmdlet . ShouldProcess ( " Add distribution information and Fix PackageName " ) )
2017-10-03 23:29:43 +02:00
{
2018-06-06 19:28:22 +02:00
$createdPackage = New-MacOsDistributionPackage -FpmPackage $createdPackage -IsPreview: $IsPreview
2017-10-03 23:29:43 +02:00
}
2017-07-23 21:29:33 +02:00
}
2017-10-03 23:29:43 +02:00
if ( Test-Path $createdPackage )
{
2017-12-07 19:48:00 +01:00
Write-Verbose " Created package: $createdPackage " -Verbose
2017-10-03 23:29:43 +02:00
return $createdPackage
}
else
{
throw " Failed to create $createdPackage "
}
2017-09-11 21:36:24 +02:00
}
2017-07-23 21:29:33 +02:00
}
2017-12-08 19:55:34 +01:00
function New-MacOsDistributionPackage
{
param (
[ Parameter ( Mandatory , HelpMessage = 'The FileInfo of the file created by FPM' ) ]
2018-06-06 19:28:22 +02:00
[ System.IO.FileInfo ] $FpmPackage ,
[ Switch ] $IsPreview
2017-12-08 19:55:34 +01:00
)
2018-09-10 21:47:32 +02:00
if ( ! $Environment . IsMacOS )
2017-12-08 19:55:34 +01:00
{
throw 'New-MacOsDistributionPackage is only supported on macOS!'
}
$packageName = Split-Path -leaf -Path $FpmPackage
# Create a temp directory to store the needed files
$tempDir = Join-Path ( [ System.IO.Path ] :: GetTempPath ( ) ) ( [ System.IO.Path ] :: GetRandomFileName ( ) )
New-Item -ItemType Directory -Path $tempDir -Force > $null
$resourcesDir = Join-Path -path $tempDir -childPath 'resources'
New-Item -ItemType Directory -Path $resourcesDir -Force > $null
#Copy background file to temp directory
2018-09-25 18:53:42 +02:00
$backgroundFile = " $RepoRoot /assets/macDialog.png "
2017-12-08 19:55:34 +01:00
Copy-Item -Path $backgroundFile -Destination $resourcesDir
# Move the current package to the temp directory
$tempPackagePath = Join-Path -path $tempDir -ChildPath $packageName
Move-Item -Path $FpmPackage -Destination $tempPackagePath -Force
# Add the OS information to the macOS package file name.
$packageExt = [ System.IO.Path ] :: GetExtension ( $FpmPackage . Name )
2018-06-14 19:01:09 +02:00
# get the package name from fpm without the extension, but replace powershell-preview at the beginning of the name with powershell.
$packageNameWithoutExt = [ System.IO.Path ] :: GetFileNameWithoutExtension ( $FpmPackage . Name ) -replace '^powershell\-preview' , 'powershell'
2017-12-08 19:55:34 +01:00
$newPackageName = " {0}-{1}{2} " -f $packageNameWithoutExt , $script:Options . Runtime , $packageExt
$newPackagePath = Join-Path $FpmPackage . DirectoryName $newPackageName
# -Force is not deleting the NewName if it exists, so delete it if it does
if ( $Force -and ( Test-Path -Path $newPackagePath ) )
{
Remove-Item -Force $newPackagePath
}
# Create the distribution xml
$distributionXmlPath = Join-Path -Path $tempDir -ChildPath 'powershellDistribution.xml'
2017-12-07 19:48:00 +01:00
2018-06-06 19:28:22 +02:00
$packageId = Get-MacOSPackageId -IsPreview: $IsPreview . IsPresent
2017-12-08 19:55:34 +01:00
# format distribution template with:
# 0 - title
# 1 - version
# 2 - package path
2018-06-06 19:28:22 +02:00
# 3 - minimum os version
# 4 - Package Identifier
$PackagingStrings . OsxDistributionTemplate -f " PowerShell - $packageVersion " , $packageVersion , $packageName , '10.12' , $packageId | Out-File -Encoding ascii -FilePath $distributionXmlPath -Force
2017-12-08 19:55:34 +01:00
2018-03-08 19:47:20 +01:00
Write-Log " Applying distribution.xml to package... "
2017-12-08 19:55:34 +01:00
Push-Location $tempDir
try
{
2017-12-08 22:47:54 +01:00
# productbuild is an xcode command line tool, and those tools are installed when you install brew
2017-12-08 19:55:34 +01:00
Start-NativeExecution -sb { productbuild - -distribution $distributionXmlPath - -resources $resourcesDir $newPackagePath }
}
finally
{
Pop-Location
Remove-item -Path $tempDir -Recurse -Force
}
return $newPackagePath
}
2017-12-07 19:48:00 +01:00
function Get-FpmArguments
{
param (
[ Parameter ( Mandatory , HelpMessage = 'Package Name' ) ]
[ String ] $Name ,
[ Parameter ( Mandatory , HelpMessage = 'Package Version' ) ]
[ String ] $Version ,
[ Parameter ( Mandatory ) ]
[ String ] $Iteration ,
[ Parameter ( Mandatory , HelpMessage = 'Package description' ) ]
[ String ] $Description ,
# From start-PSPackage without modification, already validated
# Values: deb, rpm, osxpkg
[ Parameter ( Mandatory , HelpMessage = 'Installer Type' ) ]
[ String ] $Type ,
[ Parameter ( Mandatory , HelpMessage = 'Staging folder for installation files' ) ]
[ String ] $Staging ,
[ Parameter ( Mandatory , HelpMessage = 'Install path on target machine' ) ]
[ String ] $Destination ,
[ Parameter ( Mandatory , HelpMessage = 'The built and gzipped man file.' ) ]
[ String ] $ManGzipFile ,
[ Parameter ( Mandatory , HelpMessage = 'The destination of the man file' ) ]
[ String ] $ManDestination ,
[ Parameter ( Mandatory , HelpMessage = 'Symlink to powershell executable' ) ]
[ String ] $LinkSource ,
[ Parameter ( Mandatory , HelpMessage = 'Destination for symlink to powershell executable' ) ]
[ String ] $LinkDestination ,
[ Parameter ( HelpMessage = 'Packages required to install this package. Not applicable for MacOS.' ) ]
[ ValidateScript ( {
if ( ! $Environment . IsMacOS -and $_ . Count -eq 0 )
{
throw " Must not be null or empty on this environment. "
}
return $true
} ) ]
[ String[] ] $Dependencies ,
[ Parameter ( HelpMessage = 'Script to run after the package installation.' ) ]
[ AllowNull ( ) ]
[ ValidateScript ( {
if ( ! $Environment . IsMacOS -and ! $_ )
{
throw " Must not be null on this environment. "
}
return $true
} ) ]
[ String ] $AfterInstallScript ,
[ Parameter ( HelpMessage = 'Script to run after the package removal.' ) ]
[ AllowNull ( ) ]
[ ValidateScript ( {
if ( ! $Environment . IsMacOS -and ! $_ )
{
throw " Must not be null on this environment. "
}
return $true
} ) ]
2017-12-08 19:55:34 +01:00
[ String ] $AfterRemoveScript ,
[ Parameter ( HelpMessage = 'AppsFolder used to add macOS launcher' ) ]
[ AllowNull ( ) ]
[ ValidateScript ( {
if ( $Environment . IsMacOS -and ! $_ )
{
throw " Must not be null on this environment. "
}
return $true
} ) ]
[ String ] $AppsFolder
2017-12-07 19:48:00 +01:00
)
$Arguments = @ (
" --force " , " --verbose " ,
" --name " , $Name ,
" --version " , $Version ,
" --iteration " , $Iteration ,
" --maintainer " , " PowerShell Team <PowerShellTeam@hotmail.com> " ,
" --vendor " , " Microsoft Corporation " ,
" --url " , " https://microsoft.com/powershell " ,
" --license " , " MIT License " ,
" --description " , $Description ,
" --category " , " shells " ,
" -t " , $Type ,
" -s " , " dir "
)
if ( $Environment . IsRedHatFamily ) {
$Arguments + = @ ( " --rpm-dist " , " rhel.7 " )
$Arguments + = @ ( " --rpm-os " , " linux " )
}
if ( $Environment . IsMacOS ) {
$Arguments + = @ ( " --osxpkg-identifier-prefix " , " com.microsoft " )
}
foreach ( $Dependency in $Dependencies ) {
$Arguments + = @ ( " --depends " , $Dependency )
}
if ( $AfterInstallScript ) {
$Arguments + = @ ( " --after-install " , $AfterInstallScript )
}
if ( $AfterRemoveScript ) {
$Arguments + = @ ( " --after-remove " , $AfterRemoveScript )
}
$Arguments + = @ (
" $Staging /= $Destination / " ,
" $ManGzipFile = $ManDestination " ,
" $LinkSource = $LinkDestination "
)
2018-09-10 21:47:32 +02:00
if ( $AppsFolder )
2017-12-08 19:55:34 +01:00
{
$Arguments + = " $AppsFolder =/ "
}
2017-12-07 19:48:00 +01:00
return $Arguments
}
function Test-Distribution
{
param (
[ String ]
$Distribution
)
if ( ( $Environment . IsUbuntu -or $Environment . IsDebian ) -and ! $Distribution )
{
throw " $Distribution is required for a Debian based distribution. "
}
2018-09-10 21:47:32 +02:00
if ( $Script:DebianDistributions -notcontains $Distribution )
2017-12-07 19:48:00 +01:00
{
throw " $Distribution should be one of the following: $Script:DebianDistributions "
}
return $true
}
function Get-PackageDependencies
{
param (
[ String ]
[ ValidateScript ( { Test-Distribution -Distribution $_ } ) ]
$Distribution
)
End {
# These should match those in the Dockerfiles, but exclude tools like Git, which, and curl
$Dependencies = @ ( )
if ( $Environment . IsUbuntu -or $Environment . IsDebian ) {
$Dependencies = @ (
" libc6 " ,
" libgcc1 " ,
" libgssapi-krb5-2 " ,
" liblttng-ust0 " ,
" libstdc++6 " ,
" zlib1g "
)
switch ( $Distribution ) {
" ubuntu.14.04 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu52 " ) }
" ubuntu.16.04 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu55 " ) }
2018-05-07 21:30:58 +02:00
" ubuntu.17.10 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu57 " ) }
" ubuntu.18.04 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu60 " ) }
2017-12-07 19:48:00 +01:00
" debian.8 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu52 " ) }
" debian.9 " { $Dependencies + = @ ( " libssl1.0.2 " , " libicu57 " ) }
default { throw " Debian distro ' $Distribution ' is not supported. " }
}
} elseif ( $Environment . IsRedHatFamily ) {
$Dependencies = @ (
" openssl-libs " ,
" libicu "
)
2018-10-03 21:29:13 +02:00
} elseif ( $Environment . IsSUSEFamily ) {
$Dependencies = @ (
" libopenssl1_0_0 " ,
" libicu "
)
2017-12-07 19:48:00 +01:00
}
return $Dependencies
}
}
function Test-Dependencies
{
foreach ( $Dependency in " fpm " , " ronn " ) {
if ( ! ( precheck $Dependency " Package dependency ' $Dependency ' not found. Run Start-PSBootstrap -Package " ) ) {
# These tools are not added to the path automatically on OpenSUSE 13.2
# try adding them to the path and re-tesing first
[ string ] $gemsPath = $null
[ string ] $depenencyPath = $null
$gemsPath = Get-ChildItem -Path / usr / lib64 / ruby / gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName
2018-09-10 21:47:32 +02:00
if ( $gemsPath ) {
2017-12-07 19:48:00 +01:00
$depenencyPath = Get-ChildItem -Path ( Join-Path -Path $gemsPath -ChildPath " gems " -AdditionalChildPath $Dependency ) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName
$originalPath = $env:PATH
$env:PATH = $ENV:PATH + " : " + $depenencyPath
2018-09-10 21:47:32 +02:00
if ( ( precheck $Dependency " Package dependency ' $Dependency ' not found. Run Start-PSBootstrap -Package " ) ) {
2017-12-07 19:48:00 +01:00
continue
}
else {
$env:PATH = $originalPath
}
}
throw " Dependency precheck failed! "
}
}
}
function New-AfterScripts
{
2018-06-09 01:31:38 +02:00
param (
[ Parameter ( Mandatory ) ]
[ string ]
$Link
)
2017-12-07 19:48:00 +01:00
if ( $Environment . IsRedHatFamily ) {
# add two symbolic links to system shared libraries that libmi.so is dependent on to handle
# platform specific changes. This is the only set of platforms needed for this currently
# as Ubuntu has these specific library files in the platform and macOS builds for itself
# against the correct versions.
New-Item -Force -ItemType SymbolicLink -Target " /lib64/libssl.so.10 " -Path " $Staging /libssl.so.1.0.0 " > $null
New-Item -Force -ItemType SymbolicLink -Target " /lib64/libcrypto.so.10 " -Path " $Staging /libcrypto.so.1.0.0 " > $null
$AfterInstallScript = [ io.path ] :: GetTempFileName ( )
$AfterRemoveScript = [ io.path ] :: GetTempFileName ( )
2018-06-09 01:31:38 +02:00
$packagingStrings . RedHatAfterInstallScript -f " $Link " | Out-File -FilePath $AfterInstallScript -Encoding ascii
$packagingStrings . RedHatAfterRemoveScript -f " $Link " | Out-File -FilePath $AfterRemoveScript -Encoding ascii
2017-12-07 19:48:00 +01:00
}
2018-01-22 23:58:17 +01:00
elseif ( $Environment . IsUbuntu -or $Environment . IsDebian -or $Environment . IsSUSEFamily ) {
2017-12-07 19:48:00 +01:00
$AfterInstallScript = [ io.path ] :: GetTempFileName ( )
$AfterRemoveScript = [ io.path ] :: GetTempFileName ( )
2018-06-09 01:31:38 +02:00
$packagingStrings . UbuntuAfterInstallScript -f " $Link " | Out-File -FilePath $AfterInstallScript -Encoding ascii
$packagingStrings . UbuntuAfterRemoveScript -f " $Link " | Out-File -FilePath $AfterRemoveScript -Encoding ascii
2018-08-25 00:20:22 +02:00
if ( $Environment . IsDebian9 ) {
# add two symbolic links to system shared libraries that libmi.so is dependent on to handle
# platform specific changes. This appears to be a change in Debian 9; Debian 8 did not need these
# symlinks.
New-Item -Force -ItemType SymbolicLink -Target " /usr/lib/x86_64-linux-gnu/libssl.so.1.0.2 " -Path " $Staging /libssl.so.1.0.0 " > $null
New-Item -Force -ItemType SymbolicLink -Target " /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.2 " -Path " $Staging /libcrypto.so.1.0.0 " > $null
}
2017-12-07 19:48:00 +01:00
}
return [ PSCustomObject ] @ {
AfterInstallScript = $AfterInstallScript
AfterRemoveScript = $AfterRemoveScript
}
}
function New-ManGzip
{
2018-06-09 01:31:38 +02:00
param (
[ switch ]
$IsPreview
)
2017-12-07 19:48:00 +01:00
# run ronn to convert man page to roff
2018-09-25 18:53:42 +02:00
$RonnFile = " $RepoRoot /assets/pwsh.1.ronn "
2018-09-10 21:47:32 +02:00
if ( $IsPreview . IsPresent )
2018-06-09 01:31:38 +02:00
{
$newRonnFile = $RonnFile -replace 'pwsh' , 'pwsh-preview'
Copy-Item -Path $RonnFile -Destination $newRonnFile -force
$RonnFile = $newRonnFile
}
2017-12-07 19:48:00 +01:00
$RoffFile = $RonnFile -replace " \.ronn $ "
# Run ronn on assets file
2018-06-09 01:31:38 +02:00
Start-NativeExecution { ronn - -roff $RonnFile } -VerboseOutputOnError
2018-09-10 21:47:32 +02:00
if ( $IsPreview . IsPresent )
2018-06-09 01:31:38 +02:00
{
Remove-item $RonnFile
}
2017-12-07 19:48:00 +01:00
# gzip in assets directory
$GzipFile = " $RoffFile .gz "
2018-06-09 01:31:38 +02:00
Start-NativeExecution { gzip -f $RoffFile } -VerboseOutputOnError
2017-12-07 19:48:00 +01:00
$ManFile = Join-Path " /usr/local/share/man/man1 " ( Split-Path -Leaf $GzipFile )
return [ PSCustomObject ] @ {
GZipFile = $GzipFile
ManFile = $ManFile
}
}
2018-06-06 19:28:22 +02:00
# Returns the macOS Package Identifier
function Get-MacOSPackageId
{
param (
[ switch ]
$IsPreview
)
2018-09-10 21:47:32 +02:00
if ( $IsPreview . IsPresent )
2018-06-06 19:28:22 +02:00
{
return 'com.microsoft.powershell-preview'
}
else
{
return 'com.microsoft.powershell'
}
}
2018-07-20 19:53:09 +02:00
# Dynamically build macOS launcher application.
2017-12-07 19:48:00 +01:00
function New-MacOSLauncher
{
param (
[ Parameter ( Mandatory ) ]
[ String ] $Version
)
2018-06-06 19:28:22 +02:00
$IsPreview = Test-IsPreview -Version $Version
$packageId = Get-MacOSPackageId -IsPreview: $IsPreview
2018-07-20 19:53:09 +02:00
# Define folder for launcher application.
$suffix = if ( $IsPreview ) { " -preview " }
$macosapp = " $PSScriptRoot /macos/launcher/ROOT/Applications/PowerShell $suffix .app "
2017-12-07 19:48:00 +01:00
2018-07-20 19:53:09 +02:00
# Create folder structure for launcher application.
New-Item -Force -ItemType Directory -Path " $macosapp /Contents/MacOS " | Out-Null
New-Item -Force -ItemType Directory -Path " $macosapp /Contents/Resources " | Out-Null
# Define icns file information.
2018-08-05 20:00:39 +02:00
if ( $IsPreview )
{
2018-09-25 18:53:42 +02:00
$iconfile = " $RepoRoot /assets/Powershell-preview.icns "
2018-08-05 20:00:39 +02:00
}
else
{
2018-09-25 18:53:42 +02:00
$iconfile = " $RepoRoot /assets/Powershell.icns "
2018-08-05 20:00:39 +02:00
}
2017-12-07 19:48:00 +01:00
$iconfilebase = ( Get-Item -Path $iconfile ) . BaseName
2018-07-20 19:53:09 +02:00
# Copy icns file.
2017-12-07 19:48:00 +01:00
Copy-Item -Force -Path $iconfile -Destination " $macosapp /Contents/Resources "
2018-07-20 19:53:09 +02:00
# Create plist file.
2017-12-07 19:48:00 +01:00
$plist = " $macosapp /Contents/Info.plist "
2018-07-20 19:53:09 +02:00
$plistcontent = $packagingStrings . MacOSLauncherPlistTemplate -f $packageId , $Version , $iconfilebase
$plistcontent | Out-File -Force -Path $plist -Encoding utf8
2017-12-07 19:48:00 +01:00
2018-07-20 19:53:09 +02:00
# Create shell script.
$executablepath = if ( $IsPreview ) { " /usr/local/bin/pwsh-preview " } else { " /usr/local/bin/pwsh " }
2017-12-07 19:48:00 +01:00
$shellscript = " $macosapp /Contents/MacOS/PowerShell.sh "
2018-07-20 19:53:09 +02:00
$shellscriptcontent = $packagingStrings . MacOSLauncherScript -f $executablepath
$shellscriptcontent | Out-File -Force -Path $shellscript -Encoding utf8
# Set permissions for plist and shell script.
2017-12-07 19:48:00 +01:00
Start-NativeExecution {
chmod 644 $plist
chmod 755 $shellscript
}
# Add app folder to fpm paths.
$appsfolder = ( Resolve-Path -Path " $macosapp /.. " ) . Path
return $appsfolder
}
function Clear-MacOSLauncher
{
# This is needed to prevent installer from picking up
# the launcher app in the build structure and updating
# it which locks out subsequent package builds due to
# increase permissions.
2018-07-20 19:53:09 +02:00
# Remove launcher application.
$macosfolder = " $PSScriptRoot /macos "
Remove-Item -Force -Recurse -Path $macosfolder
2017-12-07 19:48:00 +01:00
}
2017-08-01 23:35:50 +02:00
function New-StagingFolder
{
param (
[ Parameter ( Mandatory ) ]
[ string ]
2017-10-18 02:25:11 +02:00
$StagingPath
2017-08-01 23:35:50 +02:00
)
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $StagingPath
Copy-Item -Recurse $PackageSourcePath $StagingPath
}
2017-07-23 21:29:33 +02:00
# Function to create a zip file for Nano Server and xcopy deployment
function New-ZipPackage
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
# Name of the Product
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageName = 'PowerShell' ,
# Suffix of the Name
[ string ] $PackageNameSuffix ,
# Version of the Product
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageVersion ,
# Source Path to the Product Files - required to package the contents into an Zip
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
2017-08-03 00:14:47 +02:00
[ string ] $PackageSourcePath ,
[ switch ] $Force
2017-07-23 21:29:33 +02:00
)
$ProductSemanticVersion = Get-PackageSemanticVersion -Version $PackageVersion
$zipPackageName = $PackageName + " - " + $ProductSemanticVersion
if ( $PackageNameSuffix ) {
$zipPackageName = $zipPackageName , $PackageNameSuffix -join " - "
}
Write-Verbose " Create Zip for Product $zipPackageName "
$zipLocationPath = Join-Path $PWD " $zipPackageName .zip "
2018-09-10 21:47:32 +02:00
if ( $Force . IsPresent )
2017-08-01 23:35:50 +02:00
{
2018-09-10 21:47:32 +02:00
if ( Test-Path $zipLocationPath )
2017-08-01 23:35:50 +02:00
{
Remove-Item $zipLocationPath
}
}
2018-09-10 21:47:32 +02:00
if ( Get-Command Compress-Archive -ErrorAction Ignore )
2017-07-23 21:29:33 +02:00
{
2018-09-10 21:47:32 +02:00
if ( $pscmdlet . ShouldProcess ( " Create zip package " ) )
2017-07-23 21:29:33 +02:00
{
Compress-Archive -Path $PackageSourcePath \ * -DestinationPath $zipLocationPath
}
2017-09-11 21:36:24 +02:00
if ( Test-Path $zipLocationPath )
{
2018-03-08 19:47:20 +01:00
Write-Log " You can find the Zip @ $zipLocationPath "
2017-09-11 21:36:24 +02:00
$zipLocationPath
}
else
{
throw " Failed to create $zipLocationPath "
}
2017-07-23 21:29:33 +02:00
}
#TODO: Use .NET Api to do compresss-archive equivalent if the pscmdlet is not present
else
{
Write-Error -Message " Compress-Archive cmdlet is missing in this PowerShell version "
}
}
2017-08-01 23:35:50 +02:00
2018-02-27 00:35:09 +01:00
function CreateNugetPlatformFolder
{
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $Platform ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageRuntimesFolder ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PlatformBinPath
)
$destPath = New-Item -ItemType Directory -Path ( Join-Path $PackageRuntimesFolder " $Platform /lib/netstandard2.0 " )
$fullPath = Join-Path $PlatformBinPath $file
if ( -not ( Test-Path $fullPath ) ) {
throw " File not found: $fullPath "
}
Copy-Item -Path $fullPath -Destination $destPath
2018-03-08 19:47:20 +01:00
Write-Log " Copied $file to $Platform "
2018-02-27 00:35:09 +01:00
}
<#
. SYNOPSIS
Creates NuGet packages containing linux , osx and Windows runtime assemblies .
. DESCRIPTION
Creates a NuGet package for linux , osx , Windows runtimes for 32 bit , 64 bit and ARM .
The packages for Microsoft . PowerShell . Commands . Diagnostics , Microsoft . PowerShell . Commands . Management ,
Microsoft . PowerShell . Commands . Utility , Microsoft . PowerShell . ConsoleHost , Microsoft . PowerShell . CoreCLR . Eventing ,
Microsoft . PowerShell . SDK , Microsoft . PowerShell . Security , Microsoft . WSMan . Management , Microsoft . WSMan . Runtime ,
System . Management . Automation are created .
. PARAMETER PackagePath
Path where the package will be created .
. PARAMETER PackageVersion
Version of the created package .
. PARAMETER Winx86BinPath
Path to folder containing Windows x86 assemblies .
. PARAMETER Winx64BinPath
Path to folder containing Windows x64 assemblies .
. PARAMETER WinArm32BinPath
Path to folder containing Windows arm32 assemblies .
. PARAMETER WinArm64BinPath
Path to folder containing Windows arm64 assemblies .
. PARAMETER LinuxArm32BinPath
Path to folder containing linux arm32 assemblies .
. PARAMETER LinuxBinPath
Path to folder containing linux x64 assemblies .
. PARAMETER OsxBinPath
Path to folder containing osx assemblies .
. PARAMETER GenAPIToolPath
Path to the GenAPI . exe tool .
#>
function New-UnifiedNugetPackage
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackagePath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageVersion ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $Winx86BinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $Winx64BinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $WinArm32BinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $WinArm64BinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $LinuxArm32BinPath ,
2018-07-20 20:08:25 +02:00
[ Parameter ( Mandatory = $false ) ]
[ string ] $LinuxMuslBinPath ,
2018-06-28 00:30:38 +02:00
2018-02-27 00:35:09 +01:00
[ Parameter ( Mandatory = $true ) ]
[ string ] $LinuxBinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $OsxBinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $GenAPIToolPath
)
2018-09-10 21:47:32 +02:00
if ( -not $Environment . IsWindows )
2018-02-27 00:35:09 +01:00
{
throw " New-UnifiedNugetPackage can be only executed on Windows platform. "
}
$fileList = @ (
" Microsoft.PowerShell.Commands.Diagnostics.dll " ,
" Microsoft.PowerShell.Commands.Management.dll " ,
" Microsoft.PowerShell.Commands.Utility.dll " ,
" Microsoft.PowerShell.ConsoleHost.dll " ,
" Microsoft.PowerShell.CoreCLR.Eventing.dll " ,
" Microsoft.PowerShell.Security.dll " ,
" Microsoft.PowerShell.SDK.dll " ,
" Microsoft.WSMan.Management.dll " ,
" Microsoft.WSMan.Runtime.dll " ,
2018-08-03 08:00:54 +02:00
" System.Management.Automation.dll " ,
" Microsoft.PowerShell.MarkdownRender.dll " )
2018-02-27 00:35:09 +01:00
$linuxExceptionList = @ (
" Microsoft.PowerShell.Commands.Diagnostics.dll " ,
" Microsoft.WSMan.Management.dll " ,
" Microsoft.WSMan.Runtime.dll " )
if ( $PSCmdlet . ShouldProcess ( " Create nuget packages at: $PackagePath " ) )
{
$refBinPath = New-TempFolder
2018-09-25 18:53:42 +02:00
$SnkFilePath = " $RepoRoot \src\signing\visualstudiopublic.snk "
2018-02-27 00:35:09 +01:00
2018-03-15 18:12:56 +01:00
New-ReferenceAssembly -linux64BinPath $linuxBinPath -RefAssemblyDestinationPath $refBinPath -RefAssemblyVersion $PackageVersion -SnkFilePath $SnkFilePath -GenAPIToolPath $GenAPIToolPath
2018-02-27 00:35:09 +01:00
$refBinFullName = Join-Path $refBinPath 'System.Management.Automation.dll'
foreach ( $file in $fileList )
{
$tmpPackageRoot = New-TempFolder
# Remove '.dll' at the end
$fileBaseName = [ System.IO.Path ] :: GetFileNameWithoutExtension ( $file )
$filePackageFolder = New-Item ( Join-Path $tmpPackageRoot $fileBaseName ) -ItemType Directory -Force
$packageRuntimesFolder = New-Item ( Join-Path $filePackageFolder . FullName 'runtimes' ) -ItemType Directory
#region ref
$refFolder = New-Item ( Join-Path $filePackageFolder . FullName 'ref/netstandard2.0' ) -ItemType Directory -Force
Copy-Item $refBinFullName -Destination $refFolder -Force
2018-03-08 19:47:20 +01:00
Write-Log " Copied file $refBinFullName to $refFolder "
2018-02-27 00:35:09 +01:00
#endregion ref
$packageRuntimesFolderPath = $packageRuntimesFolder . FullName
CreateNugetPlatformFolder -Platform 'win-x86' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winX86BinPath
CreateNugetPlatformFolder -Platform 'win-x64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winX64BinPath
CreateNugetPlatformFolder -Platform 'win-arm' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winArm32BinPath
CreateNugetPlatformFolder -Platform 'win-arm64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winArm64BinPath
if ( $linuxExceptionList -notcontains $file )
{
CreateNugetPlatformFolder -Platform 'linux-arm' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $linuxArm32BinPath
2018-07-20 20:08:25 +02:00
2018-09-10 21:47:32 +02:00
if ( $linuxMuslBinPath )
2018-07-20 20:08:25 +02:00
{
CreateNugetPlatformFolder -Platform 'linux-musl-x64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $linuxMuslBinPath
}
2018-02-27 00:35:09 +01:00
CreateNugetPlatformFolder -Platform 'linux-x64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $linuxBinPath
CreateNugetPlatformFolder -Platform 'osx' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $osxBinPath
}
#region nuspec
# filed a tracking bug for automating generation of dependecy list: https://github.com/PowerShell/PowerShell/issues/6247
$deps = [ System.Collections.ArrayList ] :: new ( )
switch ( $fileBaseName ) {
'Microsoft.PowerShell.Commands.Diagnostics' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
}
'Microsoft.PowerShell.Commands.Management' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.Security' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
'Microsoft.PowerShell.Commands.Utility' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-08-03 08:00:54 +02:00
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.MarkdownRender' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
'Microsoft.PowerShell.ConsoleHost' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
'Microsoft.PowerShell.CoreCLR.Eventing' {
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
'Microsoft.PowerShell.SDK' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.Commands.Management' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.Commands.Utility' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.ConsoleHost' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.Security' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-08-03 08:00:54 +02:00
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.WSMan.Management' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.Commands.Diagnostics' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-02-27 00:35:09 +01:00
}
'Microsoft.PowerShell.Security' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
}
'Microsoft.WSMan.Management' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.WSMan.Runtime' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
'Microsoft.WSMan.Runtime' {
## No dependencies
}
'System.Management.Automation' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.PowerShell.CoreCLR.Eventing' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
2018-07-13 06:00:35 +02:00
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
}
2018-08-03 08:00:54 +02:00
'Microsoft.PowerShell.MarkdownRender' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
foreach ( $packageInfo in ( Get-ProjectPackageInformation -ProjectName $fileBaseName ) )
{
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , $packageInfo . Name ) , [ tuple ] :: Create ( 'version' , $packageInfo . Version ) ) ) > $null
}
}
2018-02-27 00:35:09 +01:00
}
New-NuSpec -PackageId $fileBaseName -PackageVersion $PackageVersion -Dependency $deps -FilePath ( Join-Path $filePackageFolder . FullName " $fileBaseName .nuspec " )
New-NugetPackage -NuSpecPath $filePackageFolder . FullName -PackageDestinationPath $PackagePath
}
2018-09-10 21:47:32 +02:00
if ( Test-Path $refBinPath )
2018-02-27 00:35:09 +01:00
{
Remove-Item $refBinPath -Recurse -Force -ErrorAction SilentlyContinue
}
2018-09-10 21:47:32 +02:00
if ( Test-Path $tmpPackageRoot )
2018-02-27 00:35:09 +01:00
{
Remove-Item $tmpPackageRoot -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
2018-07-13 06:00:35 +02:00
<#
. SYNOPSIS
Return the list of packages and versions used by a project
. PARAMETER ProjectName
The name of the project to get the projects for .
#>
function Get-ProjectPackageInformation
{
param (
[ Parameter ( Mandatory = $true ) ]
[ string ]
$ProjectName
)
2018-09-25 18:53:42 +02:00
$csproj = " $RepoRoot \src\ $ProjectName \ $ProjectName .csproj "
2018-07-13 06:00:35 +02:00
[ xml ] $csprojXml = ( Get-content -Raw -Path $csproj )
# get the package references
$packages = $csprojXml . Project . ItemGroup . PackageReference
# check to see if there is a newer package for each refernce
foreach ( $package in $packages )
{
2018-09-10 21:47:32 +02:00
if ( $package . Version -notmatch '\*' -and $package . Include )
2018-07-13 06:00:35 +02:00
{
# Get the name of the package
[ PSCustomObject ] @ {
Name = $package . Include
Version = $package . Version
}
}
}
}
2018-02-27 00:35:09 +01:00
<#
. SYNOPSIS
Creates a nuspec file .
. PARAMETER PackageId
ID of the package .
. PARAMETER PackageVersion
Version of the package .
. PARAMETER Dependency
Depedencies of the package .
. PARAMETER FilePath
Path to create the nuspec file .
#>
function New-NuSpec {
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageId ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageVersion ,
[ Parameter ( Mandatory = $false ) ]
# An array of tuples of tuples to define the dependencies.
# First tuple defines 'id' and value eg: ["id", "System.Data.SqlClient"]
# Second tuple defines 'version' and vale eg: ["version", "4.4.2"]
# Both these tuples combined together define one dependency.
# An array represents all the dependencies.
[ tuple[ [tuple[string, string]], [tuple[string, string]] ] [] ] $Dependency ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $FilePath
)
2018-09-10 21:47:32 +02:00
if ( -not $Environment . IsWindows )
2018-02-27 00:35:09 +01:00
{
throw " New-NuSpec can be only executed on Windows platform. "
}
$nuspecTemplate = $packagingStrings . NuspecTemplate -f $PackageId , $PackageVersion
$nuspecObj = [ xml ] $nuspecTemplate
2018-09-25 18:53:42 +02:00
if ( ( $null -ne $Dependency ) -and $Dependency . Count -gt 0 ) {
2018-02-27 00:35:09 +01:00
foreach ( $dep in $Dependency ) {
# Each item is [tuple[ [tuple[string, string]], [tuple[string, string]] ]
$d = $nuspecObj . package . metadata . dependencies . group . AppendChild ( $nuspecObj . CreateElement ( " dependency " ) )
# 'id' and value
$d . SetAttribute ( $dep . Item1 . Item1 , $dep . Item1 . Item2 )
# 'version' and value
$d . SetAttribute ( $dep . Item2 . Item1 , $dep . Item2 . Item2 )
}
}
$nuspecObj . Save ( $filePath )
}
<#
. SYNOPSIS
Create a reference assembly from System . Management . Automation . dll
. DESCRIPTION
A unix variant of System . Management . Automation . dll is converted to a reference assembly .
GenAPI . exe generated the CS file containing the APIs .
This file is cleaned up and then compiled into a dll .
. PARAMETER Unix64BinPath
Path to the folder containing unix 64 bit assemblies .
. PARAMETER RefAssemblyDestinationPath
Path to the folder where the reference assembly is created .
. PARAMETER RefAssemblyVersion
Version of the reference assembly .
. PARAMETER GenAPIToolPath
Path to GenAPI . exe . Tool from https : / / www . nuget . org / packages / Microsoft . DotNet . BuildTools . GenAPI /
. PARAMETER SnkFilePath
Path to the snk file for strong name signing .
#>
function New-ReferenceAssembly
{
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $Linux64BinPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $RefAssemblyDestinationPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $RefAssemblyVersion ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $GenAPIToolPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $SnkFilePath
)
2018-09-10 21:47:32 +02:00
if ( -not $Environment . IsWindows )
2018-02-27 00:35:09 +01:00
{
throw " New-ReferenceAssembly can be only executed on Windows platform. "
}
$genAPIFolder = New-TempFolder
$smaProjectFolder = New-Item -Path " $genAPIFolder /System.Management.Automation " -ItemType Directory -Force
$smaCs = Join-Path $smaProjectFolder 'System.Management.Automation.cs'
$smaCsFiltered = Join-Path $smaProjectFolder 'System.Management.Automation_Filtered.cs'
2018-03-08 19:47:20 +01:00
Write-Log " Working directory: $genAPIFolder . "
2018-02-27 00:35:09 +01:00
#region GenAPI
$genAPIExe = Get-ChildItem -Path " $GenAPIToolPath /*GenAPI.exe " -Recurse
2018-09-10 21:47:32 +02:00
if ( -not ( Test-Path $genAPIExe ) )
2018-02-27 00:35:09 +01:00
{
throw " GenAPI.exe was not found at: $GenAPIToolPath "
}
2018-03-08 19:47:20 +01:00
Write-Log " GenAPI nuget package saved and expanded. "
2018-02-27 00:35:09 +01:00
$linuxSMAPath = Join-Path $Linux64BinPath " System.Management.Automation.dll "
2018-09-10 21:47:32 +02:00
if ( -not ( Test-Path $linuxSMAPath ) )
2018-02-27 00:35:09 +01:00
{
throw " System.Management.Automation.dll was not found at: $Linux64BinPath "
}
$genAPIArgs = " $linuxSMAPath " , " -libPath: $Linux64BinPath "
2018-03-08 19:47:20 +01:00
Write-Log " GenAPI cmd: $genAPIExe $genAPIArgsString "
2018-02-27 00:35:09 +01:00
Start-NativeExecution { & $genAPIExe $genAPIArgs } | Out-File $smaCs -Force
2018-03-08 19:47:20 +01:00
Write-Log " Reference assembly file generated at: $smaCs "
2018-02-27 00:35:09 +01:00
#endregion GenAPI
#region Cleanup SMA.cs
$patternsToRemove = @ (
'[System.Management.Automation.ArgumentToEncodingTransformationAttribute]' ,
'typeof(System.Security.AccessControl.FileSecurity)' ,
'[System.Management.Automation.ArgumentTypeConverterAttribute' ,
'[System.Runtime.CompilerServices.IteratorStateMachineAttribute' ,
'[Microsoft.PowerShell.Commands.ArgumentToModuleTransformationAttribute]' ,
'[Microsoft.PowerShell.Commands.SetStrictModeCommand.ArgumentToVersionTransformationAttribute]' ,
'[Microsoft.PowerShell.Commands.SetStrictModeCommand.ValidateVersionAttribute]' ,
'[System.Management.Automation.OutputTypeAttribute(typeof(System.Management.Automation.PSRemotingJob))]' ,
'typeof(System.Management.Automation.LanguagePrimitives.EnumMultipleTypeConverter)' ,
'[System.Management.Automation.Internal.CommonParameters.ValidateVariableName]'
)
$reader = [ System.IO.File ] :: OpenText ( $smaCs )
$writer = [ System.IO.File ] :: CreateText ( $smaCsFiltered )
2018-09-25 18:53:42 +02:00
while ( $null -ne ( $line = $reader . ReadLine ( ) ) )
2018-02-27 00:35:09 +01:00
{
$match = $line | Select-String -Pattern $patternsToRemove -SimpleMatch
2018-09-25 18:53:42 +02:00
if ( $null -ne $match )
2018-02-27 00:35:09 +01:00
{
$writer . WriteLine ( " // $line " )
}
else
{
$writer . WriteLine ( $line )
}
}
2018-09-25 18:53:42 +02:00
if ( $null -ne $reader )
2018-02-27 00:35:09 +01:00
{
$reader . Close ( )
}
2018-09-25 18:53:42 +02:00
if ( $null -ne $writer )
2018-02-27 00:35:09 +01:00
{
$writer . Close ( )
}
Move-Item $smaCsFiltered $smaCs -Force
2018-03-08 19:47:20 +01:00
Write-Log " Reference assembly code cleanup complete. "
2018-02-27 00:35:09 +01:00
#endregion Cleanup SMA.cs
#region Build SMA ref assembly
try
{
Push-Location $smaProjectFolder
$csProj = $packagingStrings . RefAssemblyCsProj -f $RefAssemblyVersion , $SnkFilePath
$csProj | Out-File -FilePath " $smaProjectFolder /System.Management.Automation.csproj " -Force
$packagingStrings . NugetConfigFile | Out-File -FilePath " $genAPIFolder /Nuget.config " -Force
Start-NativeExecution { dotnet build -c Release } > $null
$refBinPath = Join-Path $smaProjectFolder 'bin/Release/netstandard2.0/System.Management.Automation.dll'
2018-09-25 18:53:42 +02:00
if ( $null -eq $refBinPath )
2018-02-27 00:35:09 +01:00
{
throw " Reference assembly was not built. "
}
Copy-Item $refBinPath $RefAssemblyDestinationPath -Force
2018-03-08 19:47:20 +01:00
Write-Log " Reference assembly built and copied to $RefAssemblyDestinationPath "
2018-02-27 00:35:09 +01:00
}
finally
{
Pop-Location
}
2018-09-10 21:47:32 +02:00
if ( Test-Path $genAPIFolder )
2018-02-27 00:35:09 +01:00
{
Remove-Item $genAPIFolder -Recurse -Force -ErrorAction SilentlyContinue
}
#endregion Build SMA ref assembly
}
<#
. SYNOPSIS
Create a NuGet package from a nuspec .
. DESCRIPTION
Creates a NuGet using the nuspec using at the specified folder .
It is expected that the lib / ref / runtime folders are welformed .
The genereated NuGet package is copied over to the $PackageDestinationPath
. PARAMETER NuSpecPath
Path to the folder containing the nuspec file .
. PARAMETER PackageDestinationPath
Path to which NuGet package should be copied . Destination is created if it does not exist .
#>
2017-08-01 23:35:50 +02:00
function New-NugetPackage
2018-02-27 00:35:09 +01:00
{
[ CmdletBinding ( ) ]
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $NuSpecPath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageDestinationPath
)
$nuget = Get-Command -Type Application nuget -ErrorAction SilentlyContinue
2018-09-25 18:53:42 +02:00
if ( $null -eq $nuget )
2018-02-27 00:35:09 +01:00
{
throw 'nuget application is not available in PATH'
}
Push-Location $NuSpecPath
Start-NativeExecution { nuget pack . } > $null
2018-09-10 21:47:32 +02:00
if ( -not ( Test-Path $PackageDestinationPath ) )
2018-02-27 00:35:09 +01:00
{
New-Item $PackageDestinationPath -ItemType Directory -Force > $null
}
Copy-Item * . nupkg $PackageDestinationPath -Force -Verbose
Pop-Location
}
<#
. SYNOPSIS
Publish the specified Nuget Package to MyGet feed .
. DESCRIPTION
The specified nuget package is published to the powershell . myget . org / powershell-core feed .
. PARAMETER PackagePath
Path to the NuGet Package .
. PARAMETER ApiKey
API key for powershell . myget . org
#>
function Publish-NugetToMyGet
{
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackagePath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $ApiKey
)
$nuget = Get-Command -Type Application nuget -ErrorAction SilentlyContinue
2018-09-25 18:53:42 +02:00
if ( $null -eq $nuget )
2018-02-27 00:35:09 +01:00
{
throw 'nuget application is not available in PATH'
}
Get-ChildItem $PackagePath | ForEach-Object {
2018-03-08 19:47:20 +01:00
Write-Log " Pushing $_ to PowerShell Myget "
2018-02-27 00:35:09 +01:00
Start-NativeExecution { nuget push $_ . FullName -Source 'https://powershell.myget.org/F/powershell-core/api/v2/package' -ApiKey $ApiKey } > $null
}
}
<#
. SYNOPSIS
The function creates a nuget package for daily feed .
. DESCRIPTION
The nuget package created is a content package and has all the binaries laid out in a flat structure .
This package is used by install-powershell . ps1
#>
function New-NugetContentPackage
2017-08-01 23:35:50 +02:00
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
# Name of the Product
[ ValidateNotNullOrEmpty ( ) ]
2017-08-09 23:36:23 +02:00
[ string ] $PackageName = 'powershell' ,
2017-08-01 23:35:50 +02:00
# Suffix of the Name
[ string ] $PackageNameSuffix ,
# Version of the Product
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageVersion ,
# Runtime of the Product
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageRuntime ,
# Configuration of the Product
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageConfiguration ,
# Source Path to the Product Files - required to package the contents into an Zip
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $PackageSourcePath ,
[ Switch ]
$Force
)
2018-03-08 19:47:20 +01:00
Write-Log " PackageVersion: $PackageVersion "
2017-08-01 23:35:50 +02:00
$nugetSemanticVersion = Get-NugetSemanticVersion -Version $PackageVersion
2018-03-08 19:47:20 +01:00
Write-Log " nugetSemanticVersion: $nugetSemanticVersion "
2017-08-01 23:35:50 +02:00
$nugetFolder = New-SubFolder -Path $PSScriptRoot -ChildPath 'nugetOutput' -Clean
2017-08-09 23:36:23 +02:00
$nuspecPackageName = $PackageName
2018-09-10 21:47:32 +02:00
if ( $PackageNameSuffix )
2017-08-09 23:36:23 +02:00
{
$nuspecPackageName + = '-' + $PackageNameSuffix
}
2017-08-01 23:35:50 +02:00
# Setup staging directory so we don't change the original source directory
$stagingRoot = New-SubFolder -Path $PSScriptRoot -ChildPath 'nugetStaging' -Clean
$contentFolder = Join-Path -path $stagingRoot -ChildPath 'content'
if ( $pscmdlet . ShouldProcess ( " Create staging folder " ) ) {
2017-10-18 02:25:11 +02:00
New-StagingFolder -StagingPath $contentFolder
2017-08-01 23:35:50 +02:00
}
$projectFolder = Join-Path $PSScriptRoot -ChildPath 'project'
$arguments = @ ( 'pack' )
$arguments + = @ ( '--output' , $nugetFolder )
$arguments + = @ ( '--configuration' , $PackageConfiguration )
$arguments + = @ ( '--runtime' , $PackageRuntime )
$arguments + = " /p:StagingPath= $stagingRoot "
$arguments + = " /p:RID= $PackageRuntime "
$arguments + = " /p:SemVer= $nugetSemanticVersion "
2017-08-09 23:36:23 +02:00
$arguments + = " /p:PackageName= $nuspecPackageName "
2017-08-01 23:35:50 +02:00
$arguments + = $projectFolder
2018-03-08 19:47:20 +01:00
Write-Log " Running dotnet $arguments "
Write-Log " Use -verbose to see output... "
2017-08-01 23:35:50 +02:00
Start-NativeExecution -sb { dotnet $arguments } | Foreach-Object { Write-Verbose $_ }
2017-09-11 21:36:24 +02:00
$nupkgFile = " ${nugetFolder} \ ${nuspecPackageName} - ${packageRuntime} . ${nugetSemanticVersion} .nupkg "
if ( Test-Path $nupkgFile )
{
Get-ChildItem $nugetFolder \ * | Select-Object -ExpandProperty FullName
}
else
{
throw " Failed to create $nupkgFile "
}
2017-08-01 23:35:50 +02:00
}
function New-SubFolder
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ string ]
$Path ,
[ String ]
$ChildPath ,
[ switch ]
$Clean
)
$subFolderPath = Join-Path -Path $Path -ChildPath $ChildPath
2018-09-10 21:47:32 +02:00
if ( $Clean . IsPresent -and ( Test-Path $subFolderPath ) )
2017-08-01 23:35:50 +02:00
{
Remove-Item -Path $subFolderPath -Recurse -Force -ErrorAction SilentlyContinue
}
2018-09-10 21:47:32 +02:00
if ( ! ( Test-Path $subFolderPath ) )
2017-08-01 23:35:50 +02:00
{
$null = New-Item -Path $subFolderPath -ItemType Directory
}
return $subFolderPath
}
# Builds coming out of this project can have version number as 'a.b.c-stringf.d-e-f' OR 'a.b.c.d-e-f'
# This function converts the above version into semantic version major.minor[.build-quality[.revision]] format
function Get-PackageSemanticVersion
{
[ CmdletBinding ( ) ]
param (
# Version of the Package
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $Version ,
[ switch ] $NuGet
)
Write-Verbose " Extract the semantic version in the form of major.minor[.build-quality[.revision]] for $Version "
$packageVersionTokens = $Version . Split ( '.' )
2017-11-16 19:17:31 +01:00
if ( $packageVersionTokens . Count -eq 3 ) {
# In case the input is of the form a.b.c, we use the same form
$packageSemanticVersion = $Version
} elseif ( $packageVersionTokens . Count -eq 4 ) {
2017-08-01 23:35:50 +02:00
# We have all the four fields
$packageRevisionTokens = ( $packageVersionTokens [ 3 ] . Split ( '-' ) ) [ 0 ]
2018-09-10 21:47:32 +02:00
if ( $NuGet . IsPresent )
2017-08-01 23:35:50 +02:00
{
$packageRevisionTokens = $packageRevisionTokens . Replace ( '.' , '-' )
}
$packageSemanticVersion = $packageVersionTokens [ 0 ] , $packageVersionTokens [ 1 ] , $packageVersionTokens [ 2 ] , $packageRevisionTokens -join '.'
} else {
throw " Cannot create Semantic Version from the string $Version containing 4 or more tokens "
}
$packageSemanticVersion
}
2018-03-07 20:45:21 +01:00
# Builds coming out of this project can have version number as 'M.m.p-previewName[Number]' OR 'M.m.p'
# This function converts the above version into semantic version major.minor.patch[~previewName[Number]] format
function Get-LinuxPackageSemanticVersion
{
[ CmdletBinding ( ) ]
param (
# Version of the Package
[ Parameter ( Mandatory = $true ) ]
[ ValidatePattern ( " ^\d+\.\d+\.\d+(-\w+(\.\d+)?)? $ " ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $Version
)
Write-Verbose " Extract the semantic version in the form of major.minor[.build-quality[.revision]] for $Version "
$packageVersionTokens = $Version . Split ( '-' )
if ( $packageVersionTokens . Count -eq 1 ) {
# In case the input is of the form a.b.c, we use the same form
$packageSemanticVersion = $Version
} elseif ( $packageVersionTokens . Count -ge 2 ) {
$packageRevisionTokens = ( $packageVersionTokens [ 1 . . ( $packageVersionTokens . Count - 1 ) ] -join '-' )
$packageSemanticVersion = ( '{0}~{1}' -f $packageVersionTokens [ 0 ] , $packageRevisionTokens )
}
$packageSemanticVersion
}
2017-08-01 23:35:50 +02:00
# Builds coming out of this project can have version number as 'a.b.c-stringf.d-e-f' OR 'a.b.c.d-e-f'
# This function converts the above version into semantic version major.minor[.build-quality[-revision]] format needed for nuget
function Get-NugetSemanticVersion
{
[ CmdletBinding ( ) ]
param (
# Version of the Package
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $Version
)
$packageVersionTokens = $Version . Split ( '.' )
Write-Verbose " Extract the semantic version in the form of major.minor[.build-quality[-revision]] for $Version "
$versionPartTokens = @ ( )
$identifierPortionTokens = @ ( )
$inIdentifier = $false
foreach ( $token in $packageVersionTokens ) {
$tokenParts = $null
2018-09-10 21:47:32 +02:00
if ( $token -match '-' ) {
2017-08-01 23:35:50 +02:00
$tokenParts = $token . Split ( '-' )
}
2018-09-10 21:47:32 +02:00
elseif ( $inIdentifier ) {
2017-08-01 23:35:50 +02:00
$tokenParts = @ ( $token )
}
# If we don't have token parts, then it's a versionPart
2018-09-10 21:47:32 +02:00
if ( ! $tokenParts ) {
2017-08-01 23:35:50 +02:00
$versionPartTokens + = $token
}
else {
foreach ( $idToken in $tokenParts ) {
# The first token after we detect the id Part is still
# a version part
2018-09-10 21:47:32 +02:00
if ( ! $inIdentifier ) {
2017-08-01 23:35:50 +02:00
$versionPartTokens + = $idToken
$inIdentifier = $true
}
else {
$identifierPortionTokens + = $idToken
}
}
}
}
2018-09-10 21:47:32 +02:00
if ( $versionPartTokens . Count -gt 3 ) {
2017-08-01 23:35:50 +02:00
throw " Cannot create Semantic Version from the string $Version containing 4 or more version tokens "
}
$packageSemanticVersion = ( $versionPartTokens -join '.' )
2018-09-10 21:47:32 +02:00
if ( $identifierPortionTokens . Count -gt 0 ) {
2017-08-01 23:35:50 +02:00
$packageSemanticVersion + = '-' + ( $identifierPortionTokens -join '-' )
}
$packageSemanticVersion
}
2018-02-22 22:31:00 +01:00
2018-03-26 23:39:48 +02:00
# Get the paths to various WiX tools
function Get-WixPath
{
## AppVeyor base image might update the version for Wix. Hence, we should
## not hard code version numbers.
$wixToolsetBinPath = " $ {env:ProgramFiles(x86)}\WiX Toolset *\bin "
Write-Verbose " Ensure Wix Toolset is present on the machine @ $wixToolsetBinPath "
if ( -not ( Test-Path $wixToolsetBinPath ) )
{
throw " The latest version of Wix Toolset 3.11 is required to create MSI package. Please install it from https://github.com/wixtoolset/wix3/releases "
}
## Get the latest if multiple versions exist.
$wixToolsetBinPath = ( Get-ChildItem $wixToolsetBinPath ) . FullName | Sort-Object -Descending | Select-Object -First 1
Write-Verbose " Initialize Wix executables... "
$wixHeatExePath = Join-Path $wixToolsetBinPath " heat.exe "
$wixMeltExePath = Join-Path $wixToolsetBinPath " melt.exe "
$wixTorchExePath = Join-Path $wixToolsetBinPath " torch.exe "
$wixPyroExePath = Join-Path $wixToolsetBinPath " pyro.exe "
$wixCandleExePath = Join-Path $wixToolsetBinPath " Candle.exe "
$wixLightExePath = Join-Path $wixToolsetBinPath " Light.exe "
return [ PSCustomObject ] @ {
WixHeatExePath = $wixHeatExePath
WixMeltExePath = $wixMeltExePath
WixTorchExePath = $wixTorchExePath
WixPyroExePath = $wixPyroExePath
WixCandleExePath = $wixCandleExePath
WixLightExePath = $wixLightExePath
}
}
<#
. Synopsis
Creates a Windows installer MSP package from two MSIs and WIXPDB files
This only works on a Windows machine due to the usage of WiX .
. EXAMPLE
# This example shows how to produce a x64 patch from 6.0.2 to a theoretical 6.0.3
cd $RootPathOfPowerShellRepo
Import-Module . \ build . psm1 ; Import-Module . \ tools \ packaging \ packaging . psm1
New-MSIPatch -NewVersion 6.0 . 1 -BaselineMsiPath . \ PowerShell - 6.0 . 2 -win -x64 . msi -BaselineWixPdbPath . \ PowerShell - 6.0 . 2 -win -x64 . wixpdb -PatchMsiPath . \ PowerShell - 6.0 . 3 -win -x64 . msi -PatchWixPdbPath . \ PowerShell - 6.0 . 3 -win -x64 . wixpdb
#>
function New-MSIPatch
{
param (
[ Parameter ( Mandatory , HelpMessage = 'The version of the fixed or patch MSI.' ) ]
[ ValidatePattern ( " ^\d+\.\d+\.\d+ $ " ) ]
[ string ] $NewVersion ,
[ Parameter ( Mandatory , HelpMessage = 'The path to the original or baseline MSI.' ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { ( Test-Path $_ ) -and $_ -like '*.msi' } ) ]
[ string ] $BaselineMsiPath ,
[ Parameter ( Mandatory , HelpMessage = 'The path to the WIXPDB for the original or baseline MSI.' ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { ( Test-Path $_ ) -and $_ -like '*.wixpdb' } ) ]
[ string ] $BaselineWixPdbPath ,
[ Parameter ( Mandatory , HelpMessage = 'The path to the fixed or patch MSI.' ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { ( Test-Path $_ ) -and $_ -like '*.msi' } ) ]
[ string ] $PatchMsiPath ,
[ Parameter ( Mandatory , HelpMessage = 'The path to the WIXPDB for the fixed or patch MSI.' ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { ( Test-Path $_ ) -and $_ -like '*.wixpdb' } ) ]
[ string ] $PatchWixPdbPath ,
[ Parameter ( HelpMessage = 'Path to the patch template WXS. Usually you do not need to specify this' ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $PatchWxsPath = " $RepoRoot \assets\patch-template.wxs " ,
2018-03-26 23:39:48 +02:00
[ Parameter ( HelpMessage = 'Produce a delta patch instead of a full patch. Usually not worth it.' ) ]
[ switch ] $Delta
)
$mspName = ( Split-Path -Path $PatchMsiPath -Leaf ) . Replace ( '.msi' , '.fullpath.msp' )
$mspDeltaName = ( Split-Path -Path $PatchMsiPath -Leaf ) . Replace ( '.msi' , '.deltapatch.msp' )
$wixPatchXmlPath = Join-Path $env:Temp " patch.wxs "
$wixBaselineOriginalPdbPath = Join-Path $env:Temp " baseline.original.wixpdb "
$wixBaselinePdbPath = Join-Path $env:Temp " baseline.wixpdb "
$wixBaselineBinariesPath = Join-Path $env:Temp " baseline.binaries "
$wixPatchOriginalPdbPath = Join-Path $env:Temp " patch.original.wixpdb "
$wixPatchPdbPath = Join-Path $env:Temp " patch.wixpdb "
$wixPatchBinariesPath = Join-Path $env:Temp " patch.binaries "
$wixPatchMstPath = Join-Path $env:Temp " patch.wixmst "
$wixPatchObjPath = Join-Path $env:Temp " patch.wixobj "
$wixPatchWixMspPath = Join-Path $env:Temp " patch.wixmsp "
$filesToCleanup = @ (
$wixPatchXmlPath
$wixBaselinePdbPath
$wixBaselineBinariesPath
$wixPatchPdbPath
$wixPatchBinariesPath
$wixPatchMstPath
$wixPatchObjPath
$wixPatchWixMspPath
$wixPatchOriginalPdbPath
$wixBaselineOriginalPdbPath
)
# cleanup from previous builds
Remove-Item -Path $filesToCleanup -Force -Recurse -ErrorAction SilentlyContinue
# Melt changes the original, so copy before running melt
Copy-Item -Path $BaselineWixPdbPath -Destination $wixBaselineOriginalPdbPath -Force
Copy-Item -Path $PatchWixPdbPath -Destination $wixPatchOriginalPdbPath -Force
2018-09-25 18:53:42 +02:00
[ xml ] $filesAssetXml = Get-Content -Raw -Path " $RepoRoot \assets\files.wxs "
2018-03-26 23:39:48 +02:00
[ xml ] $patchTemplateXml = Get-Content -Raw -Path $PatchWxsPath
# Update the patch version
$patchFamilyNode = $patchTemplateXml . Wix . Fragment . PatchFamily
$patchFamilyNode . SetAttribute ( 'Version' , $NewVersion )
# get all the file components from the files.wxs
$components = $filesAssetXml . GetElementsByTagName ( 'Component' )
# add all the file components to the patch
foreach ( $component in $components )
{
$id = $component . Id
$componentRef = $patchTemplateXml . CreateElement ( 'ComponentRef' , 'http://schemas.microsoft.com/wix/2006/wi' )
$idAttribute = $patchTemplateXml . CreateAttribute ( 'Id' )
$idAttribute . Value = $id
$null = $componentRef . Attributes . Append ( $idAttribute )
$null = $patchFamilyNode . AppendChild ( $componentRef )
}
# save the updated patch xml
$patchTemplateXml . Save ( $wixPatchXmlPath )
$wixPaths = Get-WixPath
Write-Log " Processing baseline msi... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixMeltExePath -nologo $BaselineMsiPath $wixBaselinePdbPath -pdb $wixBaselineOriginalPdbPath -x $wixBaselineBinariesPath }
Write-Log " Processing patch msi... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixMeltExePath -nologo $PatchMsiPath $wixPatchPdbPath -pdb $wixPatchOriginalPdbPath -x $wixPatchBinariesPath }
Write-Log " generate diff... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixTorchExePath -nologo -p -xi $wixBaselinePdbPath $wixPatchPdbPath -out $wixPatchMstPath }
Write-Log " Compiling patch... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixCandleExePath -nologo $wixPatchXmlPath -out $wixPatchObjPath }
Write-Log " Linking patch... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixLightExePath -nologo $wixPatchObjPath -out $wixPatchWixMspPath }
2018-09-10 21:47:32 +02:00
if ( $Delta . IsPresent )
2018-03-26 23:39:48 +02:00
{
Write-Log " Generating delta msp... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixPyroExePath -nologo $wixPatchWixMspPath -out $mspDeltaName -t RTM $wixPatchMstPath }
}
else
{
Write-Log " Generating full msp... "
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixPyroExePath -nologo $wixPatchWixMspPath -out $mspName -t RTM $wixPatchMstPath }
}
# cleanup temporary files
Remove-Item -Path $filesToCleanup -Force -Recurse -ErrorAction SilentlyContinue
}
2018-02-22 22:31:00 +01:00
<#
. Synopsis
Creates a Windows installer MSI package and assumes that the binaries are already built using 'Start-PSBuild' .
This only works on a Windows machine due to the usage of WiX .
. EXAMPLE
# This example shows how to produce a Debug-x64 installer for development purposes.
cd $RootPathOfPowerShellRepo
Import-Module . \ build . psm1 ; Import-Module . \ tools \ packaging \ packaging . psm1
2018-05-03 01:58:39 +02:00
New-MSIPackage -Verbose -ProductCode ( New-Guid ) -ProductSourcePath '.\src\powershell-win-core\bin\Debug\netcoreapp2.1\win7-x64\publish' -ProductTargetArchitecture x64 -ProductVersion '1.2.3'
2018-02-22 22:31:00 +01:00
#>
function New-MSIPackage
{
[ CmdletBinding ( ) ]
param (
# Name of the Product
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductName = 'PowerShell' ,
# Suffix of the Name
[ string ] $ProductNameSuffix ,
# Version of the Product
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductVersion ,
# The ProductCode property is a unique identifier for the particular product release
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductCode ,
# Source Path to the Product Files - required to package the contents into an MSI
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductSourcePath ,
# File describing the MSI Package creation semantics
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $ProductWxsPath = " $RepoRoot \assets\Product.wxs " ,
2018-02-22 22:31:00 +01:00
2018-03-06 19:13:26 +01:00
# File describing the MSI file components
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $FilesWxsPath = " $RepoRoot \assets\Files.wxs " ,
2018-03-06 19:13:26 +01:00
2018-02-22 22:31:00 +01:00
# Path to Assets folder containing artifacts such as icons, images
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $AssetsPath = " $RepoRoot \assets " ,
2018-02-22 22:31:00 +01:00
# Path to license.rtf file - for the EULA
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $LicenseFilePath = " $RepoRoot \assets\license.rtf " ,
2018-02-22 22:31:00 +01:00
# Architecture to use when creating the MSI
[ Parameter ( Mandatory = $true ) ]
[ ValidateSet ( " x86 " , " x64 " ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductTargetArchitecture ,
# Force overwrite of package
[ Switch ] $Force
)
2018-03-26 23:39:48 +02:00
$wixPaths = Get-WixPath
2018-02-22 22:31:00 +01:00
$ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion
2018-04-02 19:47:29 +02:00
$simpleProductVersion = '6'
2018-06-06 19:28:22 +02:00
$isPreview = Test-IsPreview -Version $ProductSemanticVersion
2018-09-10 21:47:32 +02:00
if ( $isPreview )
2018-04-02 19:47:29 +02:00
{
$simpleProductVersion + = '-preview'
}
2018-02-22 22:31:00 +01:00
$ProductVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $ProductVersion
$assetsInSourcePath = Join-Path $ProductSourcePath 'assets'
New-Item $assetsInSourcePath -type directory -Force | Write-Verbose
Write-Verbose " Place dependencies such as icons to $assetsInSourcePath "
Copy-Item " $AssetsPath \*.ico " $assetsInSourcePath -Force
$productVersionWithName = $ProductName + '_' + $ProductVersion
$productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion
2018-03-06 19:13:26 +01:00
$productDirectoryName = 'PowerShell_6'
2018-02-22 22:31:00 +01:00
Write-Verbose " Create MSI for Product $productSemanticVersionWithName "
[ Environment ] :: SetEnvironmentVariable ( " ProductSourcePath " , $ProductSourcePath , " Process " )
# These variables are used by Product.wxs in assets directory
2018-03-06 19:13:26 +01:00
[ Environment ] :: SetEnvironmentVariable ( " ProductDirectoryName " , $productDirectoryName , " Process " )
2018-02-22 22:31:00 +01:00
[ Environment ] :: SetEnvironmentVariable ( " ProductName " , $ProductName , " Process " )
[ Environment ] :: SetEnvironmentVariable ( " ProductCode " , $ProductCode , " Process " )
[ Environment ] :: SetEnvironmentVariable ( " ProductVersion " , $ProductVersion , " Process " )
2018-04-02 19:47:29 +02:00
[ Environment ] :: SetEnvironmentVariable ( " SimpleProductVersion " , $simpleProductVersion , " Process " )
2018-02-22 22:31:00 +01:00
[ Environment ] :: SetEnvironmentVariable ( " ProductSemanticVersion " , $ProductSemanticVersion , " Process " )
[ Environment ] :: SetEnvironmentVariable ( " ProductVersionWithName " , $productVersionWithName , " Process " )
2018-09-10 21:47:32 +02:00
if ( ! $isPreview )
2018-03-05 19:27:47 +01:00
{
2018-09-10 23:35:02 +02:00
[ Environment ] :: SetEnvironmentVariable ( " PwshPath " , " [ $productDirectoryName ] " , " Process " )
2018-03-05 19:27:47 +01:00
[ Environment ] :: SetEnvironmentVariable ( " UpgradeCodeX64 " , '31ab5147-9a97-4452-8443-d9709f0516e1' , " Process " )
[ Environment ] :: SetEnvironmentVariable ( " UpgradeCodeX86 " , '1d00683b-0f84-4db8-a64f-2f98ad42fe06' , " Process " )
2018-06-19 00:54:11 +02:00
[ Environment ] :: SetEnvironmentVariable ( " IconPath " , 'assets\Powershell_black.ico' , " Process " )
2018-03-05 19:27:47 +01:00
}
else
{
2018-09-10 23:35:02 +02:00
[ Environment ] :: SetEnvironmentVariable ( " PwshPath " , " [ $productDirectoryName ]preview " , " Process " )
2018-03-05 19:27:47 +01:00
[ Environment ] :: SetEnvironmentVariable ( " UpgradeCodeX64 " , '39243d76-adaf-42b1-94fb-16ecf83237c8' , " Process " )
[ Environment ] :: SetEnvironmentVariable ( " UpgradeCodeX86 " , '86abcfbd-1ccc-4a88-b8b2-0facfde29094' , " Process " )
2018-06-19 00:54:11 +02:00
[ Environment ] :: SetEnvironmentVariable ( " IconPath " , 'assets\Powershell_av_colors.ico' , " Process " )
2018-03-05 19:27:47 +01:00
}
2018-03-13 22:02:12 +01:00
$fileArchitecture = 'amd64'
2018-02-22 22:31:00 +01:00
$ProductProgFilesDir = " ProgramFiles64Folder "
if ( $ProductTargetArchitecture -eq " x86 " )
{
2018-03-13 22:02:12 +01:00
$fileArchitecture = 'x86'
2018-02-22 22:31:00 +01:00
$ProductProgFilesDir = " ProgramFilesFolder "
}
[ Environment ] :: SetEnvironmentVariable ( " ProductProgFilesDir " , $ProductProgFilesDir , " Process " )
2018-03-13 22:02:12 +01:00
[ Environment ] :: SetEnvironmentVariable ( " FileArchitecture " , $fileArchitecture , " Process " )
2018-02-22 22:31:00 +01:00
$wixFragmentPath = Join-Path $env:Temp " Fragment.wxs "
$wixObjProductPath = Join-Path $env:Temp " Product.wixobj "
2018-03-06 19:13:26 +01:00
$wixObjFragmentPath = Join-Path $env:Temp " files.wixobj "
2018-02-22 22:31:00 +01:00
2018-02-27 00:45:15 +01:00
# cleanup any garbage on the system
Remove-Item -ErrorAction SilentlyContinue $wixFragmentPath -Force
Remove-Item -ErrorAction SilentlyContinue $wixObjProductPath -Force
Remove-Item -ErrorAction SilentlyContinue $wixObjFragmentPath -Force
2018-02-22 22:31:00 +01:00
$packageName = $productSemanticVersionWithName
if ( $ProductNameSuffix ) {
$packageName + = " - $ProductNameSuffix "
}
$msiLocationPath = Join-Path $pwd " $packageName .msi "
2018-02-27 00:45:15 +01:00
$msiPdbLocationPath = Join-Path $pwd " $packageName .wixpdb "
2018-02-22 22:31:00 +01:00
2018-09-10 21:47:32 +02:00
if ( ! $Force . IsPresent -and ( Test-Path -Path $msiLocationPath ) )
2018-02-22 22:31:00 +01:00
{
Write-Error -Message " Package already exists, use -Force to overwrite, path: $msiLocationPath " -ErrorAction Stop
}
2018-03-08 19:47:20 +01:00
Write-Log " verifying no new files have been added or removed... "
2018-03-26 23:39:48 +02:00
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixHeatExePath dir $ProductSourcePath -dr $productDirectoryName -cg $productDirectoryName -gg -sfrag -srd -scom -sreg -out $wixFragmentPath -var env . ProductSourcePath -v }
2018-03-06 19:13:26 +01:00
Test-FileWxs -FilesWxsPath $FilesWxsPath -HeatFilesWxsPath $wixFragmentPath
2018-02-27 00:45:15 +01:00
2018-03-08 19:47:20 +01:00
Write-Log " running candle... "
2018-03-26 23:39:48 +02:00
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixCandleExePath " $ProductWxsPath " " $FilesWxsPath " -out ( Join-Path " $env:Temp " " \\ " ) -ext WixUIExtension -ext WixUtilExtension -arch $ProductTargetArchitecture -v }
2018-02-27 00:45:15 +01:00
2018-03-08 19:47:20 +01:00
Write-Log " running light... "
2018-02-27 00:45:15 +01:00
# suppress ICE61, because we allow same version upgrades
# suppress ICE57, this suppresses an error caused by our shortcut not being installed per user
2018-03-26 23:39:48 +02:00
Start-NativeExecution -VerboseOutputOnError { & $wixPaths . wixLightExePath -sice: ICE61 -sice: ICE57 -out $msiLocationPath -pdbout $msiPdbLocationPath $wixObjProductPath $wixObjFragmentPath -ext WixUIExtension -ext WixUtilExtension -dWixUILicenseRtf = " $LicenseFilePath " }
2018-02-22 22:31:00 +01:00
Remove-Item -ErrorAction SilentlyContinue $wixFragmentPath -Force
Remove-Item -ErrorAction SilentlyContinue $wixObjProductPath -Force
Remove-Item -ErrorAction SilentlyContinue $wixObjFragmentPath -Force
2018-02-27 00:45:15 +01:00
if ( ( Test-Path $msiLocationPath ) -and ( Test-Path $msiPdbLocationPath ) )
2018-02-22 22:31:00 +01:00
{
2018-02-27 00:45:15 +01:00
Write-Verbose " You can find the WixPdb @ $msiPdbLocationPath " -Verbose
2018-02-22 22:31:00 +01:00
Write-Verbose " You can find the MSI @ $msiLocationPath " -Verbose
2018-02-27 00:45:15 +01:00
[ pscustomobject ] @ {
msi = $msiLocationPath
wixpdb = $msiPdbLocationPath
}
2018-02-22 22:31:00 +01:00
}
else
{
$errorMessage = " Failed to create $msiLocationPath "
if ( $null -ne $env:CI )
{
Add-AppveyorCompilationMessage $errorMessage -Category Error -FileName $MyInvocation . ScriptName -Line $MyInvocation . ScriptLineNumber
}
throw $errorMessage
}
}
2018-03-06 19:13:26 +01:00
# verify no files have been added or removed
# if so, write an error with details
function Test-FileWxs
{
param
(
# File describing the MSI file components from the asset folder
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
2018-09-25 18:53:42 +02:00
[ string ] $FilesWxsPath = " $RepoRoot \assets\Files.wxs " ,
2018-03-06 19:13:26 +01:00
# File describing the MSI file components generated by heat
[ ValidateNotNullOrEmpty ( ) ]
[ ValidateScript ( { Test-Path $_ } ) ]
[ string ] $HeatFilesWxsPath
)
2018-03-13 22:02:12 +01:00
# Update the fileArchitecture in our file to the actual value. Since, the heat file will have the actual value.
# Wix will update this automaticaly, but the output is not the same xml
$filesAssetString = ( Get-Content -Raw -Path $FilesWxsPath ) . Replace ( '$(var.FileArchitecture)' , $env:FileArchitecture )
[ xml ] $filesAssetXml = $filesAssetString
2018-08-31 21:50:51 +02:00
[ xml ] $newFilesAssetXml = $filesAssetString
$xmlns = [ System.Xml.XmlNamespaceManager ] :: new ( $newFilesAssetXml . NameTable )
$xmlns . AddNamespace ( 'Wix' , 'http://schemas.microsoft.com/wix/2006/wi' )
2018-03-06 19:13:26 +01:00
[ xml ] $heatFilesXml = Get-Content -Raw -Path $HeatFilesWxsPath
$assetFiles = $filesAssetXml . GetElementsByTagName ( 'File' )
$heatFiles = $heatFilesXml . GetElementsByTagName ( 'File' )
2018-08-31 21:50:51 +02:00
$heatNodesByFile = @ { }
2018-03-06 19:13:26 +01:00
# Index the list of files generated by heat
foreach ( $file in $heatFiles )
{
2018-08-31 21:50:51 +02:00
$heatNodesByFile . Add ( $file . Source , $file )
2018-03-06 19:13:26 +01:00
}
# Index the files from the asset wxs
# and verify that no files have been removed.
$passed = $true
$indexedAssetFiles = @ ( )
foreach ( $file in $assetFiles )
{
$name = $file . Source
2018-09-10 21:47:32 +02:00
if ( $heatNodesByFile . Keys -inotcontains $name )
2018-03-06 19:13:26 +01:00
{
$passed = $false
Write-Warning " { $name } is no longer in product and should be removed from { $FilesWxsPath } "
2018-08-31 21:50:51 +02:00
$componentId = $file . ParentNode . Id
$componentXPath = '//Wix:Component[@Id="{0}"]' -f $componentId
$componentNode = Get-XmlNodeByXPath -XmlDoc $newFilesAssetXml -XmlNsManager $xmlns -XPath $componentXPath
2018-09-10 21:47:32 +02:00
if ( $componentNode )
2018-08-31 21:50:51 +02:00
{
# Remove the Component
Remove-XmlElement -Element $componentNode -RemoveEmptyParents
# Remove teh ComponentRef
Remove-ComponentRefNode -Id $componentId -XmlDoc $newFilesAssetXml -XmlNsManager $xmlns
}
else
{
Write-Warning " Could not remove this node! "
}
2018-03-06 19:13:26 +01:00
}
$indexedAssetFiles + = $name
}
# verify that no files have been added.
2018-08-31 21:50:51 +02:00
foreach ( $file in $heatNodesByFile . Keys )
2018-03-06 19:13:26 +01:00
{
2018-09-10 21:47:32 +02:00
if ( $indexedAssetFiles -inotcontains $file )
2018-03-06 19:13:26 +01:00
{
$passed = $false
2018-08-31 21:50:51 +02:00
$folder = Split-Path -Path $file
$name = Split-Path -Path $file -Leaf
$heatNode = $heatNodesByFile [ $file ]
$compGroupNode = Get-ComponentGroupNode -XmlDoc $newFilesAssetXml -XmlNsManager $xmlns
$filesNode = Get-DirectoryNode -Node $heatNode -XmlDoc $newFilesAssetXml -XmlNsManager $xmlns
# Create new Component
$newComponent = New-XmlElement -XmlDoc $newFilesAssetXml -LocalName 'Component' -Node $filesNode -PassThru -NamespaceUri 'http://schemas.microsoft.com/wix/2006/wi'
$componentId = New-WixId -Prefix 'cmp'
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newComponent -Name 'Id' -Value $componentId
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newComponent -Name 'Guid' -Value " { $( New-Guid ) } "
# Crete new File in Component
$newFile = New-XmlElement -XmlDoc $newFilesAssetXml -LocalName 'File' -Node $newComponent -PassThru -NamespaceUri 'http://schemas.microsoft.com/wix/2006/wi'
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newFile -Name 'Id' -Value ( New-WixId -Prefix 'fil' )
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newFile -Name 'KeyPath' -Value " yes "
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newFile -Name 'Source' -Value $file
# Create new ComponentRef
$newComponentRef = New-XmlElement -XmlDoc $newFilesAssetXml -LocalName 'ComponentRef' -Node $compGroupNode -PassThru -NamespaceUri 'http://schemas.microsoft.com/wix/2006/wi'
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newComponentRef -Name 'Id' -Value $componentId
Write-Warning " new file in { $folder } with name { $name } in a { $( $filesNode . LocalName ) } need to be added to { $FilesWxsPath } "
2018-03-06 19:13:26 +01:00
}
}
2018-09-10 21:47:32 +02:00
if ( ! $passed )
2018-03-06 19:13:26 +01:00
{
2018-09-25 18:53:42 +02:00
$newXmlFileName = Join-Path -Path $env:TEMP -ChildPath ( [ System.io.path ] :: GetRandomFileName ( ) + '.wxs' )
2018-08-31 21:50:51 +02:00
$newFilesAssetXml . Save ( $newXmlFileName )
$newXml = Get-Content -raw $newXmlFileName
$newXml = $newXml -replace 'amd64' , '$(var.FileArchitecture)'
$newXml = $newXml -replace 'x86' , '$(var.FileArchitecture)'
$newXml | Out-File -FilePath $newXmlFileName -Encoding ascii
2018-09-25 18:53:42 +02:00
Write-Log -message " Updated xml saved to $newXmlFileName . "
Write-Log -message " If component files were intentionally changed, such as due to moving to a newer .NET Core runtime, update ' $FilesWxsPath ' with the content from ' $newXmlFileName '. "
2018-09-10 21:47:32 +02:00
if ( $env:appveyor )
2018-03-08 04:47:21 +01:00
{
try
{
2018-08-31 21:50:51 +02:00
Push-AppveyorArtifact $newXmlFileName
2018-03-08 04:47:21 +01:00
}
catch
{
2018-03-09 00:58:59 +01:00
Write-Warning -Message " Pushing MSI File fragment failed. "
2018-03-08 04:47:21 +01:00
}
}
2018-09-10 21:47:32 +02:00
elseif ( $env:TF_BUILD -and $env:BUILD_REASON -ne 'PullRequest' )
2018-08-31 21:50:51 +02:00
{
Write-Host " ##vso[artifact.upload containerfolder=wix;artifactname=wix] $newXmlFileName "
}
2018-03-08 04:47:21 +01:00
2018-03-06 19:13:26 +01:00
throw " Current files to not match { $FilesWxsPath } "
}
}
2018-08-31 21:50:51 +02:00
# Removes a ComponentRef node in the files.wxs Xml Doc
function Remove-ComponentRefNode
{
param (
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlDocument ]
$XmlDoc ,
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlNamespaceManager ]
$XmlNsManager ,
[ Parameter ( Mandatory ) ]
[ string ]
$Id
)
$compRefXPath = '//Wix:ComponentRef[@Id="{0}"]' -f $Id
$node = Get-XmlNodeByXPath -XmlDoc $XmlDoc -XmlNsManager $XmlNsManager -XPath $compRefXPath
2018-09-10 21:47:32 +02:00
if ( $node )
2018-08-31 21:50:51 +02:00
{
Remove-XmlElement -element $node
}
else
{
Write-Warning " could not remove node "
}
}
# Get the ComponentGroup node in the files.wxs Xml Doc
function Get-ComponentGroupNode
{
param (
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlDocument ]
$XmlDoc ,
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlNamespaceManager ]
$XmlNsManager
)
2018-09-10 21:47:32 +02:00
if ( ! $XmlNsManager . HasNamespace ( 'Wix' ) )
2018-08-31 21:50:51 +02:00
{
throw 'Namespace manager must have "wix" defined.'
}
$compGroupXPath = '//Wix:ComponentGroup'
$node = Get-XmlNodeByXPath -XmlDoc $XmlDoc -XmlNsManager $XmlNsManager -XPath $compGroupXPath
return $node
}
# Gets the Directory Node the files.wxs Xml Doc
# Creates it if it does not exist
function Get-DirectoryNode
{
param (
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlElement ]
$Node ,
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlDocument ]
$XmlDoc ,
[ Parameter ( Mandatory ) ]
[ System.Xml.XmlNamespaceManager ]
$XmlNsManager
)
2018-09-10 21:47:32 +02:00
if ( ! $XmlNsManager . HasNamespace ( 'Wix' ) )
2018-08-31 21:50:51 +02:00
{
throw 'Namespace manager must have "wix" defined.'
}
$pathStack = [ System.Collections.Stack ] :: new ( )
[ System.Xml.XmlElement ] $dirNode = $Node . ParentNode . ParentNode
$dirNodeType = $dirNode . LocalName
2018-09-10 21:47:32 +02:00
if ( $dirNodeType -eq 'DirectoryRef' )
2018-08-31 21:50:51 +02:00
{
return Get-XmlNodeByXPath -XmlDoc $XmlDoc -XmlNsManager $XmlNsManager -XPath " //Wix:DirectoryRef "
}
2018-09-10 21:47:32 +02:00
if ( $dirNodeType -eq 'Directory' )
2018-08-31 21:50:51 +02:00
{
while ( $dirNode . LocalName -eq 'Directory' ) {
$pathStack . Push ( $dirNode . Name )
$dirNode = $dirNode . ParentNode
}
$path = " // "
[ System.Xml.XmlElement ] $lastNode = $null
while ( $pathStack . Count -gt 0 ) {
$dirName = $pathStack . Pop ( )
$path + = 'Wix:Directory[@Name="{0}"]' -f $dirName
$node = Get-XmlNodeByXPath -XmlDoc $XmlDoc -XmlNsManager $XmlNsManager -XPath $path
2018-09-10 21:47:32 +02:00
if ( ! $node )
2018-08-31 21:50:51 +02:00
{
2018-09-10 21:47:32 +02:00
if ( ! $lastNode )
2018-08-31 21:50:51 +02:00
{
# Inserting at the root
$lastNode = Get-XmlNodeByXPath -XmlDoc $XmlDoc -XmlNsManager $XmlNsManager -XPath " //Wix:DirectoryRef "
}
$newDirectory = New-XmlElement -XmlDoc $XmlDoc -LocalName 'Directory' -Node $lastNode -PassThru -NamespaceUri 'http://schemas.microsoft.com/wix/2006/wi'
New-XmlAttribute -XmlDoc $XmlDoc -Element $newDirectory -Name 'Name' -Value $dirName
New-XmlAttribute -XmlDoc $XmlDoc -Element $newDirectory -Name 'Id' -Value ( New-WixId -Prefix 'dir' )
$lastNode = $newDirectory
}
else
{
$lastNode = $node
}
if ( $pathStack . Count -gt 0 )
{
$path + = '/'
}
}
return $lastNode
}
throw " unknown element type: $dirNodeType "
}
# Creates a new Wix Id in the proper format
function New-WixId
{
param (
[ Parameter ( Mandatory ) ]
[ string ]
$Prefix
)
$guidPortion = ( New-Guid ) . Guid . ToUpperInvariant ( ) -replace '\-' , ''
" $Prefix $guidPortion "
}
2018-02-22 22:31:00 +01:00
# Builds coming out of this project can have version number as 'a.b.c' OR 'a.b.c-d-f'
# This function converts the above version into major.minor[.build[.revision]] format
function Get-PackageVersionAsMajorMinorBuildRevision
{
[ CmdletBinding ( ) ]
param (
# Version of the Package
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $Version
)
Write-Verbose " Extract the version in the form of major.minor[.build[.revision]] for $Version "
$packageVersionTokens = $Version . Split ( '-' )
$packageVersion = ( [ regex ] :: matches ( $Version , " \d+(\.\d+)+ " ) ) [ 0 ] . value
if ( 1 -eq $packageVersionTokens . Count ) {
# In case the input is of the form a.b.c, add a '0' at the end for revision field
$packageVersion = $packageVersion + '.0'
} elseif ( 1 -lt $packageVersionTokens . Count ) {
# We have all the four fields
$packageBuildTokens = ( [ regex ] :: Matches ( $packageVersionTokens [ 1 ] , " \d+ " ) ) [ 0 ] . value
if ( $packageBuildTokens )
{
$packageVersion = $packageVersion + '.' + $packageBuildTokens
}
else
{
$packageVersion = $packageVersion
}
}
$packageVersion
}