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
2019-11-11 21:29:24 +01:00
$DebianDistributions = @ ( " ubuntu.16.04 " , " ubuntu.18.04 " , " debian.9 " , " debian.10 " , " debian.11 " )
$RedhatDistributions = @ ( " rhel.7 " , " centos.8 " )
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 (
2019-01-24 21:50:11 +01:00
# PowerShell packages use Semantic Versioning https://semver.org/
2017-07-23 21:29:33 +02:00
[ 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
2019-07-13 02:18:11 +02:00
[ ValidateSet ( " msix " , " deb " , " osxpkg " , " rpm " , " msi " , " zip " , " nupkg " , " tar " , " tar-arm " , " tar-arm64 " , " tar-alpine " , " fxdependent " , " fxdependent-win-desktop " ) ]
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 ,
2020-02-05 01:21:59 +01:00
[ switch ] $NoSudo ,
[ switch ] $LTS
2017-07-23 21:29:33 +02:00
)
2017-10-23 21:30:25 +02:00
DynamicParam {
2019-07-13 02:18:11 +02:00
if ( " zip " -eq $Type -or " fxdependent " -eq $Type -or " fxdependent-win-desktop " -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 "
2018-11-27 19:45:49 +01:00
} elseif ( $Type -eq " tar-alpine " ) {
New-PSOptions -Configuration " Release " -Runtime " alpine-x64 " -WarningAction SilentlyContinue | ForEach-Object { $_ . Runtime , $_ . Configuration }
2018-12-05 19:55:09 +01:00
} elseif ( $Type -eq " tar-arm " ) {
New-PSOptions -Configuration " Release " -Runtime " Linux-ARM " -WarningAction SilentlyContinue | ForEach-Object { $_ . Runtime , $_ . Configuration }
} elseif ( $Type -eq " tar-arm64 " ) {
New-PSOptions -Configuration " Release " -Runtime " Linux-ARM64 " -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 ' "
2019-07-13 02:18:11 +02:00
} elseif ( $Type -eq 'fxdependent-win-desktop' ) {
$NameSuffix = " win-fxdependentWinDesktop "
Write-Log " Packaging : ' $Type '; Packaging Configuration: ' $Configuration ' "
2018-09-10 21:47:32 +02:00
} 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
2019-02-04 20:48:48 +01:00
$actualParams = @ ( )
2017-10-23 21:30:25 +02:00
$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 ) {
2019-02-04 20:48:48 +01:00
$actualParams + = '-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 ) {
2019-02-04 20:48:48 +01:00
$actualParams + = '-PSModuleRestore'
2017-11-02 21:52:17 +01:00
$PSModuleRestoreCorrect = $true
}
elseif ( $IncludeSymbols . IsPresent -and ! $Script:Options . PSModuleRestore ) {
$PSModuleRestoreCorrect = $true
2017-10-23 21:30:25 +02:00
}
2019-02-04 20:48:48 +01:00
else {
$actualParams + = '-PSModuleRestore'
}
2017-10-23 21:30:25 +02:00
2019-07-13 02:18:11 +02:00
$precheckFailed = if ( $Type -like 'fxdependent*' -or $Type -eq 'tar-alpine' ) {
2018-09-10 21:47:32 +02:00
## 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'
2019-10-19 01:49:25 +02:00
$Script:Options . Framework -ne " netcoreapp3.1 " ## Last build wasn't for CoreCLR
2018-09-10 21:47:32 +02:00
} 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'
2019-10-19 01:49:25 +02:00
$Script:Options . Framework -ne " netcoreapp3.1 " ## Last build wasn't for CoreCLR
2018-09-10 21:47:32 +02:00
}
# 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.
2019-02-04 20:48:48 +01:00
2017-10-23 21:30:25 +02:00
$params = @ ( '-Clean' )
2018-09-10 21:47:32 +02:00
# CrossGen cannot be done for framework dependent package as it is runtime agnostic.
2019-07-13 02:18:11 +02:00
if ( $Type -notlike 'fxdependent*' ) {
2018-09-10 21:47:32 +02:00
$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
2019-02-04 20:48:48 +01:00
$actualParams + = '-Runtime ' + $Script:Options . Runtime
2018-09-10 21:47:32 +02:00
if ( $Type -eq 'fxdependent' ) {
$params + = '-Runtime' , 'fxdependent'
2019-07-13 02:18:11 +02:00
} elseif ( $Type -eq 'fxdependent-win-desktop' ) {
$params + = '-Runtime' , 'fxdependent-win-desktop'
2018-09-10 21:47:32 +02:00
} else {
$params + = '-Runtime' , $Runtime
}
2017-10-23 21:30:25 +02:00
$params + = '-Configuration' , $Configuration
2019-02-04 20:48:48 +01:00
$actualParams + = '-Configuration ' + $Script:Options . Configuration
2017-10-23 21:30:25 +02:00
2019-02-04 20:48:48 +01:00
Write-Warning " Build started with unexpected parameters 'Start-PSBuild $actualParams "
2017-10-23 21:30:25 +02:00
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
2019-10-19 19:32:34 +02:00
$signingXml = [ xml ] ( Get-Content ( Join-Path $PSScriptRoot " ..\releaseBuild\signing.xml " -Resolve ) )
# Only include the files we sign for compliance scanning, those are the files we build.
$filesToInclude = $signingXml . SignConfigXML . job . file . src | Where-Object { -not $_ . endswith ( 'pwsh.exe' ) -and ( $_ . endswith ( " .dll " ) -or $_ . endswith ( " .exe " ) ) } | ForEach-Object { ( $_ -split '\\' ) [ -1 ] }
$filesToInclude + = $filesToInclude | ForEach-Object { $_ -replace '.dll' , '.pdb' }
Get-ChildItem -Path $buildSource | Where-Object { $_ . Name -in $filesToInclude } | Copy-Item -Destination $symbolsSource -Recurse
2017-11-03 22:49:15 +01:00
# 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 " ) {
2019-02-04 23:53:25 +01:00
" deb " , " nupkg " , " tar "
2017-10-23 21:30:25 +02:00
} elseif ( $Environment . IsRedHatFamily ) {
2020-02-04 20:21:08 +01:00
" rpm " , " nupkg "
2018-01-22 23:58:17 +01:00
} elseif ( $Environment . IsSUSEFamily ) {
2020-02-04 20:21:08 +01:00
" rpm " , " nupkg "
2017-10-23 21:30:25 +02:00
} else {
throw " Building packages for $( $Environment . LinuxInfo . PRETTY_NAME ) is unsupported! "
}
} elseif ( $Environment . IsMacOS ) {
2019-02-04 23:53:25 +01:00
" osxpkg " , " nupkg " , " tar "
2017-10-23 21:30:25 +02:00
} elseif ( $Environment . IsWindows ) {
2019-04-16 02:07:15 +02:00
" msi " , " nupkg " , " msix "
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
}
2019-07-13 02:18:11 +02:00
{ $_ -like " fxdependent* " } {
2018-10-12 03:08:28 +02:00
## Remove PDBs from package to reduce size.
if ( -not $IncludeSymbols . IsPresent ) {
2019-01-16 01:28:52 +01:00
Get-ChildItem $Source -Filter * . pdb | Remove-Item -Force
2018-10-12 03:08:28 +02:00
}
2019-01-22 20:25:25 +01:00
if ( $Environment . IsWindows ) {
2018-09-10 21:47:32 +02:00
$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
}
2019-04-16 02:07:15 +02:00
" msix " {
$Arguments = @ {
ProductNameSuffix = $NameSuffix
ProductSourcePath = $Source
ProductVersion = $Version
2019-10-24 22:50:28 +02:00
Architecture = $WindowsRuntime . Split ( '-' ) [ 1 ]
2019-04-16 02:07:15 +02:00
Force = $Force
}
if ( $PSCmdlet . ShouldProcess ( " Create MSIX Package " ) ) {
New-MSIXPackage @Arguments
}
}
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 "
2020-01-29 23:24:38 +01:00
ExcludeSymbolicLinks = $true
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-12-05 19:55:09 +01:00
" tar-arm64 " {
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
Architecture = " arm64 "
2020-01-29 23:24:38 +01:00
ExcludeSymbolicLinks = $true
2018-12-05 19:55:09 +01:00
}
if ( $PSCmdlet . ShouldProcess ( " Create tar.gz Package " ) ) {
New-TarballPackage @Arguments
}
}
2018-11-27 19:45:49 +01:00
" tar-alpine " {
2018-06-28 00:30:38 +02:00
$Arguments = @ {
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
2018-11-27 19:45:49 +01:00
Architecture = " alpine-x64 "
2020-01-29 23:24:38 +01:00
ExcludeSymbolicLinks = $true
2018-06-28 00:30:38 +02:00
}
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
2020-02-05 01:21:59 +01:00
LTS = $LTS
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
}
2019-11-11 21:29:24 +01:00
'rpm' {
$Arguments = @ {
Type = 'rpm'
PackageSourcePath = $Source
Name = $Name
Version = $Version
Force = $Force
NoSudo = $NoSudo
2020-02-05 01:21:59 +01:00
LTS = $LTS
2019-11-11 21:29:24 +01:00
}
foreach ( $Distro in $Script:RedhatDistributions ) {
$Arguments [ " Distribution " ] = $Distro
if ( $PSCmdlet . ShouldProcess ( " Create RPM Package for $Distro " ) ) {
New-UnixPackage @Arguments
}
}
}
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
2020-02-05 01:21:59 +01:00
LTS = $LTS
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
2020-01-29 23:24:38 +01:00
[ switch ] $Force ,
2020-02-19 00:01:54 +01:00
[ switch ] $ExcludeSymbolicLinks
2017-10-12 22:36:46 +02:00
)
2018-09-10 21:47:32 +02:00
if ( $PackageNameSuffix ) {
$packageName = " $Name - $Version -{0}- $Architecture - $PackageNameSuffix .tar.gz "
} else {
2020-02-19 00:01:54 +01:00
$packageName = " $Name - $Version -{0}- $Architecture .tar.gz "
2018-09-10 21:47:32 +02:00
}
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
}
}
2020-02-05 01:21:59 +01:00
$Staging = " $PSScriptRoot /staging "
New-StagingFolder -StagingPath $Staging
2020-01-29 23:24:38 +01:00
if ( -not $ExcludeSymbolicLinks . IsPresent ) {
2020-02-05 01:21:59 +01:00
New-PSSymbolicLinks -Distribution 'ubuntu.16.04' -Staging $Staging
2020-01-29 23:24:38 +01:00
}
2017-10-12 22:36:46 +02:00
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 {
2020-02-05 01:21:59 +01:00
Push-Location -Path $Staging
2017-10-12 22:36:46 +02:00
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 "
2019-02-04 23:53:25 +01:00
return ( Get-Item $packagePath )
2017-10-12 22:36:46 +02:00
} 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 ]
2020-02-05 01:21:59 +01:00
$NoSudo ,
[ switch ]
$LTS
2017-07-23 21:29:33 +02:00
)
2017-10-03 23:29:43 +02:00
DynamicParam {
2019-11-11 21:29:24 +01:00
if ( $Type -eq " deb " -or $Type -eq 'rpm' ) {
2017-10-03 23:29:43 +02:00
# 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 "
2019-11-11 21:29:24 +01:00
if ( $type -eq 'deb' )
{
$ValidateSetAttr = New-Object " System.Management.Automation.ValidateSetAttribute " -ArgumentList $Script:DebianDistributions
}
else
{
$ValidateSetAttr = New-Object " System.Management.Automation.ValidateSetAttribute " -ArgumentList $Script:RedHatDistributions
}
2017-10-03 23:29:43 +02:00
$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 . 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 . 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 " {
2019-11-11 21:29:24 +01:00
if ( $PSBoundParameters . ContainsKey ( 'Distribution' ) ) {
$DebDistro = $PSBoundParameters [ 'Distribution' ]
} elseif ( $Environment . IsRedHatFamily ) {
$DebDistro = " rhel.7 "
} else {
throw " The current distribution is not supported. "
}
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 " )
}
2019-11-11 21:29:24 +01:00
$DebDistro = 'macOS'
2017-10-03 23:29:43 +02:00
}
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
2020-02-05 01:21:59 +01:00
$Name = if ( $LTS ) {
" powershell-lts "
}
elseif ( $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
2020-02-05 01:21:59 +01:00
$Suffix = if ( $IsPreview ) { $MajorVersion + " -preview " } elseif ( $LTS ) { $MajorVersion + " -lts " } 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 "
2020-01-13 20:19:12 +01:00
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
2020-02-14 03:46:10 +01:00
$Link = Get-PwshExecutablePath -IsPreview: $IsPreview
$links = @ ( New-LinkInfo -LinkDestination $Link -LinkTarget " $Destination /pwsh " )
if ( $LTS ) {
$links + = New-LinkInfo -LinkDestination ( Get-PwshExecutablePath -IsLTS: $LTS ) -LinkTarget " $Destination /pwsh "
}
2017-07-23 21:29:33 +02:00
2020-01-13 20:19:12 +01:00
if ( $PSCmdlet . ShouldProcess ( " Create package file system " ) )
2017-10-03 23:29:43 +02:00
{
2017-12-07 19:48:00 +01:00
# Generate After Install and After Remove scripts
2019-11-11 21:29:24 +01:00
$AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro
2020-01-29 23:24:38 +01:00
New-PSSymbolicLinks -Distribution $DebDistro -Staging $Staging
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
2018-11-14 02:04:39 +01:00
Write-Log " Setting permissions... "
2017-10-03 23:29:43 +02:00
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
{
2019-01-16 02:18:20 +01:00
Write-Log " Adding macOS launch application... "
2020-01-13 20:19:12 +01: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 `
2020-02-14 03:46:10 +01:00
-LinkInfo $Links `
2017-12-08 19:55:34 +01:00
-AppsFolder $AppsFolder `
2019-11-11 21:29:24 +01:00
-Distribution $DebDistro `
2017-12-08 19:55:34 +01:00
-ErrorAction Stop
2017-12-07 19:48:00 +01:00
2017-10-03 23:29:43 +02:00
# Build package
try {
2020-01-13 20:19:12 +01:00
if ( $PSCmdlet . ShouldProcess ( " Create $type package " ) ) {
2018-11-14 02:04:39 +01:00
Write-Log " Creating package with fpm... "
2017-10-03 23:29:43 +02:00
$Output = Start-NativeExecution { fpm $Arguments }
}
} finally {
if ( $Environment . IsMacOS ) {
2018-11-14 02:04:39 +01:00
Write-Log " Starting Cleanup for mac packaging... "
2020-01-13 20:19:12 +01: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) "
2020-02-14 03:46:10 +01:00
Start-NativeExecution -sb ( [ ScriptBlock ] :: Create ( " $sudo mv $hack_dest $symlink_dest " ) ) -VerboseOutputOnError
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 ) {
2020-01-13 20:19:12 +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
}
2020-02-14 03:46:10 +01:00
Function New-LinkInfo
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ Parameter ( Mandatory ) ]
[ string ]
$LinkDestination ,
[ Parameter ( Mandatory ) ]
[ string ]
$linkTarget
)
$linkDir = Join-Path -path '/tmp' -ChildPath ( [ System.IO.Path ] :: GetRandomFileName ( ) )
$null = New-Item -ItemType Directory -Path $linkDir
$linkSource = Join-Path -Path $linkDir -ChildPath 'pwsh'
Write-Log " Creating link to target ' $LinkTarget ', with a temp source of ' $LinkSource ' and a Package Destination of ' $LinkDestination ' "
if ( $PSCmdlet . ShouldProcess ( " Create package symbolic from $linkDestination to $linkTarget " ) )
{
# refers to executable, does not vary by channel
New-Item -Force -ItemType SymbolicLink -Path $linkSource -Target $LinkTarget > $null
}
[ LinkInfo ] @ {
Source = $linkSource
Destination = $LinkDestination
}
}
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
2019-11-24 13:41:53 +01:00
$PackagingStrings . OsxDistributionTemplate -f " PowerShell - $packageVersion " , $packageVersion , $packageName , '10.13' , $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
2019-02-04 23:53:25 +01:00
Start-NativeExecution -sb { productbuild - -distribution $distributionXmlPath - -resources $resourcesDir $newPackagePath } -VerboseOutputOnError
2017-12-08 19:55:34 +01:00
}
finally
{
Pop-Location
Remove-item -Path $tempDir -Recurse -Force
}
2019-02-04 23:53:25 +01:00
return ( Get-Item $newPackagePath )
2017-12-08 19:55:34 +01:00
}
2020-02-14 03:46:10 +01:00
Class LinkInfo
{
[ string ] $Source
[ string ] $Destination
}
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' ) ]
2020-02-14 03:46:10 +01:00
[ LinkInfo[] ] $LinkInfo ,
2017-12-07 19:48:00 +01:00
[ 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
} ) ]
2019-11-11 21:29:24 +01:00
[ String ] $AppsFolder ,
[ String ] $Distribution = 'rhel.7'
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 ) {
2019-11-11 21:29:24 +01:00
$Arguments + = @ ( " --rpm-dist " , $Distribution )
2017-12-07 19:48:00 +01:00
$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 / " ,
2020-02-14 03:46:10 +01:00
" $ManGzipFile = $ManDestination "
2017-12-07 19:48:00 +01:00
)
2020-02-14 03:46:10 +01:00
foreach ( $link in $LinkInfo )
{
$linkArgument = " $( $link . Source ) = $( $link . Destination ) "
$Arguments + = $linkArgument
}
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
)
2019-11-11 21:29:24 +01:00
if ( $Environment . IsDebianFamily -and ! $Distribution )
2017-12-07 19:48:00 +01:00
{
throw " $Distribution is required for a Debian based distribution. "
}
2019-11-11 21:29:24 +01:00
if ( $Environment . IsDebianFamily -and $Script:DebianDistributions -notcontains $Distribution )
2017-12-07 19:48:00 +01:00
{
throw " $Distribution should be one of the following: $Script:DebianDistributions "
}
2019-11-11 21:29:24 +01:00
if ( $Environment . IsRedHatFamily -and $Script:RedHatDistributions -notcontains $Distribution )
{
throw " $Distribution should be one of the following: $Script:RedHatDistributions "
}
2017-12-07 19:48:00 +01:00
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 = @ ( )
2019-11-11 21:29:24 +01:00
if ( $Environment . IsDebianFamily ) {
2017-12-07 19:48:00 +01:00
$Dependencies = @ (
" libc6 " ,
" libgcc1 " ,
" libgssapi-krb5-2 " ,
" liblttng-ust0 " ,
" libstdc++6 " ,
" zlib1g "
)
2019-11-11 21:29:24 +01:00
switch -regex ( $Distribution ) {
" ubuntu\.16\.04 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu55 " ) }
" ubuntu\.18\.04 " { $Dependencies + = @ ( " libssl1.0.0 " , " libicu60 " ) }
2019-12-03 20:39:06 +01:00
" debian\.9 " { $Dependencies + = @ ( " libssl1.0.2 " , " libicu57 " ) }
" debian\.(10|11) " { $Dependencies + = @ ( " libssl1.1 " , " libicu63 " ) }
2017-12-07 19:48:00 +01:00
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
2019-01-15 23:23:59 +01:00
$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 ) {
2019-01-15 23:23:59 +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
2017-12-07 19:48:00 +01:00
$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 ]
2019-11-11 21:29:24 +01:00
$Link ,
[ Parameter ( Mandatory ) ]
[ string ]
$Distribution
2018-06-09 01:31:38 +02:00
)
2020-01-29 23:24:38 +01:00
Write-Verbose -Message " AfterScript Distribution: $Distribution " -Verbose
if ( $Environment . IsRedHatFamily ) {
$AfterInstallScript = [ io.path ] :: GetTempFileName ( )
$AfterRemoveScript = [ io.path ] :: GetTempFileName ( )
$packagingStrings . RedHatAfterInstallScript -f " $Link " | Out-File -FilePath $AfterInstallScript -Encoding ascii
$packagingStrings . RedHatAfterRemoveScript -f " $Link " | Out-File -FilePath $AfterRemoveScript -Encoding ascii
}
elseif ( $Environment . IsDebianFamily -or $Environment . IsSUSEFamily ) {
$AfterInstallScript = [ io.path ] :: GetTempFileName ( )
$AfterRemoveScript = [ io.path ] :: GetTempFileName ( )
$packagingStrings . UbuntuAfterInstallScript -f " $Link " | Out-File -FilePath $AfterInstallScript -Encoding ascii
$packagingStrings . UbuntuAfterRemoveScript -f " $Link " | Out-File -FilePath $AfterRemoveScript -Encoding ascii
}
elseif ( $Environment . IsMacOS ) {
# NOTE: The macos pkgutil doesn't support uninstall actions so we did not implement it.
# Handling uninstall can be done in Homebrew so we'll take advantage of that in the brew formula.
$AfterInstallScript = [ io.path ] :: GetTempFileName ( )
$packagingStrings . MacOSAfterInstallScript -f " $Link " | Out-File -FilePath $AfterInstallScript -Encoding ascii
}
return [ PSCustomObject ] @ {
AfterInstallScript = $AfterInstallScript
AfterRemoveScript = $AfterRemoveScript
}
}
function New-PSSymbolicLinks
{
param (
[ Parameter ( Mandatory ) ]
[ string ]
$Distribution ,
[ Parameter ( Mandatory ) ]
[ string ]
$Staging
)
Write-Verbose -Message " PSSymLinks-Distribution: $Distribution " -Verbose
2017-12-07 19:48:00 +01:00
if ( $Environment . IsRedHatFamily ) {
2019-11-11 21:29:24 +01:00
switch -regex ( $Distribution )
{
# 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.
'centos\.8' {
New-Item -Force -ItemType SymbolicLink -Target " /lib64/libssl.so.1.1 " -Path " $Staging /libssl.so.1.0.0 " > $null
New-Item -Force -ItemType SymbolicLink -Target " /lib64/libcrypto.so.1.1.1 " -Path " $Staging /libcrypto.so.1.0.0 " > $null
}
default {
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
}
}
2017-12-07 19:48:00 +01:00
}
2019-11-11 21:29:24 +01:00
elseif ( $Environment . IsDebianFamily -or $Environment . IsSUSEFamily ) {
2020-01-29 23:24:38 +01:00
switch -regex ( $Distribution )
2019-11-11 21:29:24 +01:00
{
2018-08-25 00:20:22 +02:00
# 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.
2020-01-08 01:54:03 +01:00
'debian\.9' {
2019-11-11 21:29:24 +01:00
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
}
2020-01-08 01:54:03 +01:00
'debian\.(10|11)' {
2019-11-11 21:29:24 +01:00
New-Item -Force -ItemType SymbolicLink -Target " /usr/lib/x86_64-linux-gnu/libssl.so.1.1 " -Path " $Staging /libssl.so.1.0.0 " > $null
New-Item -Force -ItemType SymbolicLink -Target " /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 " -Path " $Staging /libcrypto.so.1.0.0 " > $null
}
2020-01-29 23:24:38 +01:00
default {
# Default to old behavior before this change
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
}
2018-08-25 00:20:22 +02:00
}
2017-12-07 19:48:00 +01:00
}
}
function New-ManGzip
{
2018-06-09 01:31:38 +02:00
param (
[ switch ]
$IsPreview
)
2018-11-14 02:04:39 +01:00
Write-Log " Creating man gz... "
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-11-14 02:04:39 +01:00
Write-Log " Creating man gz - running ronn... "
Start-NativeExecution { ronn - -roff $RonnFile }
2018-06-09 01:31:38 +02:00
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-11-14 02:04:39 +01:00
Write-Log " Creating man gz - running gzip... "
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 ) ]
2020-02-05 01:21:59 +01:00
[ String ] $Version ,
[ switch ] $LTS
2017-12-07 19:48:00 +01:00
)
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.
2020-02-05 01:21:59 +01:00
$suffix = if ( $IsPreview ) { " -preview " } elseif ( $LTS ) { " -lts " }
2018-07-20 19:53:09 +02:00
$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.
2020-02-05 01:21:59 +01:00
$executablepath = Get-PwshExecutablePath -IsPreview: $IsPreview -IsLTS: $LTS
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
}
2020-02-05 01:21:59 +01:00
function Get-PwshExecutablePath
{
param (
[ switch ] $IsPreview ,
[ switch ] $IsLTS
)
if ( $IsPreview -and $IsLTS )
{
throw " Cannot be LTS and Preview "
}
$executableName = if ( $IsPreview ) {
" pwsh-preview "
2020-02-14 03:46:10 +01:00
} elseif ( $IsLTS ) {
2020-02-05 01:21:59 +01:00
" pwsh-lts "
} else {
" pwsh "
}
if ( $Environment . IsLinux ) {
" /usr/bin/ $executableName "
} elseif ( $Environment . IsMacOS ) {
" /usr/local/bin/ $executableName "
}
}
2017-12-07 19:48:00 +01:00
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
{
2020-01-13 20:19:12 +01: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
)
2019-10-19 01:49:25 +02:00
$destPath = New-Item -ItemType Directory -Path ( Join-Path $PackageRuntimesFolder " $Platform /lib/netcoreapp3.1 " )
2018-02-27 00:35:09 +01:00
$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
2019-03-21 18:03:46 +01:00
Creates a NuGet package of IL assemblies for unix and windows .
2018-02-27 00:35:09 +01:00
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 .
2019-03-21 18:03:46 +01:00
. PARAMETER WinFxdBinPath
Path to folder containing Windows framework dependent assemblies .
2018-02-27 00:35:09 +01:00
2019-03-21 18:03:46 +01:00
. PARAMETER LinuxFxdBinPath
Path to folder containing Linux framework dependent assemblies .
2018-02-27 00:35:09 +01:00
. PARAMETER GenAPIToolPath
Path to the GenAPI . exe tool .
#>
2019-03-21 18:03:46 +01:00
function New-ILNugetPackage
2018-02-27 00:35:09 +01:00
{
[ CmdletBinding ( SupportsShouldProcess = $true ) ]
param (
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackagePath ,
[ Parameter ( Mandatory = $true ) ]
[ string ] $PackageVersion ,
[ Parameter ( Mandatory = $true ) ]
2019-03-21 18:03:46 +01:00
[ string ] $WinFxdBinPath ,
2018-02-27 00:35:09 +01:00
[ Parameter ( Mandatory = $true ) ]
2019-03-21 18:03:46 +01:00
[ string ] $LinuxFxdBinPath ,
2018-02-27 00:35:09 +01:00
[ 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
{
2019-03-21 18:03:46 +01:00
throw " New-ILNugetPackage can be only executed on Windows platform. "
2018-02-27 00:35:09 +01:00
}
$fileList = @ (
2020-02-12 01:13:21 +01:00
" Microsoft.Management.Infrastructure.CimCmdlets.dll " ,
2018-02-27 00:35:09 +01:00
" 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 = @ (
2020-02-12 01:13:21 +01:00
" Microsoft.Management.Infrastructure.CimCmdlets.dll " ,
2018-02-27 00:35:09 +01:00
" Microsoft.PowerShell.Commands.Diagnostics.dll " ,
2019-08-12 18:59:02 +02:00
" Microsoft.PowerShell.CoreCLR.Eventing.dll " ,
2018-02-27 00:35:09 +01:00
" 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
2019-03-21 18:03:46 +01:00
New-ReferenceAssembly -linux64BinPath $LinuxFxdBinPath -RefAssemblyDestinationPath $refBinPath -RefAssemblyVersion $PackageVersion -SnkFilePath $SnkFilePath -GenAPIToolPath $GenAPIToolPath
2018-02-27 00:35:09 +01:00
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
2019-10-19 01:49:25 +02:00
$refFolder = New-Item ( Join-Path $filePackageFolder . FullName 'ref/netcoreapp3.1' ) -ItemType Directory -Force
2019-01-23 20:42:32 +01:00
CopyReferenceAssemblies -assemblyName $fileBaseName -refBinPath $refBinPath -refNugetPath $refFolder -assemblyFileList $fileList
2018-02-27 00:35:09 +01:00
#endregion ref
$packageRuntimesFolderPath = $packageRuntimesFolder . FullName
2019-03-21 18:03:46 +01:00
CreateNugetPlatformFolder -Platform 'win' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $WinFxdBinPath
2018-02-27 00:35:09 +01:00
if ( $linuxExceptionList -notcontains $file )
{
2019-03-21 18:03:46 +01:00
CreateNugetPlatformFolder -Platform 'unix' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $LinuxFxdBinPath
2018-02-27 00:35:09 +01:00
}
2019-09-26 01:26:19 +02:00
if ( $file -eq " Microsoft.PowerShell.SDK.dll " )
{
2020-01-13 20:35:33 +01:00
# Copy the '$PSHOME\ref' folder to the NuGet package, so 'dotnet publish' can deploy the 'ref' folder to the publish folder.
2019-09-26 01:26:19 +02:00
# This is to make 'Add-Type' work in application that hosts PowerShell.
$contentFolder = New-Item ( Join-Path $filePackageFolder " contentFiles\any\any " ) -ItemType Directory -Force
$dotnetRefAsmFolder = Join-Path -Path $WinFxdBinPath -ChildPath " ref "
Copy-Item -Path $dotnetRefAsmFolder -Destination $contentFolder -Recurse -Force
2020-02-12 01:13:21 +01:00
Write-Log " Copied the reference assembly folder to contentFiles for the SDK package "
# Copy the built-in module folders to the NuGet package, so 'dotnet publish' can deploy those modules to the $pshome module path.
# This is for enabling applications that hosts PowerShell to ship the built-in modules.
$winBuiltInModules = @ (
" CimCmdlets " ,
" Microsoft.PowerShell.Diagnostics " ,
" Microsoft.PowerShell.Host " ,
" Microsoft.PowerShell.Management " ,
" Microsoft.PowerShell.Security " ,
" Microsoft.PowerShell.Utility " ,
" Microsoft.WSMan.Management " ,
" PSDiagnostics "
)
$unixBuiltInModules = @ (
" Microsoft.PowerShell.Host " ,
" Microsoft.PowerShell.Management " ,
" Microsoft.PowerShell.Security " ,
" Microsoft.PowerShell.Utility "
)
$winModuleFolder = New-Item ( Join-Path $contentFolder " runtimes\win\lib\netcoreapp3.1\Modules " ) -ItemType Directory -Force
$unixModuleFolder = New-Item ( Join-Path $contentFolder " runtimes\unix\lib\netcoreapp3.1\Modules " ) -ItemType Directory -Force
foreach ( $module in $winBuiltInModules ) {
$source = Join-Path $WinFxdBinPath " Modules\ $module "
Copy-Item -Path $source -Destination $winModuleFolder -Recurse -Force
}
foreach ( $module in $unixBuiltInModules ) {
$source = Join-Path $LinuxFxdBinPath " Modules\ $module "
Copy-Item -Path $source -Destination $unixModuleFolder -Recurse -Force
}
Write-Log " Copied the built-in modules to contentFiles for the SDK package "
2019-09-26 01:26:19 +02:00
}
2018-02-27 00:35:09 +01:00
#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 ) {
2020-02-12 01:13:21 +01:00
'Microsoft.Management.Infrastructure.CimCmdlets' {
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'System.Management.Automation' ) , [ tuple ] :: Create ( 'version' , $PackageVersion ) ) ) > $null
}
2018-02-27 00:35:09 +01:00
'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
2020-02-12 01:13:21 +01:00
$deps . Add ( [ tuple ] :: Create ( [ tuple ] :: Create ( 'id' , 'Microsoft.Management.Infrastructure.CimCmdlets' ) , [ 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
}
}
}
2019-01-23 20:42:32 +01:00
<#
2019-05-21 07:43:51 +02:00
Copy the generated reference assemblies to the 'ref/netcoreapp3.0' folder properly .
2019-03-21 18:03:46 +01:00
This is a helper function used by 'New-ILNugetPackage'
2019-01-23 20:42:32 +01:00
#>
function CopyReferenceAssemblies
{
param (
[ string ] $assemblyName ,
[ string ] $refBinPath ,
[ string ] $refNugetPath ,
[ string[] ] $assemblyFileList
)
2020-01-14 00:58:02 +01:00
$supportedRefList = @ (
" Microsoft.PowerShell.Commands.Utility " ,
" Microsoft.PowerShell.ConsoleHost " )
2019-01-23 20:42:32 +01:00
switch ( $assemblyName ) {
2020-01-14 00:58:02 +01:00
{ $_ -in $supportedRefList } {
$refDll = Join-Path -Path $refBinPath -ChildPath " $assemblyName .dll "
Copy-Item $refDll -Destination $refNugetPath -Force
Write-Log " Copied file $refDll to $refNugetPath "
2019-01-23 20:42:32 +01:00
}
" Microsoft.PowerShell.SDK " {
foreach ( $asmFileName in $assemblyFileList ) {
$refFile = Join-Path -Path $refBinPath -ChildPath $asmFileName
if ( Test-Path -Path $refFile ) {
Copy-Item $refFile -Destination $refNugetPath -Force
Write-Log " Copied file $refFile to $refNugetPath "
}
}
}
default {
$ref_SMA = Join-Path -Path $refBinPath -ChildPath System . Management . Automation . dll
Copy-Item $ref_SMA -Destination $refNugetPath -Force
Write-Log " Copied file $ref_SMA to $refNugetPath "
}
}
}
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. "
}
$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
2019-01-23 20:42:32 +01:00
$genAPIFolder = New-TempFolder
$packagingStrings . NugetConfigFile | Out-File -FilePath " $genAPIFolder /Nuget.config " -Force
Write-Log " Working directory: $genAPIFolder . "
2018-02-27 00:35:09 +01:00
2019-01-23 20:42:32 +01:00
$SMAReferenceAssembly = $null
$assemblyNames = @ (
" System.Management.Automation " ,
2020-01-14 00:58:02 +01:00
" Microsoft.PowerShell.Commands.Utility " ,
" Microsoft.PowerShell.ConsoleHost "
2019-01-23 20:42:32 +01:00
)
foreach ( $assemblyName in $assemblyNames ) {
2019-01-25 20:10:47 +01:00
Write-Log " Building reference assembly for ' $assemblyName ' "
2019-01-23 20:42:32 +01:00
$projectFolder = New-Item -Path " $genAPIFolder / $assemblyName " -ItemType Directory -Force
$generatedSource = Join-Path $projectFolder " $assemblyName .cs "
$filteredSource = Join-Path $projectFolder " ${assemblyName} _Filtered.cs "
$linuxDllPath = Join-Path $Linux64BinPath " $assemblyName .dll "
if ( -not ( Test-Path $linuxDllPath ) ) {
throw " $assemblyName .dll was not found at: $Linux64BinPath "
}
2018-02-27 00:35:09 +01:00
2019-03-21 18:03:46 +01:00
$genAPIArgs = " $linuxDllPath " , " -libPath: $Linux64BinPath , $Linux64BinPath \ref "
2019-01-23 20:42:32 +01:00
Write-Log " GenAPI cmd: $genAPIExe $genAPIArgsString "
2018-02-27 00:35:09 +01:00
2019-01-23 20:42:32 +01:00
Start-NativeExecution { & $genAPIExe $genAPIArgs } | Out-File $generatedSource -Force
Write-Log " Reference assembly file generated at: $generatedSource "
2018-02-27 00:35:09 +01:00
2019-01-23 20:42:32 +01:00
CleanupGeneratedSourceCode -assemblyName $assemblyName -generatedSource $generatedSource -filteredSource $filteredSource
2018-02-27 00:35:09 +01:00
2019-01-23 20:42:32 +01:00
try
{
Push-Location $projectFolder
2019-01-25 22:44:25 +01:00
$sourceProjectRoot = Join-Path $PSScriptRoot " projects/reference/ $assemblyName "
2019-01-25 20:10:47 +01:00
$sourceProjectFile = Join-Path $sourceProjectRoot " $assemblyName .csproj "
Copy-Item -Path $sourceProjectFile -Destination " $projectFolder / $assemblyName .csproj " -Force
2019-01-23 20:42:32 +01:00
Write-Host " ##vso[artifact.upload containerfolder=artifact;artifactname=artifact] $projectFolder / $assemblyName .csproj "
Write-Host " ##vso[artifact.upload containerfolder=artifact;artifactname=artifact] $generatedSource "
2019-01-25 20:10:47 +01:00
$arguments = GenerateBuildArguments -AssemblyName $assemblyName -RefAssemblyVersion $RefAssemblyVersion -SnkFilePath $SnkFilePath -SMAReferencePath $SMAReferenceAssembly
2019-01-23 20:42:32 +01:00
2019-01-25 20:10:47 +01:00
Write-Log " Running: dotnet $arguments "
Start-NativeExecution -sb { dotnet $arguments }
2019-10-19 01:49:25 +02:00
$refBinPath = Join-Path $projectFolder " bin/Release/netcoreapp3.1/ $assemblyName .dll "
2019-01-23 20:42:32 +01:00
if ( $null -eq $refBinPath ) {
throw " Reference assembly was not built. "
}
2018-02-27 00:35:09 +01:00
2019-01-23 20:42:32 +01:00
Copy-Item $refBinPath $RefAssemblyDestinationPath -Force
Write-Log " Reference assembly ' $assemblyName .dll' built and copied to $RefAssemblyDestinationPath "
if ( $assemblyName -eq " System.Management.Automation " ) {
$SMAReferenceAssembly = $refBinPath
}
}
finally
{
Pop-Location
}
}
if ( Test-Path $genAPIFolder )
{
Remove-Item $genAPIFolder -Recurse -Force -ErrorAction SilentlyContinue
}
}
2019-01-25 20:10:47 +01:00
<#
Helper function for New-ReferenceAssembly to further clean up the
C # source code generated from GenApi.exe.
#>
2019-01-23 20:42:32 +01:00
function CleanupGeneratedSourceCode
{
param (
[ string ] $assemblyName ,
[ string ] $generatedSource ,
[ string ] $filteredSource
)
2018-02-27 00:35:09 +01:00
$patternsToRemove = @ (
2018-10-16 22:23:57 +02:00
'[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)'
2018-02-27 00:35:09 +01:00
'[System.Management.Automation.Internal.CommonParameters.ValidateVariableName]'
2018-10-16 22:23:57 +02:00
'[System.Management.Automation.ArgumentEncodingCompletionsAttribute]'
2019-01-23 20:42:32 +01:00
'[Microsoft.PowerShell.Commands.AddMemberCommand'
'[System.Management.Automation.ArgumentCompleterAttribute(typeof(Microsoft.PowerShell.Commands.Utility.JoinItemCompleter))]'
'[System.Management.Automation.ArgumentCompleterAttribute(typeof(System.Management.Automation.PropertyNameCompleter))]'
'[System.Management.Automation.OutputTypeAttribute(typeof(Microsoft.PowerShell.MarkdownRender'
'[Microsoft.PowerShell.Commands.ArgumentToTypeNameTransformationAttribute]'
'[System.Management.Automation.Internal.ArchitectureSensitiveAttribute]'
'[Microsoft.PowerShell.Commands.SelectStringCommand.FileinfoToStringAttribute]'
'[System.Runtime.CompilerServices.IsReadOnlyAttribute]'
2018-02-27 00:35:09 +01:00
)
2019-01-23 20:42:32 +01:00
$patternsToReplace = @ (
@ {
ApplyTo = " Microsoft.PowerShell.Commands.Utility "
Pattern = " [System.Runtime.CompilerServices.IsReadOnlyAttribute]ref Microsoft.PowerShell.Commands.JsonObject.ConvertToJsonContext "
Replacement = " in Microsoft.PowerShell.Commands.JsonObject.ConvertToJsonContext "
} ,
@ {
ApplyTo = " Microsoft.PowerShell.Commands.Utility "
Pattern = " public partial struct ConvertToJsonContext "
Replacement = " public readonly struct ConvertToJsonContext "
2019-03-21 18:03:46 +01:00
} ,
@ {
ApplyTo = " Microsoft.PowerShell.Commands.Utility "
Pattern = " Unable to resolve assembly 'Assembly(Name=Newtonsoft.Json "
Replacement = " // Unable to resolve assembly 'Assembly(Name=Newtonsoft.Json "
} ,
@ {
ApplyTo = " System.Management.Automation "
Pattern = " Unable to resolve assembly 'Assembly(Name=System.Security.Principal.Windows "
Replacement = " // Unable to resolve assembly 'Assembly(Name=System.Security.Principal.Windows "
} ,
@ {
ApplyTo = " System.Management.Automation "
Pattern = " Unable to resolve assembly 'Assembly(Name=Microsoft.Management.Infrastructure "
Replacement = " // Unable to resolve assembly 'Assembly(Name=Microsoft.Management.Infrastructure "
} ,
@ {
ApplyTo = " System.Management.Automation "
Pattern = " Unable to resolve assembly 'Assembly(Name=System.Security.AccessControl "
Replacement = " // Unable to resolve assembly 'Assembly(Name=System.Security.AccessControl "
2019-01-23 20:42:32 +01:00
}
)
$reader = [ System.IO.File ] :: OpenText ( $generatedSource )
$writer = [ System.IO.File ] :: CreateText ( $filteredSource )
2018-02-27 00:35:09 +01:00
2018-09-25 18:53:42 +02:00
while ( $null -ne ( $line = $reader . ReadLine ( ) ) )
2018-02-27 00:35:09 +01:00
{
2019-01-23 20:42:32 +01:00
$lineWasProcessed = $false
foreach ( $patternToReplace in $patternsToReplace )
2018-02-27 00:35:09 +01:00
{
2019-01-23 20:42:32 +01:00
if ( $assemblyName -eq $patternToReplace . ApplyTo -and $line . Contains ( $patternToReplace . Pattern ) ) {
$line = $line . Replace ( $patternToReplace . Pattern , $patternToReplace . Replacement )
$lineWasProcessed = $true
break
}
2018-02-27 00:35:09 +01:00
}
2019-01-23 20:42:32 +01:00
if ( ! $lineWasProcessed ) {
$match = Select-String -InputObject $line -Pattern $patternsToRemove -SimpleMatch
if ( $null -ne $match )
{
$line = " // $line "
}
2018-02-27 00:35:09 +01:00
}
2019-01-23 20:42:32 +01:00
$writer . WriteLine ( $line )
2018-02-27 00:35:09 +01:00
}
2019-01-23 20:42:32 +01:00
2018-09-25 18:53:42 +02:00
if ( $null -ne $reader )
2018-02-27 00:35:09 +01:00
{
$reader . Close ( )
}
2019-01-23 20:42:32 +01:00
2018-09-25 18:53:42 +02:00
if ( $null -ne $writer )
2018-02-27 00:35:09 +01:00
{
$writer . Close ( )
}
2019-01-23 20:42:32 +01:00
Move-Item $filteredSource $generatedSource -Force
Write-Log " Code cleanup complete for reference assembly ' $assemblyName '. "
}
2018-02-27 00:35:09 +01:00
2019-01-25 20:10:47 +01:00
<#
Helper function for New-ReferenceAssembly to get the arguments
for building reference assemblies .
#>
function GenerateBuildArguments
2019-01-23 20:42:32 +01:00
{
param (
[ string ] $AssemblyName ,
[ string ] $RefAssemblyVersion ,
[ string ] $SnkFilePath ,
[ string ] $SMAReferencePath
)
2018-02-27 00:35:09 +01:00
2019-01-25 20:10:47 +01:00
$arguments = @ ( 'build' )
$arguments + = @ ( '-c' , 'Release' )
$arguments + = " /p:RefAsmVersion= $RefAssemblyVersion "
$arguments + = " /p:SnkFile= $SnkFilePath "
2018-02-27 00:35:09 +01:00
2020-01-14 00:58:02 +01:00
if ( $AssemblyName -ne " System.Management.Automation " ) {
$arguments + = " /p:SmaRefFile= $SMAReferencePath "
2018-02-27 00:35:09 +01:00
}
2019-01-25 20:10:47 +01:00
return $arguments
2018-02-27 00:35:09 +01:00
}
<#
. 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'
2020-01-13 20:19:12 +01:00
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
}
2019-01-25 20:10:47 +01:00
$projectFolder = Join-Path $PSScriptRoot 'projects/nuget'
2017-08-01 23:35:50 +02:00
$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 )
{
2019-02-04 23:53:25 +01:00
Get-Item $nupkgFile
2017-09-11 21:36:24 +02:00
}
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'
2018-11-13 18:52:48 +01:00
# This function converts the above version into semantic version major.minor.patch[-previewName[Number]] format
2018-03-07 20:45:21 +01:00
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 '-' )
2018-11-13 18:52:48 +01:00
$packageSemanticVersion = ( '{0}-{1}' -f $packageVersionTokens [ 0 ] , $packageRevisionTokens )
2018-03-07 20:45:21 +01:00
}
$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
{
$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
2019-05-21 07:43:51 +02:00
New-MSIPackage -Verbose -ProductCode ( New-Guid ) -ProductSourcePath '.\src\powershell-win-core\bin\Debug\netcoreapp3.0\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
2019-05-30 00:37:18 +02:00
$simpleProductVersion = '7'
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 " )
Preserve user shortcuts pinned to Taskbar during MSI upgrade (#9305)
Fixes #8919
Preserve user shortcuts pinned to Taskbar during MSI upgrade by not removing shortcuts in this case (assuming the user has not changed the installation directory), see https://stackoverflow.com/a/33402698/1810304
This also requires the Guid to not always be re-generated, which PR #7701 originally added to ensure shortcuts get removed when RTM and preview are installed, the underlying problem was rather that RTM and preview shared the same GUIDs, therefore the GUIDs are hard-coded again but different for RTM and preview, therefore the shortcuts will still always get removed on uninstall. But this also means those GUIDs should change when the default installation directory changes, i.e. in PowerShell 7. Should we write the code to already take this into account that it does not get forgotten?
Tested by first reproducing the issue by building installers locally (and bumping the patch version. Then the fix was applied to verify the solution, it. For this to take effect the version from which an MSI is being upgraded must have this fix already, i.e. if this fix got shipped in `6.2.1`, then on upgrading to it, the issue would still occur but when upgrading `6.2.1` to `6.2.2` the shortcut would start being preserved. I am wondering if we could maybe improve this to show effect earlier by trying to extract the used (auto-generated) GUIDs in the `6.2.0` and `6.2.0-rc` packages out and use them...
Please not that we probably need to take this out for `7.0` because the base installation directory will change. This also assumes that the user has not specified a different installation directory on upgrade but this is a bit of an edge case where I think other things might break as well.
2019-04-07 21:25:56 +02:00
# The ApplicationProgramsMenuShortcut GUID should be changed when bumping the major version because the installation directory changes
[ Environment ] :: SetEnvironmentVariable ( " ApplicationProgramsMenuShortcut " , '6a69de6c-183d-4bf4-a40e-83007d6293bf' , " 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 " )
Preserve user shortcuts pinned to Taskbar during MSI upgrade (#9305)
Fixes #8919
Preserve user shortcuts pinned to Taskbar during MSI upgrade by not removing shortcuts in this case (assuming the user has not changed the installation directory), see https://stackoverflow.com/a/33402698/1810304
This also requires the Guid to not always be re-generated, which PR #7701 originally added to ensure shortcuts get removed when RTM and preview are installed, the underlying problem was rather that RTM and preview shared the same GUIDs, therefore the GUIDs are hard-coded again but different for RTM and preview, therefore the shortcuts will still always get removed on uninstall. But this also means those GUIDs should change when the default installation directory changes, i.e. in PowerShell 7. Should we write the code to already take this into account that it does not get forgotten?
Tested by first reproducing the issue by building installers locally (and bumping the patch version. Then the fix was applied to verify the solution, it. For this to take effect the version from which an MSI is being upgraded must have this fix already, i.e. if this fix got shipped in `6.2.1`, then on upgrading to it, the issue would still occur but when upgrading `6.2.1` to `6.2.2` the shortcut would start being preserved. I am wondering if we could maybe improve this to show effect earlier by trying to extract the used (auto-generated) GUIDs in the `6.2.0` and `6.2.0-rc` packages out and use them...
Please not that we probably need to take this out for `7.0` because the base installation directory will change. This also assumes that the user has not specified a different installation directory on upgrade but this is a bit of an edge case where I think other things might break as well.
2019-04-07 21:25:56 +02:00
[ Environment ] :: SetEnvironmentVariable ( " ApplicationProgramsMenuShortcut " , 'ab727c4f-2311-474c-9ade-f2c6fd7f7322' , " 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 "
2019-02-28 23:05:27 +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 "
}
2020-01-13 20:24:10 +01:00
$msiLocationPath = Join-Path $PWD " $packageName .msi "
$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 }
2019-02-28 23:05:27 +01:00
# We are verifying that the generated $wixFragmentPath and $FilesWxsPath are functionally the same
2018-03-06 19:13:26 +01:00
Test-FileWxs -FilesWxsPath $FilesWxsPath -HeatFilesWxsPath $wixFragmentPath
2018-02-27 00:45:15 +01:00
2019-02-28 23:05:27 +01:00
if ( $isPreview )
{
# Now that we know that the two are functionally the same,
# We only need to use $FilesWxsPath for release we want to be able to Path
# and two releases shouldn't have the same identifiers,
# so we use the generated one for preview
$FilesWxsPath = $wixFragmentPath
$wixObjFragmentPath = Join-Path $env:Temp " Fragment.wixobj "
# cleanup any garbage on the system
Remove-Item -ErrorAction SilentlyContinue $wixObjFragmentPath -Force
}
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 "
throw $errorMessage
}
}
2019-04-16 02:07:15 +02:00
<#
. Synopsis
Creates a Windows AppX MSIX package and assumes that the binaries are already built using 'Start-PSBuild' .
This only works on a Windows machine due to the usage of makeappx . exe .
. 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
2019-05-21 07:43:51 +02:00
New-MSIXPackage -Verbose -ProductSourcePath '.\src\powershell-win-core\bin\Debug\netcoreapp3.0\win7-x64\publish' -ProductTargetArchitecture x64 -ProductVersion '1.2.3'
2019-04-16 02:07:15 +02:00
#>
function New-MSIXPackage
{
[ CmdletBinding ( SupportsShouldProcess , ConfirmImpact = 'Low' ) ]
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 ,
# Source Path to the Product Files - required to package the contents into an MSIX
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ProductSourcePath ,
2019-10-24 22:50:28 +02:00
# Processor Architecture
[ Parameter ( Mandatory = $true ) ]
[ ValidateSet ( 'x64' , 'x86' , 'arm' , 'arm64' ) ]
[ string ] $Architecture ,
2019-04-16 02:07:15 +02:00
# Force overwrite of package
[ Switch ] $Force
)
$makeappx = Get-Command makeappx -CommandType Application -ErrorAction Ignore
if ( $null -eq $makeappx ) {
# This is location in our dockerfile
$dockerPath = Join-Path $env:SystemDrive " makeappx "
if ( Test-Path $dockerPath ) {
$makeappx = Get-ChildItem $dockerPath -Include makeappx . exe -Recurse | Select-Object -First 1
}
if ( $null -eq $makeappx ) {
# Try to find in well known location
$makeappx = Get-ChildItem " $ {env:ProgramFiles(x86)}\Windows Kits\10\bin\*\x64 " -Include makeappx . exe -Recurse | Select-Object -First 1
if ( $null -eq $makeappx ) {
throw " Could not locate makeappx.exe, make sure Windows 10 SDK is installed "
}
}
}
$makepri = Get-Item ( Join-Path $makeappx . Directory " makepri.exe " ) -ErrorAction Stop
$ProductSemanticVersion = Get-PackageSemanticVersion -Version $ProductVersion
$productSemanticVersionWithName = $ProductName + '-' + $ProductSemanticVersion
$packageName = $productSemanticVersionWithName
if ( $ProductNameSuffix ) {
$packageName + = " - $ProductNameSuffix "
}
2019-10-24 22:50:28 +02:00
$displayName = $productName
2020-01-09 20:58:51 +01:00
if ( $packageName . Contains ( '-' ) ) {
2019-10-24 22:50:28 +02:00
$ProductName + = 'Preview'
$displayName + = ' Preview'
}
Write-Verbose -Verbose " ProductName: $productName "
Write-Verbose -Verbose " DisplayName: $displayName "
2019-04-16 02:07:15 +02:00
$ProductVersion = Get-PackageVersionAsMajorMinorBuildRevision -Version $ProductVersion
if ( ( [ Version ] $ProductVersion ) . Revision -eq -1 ) {
$ProductVersion + = " .0 "
}
2019-09-23 21:26:20 +02:00
# The Store requires the last digit of the version to be 0 so we swap the build and revision
# This only affects Preview versions where the last digit is the preview number
# For stable versions, the last digit is already zero so no changes
$pversion = [ version ] $ProductVersion
if ( $pversion . Revision -ne 0 ) {
2020-01-09 20:58:51 +01:00
$revision = $pversion . Revision
if ( $packageName . Contains ( '-rc' ) ) {
# For Release Candidates, we use numbers in the 100 range
$revision + = 100
}
$pversion = [ version ] :: new ( $pversion . Major , $pversion . Minor , $revision , 0 )
2019-09-23 21:26:20 +02:00
$ProductVersion = $pversion . ToString ( )
}
Write-Verbose " Version: $productversion " -Verbose
2019-04-16 02:07:15 +02:00
# Appx manifest needs to be in root of source path, but the embedded version needs to be updated
$appxManifest = Get-Content " $RepoRoot \assets\AppxManifest.xml " -Raw
2019-10-24 22:50:28 +02:00
$appxManifest = $appxManifest . Replace ( '$VERSION$' , $ProductVersion ) . Replace ( '$ARCH$' , $Architecture ) . Replace ( '$PRODUCTNAME$' , $productName ) . Replace ( '$DISPLAYNAME$' , $displayName )
2019-04-16 02:07:15 +02:00
Set-Content -Path " $ProductSourcePath \AppxManifest.xml " -Value $appxManifest -Force
# Necessary image assets need to be in source assets folder
$assets = @ (
2019-04-22 19:41:34 +02:00
'Square150x150Logo'
'Square44x44Logo'
'Square44x44Logo.targetsize-48'
'Square44x44Logo.targetsize-48_altform-unplated'
'StoreLogo'
2019-04-16 02:07:15 +02:00
)
if ( ! ( Test-Path " $ProductSourcePath \assets " ) ) {
$null = New-Item -ItemType Directory -Path " $ProductSourcePath \assets "
}
2019-04-22 19:41:34 +02:00
$isPreview = Test-IsPreview -Version $ProductSemanticVersion
if ( $isPreview ) {
Write-Verbose " Using Preview assets " -Verbose
}
2019-04-16 02:07:15 +02:00
$assets | ForEach-Object {
2019-04-22 19:41:34 +02:00
if ( $isPreview ) {
Copy-Item -Path " $RepoRoot \assets\ $_ -Preview.png " -Destination " $ProductSourcePath \assets\ $_ .png "
}
else {
Copy-Item -Path " $RepoRoot \assets\ $_ .png " -Destination " $ProductSourcePath \assets\ "
}
2019-04-16 02:07:15 +02:00
}
if ( $PSCmdlet . ShouldProcess ( " Create .msix package? " ) ) {
Write-Verbose " Creating priconfig.xml " -Verbose
Start-NativeExecution -VerboseOutputOnError { & $makepri createconfig / o / cf ( Join-Path $ProductSourcePath " priconfig.xml " ) / dq en-US }
Write-Verbose " Creating resources.pri " -Verbose
Push-Location $ProductSourcePath
Start-NativeExecution -VerboseOutputOnError { & $makepri new / v / o / pr $ProductSourcePath / cf ( Join-Path $ProductSourcePath " priconfig.xml " ) }
Pop-Location
Write-Verbose " Creating msix package " -Verbose
Start-NativeExecution -VerboseOutputOnError { & $makeappx pack / o / v / h SHA256 / d $ProductSourcePath / p ( Join-Path -Path $PWD -ChildPath " $packageName .msix " ) }
Write-Verbose " Created $packageName .msix " -Verbose
}
}
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
$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
}
2020-01-04 21:14:35 +01:00
}
# get all the file components from the files.wxs
$components = $filesAssetXml . GetElementsByTagName ( 'Component' )
$componentRefs = $filesAssetXml . GetElementsByTagName ( 'ComponentRef' )
$componentComparison = Compare-Object -ReferenceObject $components . id -DifferenceObject $componentRefs . id
if ( $componentComparison . Count -gt 0 ) {
$passed = $false
Write-Verbose " Rebuilding componentRefs " -Verbose
# add all the file components to the patch
foreach ( $component in $components )
{
$componentId = $component . Id
Write-Verbose " Removing $componentId " -Verbose
Remove-ComponentRefNode -Id $componentId -XmlDoc $newFilesAssetXml -XmlNsManager $xmlns
}
# There is only one ComponentGroup.
# So we get all of them and select the first one.
$componentGroups = @ ( $newFilesAssetXml . GetElementsByTagName ( 'ComponentGroup' ) )
$componentGroup = $componentGroups [ 0 ]
# add all the file components to the patch
foreach ( $component in $components )
{
$id = $component . Id
Write-Verbose " Adding $id " -Verbose
$newComponentRef = New-XmlElement -XmlDoc $newFilesAssetXml -LocalName 'ComponentRef' -Node $componentGroup -PassThru -NamespaceUri 'http://schemas.microsoft.com/wix/2006/wi'
New-XmlAttribute -XmlDoc $newFilesAssetXml -Element $newComponentRef -Name 'Id' -Value $id
}
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 '. "
2019-03-12 20:13:55 +01:00
if ( $env:TF_BUILD )
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 )
{
2019-08-28 18:44:02 +02:00
if ( $packageBuildTokens . length -gt 4 )
{
# MSIX will fail if it is more characters
$packageBuildTokens = $packageBuildTokens . Substring ( 0 , 4 )
}
2018-02-22 22:31:00 +01:00
$packageVersion = $packageVersion + '.' + $packageBuildTokens
}
else
{
$packageVersion = $packageVersion
}
}
$packageVersion
}
2019-01-16 01:28:52 +01:00
<#
. SYNOPSIS
Create a smaller framework dependent package based off fxdependent package for dotnet-sdk container images .
2019-02-26 21:56:29 +01:00
. PARAMETER Path
2019-01-16 01:28:52 +01:00
Path to the folder containing the fxdependent package .
2019-03-20 21:44:40 +01:00
. PARAMETER KeepWindowsRuntimes
Specify this switch if the Windows runtimes are to be kept .
2019-01-16 01:28:52 +01:00
#>
2019-02-26 21:56:29 +01:00
function ReduceFxDependentPackage
{
[ CmdletBinding ( ) ]
2019-01-16 01:28:52 +01:00
param (
2019-03-20 21:44:40 +01:00
[ Parameter ( Mandatory ) ] [ string ] $Path ,
[ switch ] $KeepWindowsRuntimes
2019-02-26 21:56:29 +01:00
)
2019-01-29 19:59:30 +01:00
2019-02-26 21:56:29 +01:00
if ( -not ( Test-Path $path ) )
{
throw " Path not found: $Path "
}
2019-01-29 19:59:30 +01:00
2019-02-26 21:56:29 +01:00
## Remove unnecessary files
$localeFolderToRemove = 'cs' , 'de' , 'es' , 'fr' , 'it' , 'ja' , 'ko' , 'pl' , 'pt-BR' , 'ru' , 'tr' , 'zh-Hans' , 'zh-Hant'
Get-ChildItem $Path -Recurse -Directory | Where-Object { $_ . Name -in $localeFolderToRemove } | ForEach-Object { Remove-Item $_ . FullName -Force -Recurse -Verbose }
2019-01-16 01:28:52 +01:00
2019-03-20 21:44:40 +01:00
Write-Log -message " Starting to cleanup runtime folders "
2019-02-26 21:56:29 +01:00
$runtimeFolder = Get-ChildItem $Path -Recurse -Directory -Filter 'runtimes'
2019-01-16 01:28:52 +01:00
2019-03-20 21:44:40 +01:00
$runtimeFolderPath = $runtimeFolder | Out-String
Write-Log -message $runtimeFolderPath
if ( $runtimeFolder . Count -eq 0 )
{
throw " runtimes folder not found under $Path "
}
Write-Log -message ( Get-ChildItem $Path | Out-String )
2019-02-26 21:56:29 +01:00
# donet SDK container image microsoft/dotnet:2.2-sdk supports the following:
# win10-x64 (Nano Server)
# win-arm (Nano Server)
# win-x64 to get PowerShell.Native components
# linux-musl-x64 (Alpine 3.8)
# linux-x64 (bionic / stretch)
# unix, linux, win for dependencies
# linux-arm and linux-arm64 for arm containers
# osx to run global tool on macOS
2019-03-20 21:44:40 +01:00
$runtimesToKeep = if ( $KeepWindowsRuntimes ) {
2019-02-26 21:56:29 +01:00
'win10-x64' , 'win-arm' , 'win-x64' , 'win'
2019-01-16 01:28:52 +01:00
} else {
2019-02-26 21:56:29 +01:00
'linux-x64' , 'linux-musl-x64' , 'unix' , 'linux' , 'linux-arm' , 'linux-arm64' , 'osx'
2019-01-16 01:28:52 +01:00
}
2019-02-26 21:56:29 +01:00
$runtimeFolder | ForEach-Object {
2019-03-20 21:44:40 +01:00
Get-ChildItem -Path $_ . FullName -Directory -Exclude $runtimesToKeep | Remove-Item -Force -Recurse -Verbose
2019-02-26 21:56:29 +01:00
}
2019-03-20 21:44:40 +01:00
## Remove the shim layer assemblies
Get-ChildItem -Path $Path -Filter " Microsoft.PowerShell.GlobalTool.Shim.* " | Remove-Item -Verbose
2019-02-26 21:56:29 +01:00
}
2019-01-22 20:25:25 +01:00
2019-02-26 21:56:29 +01:00
<#
. SYNOPSIS
Create a Global tool nuget package for PowerShell .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. DESCRIPTION
If the UnifiedPackage switch is present , then create a packag with both Windows and Unix runtimes .
Else create two packages , one for Windows and other for Linux .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. PARAMETER LinuxBinPath
Path to the folder containing the fxdependent package for Linux .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. PARAMETER WindowsBinPath
Path to the folder containing the fxdependent package for Windows .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. PARAMETER PackageVersion
Version for the NuGet package that will be generated .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. PARAMETER DestinationPath
Path to the folder where the generated packages will be copied to .
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
. PARAMETER UnifiedPackage
Create package with both Windows and Unix runtimes .
#>
function New-GlobalToolNupkg
{
[ CmdletBinding ( ) ]
param (
[ Parameter ( Mandatory ) ] [ string ] $LinuxBinPath ,
[ Parameter ( Mandatory ) ] [ string ] $WindowsBinPath ,
2019-07-13 02:18:11 +02:00
[ Parameter ( Mandatory ) ] [ string ] $WindowsDesktopBinPath ,
2019-02-26 21:56:29 +01:00
[ Parameter ( Mandatory ) ] [ string ] $PackageVersion ,
[ Parameter ( Mandatory ) ] [ string ] $DestinationPath ,
[ Parameter ( ParameterSetName = " UnifiedPackage " ) ] [ switch ] $UnifiedPackage
)
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
$packageInfo = @ ( )
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
Remove-Item -Path ( Join-Path $LinuxBinPath 'libcrypto.so.1.0.0' ) -Verbose -Force -Recurse
Remove-Item -Path ( Join-Path $LinuxBinPath 'libssl.so.1.0.0' ) -Verbose -Force -Recurse
2019-01-16 01:28:52 +01:00
2019-03-20 21:44:40 +01:00
## Remove unnecessary xml files
2019-07-13 02:18:11 +02:00
Get-ChildItem -Path $LinuxBinPath , $WindowsBinPath , $WindowsDesktopBinPath -Filter * . xml | Remove-Item -Verbose
2019-03-20 21:44:40 +01:00
2019-02-26 21:56:29 +01:00
if ( $UnifiedPackage )
{
Write-Log " Creating a unified package "
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell " ; Type = " Unified " }
2019-07-13 02:18:11 +02:00
$ShimDllPath = Join-Path $WindowsDesktopBinPath " Microsoft.PowerShell.GlobalTool.Shim.dll "
2019-02-26 21:56:29 +01:00
}
else
{
Write-Log " Reducing size of Linux package "
ReduceFxDependentPackage -Path $LinuxBinPath
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
Write-Log " Reducing size of Windows package "
2019-03-20 21:44:40 +01:00
ReduceFxDependentPackage -Path $WindowsBinPath -KeepWindowsRuntimes
2019-01-16 01:28:52 +01:00
2019-07-13 02:18:11 +02:00
Write-Log " Reducing size of WindowsDesktop package "
ReduceFxDependentPackage -Path $WindowsDesktopBinPath -KeepWindowsRuntimes
2019-02-26 21:56:29 +01:00
Write-Log " Creating a Linux and Windows packages "
2019-03-20 21:44:40 +01:00
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Linux.Alpine " ; Type = " PowerShell.Linux.Alpine " }
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Linux.x64 " ; Type = " PowerShell.Linux.x64 " }
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Linux.arm32 " ; Type = " PowerShell.Linux.arm32 " }
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Linux.arm64 " ; Type = " PowerShell.Linux.arm64 " }
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Windows.x64 " ; Type = " PowerShell.Windows.x64 " }
$packageInfo + = @ { RootFolder = ( New-TempFolder ) ; PackageName = " PowerShell.Windows.arm32 " ; Type = " PowerShell.Windows.arm32 " }
2019-02-26 21:56:29 +01:00
}
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
$packageInfo | ForEach-Object {
2019-10-19 01:49:25 +02:00
$ridFolder = New-Item -Path ( Join-Path $_ . RootFolder " tools/netcoreapp3.1/any " ) -ItemType Directory
2019-01-29 19:59:30 +01:00
2019-03-20 21:44:40 +01:00
$packageType = $_ . Type
switch ( $packageType )
2019-02-26 21:56:29 +01:00
{
" Unified "
{
$winFolder = New-Item ( Join-Path $ridFolder " win " ) -ItemType Directory
$unixFolder = New-Item ( Join-Path $ridFolder " unix " ) -ItemType Directory
2019-01-16 01:28:52 +01:00
2019-07-13 02:18:11 +02:00
Write-Log " Copying runtime assemblies from $WindowsDesktopBinPath "
Copy-Item " $WindowsDesktopBinPath \* " -Destination $winFolder -Recurse
2019-01-16 01:28:52 +01:00
2019-02-26 21:56:29 +01:00
Write-Log " Copying runtime assemblies from $LinuxBinPath "
Copy-Item " $LinuxBinPath \* " -Destination $unixFolder -Recurse
Write-Log " Copying shim dll from $ShimDllPath "
Copy-Item $ShimDllPath -Destination $ridFolder
$shimConfigFile = Join-Path ( Split-Path $ShimDllPath -Parent ) 'Microsoft.PowerShell.GlobalTool.Shim.runtimeconfig.json'
Write-Log " Copying shim config file from $shimConfigFile "
Copy-Item $shimConfigFile -Destination $ridFolder -ErrorAction Stop
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f ( Split-Path $ShimDllPath -Leaf )
}
2019-03-20 21:44:40 +01:00
" PowerShell.Linux.Alpine "
2019-02-26 21:56:29 +01:00
{
2019-03-20 21:44:40 +01:00
Write-Log " Copying runtime assemblies from $LinuxBinPath for $packageType "
2019-02-26 21:56:29 +01:00
Copy-Item " $LinuxBinPath /* " -Destination $ridFolder -Recurse
2019-03-20 21:44:40 +01:00
Remove-Item -Path $ridFolder / runtimes / linux-arm -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-arm64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / osx -Recurse -Force
2019-02-26 21:56:29 +01:00
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
}
2019-03-20 21:44:40 +01:00
" PowerShell.Linux.x64 "
2019-02-26 21:56:29 +01:00
{
2019-03-20 21:44:40 +01:00
Write-Log " Copying runtime assemblies from $LinuxBinPath for $packageType "
Copy-Item " $LinuxBinPath /* " -Destination $ridFolder -Recurse
Remove-Item -Path $ridFolder / runtimes / linux-arm -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-arm64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-musl -x64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / osx -Recurse -Force
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
}
" PowerShell.Linux.arm32 "
{
Write-Log " Copying runtime assemblies from $LinuxBinPath for $packageType "
Copy-Item " $LinuxBinPath /* " -Destination $ridFolder -Recurse
Remove-Item -Path $ridFolder / runtimes / linux-arm64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-musl -x64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-x64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / osx -Recurse -Force
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
}
" PowerShell.Linux.arm64 "
{
Write-Log " Copying runtime assemblies from $LinuxBinPath for $packageType "
Copy-Item " $LinuxBinPath /* " -Destination $ridFolder -Recurse
Remove-Item -Path $ridFolder / runtimes / linux-arm -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-musl -x64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / linux-x64 -Recurse -Force
Remove-Item -Path $ridFolder / runtimes / osx -Recurse -Force
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
}
" PowerShell.Windows.x64 "
{
2019-07-13 02:18:11 +02:00
Write-Log " Copying runtime assemblies from $WindowsDesktopBinPath for $packageType "
Copy-Item " $WindowsDesktopBinPath /* " -Destination $ridFolder -Recurse
2019-03-20 21:44:40 +01:00
Remove-Item -Path $ridFolder / runtimes / win-arm -Recurse -Force
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
}
" PowerShell.Windows.arm32 "
{
Write-Log " Copying runtime assemblies from $WindowsBinPath for $packageType "
2019-02-26 21:56:29 +01:00
Copy-Item " $WindowsBinPath /* " -Destination $ridFolder -Recurse
2019-03-20 21:44:40 +01:00
Remove-Item -Path $ridFolder / runtimes / win-x64 -Recurse -Force
2019-02-26 21:56:29 +01:00
$toolSettings = $packagingStrings . GlobalToolSettingsFile -f " pwsh.dll "
2019-01-16 01:28:52 +01:00
}
}
2019-02-26 21:56:29 +01:00
$packageName = $_ . PackageName
$nuSpec = $packagingStrings . GlobalToolNuSpec -f $packageName , $PackageVersion
$nuSpec | Out-File -FilePath ( Join-Path $_ . RootFolder " $packageName .nuspec " ) -Encoding ascii
$toolSettings | Out-File -FilePath ( Join-Path $ridFolder " DotnetToolSettings.xml " ) -Encoding ascii
Write-Log " Creating a package: $packageName "
New-NugetPackage -NuSpecPath $_ . RootFolder -PackageDestinationPath $DestinationPath
2019-01-16 01:28:52 +01:00
}
}