2016-02-24 08:21:00 +08:00
# Use the .NET Core APIs to determine the current platform; if a runtime
# exception is thrown, we are on FullCLR, not .NET Core.
#
2016-03-05 04:11:01 +08:00
# TODO: import Microsoft.PowerShell.Platform instead
2016-02-22 09:23:43 +08:00
try {
$Runtime = [ System.Runtime.InteropServices.RuntimeInformation ]
$OSPlatform = [ System.Runtime.InteropServices.OSPlatform ]
2016-03-05 04:11:01 +08:00
$IsCore = $true
$IsLinux = $Runtime :: IsOSPlatform ( $OSPlatform :: Linux )
$IsOSX = $Runtime :: IsOSPlatform ( $OSPlatform :: OSX )
$IsWindows = $Runtime :: IsOSPlatform ( $OSPlatform :: Windows )
2016-02-22 09:23:43 +08:00
} catch [ System.Management.Automation.RuntimeException ] {
2016-03-05 04:11:01 +08:00
$IsCore = $false
$IsLinux = $false
$IsOSX = $false
$IsWindows = $true
2016-02-22 09:23:43 +08:00
}
2016-02-22 08:21:04 +08:00
2016-04-02 05:41:13 +08:00
function Start-PSBuild {
2016-03-12 08:19:05 +08:00
[ CmdletBinding ( DefaultParameterSetName = 'CoreCLR' ) ]
2016-02-22 07:06:39 +08:00
param (
2016-02-24 08:21:00 +08:00
[ switch ] $Restore ,
2016-03-08 08:12:50 +08:00
[ switch ] $Clean ,
2016-03-12 08:19:05 +08:00
2016-03-04 07:54:52 +08:00
# These runtimes must match those in project.json
# We do not use ValidateScript since we want tab completion
[ ValidateSet ( " ubuntu.14.04-x64 " ,
" centos.7.1-x64 " ,
" win7-x64 " ,
" win10-x64 " ,
" osx.10.10-x64 " ,
" osx.10.11-x64 " ) ]
2016-03-12 08:19:05 +08:00
[ Parameter ( ParameterSetName = 'CoreCLR' ) ]
[ string ] $Runtime ,
[ Parameter ( ParameterSetName = 'FullCLR' ) ]
[ switch ] $FullCLR ,
[ Parameter ( ParameterSetName = 'FullCLR' ) ]
2016-03-16 04:06:26 +08:00
[ string ] $cmakeGenerator = " Visual Studio 14 2015 " ,
2016-03-12 08:19:05 +08:00
[ Parameter ( ParameterSetName = 'FullCLR' ) ]
[ ValidateSet ( " Debug " ,
2016-04-02 05:41:13 +08:00
" Release " ) ]
[ string ] $msbuildConfiguration = " Release "
2016-02-24 08:21:00 +08:00
)
2016-02-22 07:06:39 +08:00
2016-04-02 05:41:13 +08:00
function precheck([string]$command , [ string ] $missedMessage ) {
2016-03-12 08:19:05 +08:00
$c = Get-Command $command -ErrorAction SilentlyContinue
2016-04-02 05:41:13 +08:00
if ( -not $c ) {
2016-03-12 08:19:05 +08:00
Write-Warning $missedMessage
return $false
2016-04-02 05:41:13 +08:00
} else {
return $true
2016-03-12 08:19:05 +08:00
}
}
2016-04-02 05:41:13 +08:00
function log([string]$message ) {
2016-03-12 10:24:43 +08:00
Write-Host -Foreground Green $message
}
2016-04-02 03:14:09 +08:00
# simplify ParameterSetNames
2016-04-02 05:41:13 +08:00
if ( $PSCmdlet . ParameterSetName -eq 'FullCLR' ) {
2016-03-12 08:19:05 +08:00
$FullCLR = $true
}
# verify we have all tools in place to do the build
$precheck = precheck 'dotnet' " Build dependency 'dotnet' not found in PATH! See: https://dotnet.github.io/getting-started/ "
2016-04-02 05:41:13 +08:00
if ( $FullCLR ) {
2016-03-12 08:19:05 +08:00
# cmake is needed to build powershell.exe
$precheck = $precheck -and ( precheck 'cmake' 'cmake not found. You can install it from https://chocolatey.org/packages/cmake.portable' )
2016-04-02 05:41:13 +08:00
2016-03-12 08:19:05 +08:00
# msbuild is needed to build powershell.exe
2016-03-19 02:50:52 +08:00
# msbuild is part of .NET Framework, we can try to get it from well-known location.
2016-04-02 05:41:13 +08:00
if ( -not ( Get-Command -Name msbuild -ErrorAction Ignore ) ) {
2016-03-19 02:50:52 +08:00
$env:path + = " ; ${env:SystemRoot} \Microsoft.Net\Framework\v4.0.30319 "
}
$precheck = $precheck -and ( precheck 'msbuild' 'msbuild not found. Install Visual Studio 2015.' )
2016-02-22 07:06:39 +08:00
}
2016-04-02 05:41:13 +08:00
# Abort if any precheck failed
if ( -not $precheck ) {
return
}
2016-02-22 07:06:39 +08:00
2016-03-12 10:24:43 +08:00
# define key build variables
2016-04-02 05:41:13 +08:00
if ( $FullCLR ) {
2016-03-12 08:19:05 +08:00
$Top = " $PSScriptRoot \src\Microsoft.PowerShell.ConsoleHost "
$framework = 'net451'
2016-04-02 05:41:13 +08:00
} else {
$Top = " $PSScriptRoot /src/Microsoft.PowerShell.Linux.Host "
2016-03-12 08:19:05 +08:00
$framework = 'netstandardapp1.5'
}
2016-03-12 10:24:43 +08:00
# handle Restore
2016-02-22 07:06:39 +08:00
if ( $Restore -Or -Not ( Test-Path " $Top /project.lock.json " ) ) {
2016-03-12 10:24:43 +08:00
log " Run dotnet restore "
2016-03-26 05:58:09 +08:00
$Arguments = @ ( " --verbosity " )
if ( $PSCmdlet . MyInvocation . BoundParameters [ " Verbose " ] . IsPresent ) {
2016-04-02 05:41:13 +08:00
$Arguments + = " Info "
} else {
$Arguments + = " Warning "
}
2016-03-26 05:58:09 +08:00
$Arguments + = " $PSScriptRoot "
dotnet restore $Arguments
2016-02-22 07:06:39 +08:00
}
2016-03-12 08:19:05 +08:00
# Build native components
if ( -not $FullCLR )
{
if ( $IsLinux -Or $IsOSX ) {
2016-03-12 10:24:43 +08:00
log " Start building native components "
2016-03-12 08:19:05 +08:00
$InstallCommand = if ( $IsLinux ) { " apt-get " } elseif ( $IsOSX ) { " brew " }
foreach ( $Dependency in " cmake " , " g++ " ) {
if ( -Not ( Get-Command $Dependency -ErrorAction SilentlyContinue ) ) {
throw " Build dependency ' $Dependency ' not found in PATH! Run ' $InstallCommand install $Dependency ' "
}
2016-02-22 07:06:39 +08:00
}
2016-03-12 08:19:05 +08:00
$Ext = if ( $IsLinux ) { " so " } elseif ( $IsOSX ) { " dylib " }
$Native = " $PSScriptRoot /src/libpsl-native "
2016-03-29 04:58:00 +08:00
$Lib = " $Top /libpsl-native. $Ext "
2016-03-12 08:19:05 +08:00
Write-Verbose " Building $Lib "
try {
Push-Location $Native
cmake -DCMAKE_BUILD_TYPE = Debug .
make -j
make test
} finally {
Pop-Location
}
2016-02-25 03:50:56 +08:00
2016-03-12 08:19:05 +08:00
if ( -Not ( Test-Path $Lib ) ) { throw " Compilation of $Lib failed " }
}
2016-02-22 07:06:39 +08:00
}
2016-03-12 08:19:05 +08:00
else
{
2016-03-12 10:24:43 +08:00
log " Start building native powershell.exe "
2016-03-12 08:19:05 +08:00
$build = " $PSScriptRoot /build "
if ( $Clean ) {
Remove-Item -Force -Recurse $build -ErrorAction SilentlyContinue
}
2016-02-22 07:06:39 +08:00
2016-03-12 08:19:05 +08:00
mkdir $build -ErrorAction SilentlyContinue
2016-04-02 05:41:13 +08:00
try {
2016-03-12 10:24:43 +08:00
Push-Location $build
2016-02-22 07:06:39 +08:00
2016-04-02 05:41:13 +08:00
if ( $cmakeGenerator ) {
2016-03-12 10:24:43 +08:00
cmake -G $cmakeGenerator . . \ src \ powershell-native
2016-04-02 05:41:13 +08:00
} else {
2016-03-12 08:19:05 +08:00
cmake . . \ src \ powershell-native
}
msbuild powershell . vcxproj / p: Configuration = $msbuildConfiguration
2016-04-02 03:14:09 +08:00
# cp -rec $msbuildConfiguration\* $Output
2016-04-02 05:41:13 +08:00
} finally {
Pop-Location
2016-03-12 08:19:05 +08:00
}
}
2016-02-22 07:06:39 +08:00
2016-03-12 10:24:43 +08:00
log " Building PowerShell "
2016-04-02 05:41:13 +08:00
2016-04-02 03:14:09 +08:00
$Arguments = " --framework " , $framework
2016-02-27 10:49:51 +08:00
if ( $IsLinux -Or $IsOSX ) { $Arguments + = " --configuration " , " Linux " }
if ( $Runtime ) { $Arguments + = " --runtime " , $Runtime }
2016-04-02 05:41:13 +08:00
log " Run dotnet build $Arguments from $pwd "
try {
2016-04-02 03:14:09 +08:00
# Relative paths do not work well if cwd is not changed to project
Push-Location $Top
dotnet build $Arguments
2016-04-02 05:41:13 +08:00
} finally {
2016-04-02 03:14:09 +08:00
Pop-Location
2016-03-12 08:19:05 +08:00
}
2016-02-22 07:06:39 +08:00
}
2016-04-02 05:41:13 +08:00
function Start-PSPackage {
2016-02-24 08:21:00 +08:00
# PowerShell packages use Semantic Versioning http://semver.org/
#
# Ubuntu and OS X packages are supported.
2016-02-22 08:21:04 +08:00
param (
2016-02-24 08:21:00 +08:00
[ string ] $Version ,
2016-02-27 10:51:13 +08:00
[ int ] $Iteration = 1 ,
[ ValidateSet ( " deb " , " osxpkg " , " rpm " ) ]
[ string ] $Type
2016-02-24 08:21:00 +08:00
)
2016-02-22 08:21:04 +08:00
2016-03-05 04:11:01 +08:00
if ( $IsWindows ) { throw " Building Windows packages is not yet supported! " }
2016-02-22 08:21:04 +08:00
if ( -Not ( Get-Command " fpm " -ErrorAction SilentlyContinue ) ) {
throw " Build dependency 'fpm' not found in PATH! See: https://github.com/jordansissel/fpm "
}
2016-02-24 08:21:00 +08:00
if ( -Not ( Test-Path " $PSScriptRoot /bin/powershell " ) ) {
2016-03-04 07:54:52 +08:00
throw " Please Start-PSBuild with the corresponding runtime for the package "
2016-02-24 08:21:00 +08:00
}
2016-02-22 08:21:04 +08:00
2016-02-24 08:21:00 +08:00
# Change permissions for packaging
chmod -R go = u " $PSScriptRoot /bin "
2016-02-22 08:21:04 +08:00
2016-02-24 08:21:00 +08:00
# Decide package output type
2016-02-27 10:51:13 +08:00
if ( -Not ( $Type ) ) {
$Type = if ( $IsLinux ) { " deb " } elseif ( $IsOSX ) { " osxpkg " }
Write-Warning " -Type was not specified, continuing with $Type "
}
2016-02-22 08:21:04 +08:00
2016-02-24 08:21:00 +08:00
# Use Git tag if not given a version
if ( -Not ( $Version ) ) {
$Version = ( git - -git -dir = " $PSScriptRoot /.git " describe ) -Replace '^v'
}
2016-02-27 10:51:13 +08:00
$libunwind = switch ( $Type ) {
" deb " { " libunwind8 " }
" rpm " { " libunwind " }
}
$libicu = switch ( $Type ) {
" deb " { " libicu52 " }
" rpm " { " libicu " }
}
2016-02-24 08:21:00 +08:00
# Build package
2016-02-22 08:21:04 +08:00
fpm - -force - -verbose `
- -name " powershell " `
- -version $Version `
- -iteration $Iteration `
- -maintainer " Andrew Schwartzmeyer <andschwa@microsoft.com> " `
- -vendor " Microsoft <mageng@microsoft.com> " `
- -url " https://github.com/PowerShell/PowerShell " `
- -license " Unlicensed " `
- -description " Open PowerShell on .NET Core\nPowerShell is an open-source, cross-platform, scripting language and rich object shell. Built upon .NET Core, it is also a C# REPL.\n " `
- -category " shells " `
2016-02-27 10:51:13 +08:00
- -depends $libunwind `
- -depends $libicu `
2016-02-22 08:21:04 +08:00
- -deb -build -depends " dotnet " `
- -deb -build -depends " cmake " `
- -deb -build -depends " g++ " `
2016-02-27 10:51:13 +08:00
-t $Type `
2016-02-22 08:21:04 +08:00
-s dir `
2016-02-24 08:21:00 +08:00
" $PSScriptRoot /bin/=/usr/local/share/powershell/ " `
" $PSScriptRoot /package/powershell=/usr/local/bin "
2016-02-22 08:21:04 +08:00
}
2016-02-21 06:35:46 +08:00
function Start-DevPSGitHub
2016-02-04 02:53:43 +08:00
{
param (
[ switch ] $ZapDisable ,
[ string[] ] $ArgumentList = '' ,
[ switch ] $LoadProfile ,
2016-02-04 09:25:51 +08:00
[ string ] $binDir = " $PSScriptRoot \binFull " ,
[ switch ] $NoNewWindow
2016-02-04 02:53:43 +08:00
)
try
{
if ( $LoadProfile -eq $false )
{
2016-02-04 09:25:51 +08:00
$ArgumentList = @ ( '-noprofile' ) + $ArgumentList
2016-02-04 02:53:43 +08:00
}
$env:DEVPATH = $binDir
if ( $ZapDisable )
{
2016-02-22 07:06:39 +08:00
$env:COMPLUS_ZapDisable = 1
2016-02-04 02:53:43 +08:00
}
2016-02-22 07:06:39 +08:00
if ( -Not ( Test-Path $binDir \ powershell . exe . config ) )
2016-02-04 02:53:43 +08:00
{
$configContents = @"
2016-02-22 07:06:39 +08:00
< ? xml version = " 1.0 " encoding = " utf-8 " ? >
< configuration >
2016-02-04 02:53:43 +08:00
< runtime >
< developmentMode developerInstallation = " true " / >
< / runtime >
< / configuration >
" @
$configContents | Out-File -Encoding Ascii $binDir \ powershell . exe . config
}
2016-02-22 07:06:39 +08:00
# splatting for the win
2016-02-04 09:25:51 +08:00
$startProcessArgs = @ {
FilePath = " $binDir \powershell.exe "
ArgumentList = " $ArgumentList "
2016-02-22 07:06:39 +08:00
}
2016-02-05 05:19:24 +08:00
if ( $NoNewWindow ) {
$startProcessArgs . NoNewWindow = $true
$startProcessArgs . Wait = $true
}
2016-02-22 07:06:39 +08:00
2016-02-04 09:25:51 +08:00
Start-Process @startProcessArgs
2016-02-04 02:53:43 +08:00
}
finally
{
ri env : DEVPATH
if ( $ZapDisable )
{
ri env : COMPLUS_ZapDisable
}
}
2016-02-21 06:35:46 +08:00
}
2016-03-23 07:00:20 +08:00
## this function is from Dave Wyatt's answer on
## http://stackoverflow.com/questions/22002748/hashtables-from-convertfrom-json-have-different-type-from-powershells-built-in-h
function Convert-PSObjectToHashtable
{
param (
[ Parameter ( ValueFromPipeline ) ]
$InputObject
)
process
{
if ( $null -eq $InputObject ) { return $null }
if ( $InputObject -is [ System.Collections.IEnumerable ] -and $InputObject -isnot [ string ] )
{
$collection = @ (
foreach ( $object in $InputObject ) { Convert-PSObjectToHashtable $object }
)
Write-Output -NoEnumerate $collection
}
elseif ( $InputObject -is [ psobject ] )
{
$hash = @ { }
foreach ( $property in $InputObject . PSObject . Properties )
{
$hash [ $property . Name ] = Convert-PSObjectToHashtable $property . Value
}
$hash
}
else
{
$InputObject
}
}
}
<#
. EXAMPLE Copy-SubmoduleFiles # copy files FROM submodule TO src/<project> folders
. EXAMPLE Copy-SubmoduleFiles -ToSubmodule # copy files FROM src/<project> folders TO submodule
#>
function Copy-SubmoduleFiles {
2016-04-02 05:41:13 +08:00
2016-03-23 07:00:20 +08:00
[ CmdletBinding ( ) ]
param (
2016-03-24 07:57:59 +08:00
[ string ] $mappingFilePath = " $PSScriptRoot /mapping.json " ,
2016-03-23 07:00:20 +08:00
[ switch ] $ToSubmodule
)
2016-04-02 05:41:13 +08:00
2016-03-23 07:00:20 +08:00
if ( -not ( Test-Path $mappingFilePath ) )
{
throw " Mapping file not found in $mappingFilePath "
}
$m = cat -Raw $mappingFilePath | ConvertFrom-Json | Convert-PSObjectToHashtable
# mapping.json assumes the root folder
Push-Location $PSScriptRoot
try
{
$m . GetEnumerator ( ) | % {
if ( $ToSubmodule )
{
cp $_ . Value $_ . Key -Verbose: $Verbose
}
2016-04-02 05:41:13 +08:00
else
2016-03-23 07:00:20 +08:00
{
mkdir ( Split-Path $_ . Value ) -ErrorAction SilentlyContinue > $null
2016-04-02 05:41:13 +08:00
cp $_ . Key $_ . Value -Verbose: $Verbose
2016-03-23 07:00:20 +08:00
}
}
}
finally
{
Pop-Location
}
}
<#
. EXAMPLE Create-MappingFile # create mapping.json in the root folder from project.json files
#>
function New-MappingFile
{
param (
2016-03-30 05:17:19 +08:00
[ string ] $mappingFilePath = " $PSScriptRoot /mapping.json " ,
[ switch ] $IgnoreCompileFiles ,
2016-03-31 05:13:36 +08:00
[ switch ] $Ignoreresource
2016-03-23 07:00:20 +08:00
)
function Get-MappingPath([string]$project , [ string ] $path )
{
if ( $project -match 'TypeCatalogGen' )
{
return Split-Path $path -Leaf
}
2016-04-02 05:41:13 +08:00
2016-03-23 07:00:20 +08:00
if ( $project -match 'Microsoft.Management.Infrastructure' )
{
return Split-Path $path -Leaf
}
return ( $path -replace '../monad/monad/src/' , '' )
}
$mapping = [ ordered ] @ { }
# assumes the root folder
Push-Location $PSScriptRoot
try
{
$projects = ls . \ src \ -Recurse -Depth 2 -Filter 'project.json'
$projects | % {
$project = Split-Path $_ . FullName
$json = cat -Raw -Path $_ . FullName | ConvertFrom-Json
2016-03-30 05:17:19 +08:00
if ( -not $IgnoreCompileFiles ) {
$json . compileFiles | % {
if ( $_ ) {
if ( -not $_ . EndsWith ( 'AssemblyInfo.cs' ) )
{
$fullPath = Join-Path $project ( Get-MappingPath -project $project -path $_ )
$mapping [ $_ . Replace ( '../' , 'src/' ) ] = ( $fullPath . Replace ( " $( $pwd . Path ) \ " , '' ) ) . Replace ( '\' , '/' )
}
}
}
}
2016-03-31 05:13:36 +08:00
if ( ( -not $Ignoreresource ) -and ( $json . resource ) ) {
2016-03-30 05:17:19 +08:00
$json . resource | % {
if ( $_ ) {
ls $_ . Replace ( '../' , 'src/' ) | % {
2016-03-31 05:13:36 +08:00
$fullPath = Join-Path $project ( Join-Path 'resources' $_ . Name )
2016-03-30 05:17:19 +08:00
$mapping [ $_ . FullName . Replace ( " $( $pwd . Path ) \ " , '' ) . Replace ( '\' , '/' ) ] = ( $fullPath . Replace ( " $( $pwd . Path ) \ " , '' ) ) . Replace ( '\' , '/' )
}
2016-03-23 07:00:20 +08:00
}
}
}
}
}
finally
{
Pop-Location
}
Set-Content -Value ( $mapping | ConvertTo-Json ) -Path $mappingFilePath -Encoding Ascii
}
2016-03-24 07:57:59 +08:00
function Get-InvertedOrderedMap
{
param (
$h
)
$res = [ ordered ] @ { }
foreach ( $q in $h . GetEnumerator ( ) ) {
if ( $res . Contains ( $q . Value ) )
{
throw " Cannot invert hashtable: duplicated key $( $q . Value ) "
}
$res [ $q . Value ] = $q . Key
}
return $res
}
<#
2016-04-02 05:41:13 +08:00
. EXAMPLE Send-GitDiffToSd -diffArg1 45555786714d656bd31cbce67dbccb89c433b9cb -diffArg2 45555786714d656bd31cbce67dbccb89c433b9cb ~ 1 -pathToAdmin d: \ e \ ps_dev \ admin
2016-03-24 07:57:59 +08:00
Apply a signle commit to admin folder
#>
function Send-GitDiffToSd
{
param (
[ Parameter ( Mandatory ) ]
[ string ] $diffArg1 ,
[ Parameter ( Mandatory ) ]
[ string ] $diffArg2 ,
[ Parameter ( Mandatory ) ]
[ string ] $pathToAdmin ,
[ string ] $mappingFilePath = " $PSScriptRoot /mapping.json " ,
[ switch ] $WhatIf
)
$patchPath = Join-Path ( get-command git ) . Source . . \ . . \ bin \ patch
$m = cat -Raw $mappingFilePath | ConvertFrom-Json | Convert-PSObjectToHashtable
$affectedFiles = git diff - -name -only $diffArg1 $diffArg2
$rev = Get-InvertedOrderedMap $m
foreach ( $file in $affectedFiles ) {
if ( $rev . Contains )
{
$sdFilePath = Join-Path $pathToAdmin $rev [ $file ] . Substring ( 'src/monad/' . Length )
$diff = git diff $diffArg1 $diffArg2 - - $file
if ( $diff )
{
Write-Host -Foreground Green " Apply patch to $sdFilePath "
Set-Content -Value $diff -Path $env:TEMP \ diff -Encoding Ascii
if ( $WhatIf )
{
Write-Host -Foreground Green " Patch content "
cat $env:TEMP \ diff
}
2016-04-02 05:41:13 +08:00
else
2016-03-24 07:57:59 +08:00
{
2016-04-02 05:41:13 +08:00
& $patchPath - -binary -p1 $sdFilePath $env:TEMP \ diff
2016-03-24 07:57:59 +08:00
}
}
2016-04-02 05:41:13 +08:00
else
2016-03-24 07:57:59 +08:00
{
Write-Host -Foreground Green " No changes in $file "
}
}
2016-04-02 05:41:13 +08:00
else
2016-03-24 07:57:59 +08:00
{
Write-Host -Foreground Green " Ignore changes in $file , because there is no mapping for it "
}
2016-04-02 05:41:13 +08:00
}
2016-03-24 07:57:59 +08:00
}