Initial work for the build process

This will create the bin folder on the root, and inside of it the full
output binaries from building the solution, and the nuget packages for
each component
This commit is contained in:
Pedro Lamas 2016-07-15 10:27:15 +01:00
Родитель d023540faf
Коммит ff5343858a
14 изменённых файлов: 1255 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Microsoft.Windows.Toolkit.Notifications.JavaScript</id>
<version>0.0.0</version>
<authors>Microsoft</authors>
<owners>microsoft, andrewbares</owners>
<projectUrl>https://github.com/anbare/NotificationsExtensions/wiki</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<summary>Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.</summary>
<description>The official NotificationsExtensions library from Microsoft. Supports JavaScript UWP projects (see NotificationsExtensions.Win10 for the C#/C++ version).
Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.
Supports adaptive tiles and adaptive/interactive toasts for Windows 10!</description>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<tags>notifications, win10, windows 10, tile, tiles, toast, toasts, badge, xml, uwp, javascript</tags>
<licenseUrl>https://raw.githubusercontent.com/anbare/NotificationsExtensions/master/LICENSE</licenseUrl>
</metadata>
<files>
<!--For JavaScript UWP apps-->
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.winmd" target="lib\Windows"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.pri" target="lib\Windows"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.pdb" target="lib\Windows"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\Windows"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\Windows\Microsoft.Windows.Toolkit.Notifications.winmd.xml"/>
<!--Need a targets file, since auto-generated reference uses CopyLocal, which makes it not work. This will mean we have duplicate
warnings, which generates a warning, but at least it's functional!-->
<file src="Microsoft.Windows.Toolkit.Notifications.JavaScript.targets" target="build\Windows\Microsoft.Windows.Toolkit.Notifications.JavaScript.targets"/>
</files>
</package>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Reference Include="Microsoft.Windows.Toolkit.Notifications.Windows">
<HintPath>$(MSBuildThisFileDirectory)..\..\lib\Windows\Microsoft.Windows.Toolkit.Notifications.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Reference Include="NotificationsExtensions">
<HintPath>$(MSBuildThisFileDirectory)..\..\lib\native\Microsoft.Windows.Toolkit.Notifications.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
</Reference>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>Microsoft.Windows.Toolkit.Notifications</id>
<version>0.0.0</version>
<authors>Microsoft</authors>
<owners>microsoft, andrewbares</owners>
<projectUrl>https://github.com/anbare/NotificationsExtensions/wiki</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<summary>Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.</summary>
<description>The official NotificationsExtensions library from Microsoft. C# and C++ UWP project types (see NotificationsExtensions.Win10.JavaScript for the JS version). Also works with C# portable class libraries and non-UWP C# projects like server projects.
Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.
Supports adaptive tiles and adaptive/interactive toasts for Windows 10!</description>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<tags>notifications, win10, windows 10, tile, tiles, toast, toasts, badge, xml, uwp, c#, csharp, c++</tags>
<licenseUrl>https://raw.githubusercontent.com/anbare/NotificationsExtensions/master/LICENSE</licenseUrl>
</metadata>
<files>
<!--For portable class libraries-->
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.Portable\Microsoft.Windows.Toolkit.Notifications.dll" target="lib\portable-net40+sl50+win+wpa81+wp80"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.Portable\Microsoft.Windows.Toolkit.Notifications.pdb" target="lib\portable-net40+sl50+win+wpa81+wp80"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.Portable\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\portable-net40+sl50+win+wpa81+wp80"/>
<!--For C++ UWP apps-->
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.winmd" target="lib\native"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.pri" target="lib\native"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.pdb" target="lib\native"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\native"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.WinRT\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\native\Microsoft.Windows.Toolkit.Notifications.winmd.xml"/>
<!--The above file is included so that IntelliSense summaries appear, there was a bug in VS causing them not to appear without this-->
<!--For modern portable libraries-->
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.NETStandard\Microsoft.Windows.Toolkit.Notifications.dll" target="lib\dotnet"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.NETStandard\Microsoft.Windows.Toolkit.Notifications.pdb" target="lib\dotnet"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.NETStandard\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\dotnet"/>
<!--For C# UWP apps-->
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.UWP\Microsoft.Windows.Toolkit.Notifications.dll" target="lib\uap10.0"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.UWP\Microsoft.Windows.Toolkit.Notifications.pdb" target="lib\uap10.0"/>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Notifications.UWP\Microsoft.Windows.Toolkit.Notifications.xml" target="lib\uap10.0"/>
<!--For C++ UWP apps-->
<file src="Microsoft.Windows.Toolkit.Notifications.native.targets" target="build\native\Microsoft.Windows.Toolkit.Notifications.targets"/>
</files>
</package>

Просмотреть файл

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.Windows.Toolkit.Services</id>
<version>0.5.0</version>
<title>UWP Toolkit Services</title>
<authors>Microsoft Corp</authors>
<owners>Microsoft Corp</owners>
<licenseUrl>https://github.com/deltakosh/UWPToolkit</licenseUrl>
<projectUrl>https://github.com/deltakosh/UWPToolkit</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This library enable access to diferent data source like Bing, Facebook, and Twitter.</description>
<releaseNotes>Initial internal release of core data services.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>UWP Toolkit Windows AppStudio Net Portable Twitter OAuth RSS Facebook Bing</tags>
<references>
<reference file="Microsoft.Windows.Toolkit.Services.dll" />
</references>
<dependencies>
<dependency id="Newtonsoft.Json" version="8.0.3" />
</dependencies>
</metadata>
<files>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.Services\Microsoft.Windows.Toolkit.Services.*" target="lib\portable-win81+wpa81" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.Windows.Toolkit.UI.Animations</id>
<version>0.0.0</version>
<title>UWP Toolkit Services</title>
<authors>Microsoft Corp</authors>
<owners>Microsoft Corp</owners>
<licenseUrl>https://github.com/deltakosh/UWPToolkit</licenseUrl>
<projectUrl>https://github.com/deltakosh/UWPToolkit</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This library enable access to diferent data source like Bing, Facebook, and Twitter.</description>
<releaseNotes>Initial internal release of core data services.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>UWP Toolkit Windows AppStudio Net Portable Twitter OAuth RSS Facebook Bing</tags>
<dependencies>
<dependency id="Microsoft.Windows.Toolkit" />
<dependency id="Microsoft.Windows.Toolkit.UI" />
</dependencies>
</metadata>
<files>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.UI.Animations\Microsoft.Windows.Toolkit.UI.Animations.*" target="lib\uap10.0" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.Windows.Toolkit.UI.Controls</id>
<version>0.0.0</version>
<title>UWP Toolkit Services</title>
<authors>Microsoft Corp</authors>
<owners>Microsoft Corp</owners>
<licenseUrl>https://github.com/deltakosh/UWPToolkit</licenseUrl>
<projectUrl>https://github.com/deltakosh/UWPToolkit</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This library enable access to diferent data source like Bing, Facebook, and Twitter.</description>
<releaseNotes>Initial internal release of core data services.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>UWP Toolkit Windows AppStudio Net Portable Twitter OAuth RSS Facebook Bing</tags>
<dependencies>
<dependency id="Microsoft.Windows.Toolkit" />
<dependency id="Microsoft.Windows.Toolkit.UI" />
<dependency id="Microsoft.Windows.Toolkit.UI.Animations" />
</dependencies>
</metadata>
<files>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.UI.Controls\Microsoft.Windows.Toolkit.UI.Controls.*" target="lib\uap10.0" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,23 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.Windows.Toolkit.UI</id>
<version>0.0.0</version>
<title>UWP Toolkit Services</title>
<authors>Microsoft Corp</authors>
<owners>Microsoft Corp</owners>
<licenseUrl>https://github.com/deltakosh/UWPToolkit</licenseUrl>
<projectUrl>https://github.com/deltakosh/UWPToolkit</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This library enable access to diferent data source like Bing, Facebook, and Twitter.</description>
<releaseNotes>Initial internal release of core data services.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>UWP Toolkit Windows AppStudio Net Portable Twitter OAuth RSS Facebook Bing</tags>
<dependencies>
<dependency id="Microsoft.Windows.Toolkit" />
</dependencies>
</metadata>
<files>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit.UI\Microsoft.Windows.Toolkit.UI.*" target="lib\uap10.0" />
</files>
</package>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<package>
<metadata>
<id>Microsoft.Windows.Toolkit</id>
<version>0.0.0</version>
<title>UWP Toolkit Services</title>
<authors>Microsoft Corp</authors>
<owners>Microsoft Corp</owners>
<licenseUrl>https://github.com/deltakosh/UWPToolkit</licenseUrl>
<projectUrl>https://github.com/deltakosh/UWPToolkit</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>This library enable access to diferent data source like Bing, Facebook, and Twitter.</description>
<releaseNotes>Initial internal release of core data services.</releaseNotes>
<copyright>Copyright 2016</copyright>
<tags>UWP Toolkit Windows AppStudio Net Portable Twitter OAuth RSS Facebook Bing</tags>
</metadata>
<files>
<file src="..\bin\binaries\Microsoft.Windows.Toolkit\Microsoft.Windows.Toolkit.*" target="lib\uap10.0" />
</files>
</package>

42
build/build.ps1 Normal file
Просмотреть файл

@ -0,0 +1,42 @@
param(
[string]$Task = "default",
[hashtable] $Parameters = @{},
[hashtable] $Properties = @{},
[switch]$Help
)
$path = Split-Path -Parent $MyInvocation.MyCommand.Definition
Import-Module "$path\tools\psake\psake.psm1"
try
{
if ($Help){
try {
Get-Help $MyInvocation.MyCommand.Definition -full
Write-Host "Available build tasks:"
Invoke-psake -nologo -docs
}
catch {
}
return
}
Invoke-psake "$path/default.ps1" -task $Task -properties $Properties -parameters $Parameters -nologo
if ($psake.build_success -eq $false)
{
exit 1
}
else
{
exit 0
}
}
finally
{
Remove-Module psake
}

68
build/default.ps1 Normal file
Просмотреть файл

@ -0,0 +1,68 @@
$psake.use_exit_on_error = $true
properties {
$baseDir = Resolve-Path ..
$buildDir = "$baseDir\build"
$sourceDir = "$baseDir"
$toolsDir = "$baseDir\build\tools"
$binDir = "$baseDir\bin"
$isAppVeyor = Test-Path -Path env:\APPVEYOR
$version = "2.2.1"
$tempDir = "$binDir\temp"
$binariesDir = "$binDir\binaries"
$nupkgDir = "$binDir\nupkg"
$nuget = "$toolsDir\nuget\nuget.exe"
}
Framework "4.6x86"
task default -depends ?
task Clean -description "Clean the output folder" {
if (Test-Path -path $binDir) {
WriteColoredOutput -ForegroundColor Green "Deleting Working Directory...`n"
Remove-Item $binDir -Recurse -Force
}
New-Item -Path $binDir -ItemType Directory | Out-Null
}
task Setup -description "Setup environment" {
WriteColoredOutput -ForegroundColor Green "Setup environment...`n"
if ($isAppVeyor) {
$script:version = $version -replace '([0-9]+(\.[0-9]+){2}).*', ('$1-dev' + $env:APPVEYOR_BUILD_NUMBER)
Update-AppveyorBuild -Version $script:version
}
else {
$script:version = $version
}
Exec { .$nuget restore $packagesConfig "$sourceDir\Windows App Toolkit.sln" } "Error pre-installing NuGet packages"
}
task Build -depends Clean, Setup -description "Build all projects and get the assemblies" {
New-Item -Path $binariesDir -ItemType Directory | Out-Null
Exec { msbuild "/t:Clean;Build" /p:Configuration=Release "/p:OutDir=$binariesDir" /p:GenerateProjectSpecificOutputFolder=true /p:TreatWarningsAsErrors=false /m "$sourceDir\Windows App Toolkit.sln" } "Error building $solutionFile"
}
task PackNuGet -depends Build -description "Create the NuGet packages" {
New-Item -Path $nupkgDir -ItemType Directory | Out-Null
Get-ChildItem $buildDir\*.nuspec | % {
$fullFilename = $_.FullName
Exec { .$nuget pack "$fullFilename" -Version "$script:version" -Output "$nupkgDir" } "Error packaging $projectName"
}
}
task ? -description "Show the help screen" {
WriteDocumentation
}

Двоичные данные
build/tools/nuget/NuGet.exe Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,53 @@
# Helper script for those who want to run psake without importing the module.
# Example run from PowerShell:
# .\psake.ps1 "default.ps1" "BuildHelloWord" "4.0"
# Must match parameter definitions for psake.psm1/invoke-psake
# otherwise named parameter binding fails
param(
[Parameter(Position=0,Mandatory=0)]
[string]$buildFile,
[Parameter(Position=1,Mandatory=0)]
[string[]]$taskList = @(),
[Parameter(Position=2,Mandatory=0)]
[string]$framework,
[Parameter(Position=3,Mandatory=0)]
[switch]$docs = $false,
[Parameter(Position=4,Mandatory=0)]
[System.Collections.Hashtable]$parameters = @{},
[Parameter(Position=5, Mandatory=0)]
[System.Collections.Hashtable]$properties = @{},
[Parameter(Position=6, Mandatory=0)]
[alias("init")]
[scriptblock]$initialization = {},
[Parameter(Position=7, Mandatory=0)]
[switch]$nologo = $false,
[Parameter(Position=8, Mandatory=0)]
[switch]$help = $false,
[Parameter(Position=9, Mandatory=0)]
[string]$scriptPath,
[Parameter(Position=10,Mandatory=0)]
[switch]$detailedDocs = $false
)
# setting $scriptPath here, not as default argument, to support calling as "powershell -File psake.ps1"
if (!$scriptPath) {
$scriptPath = $(Split-Path -parent $MyInvocation.MyCommand.path)
}
# '[p]sake' is the same as 'psake' but $Error is not polluted
remove-module [p]sake
import-module (join-path $scriptPath psake.psm1)
if ($help) {
Get-Help Invoke-psake -full
return
}
if ($buildFile -and (-not(test-path $buildFile))) {
$absoluteBuildFile = (join-path $scriptPath $buildFile)
if (test-path $absoluteBuildFile) {
$buildFile = $absoluteBuildFile
}
}
Invoke-psake $buildFile $taskList $framework $docs $parameters $properties $initialization $nologo $detailedDocs

Просмотреть файл

@ -0,0 +1,865 @@
# psake
# Copyright (c) 2012 James Kovacs
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#Requires -Version 2.0
#-- Public Module Functions --#
# .ExternalHelp psake.psm1-help.xml
function Invoke-Task
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)] [string]$taskName
)
Assert $taskName ($msgs.error_invalid_task_name)
$taskKey = $taskName.ToLower()
if ($currentContext.aliases.Contains($taskKey)) {
$taskName = $currentContext.aliases.$taskKey.Name
$taskKey = $taskName.ToLower()
}
$currentContext = $psake.context.Peek()
Assert ($currentContext.tasks.Contains($taskKey)) ($msgs.error_task_name_does_not_exist -f $taskName)
if ($currentContext.executedTasks.Contains($taskKey)) { return }
Assert (!$currentContext.callStack.Contains($taskKey)) ($msgs.error_circular_reference -f $taskName)
$currentContext.callStack.Push($taskKey)
$task = $currentContext.tasks.$taskKey
$precondition_is_valid = & $task.Precondition
if (!$precondition_is_valid) {
WriteColoredOutput ($msgs.precondition_was_false -f $taskName) -foregroundcolor Cyan
} else {
if ($taskKey -ne 'default') {
if ($task.PreAction -or $task.PostAction) {
Assert ($task.Action -ne $null) ($msgs.error_missing_action_parameter -f $taskName)
}
if ($task.Action) {
try {
foreach($childTask in $task.DependsOn) {
Invoke-Task $childTask
}
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
$currentContext.currentTaskName = $taskName
& $currentContext.taskSetupScriptBlock
if ($task.PreAction) {
& $task.PreAction
}
if ($currentContext.config.taskNameFormat -is [ScriptBlock]) {
& $currentContext.config.taskNameFormat $taskName
} else {
WriteColoredOutput ($currentContext.config.taskNameFormat -f $taskName) -foregroundcolor Cyan
}
foreach ($variable in $task.requiredVariables) {
Assert ((test-path "variable:$variable") -and ((get-variable $variable).Value -ne $null)) ($msgs.required_variable_not_set -f $variable, $taskName)
}
& $task.Action
if ($task.PostAction) {
& $task.PostAction
}
& $currentContext.taskTearDownScriptBlock
$task.Duration = $stopwatch.Elapsed
} catch {
if ($task.ContinueOnError) {
"-"*70
WriteColoredOutput ($msgs.continue_on_error -f $taskName,$_) -foregroundcolor Yellow
"-"*70
$task.Duration = $stopwatch.Elapsed
} else {
throw $_
}
}
} else {
# no action was specified but we still execute all the dependencies
foreach($childTask in $task.DependsOn) {
Invoke-Task $childTask
}
}
} else {
foreach($childTask in $task.DependsOn) {
Invoke-Task $childTask
}
}
Assert (& $task.Postcondition) ($msgs.postcondition_failed -f $taskName)
}
$poppedTaskKey = $currentContext.callStack.Pop()
Assert ($poppedTaskKey -eq $taskKey) ($msgs.error_corrupt_callstack -f $taskKey,$poppedTaskKey)
$currentContext.executedTasks.Push($taskKey)
}
# .ExternalHelp psake.psm1-help.xml
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd),
[Parameter(Position=2,Mandatory=0)][int]$maxRetries = 0,
[Parameter(Position=3,Mandatory=0)][string]$retryTriggerErrorPattern = $null
)
$tryCount = 1
do {
try {
$global:lastexitcode = 0
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
break
}
catch [Exception]
{
if ($tryCount -gt $maxRetries) {
throw $_
}
if ($retryTriggerErrorPattern -ne $null) {
$isMatch = [regex]::IsMatch($_.Exception.Message, $retryTriggerErrorPattern)
if ($isMatch -eq $false) {
throw $_
}
}
Write-Host "Try $tryCount failed, retrying again in 1 second..."
$tryCount++
[System.Threading.Thread]::Sleep([System.TimeSpan]::FromSeconds(1))
}
}
while ($true)
}
# .ExternalHelp psake.psm1-help.xml
function Assert
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)]$conditionToCheck,
[Parameter(Position=1,Mandatory=1)]$failureMessage
)
if (!$conditionToCheck) {
throw ("Assert: " + $failureMessage)
}
}
# .ExternalHelp psake.psm1-help.xml
function Task
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][string]$name = $null,
[Parameter(Position=1,Mandatory=0)][scriptblock]$action = $null,
[Parameter(Position=2,Mandatory=0)][scriptblock]$preaction = $null,
[Parameter(Position=3,Mandatory=0)][scriptblock]$postaction = $null,
[Parameter(Position=4,Mandatory=0)][scriptblock]$precondition = {$true},
[Parameter(Position=5,Mandatory=0)][scriptblock]$postcondition = {$true},
[Parameter(Position=6,Mandatory=0)][switch]$continueOnError = $false,
[Parameter(Position=7,Mandatory=0)][string[]]$depends = @(),
[Parameter(Position=8,Mandatory=0)][string[]]$requiredVariables = @(),
[Parameter(Position=9,Mandatory=0)][string]$description = $null,
[Parameter(Position=10,Mandatory=0)][string]$alias = $null,
[Parameter(Position=11,Mandatory=0)][string]$maxRetries = 0,
[Parameter(Position=12,Mandatory=0)][string]$retryTriggerErrorPattern = $null
)
if ($name -eq 'default') {
Assert (!$action) ($msgs.error_default_task_cannot_have_action)
}
$newTask = @{
Name = $name
DependsOn = $depends
PreAction = $preaction
Action = $action
PostAction = $postaction
Precondition = $precondition
Postcondition = $postcondition
ContinueOnError = $continueOnError
Description = $description
Duration = [System.TimeSpan]::Zero
RequiredVariables = $requiredVariables
Alias = $alias
MaxRetries = $maxRetries
RetryTriggerErrorPattern = $retryTriggerErrorPattern
}
$taskKey = $name.ToLower()
$currentContext = $psake.context.Peek()
Assert (!$currentContext.tasks.ContainsKey($taskKey)) ($msgs.error_duplicate_task_name -f $name)
$currentContext.tasks.$taskKey = $newTask
if($alias)
{
$aliasKey = $alias.ToLower()
Assert (!$currentContext.aliases.ContainsKey($aliasKey)) ($msgs.error_duplicate_alias_name -f $alias)
$currentContext.aliases.$aliasKey = $newTask
}
}
# .ExternalHelp psake.psm1-help.xml
function Properties {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$properties
)
$psake.context.Peek().properties += $properties
}
# .ExternalHelp psake.psm1-help.xml
function Include {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][string]$fileNamePathToInclude
)
Assert (test-path $fileNamePathToInclude -pathType Leaf) ($msgs.error_invalid_include_path -f $fileNamePathToInclude)
$psake.context.Peek().includes.Enqueue((Resolve-Path $fileNamePathToInclude));
}
# .ExternalHelp psake.psm1-help.xml
function FormatTaskName {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)]$format
)
$psake.context.Peek().config.taskNameFormat = $format
}
# .ExternalHelp psake.psm1-help.xml
function TaskSetup {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$setup
)
$psake.context.Peek().taskSetupScriptBlock = $setup
}
# .ExternalHelp psake.psm1-help.xml
function TaskTearDown {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$teardown
)
$psake.context.Peek().taskTearDownScriptBlock = $teardown
}
# .ExternalHelp psake.psm1-help.xml
function Framework {
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][string]$framework
)
$psake.context.Peek().config.framework = $framework
ConfigureBuildEnvironment
}
# .ExternalHelp psake.psm1-help.xml
function Invoke-psake {
[CmdletBinding()]
param(
[Parameter(Position = 0, Mandatory = 0)][string] $buildFile,
[Parameter(Position = 1, Mandatory = 0)][string[]] $taskList = @(),
[Parameter(Position = 2, Mandatory = 0)][string] $framework,
[Parameter(Position = 3, Mandatory = 0)][switch] $docs = $false,
[Parameter(Position = 4, Mandatory = 0)][hashtable] $parameters = @{},
[Parameter(Position = 5, Mandatory = 0)][hashtable] $properties = @{},
[Parameter(Position = 6, Mandatory = 0)][alias("init")][scriptblock] $initialization = {},
[Parameter(Position = 7, Mandatory = 0)][switch] $nologo = $false,
[Parameter(Position = 8, Mandatory = 0)][switch] $detailedDocs = $false
)
try {
if (-not $nologo) {
"psake version {0}`nCopyright (c) 2010-2014 James Kovacs & Contributors`n" -f $psake.version
}
if (!$buildFile) {
$buildFile = $psake.config_default.buildFileName
}
elseif (!(test-path $buildFile -pathType Leaf) -and (test-path $psake.config_default.buildFileName -pathType Leaf)) {
# If the $config.buildFileName file exists and the given "buildfile" isn 't found assume that the given
# $buildFile is actually the target Tasks to execute in the $config.buildFileName script.
$taskList = $buildFile.Split(', ')
$buildFile = $psake.config_default.buildFileName
}
# Execute the build file to set up the tasks and defaults
Assert (test-path $buildFile -pathType Leaf) ($msgs.error_build_file_not_found -f $buildFile)
$psake.build_script_file = get-item $buildFile
$psake.build_script_dir = $psake.build_script_file.DirectoryName
$psake.build_success = $false
$psake.context.push(@{
"taskSetupScriptBlock" = {};
"taskTearDownScriptBlock" = {};
"executedTasks" = new-object System.Collections.Stack;
"callStack" = new-object System.Collections.Stack;
"originalEnvPath" = $env:path;
"originalDirectory" = get-location;
"originalErrorActionPreference" = $global:ErrorActionPreference;
"tasks" = @{};
"aliases" = @{};
"properties" = @();
"includes" = new-object System.Collections.Queue;
"config" = CreateConfigurationForNewContext $buildFile $framework
})
LoadConfiguration $psake.build_script_dir
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
set-location $psake.build_script_dir
LoadModules
$frameworkOldValue = $framework
. $psake.build_script_file.FullName
$currentContext = $psake.context.Peek()
if ($framework -ne $frameworkOldValue) {
writecoloredoutput $msgs.warning_deprecated_framework_variable -foregroundcolor Yellow
$currentContext.config.framework = $framework
}
ConfigureBuildEnvironment
while ($currentContext.includes.Count -gt 0) {
$includeFilename = $currentContext.includes.Dequeue()
. $includeFilename
}
if ($docs -or $detailedDocs) {
WriteDocumentation($detailedDocs)
CleanupEnvironment
return
}
foreach ($key in $parameters.keys) {
if (test-path "variable:\$key") {
set-item -path "variable:\$key" -value $parameters.$key -WhatIf:$false -Confirm:$false | out-null
} else {
new-item -path "variable:\$key" -value $parameters.$key -WhatIf:$false -Confirm:$false | out-null
}
}
# The initial dot (.) indicates that variables initialized/modified in the propertyBlock are available in the parent scope.
foreach ($propertyBlock in $currentContext.properties) {
. $propertyBlock
}
foreach ($key in $properties.keys) {
if (test-path "variable:\$key") {
set-item -path "variable:\$key" -value $properties.$key -WhatIf:$false -Confirm:$false | out-null
}
}
# Simple dot sourcing will not work. We have to force the script block into our
# module's scope in order to initialize variables properly.
. $MyInvocation.MyCommand.Module $initialization
# Execute the list of tasks or the default task
if ($taskList) {
foreach ($task in $taskList) {
invoke-task $task
}
} elseif ($currentContext.tasks.default) {
invoke-task default
} else {
throw $msgs.error_no_default_task
}
WriteColoredOutput ("`n" + $msgs.build_success + "`n") -foregroundcolor Green
WriteTaskTimeSummary $stopwatch.Elapsed
$psake.build_success = $true
} catch {
$currentConfig = GetCurrentConfigurationOrDefault
if ($currentConfig.verboseError) {
$error_message = "{0}: An Error Occurred. See Error Details Below: `n" -f (Get-Date)
$error_message += ("-" * 70) + "`n"
$error_message += "Error: {0}`n" -f (ResolveError $_ -Short)
$error_message += ("-" * 70) + "`n"
$error_message += ResolveError $_
$error_message += ("-" * 70) + "`n"
$error_message += "Script Variables" + "`n"
$error_message += ("-" * 70) + "`n"
$error_message += get-variable -scope script | format-table | out-string
} else {
# ($_ | Out-String) gets error messages with source information included.
$error_message = "Error: {0}: `n{1}" -f (Get-Date), (ResolveError $_ -Short)
}
$psake.build_success = $false
# if we are running in a nested scope (i.e. running a psake script from a psake script) then we need to re-throw the exception
# so that the parent script will fail otherwise the parent script will report a successful build
$inNestedScope = ($psake.context.count -gt 1)
if ( $inNestedScope ) {
throw $_
} else {
if (!$psake.run_by_psake_build_tester) {
WriteColoredOutput $error_message -foregroundcolor Red
}
}
} finally {
CleanupEnvironment
}
}
#-- Private Module Functions --#
function WriteColoredOutput {
param(
[string] $message,
[System.ConsoleColor] $foregroundcolor
)
$currentConfig = GetCurrentConfigurationOrDefault
if ($currentConfig.coloredOutput -eq $true) {
if (($Host.UI -ne $null) -and ($Host.UI.RawUI -ne $null) -and ($Host.UI.RawUI.ForegroundColor -ne $null)) {
$previousColor = $Host.UI.RawUI.ForegroundColor
$Host.UI.RawUI.ForegroundColor = $foregroundcolor
}
}
$message
if ($previousColor -ne $null) {
$Host.UI.RawUI.ForegroundColor = $previousColor
}
}
function LoadModules {
$currentConfig = $psake.context.peek().config
if ($currentConfig.modules) {
$scope = $currentConfig.moduleScope
$global = [string]::Equals($scope, "global", [StringComparison]::CurrentCultureIgnoreCase)
$currentConfig.modules | foreach {
resolve-path $_ | foreach {
"Loading module: $_"
$module = import-module $_ -passthru -DisableNameChecking -global:$global
if (!$module) {
throw ($msgs.error_loading_module -f $_.Name)
}
}
}
""
}
}
function LoadConfiguration {
param(
[string] $configdir = $PSScriptRoot
)
$psakeConfigFilePath = (join-path $configdir "psake-config.ps1")
if (test-path $psakeConfigFilePath -pathType Leaf) {
try {
$config = GetCurrentConfigurationOrDefault
. $psakeConfigFilePath
} catch {
throw "Error Loading Configuration from psake-config.ps1: " + $_
}
}
}
function GetCurrentConfigurationOrDefault() {
if ($psake.context.count -gt 0) {
return $psake.context.peek().config
} else {
return $psake.config_default
}
}
function CreateConfigurationForNewContext {
param(
[string] $buildFile,
[string] $framework
)
$previousConfig = GetCurrentConfigurationOrDefault
$config = new-object psobject -property @{
buildFileName = $previousConfig.buildFileName;
framework = $previousConfig.framework;
taskNameFormat = $previousConfig.taskNameFormat;
verboseError = $previousConfig.verboseError;
coloredOutput = $previousConfig.coloredOutput;
modules = $previousConfig.modules;
moduleScope = $previousConfig.moduleScope;
}
if ($framework) {
$config.framework = $framework;
}
if ($buildFile) {
$config.buildFileName = $buildFile;
}
return $config
}
function ConfigureBuildEnvironment {
$framework = $psake.context.peek().config.framework
if ($framework -cmatch '^((?:\d+\.\d+)(?:\.\d+){0,1})(x86|x64){0,1}$') {
$versionPart = $matches[1]
$bitnessPart = $matches[2]
} else {
throw ($msgs.error_invalid_framework -f $framework)
}
$versions = $null
$buildToolsVersions = $null
switch ($versionPart) {
'1.0' {
$versions = @('v1.0.3705')
}
'1.1' {
$versions = @('v1.1.4322')
}
'2.0' {
$versions = @('v2.0.50727')
}
'3.0' {
$versions = @('v2.0.50727')
}
'3.5' {
$versions = @('v3.5', 'v2.0.50727')
}
'4.0' {
$versions = @('v4.0.30319')
}
{($_ -eq '4.5.1') -or ($_ -eq '4.5.2')} {
$versions = @('v4.0.30319')
$buildToolsVersions = @('14.0', '12.0')
}
'4.6' {
$versions = @('v4.0.30319')
$buildToolsVersions = @('14.0')
}
default {
throw ($msgs.error_unknown_framework -f $versionPart, $framework)
}
}
$bitness = 'Framework'
if ($versionPart -ne '1.0' -and $versionPart -ne '1.1') {
switch ($bitnessPart) {
'x86' {
$bitness = 'Framework'
$buildToolsKey = 'MSBuildToolsPath32'
}
'x64' {
$bitness = 'Framework64'
$buildToolsKey = 'MSBuildToolsPath'
}
{ [string]::IsNullOrEmpty($_) } {
$ptrSize = [System.IntPtr]::Size
switch ($ptrSize) {
4 {
$bitness = 'Framework'
$buildToolsKey = 'MSBuildToolsPath32'
}
8 {
$bitness = 'Framework64'
$buildToolsKey = 'MSBuildToolsPath'
}
default {
throw ($msgs.error_unknown_pointersize -f $ptrSize)
}
}
}
default {
throw ($msgs.error_unknown_bitnesspart -f $bitnessPart, $framework)
}
}
}
$frameworkDirs = @()
if ($buildToolsVersions -ne $null) {
foreach($ver in $buildToolsVersions) {
if (Test-Path "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\$ver") {
$frameworkDirs += (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\$ver" -Name $buildToolsKey).$buildToolsKey
}
}
}
$frameworkDirs = $frameworkDirs + @($versions | foreach { "$env:windir\Microsoft.NET\$bitness\$_\" })
for ($i = 0; $i -lt $frameworkDirs.Count; $i++) {
$dir = $frameworkDirs[$i]
if ($dir -Match "\$\(Registry:HKEY_LOCAL_MACHINE(.*?)@(.*)\)") {
$key = "HKLM:" + $matches[1]
$name = $matches[2]
$dir = (Get-ItemProperty -Path $key -Name $name).$name
$frameworkDirs[$i] = $dir
}
}
$frameworkDirs | foreach { Assert (test-path $_ -pathType Container) ($msgs.error_no_framework_install_dir_found -f $_)}
$env:path = ($frameworkDirs -join ";") + ";$env:path"
# if any error occurs in a PS function then "stop" processing immediately
# this does not effect any external programs that return a non-zero exit code
$global:ErrorActionPreference = "Stop"
}
function CleanupEnvironment {
if ($psake.context.Count -gt 0) {
$currentContext = $psake.context.Peek()
$env:path = $currentContext.originalEnvPath
Set-Location $currentContext.originalDirectory
$global:ErrorActionPreference = $currentContext.originalErrorActionPreference
[void] $psake.context.Pop()
}
}
function SelectObjectWithDefault
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]
[PSObject]
$InputObject,
[string]
$Name,
$Value
)
process {
if ($_ -eq $null) { $Value }
elseif ($_ | Get-Member -Name $Name) {
$_.$Name
}
elseif (($_ -is [Hashtable]) -and ($_.Keys -contains $Name)) {
$_.$Name
}
else { $Value }
}
}
# borrowed from Jeffrey Snover http://blogs.msdn.com/powershell/archive/2006/12/07/resolve-error.aspx
# modified to better handle SQL errors
function ResolveError
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true)]
$ErrorRecord=$Error[0],
[Switch]
$Short
)
process {
if ($_ -eq $null) { $_ = $ErrorRecord }
$ex = $_.Exception
if (-not $Short) {
$error_message = "`nErrorRecord:{0}ErrorRecord.InvocationInfo:{1}Exception:`n{2}"
$formatted_errorRecord = $_ | format-list * -force | out-string
$formatted_invocationInfo = $_.InvocationInfo | format-list * -force | out-string
$formatted_exception = ''
$i = 0
while ($ex -ne $null) {
$i++
$formatted_exception += ("$i" * 70) + "`n" +
($ex | format-list * -force | out-string) + "`n"
$ex = $ex | SelectObjectWithDefault -Name 'InnerException' -Value $null
}
return $error_message -f $formatted_errorRecord, $formatted_invocationInfo, $formatted_exception
}
$lastException = @()
while ($ex -ne $null) {
$lastMessage = $ex | SelectObjectWithDefault -Name 'Message' -Value ''
$lastException += ($lastMessage -replace "`n", '')
if ($ex -is [Data.SqlClient.SqlException]) {
$lastException += "(Line [$($ex.LineNumber)] " +
"Procedure [$($ex.Procedure)] Class [$($ex.Class)] " +
" Number [$($ex.Number)] State [$($ex.State)] )"
}
$ex = $ex | SelectObjectWithDefault -Name 'InnerException' -Value $null
}
$shortException = $lastException -join ' --> '
$header = $null
$current = $_
$header = (($_.InvocationInfo |
SelectObjectWithDefault -Name 'PositionMessage' -Value '') -replace "`n", ' '),
($_ | SelectObjectWithDefault -Name 'Message' -Value ''),
($_ | SelectObjectWithDefault -Name 'Exception' -Value '') |
? { -not [String]::IsNullOrEmpty($_) } |
Select -First 1
$delimiter = ''
if ((-not [String]::IsNullOrEmpty($header)) -and
(-not [String]::IsNullOrEmpty($shortException)))
{ $delimiter = ' [<<==>>] ' }
return "$($header)$($delimiter)Exception: $($shortException)"
}
}
function WriteDocumentation($showDetailed) {
$currentContext = $psake.context.Peek()
if ($currentContext.tasks.default) {
$defaultTaskDependencies = $currentContext.tasks.default.DependsOn
} else {
$defaultTaskDependencies = @()
}
$docs = $currentContext.tasks.Keys | foreach-object {
if ($_ -eq "default") {
return
}
$task = $currentContext.tasks.$_
new-object PSObject -property @{
Name = $task.Name;
Alias = $task.Alias;
Description = $task.Description;
"Depends On" = $task.DependsOn -join ", "
Default = if ($defaultTaskDependencies -contains $task.Name) { $true }
}
}
if ($showDetailed) {
$docs | sort 'Name' | format-list -property Name,Alias,Description,"Depends On",Default
} else {
$docs | sort 'Name' | format-table -autoSize -wrap -property Name,Alias,"Depends On",Default,Description
}
}
function WriteTaskTimeSummary($invokePsakeDuration) {
if ($psake.context.count -gt 0) {
"-" * 70
"Build Time Report"
"-" * 70
$list = @()
$currentContext = $psake.context.Peek()
while ($currentContext.executedTasks.Count -gt 0) {
$taskKey = $currentContext.executedTasks.Pop()
$task = $currentContext.tasks.$taskKey
if ($taskKey -eq "default") {
continue
}
$list += new-object PSObject -property @{
Name = $task.Name;
Duration = $task.Duration
}
}
[Array]::Reverse($list)
$list += new-object PSObject -property @{
Name = "Total:";
Duration = $invokePsakeDuration
}
# using "out-string | where-object" to filter out the blank line that format-table prepends
$list | format-table -autoSize -property Name,Duration | out-string -stream | where-object { $_ }
}
}
DATA msgs {
convertfrom-stringdata @'
error_invalid_task_name = Task name should not be null or empty string.
error_task_name_does_not_exist = Task {0} does not exist.
error_circular_reference = Circular reference found for task {0}.
error_missing_action_parameter = Action parameter must be specified when using PreAction or PostAction parameters for task {0}.
error_corrupt_callstack = Call stack was corrupt. Expected {0}, but got {1}.
error_invalid_framework = Invalid .NET Framework version, {0} specified.
error_unknown_framework = Unknown .NET Framework version, {0} specified in {1}.
error_unknown_pointersize = Unknown pointer size ({0}) returned from System.IntPtr.
error_unknown_bitnesspart = Unknown .NET Framework bitness, {0}, specified in {1}.
error_no_framework_install_dir_found = No .NET Framework installation directory found at {0}.
error_bad_command = Error executing command {0}.
error_default_task_cannot_have_action = 'default' task cannot specify an action.
error_duplicate_task_name = Task {0} has already been defined.
error_duplicate_alias_name = Alias {0} has already been defined.
error_invalid_include_path = Unable to include {0}. File not found.
error_build_file_not_found = Could not find the build file {0}.
error_no_default_task = 'default' task required.
error_loading_module = Error loading module {0}.
warning_deprecated_framework_variable = Warning: Using global variable $framework to set .NET framework version used is deprecated. Instead use Framework function or configuration file psake-config.ps1.
required_variable_not_set = Variable {0} must be set to run task {1}.
postcondition_failed = Postcondition failed for task {0}.
precondition_was_false = Precondition was false, not executing task {0}.
continue_on_error = Error in task {0}. {1}
build_success = Build Succeeded!
'@
}
import-localizeddata -bindingvariable msgs -erroraction silentlycontinue
$script:psake = @{}
$psake.version = "4.4.1" # contains the current version of psake
$psake.context = new-object system.collections.stack # holds onto the current state of all variables
$psake.run_by_psake_build_tester = $false # indicates that build is being run by psake-BuildTester
$psake.config_default = new-object psobject -property @{
buildFileName = "default.ps1";
framework = "4.0";
taskNameFormat = "Executing {0}";
verboseError = $false;
coloredOutput = $true;
modules = $null;
moduleScope = "";
} # contains default configuration, can be overriden in psake-config.ps1 in directory with psake.psm1 or in directory with current build script
$psake.build_success = $false # indicates that the current build was successful
$psake.build_script_file = $null # contains a System.IO.FileInfo for the current build script
$psake.build_script_dir = "" # contains a string with fully-qualified path to current build script
LoadConfiguration
export-modulemember -function Invoke-psake, Invoke-Task, Task, Properties, Include, FormatTaskName, TaskSetup, TaskTearDown, Framework, Assert, Exec -variable psake