From a53547ce7869228407e17a678124b6a4a738d040 Mon Sep 17 00:00:00 2001 From: Aditya Patwardhan Date: Mon, 26 Feb 2018 15:35:09 -0800 Subject: [PATCH] Add scripts to generate unified Nuget package (#6167) Remove the functions which generated Nuget packages for Windows. Add function New-UnifiedNugetPackage to generate nuget packages for each assembly with unix and windows runtimes. Add function New-NuSpec and New-ReferenceAssembly for creating the required items forNew-UnifiedNugetPackage. Add a sample for cross platform project with conditional compilation for Linux. Add function Publish-NugetToMyGet to publish nuget packages to powershell.myget.or --- .spelling | 1 + docs/host-powershell/README.md | 16 +- .../MyApp/MyApp.csproj | 13 + .../MyApp/Program.cs | 25 + .../NuGet.config | 8 + docs/maintainers/releasing.md | 13 +- tools/packaging/packaging.psd1 | 2 +- tools/packaging/packaging.psm1 | 580 +++++++++++++++++- tools/packaging/packaging.strings.psd1 | 45 ++ 9 files changed, 685 insertions(+), 18 deletions(-) create mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj create mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs create mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config diff --git a/.spelling b/.spelling index 834889fcd4..5dcaae610e 100644 --- a/.spelling +++ b/.spelling @@ -206,6 +206,7 @@ writingpestertests.md WSMan wsmansessionoption.cs xUnit +0-powershell-crossplatform #endregion #region ./tools/install-powershell.readme.md Overrides diff --git a/docs/host-powershell/README.md b/docs/host-powershell/README.md index 0b09af9dd0..506d5b71d8 100644 --- a/docs/host-powershell/README.md +++ b/docs/host-powershell/README.md @@ -1,5 +1,11 @@ # Host PowerShell Core in .NET Core Applications +## PowerShell Core v6.0.1 and Later + +The runtime assemblies for Windows, Linux and OSX are now published in NuGet package version 6.0.1.1 and above. + +Please see the [.NET Core Sample Application](#net-core-sample-application) section for an example that uses PowerShell Core `6.0.1.1` NuGet packages. + ## PowerShell Core v6.0.0-beta.3 and Later PowerShell Core is refactored in v6.0.0-beta.3 to remove the dependency on a customized `AssemblyLoadContext`. @@ -138,6 +144,7 @@ namespace Application.Test .NET Core SDK `2.0.0-preview1-005952` or higher is required. - [sample-dotnet2.0-powershell.beta.3](./sample-dotnet2.0-powershell.beta.3) - .NET Core `2.0.0` + PowerShell Core `beta.3` NuGet packages. .NET Core SDK `2.0.0-preview1-005952` or higher is required. +- [sample-dotnet2.0-powershell-crossplatform](./sample-dotnet2.0-powershell-crossplatform) - .Net Core `2.0.0` + PowerShell Core `6.0.1.1` NuGet packages. You can find the sample application project `"MyApp"` in each of the above 3 sample folders. To build the sample project, run the following commands (make sure the required .NET Core SDK is in use): @@ -147,6 +154,9 @@ dotnet restore .\MyApp\MyApp.csproj dotnet publish .\MyApp -c release -r win10-x64 ``` +For cross platform project there is no need to specify `-r win10-x64`. +The runtime for the build machine's platform will automatically be selected. + Then you can run `MyApp.exe` from the publish folder and see the results: ```none @@ -161,9 +171,3 @@ Evaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS C System.Management.Automation.ActionPreference System.Management.Automation.AliasAttribute ``` - -## Remaining Issue - -PowerShell Core builds separately for Windows and Unix, so the assemblies are different between Windows and Unix platforms. -Unfortunately, all PowerShell NuGet packages that have been published so far only contain PowerShell assemblies built specifically for Windows. -The issue [#3417](https://github.com/PowerShell/PowerShell/issues/3417) was opened to track publishing PowerShell NuGet packages for Unix platforms. diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj new file mode 100644 index 0000000000..5ff345cbbd --- /dev/null +++ b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp2.0 + MyApp + Exe + win10-x64;linux-x64;osx.10.12-x64 + + + + + + diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs new file mode 100644 index 0000000000..74676efba2 --- /dev/null +++ b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Management.Automation; + +namespace Application.Test +{ + public class Program + { + /// + /// Managed entry point shim, which starts the actual program + /// + public static int Main(string[] args) + { + using (PowerShell ps = PowerShell.Create()) + { + Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); + var results = ps.AddScript("Get-Command Write-Output").Invoke(); + Console.WriteLine(results[0].ToString()); + } + return 0; + } + } +} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config new file mode 100644 index 0000000000..58f8d2c9b6 --- /dev/null +++ b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/maintainers/releasing.md b/docs/maintainers/releasing.md index c345acab29..267f04b501 100644 --- a/docs/maintainers/releasing.md +++ b/docs/maintainers/releasing.md @@ -173,16 +173,9 @@ Start-PSPackage -Type zip -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64' ## NuGet Packages -In the `release` branch, run `Publish-NuGetFeed` to generate PowerShell NuGet packages: - -```powershell -# Assume the to-be-used release tag is 'v6.0.0-beta.1' -Publish-NuGetFeed -ReleaseTag 'v6.0.0-beta.1' -``` - -PowerShell NuGet packages and the corresponding symbol packages will be generated at `PowerShell/nuget-artifacts` by default. -Currently the NuGet packages published to [powershell-core feed][ps-core-feed] only contain assemblies built for Windows. -Maintainers are working on including the assemblies built for non-Windows platforms. +The NuGet packages for hosting PowerShell for Windows and non-Windows are being built in our release build pipeline. +The assemblies from the individual Windows and Linux builds are consumed and packed into NuGet packages. +These are then released to [powershell-core feed][ps-core-feed]. [ps-core-feed]: https://powershell.myget.org/gallery/powershell-core diff --git a/tools/packaging/packaging.psd1 b/tools/packaging/packaging.psd1 index fccf1a40f4..df08a59ee3 100644 --- a/tools/packaging/packaging.psd1 +++ b/tools/packaging/packaging.psd1 @@ -5,7 +5,7 @@ CompanyName="Microsoft Corporation" Copyright="Copyright (c) Microsoft Corporation. All rights reserved." ModuleVersion="1.0.0" PowerShellVersion="5.0" -CmdletsToExport=@("Start-PSPackage",'New-PSSignedBuildZip') +CmdletsToExport=@("Start-PSPackage",'New-PSSignedBuildZip', 'New-UnifiedNugetPackage') RootModule="packaging.psm1" RequiredModules = @("build") } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index 885c62e1cb..18782f53b3 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -283,7 +283,7 @@ function Start-PSPackage { } if ($PSCmdlet.ShouldProcess("Create NuPkg Package")) { - New-NugetPackage @Arguments + New-NugetContentPackage @Arguments } } "tar" { @@ -1229,7 +1229,585 @@ function New-ZipPackage } } +function CreateNugetPlatformFolder +{ + param( + [Parameter(Mandatory = $true)] + [string] $Platform, + + [Parameter(Mandatory = $true)] + [string] $PackageRuntimesFolder, + + [Parameter(Mandatory = $true)] + [string] $PlatformBinPath + ) + + $destPath = New-Item -ItemType Directory -Path (Join-Path $PackageRuntimesFolder "$Platform/lib/netstandard2.0") + $fullPath = Join-Path $PlatformBinPath $file + + if (-not(Test-Path $fullPath)) { + throw "File not found: $fullPath" + } + + Copy-Item -Path $fullPath -Destination $destPath + log "Copied $file to $Platform" +} + +<# +.SYNOPSIS +Creates NuGet packages containing linux, osx and Windows runtime assemblies. + +.DESCRIPTION +Creates a NuGet package for linux, osx, Windows runtimes for 32 bit, 64 bit and ARM. +The packages for Microsoft.PowerShell.Commands.Diagnostics, Microsoft.PowerShell.Commands.Management, +Microsoft.PowerShell.Commands.Utility, Microsoft.PowerShell.ConsoleHost, Microsoft.PowerShell.CoreCLR.Eventing, +Microsoft.PowerShell.SDK, Microsoft.PowerShell.Security, Microsoft.WSMan.Management, Microsoft.WSMan.Runtime, +System.Management.Automation are created. + +.PARAMETER PackagePath +Path where the package will be created. + +.PARAMETER PackageVersion +Version of the created package. + +.PARAMETER Winx86BinPath +Path to folder containing Windows x86 assemblies. + +.PARAMETER Winx64BinPath +Path to folder containing Windows x64 assemblies. + +.PARAMETER WinArm32BinPath +Path to folder containing Windows arm32 assemblies. + +.PARAMETER WinArm64BinPath +Path to folder containing Windows arm64 assemblies. + +.PARAMETER LinuxArm32BinPath +Path to folder containing linux arm32 assemblies. + +.PARAMETER LinuxBinPath +Path to folder containing linux x64 assemblies. + +.PARAMETER OsxBinPath +Path to folder containing osx assemblies. + +.PARAMETER GenAPIToolPath +Path to the GenAPI.exe tool. +#> +function New-UnifiedNugetPackage +{ + [CmdletBinding(SupportsShouldProcess = $true)] + param( + + [Parameter(Mandatory = $true)] + [string] $PackagePath, + + [Parameter(Mandatory = $true)] + [string] $PackageVersion, + + [Parameter(Mandatory = $true)] + [string] $Winx86BinPath, + + [Parameter(Mandatory = $true)] + [string] $Winx64BinPath, + + [Parameter(Mandatory = $true)] + [string] $WinArm32BinPath, + + [Parameter(Mandatory = $true)] + [string] $WinArm64BinPath, + + [Parameter(Mandatory = $true)] + [string] $LinuxArm32BinPath, + + [Parameter(Mandatory = $true)] + [string] $LinuxBinPath, + + [Parameter(Mandatory = $true)] + [string] $OsxBinPath, + + [Parameter(Mandatory = $true)] + [string] $GenAPIToolPath + ) + + if(-not $Environment.IsWindows) + { + throw "New-UnifiedNugetPackage can be only executed on Windows platform." + } + + $fileList = @( + "Microsoft.PowerShell.Commands.Diagnostics.dll", + "Microsoft.PowerShell.Commands.Management.dll", + "Microsoft.PowerShell.Commands.Utility.dll", + "Microsoft.PowerShell.ConsoleHost.dll", + "Microsoft.PowerShell.CoreCLR.Eventing.dll", + "Microsoft.PowerShell.Security.dll", + "Microsoft.PowerShell.SDK.dll", + "Microsoft.WSMan.Management.dll", + "Microsoft.WSMan.Runtime.dll", + "System.Management.Automation.dll") + + $linuxExceptionList = @( + "Microsoft.PowerShell.Commands.Diagnostics.dll", + "Microsoft.WSMan.Management.dll", + "Microsoft.WSMan.Runtime.dll") + + if ($PSCmdlet.ShouldProcess("Create nuget packages at: $PackagePath")) + { + + $refBinPath = New-TempFolder + $SnkFilePath = Join-Path $PSScriptRoot -ChildPath '../../src/signing/visualstudiopublic.snk' -Resolve + + # This is required only for first release since the nuget package version and System.Management.Automation.dll version do not match. + # The nuget package for SMA is 6.0.1.1, but the assembly version is going to be 6.0.1. + # For future releases where NuGet version and assembly versions are going to be same, this can be removed. + $forceSMAAssemblyVersion = '6.0.1' + New-ReferenceAssembly -linux64BinPath $linuxBinPath -RefAssemblyDestinationPath $refBinPath -RefAssemblyVersion $forceSMAAssemblyVersion -SnkFilePath $SnkFilePath -GenAPIToolPath $GenAPIToolPath + $refBinFullName = Join-Path $refBinPath 'System.Management.Automation.dll' + + foreach ($file in $fileList) + { + $tmpPackageRoot = New-TempFolder + # Remove '.dll' at the end + $fileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($file) + $filePackageFolder = New-Item (Join-Path $tmpPackageRoot $fileBaseName) -ItemType Directory -Force + $packageRuntimesFolder = New-Item (Join-Path $filePackageFolder.FullName 'runtimes') -ItemType Directory + + #region ref + $refFolder = New-Item (Join-Path $filePackageFolder.FullName 'ref/netstandard2.0') -ItemType Directory -Force + Copy-Item $refBinFullName -Destination $refFolder -Force + log "Copied file $refBinFullName to $refFolder" + #endregion ref + + $packageRuntimesFolderPath = $packageRuntimesFolder.FullName + + CreateNugetPlatformFolder -Platform 'win-x86' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winX86BinPath + CreateNugetPlatformFolder -Platform 'win-x64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winX64BinPath + CreateNugetPlatformFolder -Platform 'win-arm' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winArm32BinPath + CreateNugetPlatformFolder -Platform 'win-arm64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $winArm64BinPath + + if ($linuxExceptionList -notcontains $file ) + { + CreateNugetPlatformFolder -Platform 'linux-arm' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $linuxArm32BinPath + CreateNugetPlatformFolder -Platform 'linux-x64' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $linuxBinPath + CreateNugetPlatformFolder -Platform 'osx' -PackageRuntimesFolder $packageRuntimesFolderPath -PlatformBinPath $osxBinPath + } + + #region nuspec + # filed a tracking bug for automating generation of dependecy list: https://github.com/PowerShell/PowerShell/issues/6247 + $deps = [System.Collections.ArrayList]::new() + + switch ($fileBaseName) { + 'Microsoft.PowerShell.Commands.Diagnostics' { + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Management.Automation'), [tuple]::Create('version', $PackageVersion))) > $null + } + + 'Microsoft.PowerShell.Commands.Management' { + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.PowerShell.Security'), [tuple]::Create('version', $PackageVersion))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceProcess.ServiceController'), [tuple]::Create('version', '4.4.1'))) > $null + } + + 'Microsoft.PowerShell.Commands.Utility' { + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Management.Automation'), [tuple]::Create('version', $PackageVersion))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.CodeAnalysis.CSharp'), [tuple]::Create('version', '2.6.1'))) > $null + } + + 'Microsoft.PowerShell.ConsoleHost' { + $deps.Add([tuple]::Create( [tuple]::Create('id', 'System.Management.Automation'), [tuple]::Create('version', $PackageVersion))) > $null + $deps.Add([tuple]::Create( [tuple]::Create('id', 'Microsoft.ApplicationInsights'), [tuple]::Create('version', '2.4.0'))) > $null + } + + 'Microsoft.PowerShell.CoreCLR.Eventing' { + $deps.Add([tuple]::Create( [tuple]::Create('id', 'System.Security.Principal.Windows'), [tuple]::Create('version', '4.4.1'))) > $null + } + + '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 + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Data.SqlClient'), [tuple]::Create('version', '4.4.2'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.IO.Packaging'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Net.Http.WinHttpHandler'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceModel.Duplex'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceModel.Http'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceModel.NetTcp'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceModel.Primitives'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceModel.Security'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Text.Encodings.Web'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Threading.AccessControl'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Private.ServiceModel'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.NETCore.Windows.ApiSets'), [tuple]::Create('version', '1.0.1'))) > $null + $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 + } + + '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 + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.ServiceProcess.ServiceController'), [tuple]::Create('version', '4.4.1'))) > $null + } + + 'Microsoft.WSMan.Runtime' { + ## No dependencies + } + + 'System.Management.Automation' { + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.PowerShell.CoreCLR.Eventing'), [tuple]::Create('version', $PackageVersion))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.Win32.Registry.AccessControl'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'Newtonsoft.Json'), [tuple]::Create('version', '10.0.3'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.IO.FileSystem.AccessControl'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Security.AccessControl'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Security.Cryptography.Pkcs'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Security.Permissions'), [tuple]::Create('version', '4.4.1'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'System.Text.Encoding.CodePages'), [tuple]::Create('version', '4.4.0'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'Microsoft.Management.Infrastructure'), [tuple]::Create('version', '1.0.0-alpha08'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'PowerShell.Core.Instrumentation'), [tuple]::Create('version', '6.0.0-RC2'))) > $null + $deps.Add([tuple]::Create([tuple]::Create('id', 'libpsl'), [tuple]::Create('version', '6.0.0-rc'))) > $null + } + } + + New-NuSpec -PackageId $fileBaseName -PackageVersion $PackageVersion -Dependency $deps -FilePath (Join-Path $filePackageFolder.FullName "$fileBaseName.nuspec") + New-NugetPackage -NuSpecPath $filePackageFolder.FullName -PackageDestinationPath $PackagePath + } + + if(Test-Path $refBinPath) + { + Remove-Item $refBinPath -Recurse -Force -ErrorAction SilentlyContinue + } + + if(Test-Path $tmpPackageRoot) + { + Remove-Item $tmpPackageRoot -Recurse -Force -ErrorAction SilentlyContinue + } + } +} + +<# +.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 + ) + + if(-not $Environment.IsWindows) + { + throw "New-NuSpec can be only executed on Windows platform." + } + + $nuspecTemplate = $packagingStrings.NuspecTemplate -f $PackageId,$PackageVersion + $nuspecObj = [xml] $nuspecTemplate + + if ( ($Dependency -ne $null) -and $Dependency.Count -gt 0 ) { + + 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 + ) + + if(-not $Environment.IsWindows) + { + throw "New-ReferenceAssembly can be only executed on Windows platform." + } + + $genAPIFolder = New-TempFolder + $smaProjectFolder = New-Item -Path "$genAPIFolder/System.Management.Automation" -ItemType Directory -Force + $smaCs = Join-Path $smaProjectFolder 'System.Management.Automation.cs' + $smaCsFiltered = Join-Path $smaProjectFolder 'System.Management.Automation_Filtered.cs' + + log "Working directory: $genAPIFolder." + + #region GenAPI + + $genAPIExe = Get-ChildItem -Path "$GenAPIToolPath/*GenAPI.exe" -Recurse + + if(-not (Test-Path $genAPIExe)) + { + throw "GenAPI.exe was not found at: $GenAPIToolPath" + } + + log "GenAPI nuget package saved and expanded." + + $linuxSMAPath = Join-Path $Linux64BinPath "System.Management.Automation.dll" + + if(-not (Test-Path $linuxSMAPath)) + { + throw "System.Management.Automation.dll was not found at: $Linux64BinPath" + } + + $genAPIArgs = "$linuxSMAPath","-libPath:$Linux64BinPath" + log "GenAPI cmd: $genAPIExe $genAPIArgsString" + + Start-NativeExecution { & $genAPIExe $genAPIArgs } | Out-File $smaCs -Force + + log "Reference assembly file generated at: $smaCs" + + #endregion GenAPI + + #region Cleanup SMA.cs + + $patternsToRemove = @( + '[System.Management.Automation.ArgumentToEncodingTransformationAttribute]', + 'typeof(System.Security.AccessControl.FileSecurity)', + '[System.Management.Automation.ArgumentTypeConverterAttribute', + '[System.Runtime.CompilerServices.IteratorStateMachineAttribute', + '[Microsoft.PowerShell.Commands.ArgumentToModuleTransformationAttribute]', + '[Microsoft.PowerShell.Commands.SetStrictModeCommand.ArgumentToVersionTransformationAttribute]', + '[Microsoft.PowerShell.Commands.SetStrictModeCommand.ValidateVersionAttribute]', + '[System.Management.Automation.OutputTypeAttribute(typeof(System.Management.Automation.PSRemotingJob))]', + 'typeof(System.Management.Automation.LanguagePrimitives.EnumMultipleTypeConverter)', + '[System.Management.Automation.Internal.CommonParameters.ValidateVariableName]' + ) + + $reader = [System.IO.File]::OpenText($smaCs) + $writer = [System.IO.File]::CreateText($smaCsFiltered) + + while(($line = $reader.ReadLine()) -ne $null) + { + $match = $line | Select-String -Pattern $patternsToRemove -SimpleMatch + + if($match -ne $null) + { + $writer.WriteLine("//$line") + } + else + { + $writer.WriteLine($line) + } + } + if($reader -ne $null) + { + $reader.Close() + } + if($writer -ne $null) + { + $writer.Close() + } + + Move-Item $smaCsFiltered $smaCs -Force + + log "Reference assembly code cleanup complete." + + #endregion Cleanup SMA.cs + + #region Build SMA ref assembly + + try + { + Push-Location $smaProjectFolder + + $csProj = $packagingStrings.RefAssemblyCsProj -f $RefAssemblyVersion,$SnkFilePath + + $csProj | Out-File -FilePath "$smaProjectFolder/System.Management.Automation.csproj" -Force + + $packagingStrings.NugetConfigFile | Out-File -FilePath "$genAPIFolder/Nuget.config" -Force + + Start-NativeExecution { dotnet build -c Release } > $null + + $refBinPath = Join-Path $smaProjectFolder 'bin/Release/netstandard2.0/System.Management.Automation.dll' + + if($refBinPath -eq $null) + { + throw "Reference assembly was not built." + } + + Copy-Item $refBinPath $RefAssemblyDestinationPath -Force + + log "Reference assembly built and copied to $RefAssemblyDestinationPath" + } + finally + { + Pop-Location + } + + if(Test-Path $genAPIFolder) + { + Remove-Item $genAPIFolder -Recurse -Force -ErrorAction SilentlyContinue + } + + #endregion Build SMA ref assembly +} + +<# +.SYNOPSIS +Create a NuGet package from a nuspec. + +.DESCRIPTION +Creates a NuGet using the nuspec using at the specified folder. +It is expected that the lib / ref / runtime folders are welformed. +The genereated NuGet package is copied over to the $PackageDestinationPath + +.PARAMETER NuSpecPath +Path to the folder containing the nuspec file. + +.PARAMETER PackageDestinationPath +Path to which NuGet package should be copied. Destination is created if it does not exist. +#> + function New-NugetPackage +{ + [CmdletBinding()] + param( + [Parameter(Mandatory = $true)] + [string] $NuSpecPath, + + [Parameter(Mandatory = $true)] + [string] $PackageDestinationPath + ) + + $nuget = Get-Command -Type Application nuget -ErrorAction SilentlyContinue + + if($nuget -eq $null) + { + throw 'nuget application is not available in PATH' + } + + Push-Location $NuSpecPath + + Start-NativeExecution { nuget pack . } > $null + + if(-not (Test-Path $PackageDestinationPath)) + { + 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 + + if($nuget -eq $null) + { + throw 'nuget application is not available in PATH' + } + + Get-ChildItem $PackagePath | ForEach-Object { + log "Pushing $_ to PowerShell Myget" + 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 { [CmdletBinding(SupportsShouldProcess=$true)] param ( diff --git a/tools/packaging/packaging.strings.psd1 b/tools/packaging/packaging.strings.psd1 index ffec1a6cba..e44682c003 100644 --- a/tools/packaging/packaging.strings.psd1 +++ b/tools/packaging/packaging.strings.psd1 @@ -73,4 +73,49 @@ OsxDistributionTemplate = @' {2} '@ +NuspecTemplate = @' + + + + {0} + {1} + PowerShellRuntime + Powershell + microsoft,powershell + false + PowerShell runtime for hosting PowerShell + Copyright (c) Microsoft Corporation. All rights reserved. + en-US + + + + + +'@ +RefAssemblyCsProj = @' + + + netstandard2.0 + {0} + true + {1} + true + + + + + + + +'@ +NuGetConfigFile = @' + + + + + + + +'@ }