Added build directory and created working test PSake target in build\build.ps1
Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/84abcb4d Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/84abcb4d Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/84abcb4d Branch: refs/heads/api-work Commit: 84abcb4d6d72950bc2cde6353c10e4833caf56ac Parents: 1023525 Author: Shad Storhaug <[email protected]> Authored: Mon Apr 10 21:37:16 2017 +0700 Committer: Shad Storhaug <[email protected]> Committed: Mon Apr 10 21:37:16 2017 +0700 ---------------------------------------------------------------------- Lucene.Net.Portable.sln | 19 +- Lucene.Net.sln | 5 + build/build.ps1 | 139 +++++++ build/psake.cmd | 14 + build/psake.ps1 | 53 +++ build/psake.psd1 | 31 ++ build/psake.psm1 | 925 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1178 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/Lucene.Net.Portable.sln ---------------------------------------------------------------------- diff --git a/Lucene.Net.Portable.sln b/Lucene.Net.Portable.sln index 6ec3b5e..cda3808 100644 --- a/Lucene.Net.Portable.sln +++ b/Lucene.Net.Portable.sln @@ -70,8 +70,11 @@ EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Sandbox", "src\Lucene.Net.Sandbox\Lucene.Net.Sandbox.xproj", "{232EF140-BDE1-42BE-9D29-E88A87DD98D9}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Sandbox", "src\Lucene.Net.Tests.Sandbox\Lucene.Net.Tests.Sandbox.xproj", "{7865CBC8-2C6B-462C-ACF5-B2C4D60D93C9}" +EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Highlighter", "src\Lucene.Net.Tests.Highlighter\Lucene.Net.Tests.Highlighter.xproj", "{C708701D-4318-469F-9822-49A80386CFEA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{EFA10A77-2975-493E-A360-677686B52EAA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -312,6 +315,14 @@ Global {C2349F0D-FB66-4544-9C33-4D87F73C6004}.Release|Any CPU.Build.0 = Release|Any CPU {C2349F0D-FB66-4544-9C33-4D87F73C6004}.Release|x86.ActiveCfg = Release|Any CPU {C2349F0D-FB66-4544-9C33-4D87F73C6004}.Release|x86.Build.0 = Release|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|x86.ActiveCfg = Debug|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|x86.Build.0 = Debug|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|Any CPU.Build.0 = Release|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|x86.ActiveCfg = Release|Any CPU + {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|x86.Build.0 = Release|Any CPU {35C347F4-24B2-4BE5-8117-A0E3001551CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35C347F4-24B2-4BE5-8117-A0E3001551CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {35C347F4-24B2-4BE5-8117-A0E3001551CE}.Debug|x86.ActiveCfg = Debug|Any CPU @@ -344,14 +355,6 @@ Global {7865CBC8-2C6B-462C-ACF5-B2C4D60D93C9}.Release|Any CPU.Build.0 = Release|Any CPU {7865CBC8-2C6B-462C-ACF5-B2C4D60D93C9}.Release|x86.ActiveCfg = Release|Any CPU {7865CBC8-2C6B-462C-ACF5-B2C4D60D93C9}.Release|x86.Build.0 = Release|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|x86.ActiveCfg = Debug|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Debug|x86.Build.0 = Debug|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|Any CPU.Build.0 = Release|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|x86.ActiveCfg = Release|Any CPU - {D48E1C62-CFD2-41A0-B430-AEBC48580282}.Release|x86.Build.0 = Release|Any CPU {C708701D-4318-469F-9822-49A80386CFEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C708701D-4318-469F-9822-49A80386CFEA}.Debug|Any CPU.Build.0 = Debug|Any CPU {C708701D-4318-469F-9822-49A80386CFEA}.Debug|x86.ActiveCfg = Debug|Any CPU http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/Lucene.Net.sln ---------------------------------------------------------------------- diff --git a/Lucene.Net.sln b/Lucene.Net.sln index 073a3c4..07b0efe 100644 --- a/Lucene.Net.sln +++ b/Lucene.Net.sln @@ -82,6 +82,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Highlighter", "s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Highlighter", "src\Lucene.Net.Tests.Highlighter\Lucene.Net.Tests.Highlighter.csproj", "{FBCD6AFE-0A5C-4399-8044-99C58D2912D1}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9811D53E-7CC9-4FAB-AB08-ED2D5DE7C7BB}" + ProjectSection(SolutionItems) = preProject + build\build.ps1 = build\build.ps1 + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/build/build.ps1 ---------------------------------------------------------------------- diff --git a/build/build.ps1 b/build/build.ps1 new file mode 100644 index 0000000..d56f8df --- /dev/null +++ b/build/build.ps1 @@ -0,0 +1,139 @@ + properties { + [string]$base_directory = Resolve-Path "..\." + [string]$release_directory = "$base_directory\release" + [string]$source_directory = "$base_directory" + [string]$tools_directory = "$base_directory\lib" + [string]$nuget_package_directory = "$release_directory\packagesource" + + [string]$packageVersion = "1.0.0" + [string]$version = "0.0.0" + [string]$configuration = "Release" + + [string]$common_assembly_info = "$base_directory\src\CommonAssemblyInfo.cs" + [string]$copyright_year = [DateTime]::Today.Year.ToString() #Get the current year from the system + [string]$copyright = "Copyright © 2006 - $copyright_year The Apache Software Foundation" + [string]$company_name = "The Apache Software Foundation" + [string]$product_name = "Lucene.Net" + + #test paramters + [string]$frameworks_to_test = "net451,netcoreapp1.0" + [string]$where +} + +task default -depends Build + +task Clean -description "This task cleans up the build directory" { + #Remove-Item $release_directory -Force -Recurse -ErrorAction SilentlyContinue +} + +task Init -description "This task makes sure the build environment is correctly setup" { + & where.exe dotnet.exe + + if ($LASTEXITCODE -ne 0) { + Write-Error "Could not find dotnet CLI in PATH. Please install the .NET Core 1.1 SDK." + } + + & dotnet.exe --version + Write-Host "Base Directory: $base_directory" + Write-Host "Release Directory: $release_directory" + Write-Host "Source Directory: $source_directory" + Write-Host "Tools Directory: $tools_directory" + Write-Host "NuGet Package Directory: $nuget_package_directory" + Write-Host "Version: $version" + Write-Host "Package Version: $packageVersion" + Write-Host "Configuration: $configuration" + + #If version is not passed in, parse it from $packageVersion + if ($version -eq "0.0.0" -or [string]::IsNullOrEmpty($version)) { + $version = $packageVersion + if ($version.Contains("-") -eq $true) { + $version = $version.SubString(0, $version.IndexOf("-")) + } + Write-Host "Updated version to: $version" + } + + Ensure-Directory-Exists "$release_directory" + + #ensure we have the latest version of NuGet + #exec { + # &"$tools_directory\nuget\nuget.exe" update -self + #} -ErrorAction SilentlyContinue +} + +task Restore -depends Clean -description "This task runs NuGet package restore" { + #& dotnet.exe restore +} + +#task Compile -depends Clean, Init, Restore -description "This task compiles the solution" -PreAction { Write-Host "Pre-action (compile)" } -Action { +# Write-Host "Compile" +#} -PostAction { Write-Host "Post-action (compile)" } + +#task Pack -depends Compile -description "This tasks creates the NuGet packages" -PreAction { Write-Host "Pre-action (pack)" } -Action { +# Write-Host "Pack" +# Start-Sleep 5 +#} -PostAction { Write-Host "Post-action (pack)" } + +task Build -depends Clean, Init, Restore -description "This task builds and packages the assemblies" { + +} + +task Test -description "This task runs the tests" { + Write-Host "Running tests..." -ForegroundColor DarkCyan + + pushd $base_directory + $testProjects = Get-ChildItem -Path "project.json" -Recurse | ? { $_.Directory.Name.Contains(".Tests") } + popd + + $frameworksToTest = $frameworks_to_test -split "\s*?,\s*?" + + foreach ($framework in $frameworksToTest) { + Write-Host "Framework: $framework" -ForegroundColor Blue + + if ($framework.StartsWith("netcore")) { + $testExpression = "dotnet.exe test --framework $framework --no-build" + } else { + foreach ($testProject in $testProjects) { + $projectDirectory = $testProject.DirectoryName + $testName = $testProject.Directory.Name + $binaryRoot = "$projectDirectory\bin\$Configuration\$framework" + + $testBinary = "$binaryRoot\win7-x64\$testName.dll" + if (-not (Test-Path $testBinary)) { + $testBinary = "$binaryRoot\win7-x32\$testName.dll" + } + if (-not (Test-Path $testBinary)) { + $testBinary = "$binaryRoot\$testName.dll" + } + + if ($testBinaries -eq $null) { + $testBinaries = @($testBinary) + } else { + $testBinaries = $testBinaries += $testBinary + } + } + + $binaryString = $testBinaries -join ';' + $testExpression = "$tools_directory\NUnit\NUnit.ConsoleRunner.3.5.0\tools\nunit3-console.exe $binaryString" + } + + if ($where -ne $null -and (-Not [System.String]::IsNullOrEmpty($where))) { + $testExpression = "$testExpression --where $where" + } + + Write-Host $testExpression -ForegroundColor Magenta + + Invoke-Expression $testExpression + } +} + + + + + + +function Ensure-Directory-Exists([string] $path) +{ + if (!(Test-Path $path)) { + New-Item $path -ItemType Directory + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/build/psake.cmd ---------------------------------------------------------------------- diff --git a/build/psake.cmd b/build/psake.cmd new file mode 100644 index 0000000..f1aadc4 --- /dev/null +++ b/build/psake.cmd @@ -0,0 +1,14 @@ +@echo off +rem Helper script for those who want to run psake from cmd.exe +rem Example run from cmd.exe: +rem psake "default.ps1" "BuildHelloWord" "4.0" + +if '%1'=='/?' goto help +if '%1'=='-help' goto help +if '%1'=='-h' goto help + +powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0\psake.ps1' %*; if ($psake.build_success -eq $false) { exit 1 } else { exit 0 }" +exit /B %errorlevel% + +:help +powershell -NoProfile -ExecutionPolicy Bypass -Command "& '%~dp0\psake.ps1' -help" http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/build/psake.ps1 ---------------------------------------------------------------------- diff --git a/build/psake.ps1 b/build/psake.ps1 new file mode 100644 index 0000000..23c6f2d --- /dev/null +++ b/build/psake.ps1 @@ -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 http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/build/psake.psd1 ---------------------------------------------------------------------- diff --git a/build/psake.psd1 b/build/psake.psd1 new file mode 100644 index 0000000..7e00532 --- /dev/null +++ b/build/psake.psd1 @@ -0,0 +1,31 @@ +@{ + ModuleToProcess = 'psake.psm1' + ModuleVersion = '4.6.0' + GUID = 'cfb53216-072f-4a46-8975-ff7e6bda05a5' + Author = 'James Kovacs' + Copyright = 'Copyright (c) 2012-16 James Kovacs, Damian Hickey and Contributors' + PowerShellVersion = '2.0' + Description = 'psake is a build automation tool written in PowerShell.' + FunctionsToExport = @('Invoke-psake', + 'Invoke-Task', + 'Get-PSakeScriptTasks', + 'Task', + 'Properties', + 'Include', + 'FormatTaskName', + 'TaskSetup', + 'TaskTearDown', + 'Framework', + 'Assert', + 'Exec') + VariablesToExport = 'psake' + + PrivateData = @{ + PSData = @{ + LicenseUri = 'https://github.com/psake/psake/blob/master/license.txt' + ProjectUri = 'https://github.com/psake/psake' + Tags = @('Build', 'Task') + IconUri = 'https://raw.githubusercontent.com/psake/graphics/master/jpg/psake-full-icon-teal-bg-256x256.jpg' + } + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/84abcb4d/build/psake.psm1 ---------------------------------------------------------------------- diff --git a/build/psake.psm1 b/build/psake.psm1 new file mode 100644 index 0000000..e5f8f3c --- /dev/null +++ b/build/psake.psm1 @@ -0,0 +1,925 @@ +# 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 + +if ($PSVersionTable.PSVersion.Major -ge 3) +{ + $script:IgnoreError = 'Ignore' +} +else +{ + $script:IgnoreError = 'SilentlyContinue' +} + +#-- 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 + ) + 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 + } + + $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 Get-PSakeScriptTasks { + [CmdletBinding()] + param( + [Parameter(Position = 0, Mandatory = 0)][string] $buildFile + ) + + if (!$buildFile) { + $buildFile = $psake.config_default.buildFileName + } + + try + { + ExecuteInBuildFileScope $buildFile $MyInvocation.MyCommand.Module { + param($currentContext, $module) + return GetTasksFromContext $currentContext + } + + } finally { + + CleanupEnvironment + } +} + +# .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, + [Parameter(Position = 9, Mandatory = 0)][switch] $notr = $false # disable time report + ) + 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 + } + + ExecuteInBuildFileScope $buildFile $MyInvocation.MyCommand.Module { + param($currentContext, $module) + + $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + + if ($docs -or $detailedDocs) { + WriteDocumentation($detailedDocs) + 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. + . $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 + + $stopwatch.Stop() + if (-not $notr) { + 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') + } + {($_ -eq '4.6') -or ($_ -eq '4.6.1')} { + $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 ExecuteInBuildFileScope { + param([string]$buildFile, $module, [scriptblock]$sb) + + # 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 + + 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 + } + + & $sb $currentContext $module +} + +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 GetTasksFromContext($currentContext) { + + $docs = $currentContext.tasks.Keys | foreach-object { + + $task = $currentContext.tasks.$_ + new-object PSObject -property @{ + Name = $task.Name; + Alias = $task.Alias; + Description = $task.Description; + DependsOn = $task.DependsOn; + } + } + + return $docs +} + +function WriteDocumentation($showDetailed) { + + $currentContext = $psake.context.Peek() + + if ($currentContext.tasks.default) { + $defaultTaskDependencies = $currentContext.tasks.default.DependsOn + } else { + $defaultTaskDependencies = @() + } + + $docs = GetTasksFromContext $currentContext | + Where {$_.Name -ne 'default'} | + ForEach { + $isDefault = $null + if ($defaultTaskDependencies -contains $_.Name) { + $isDefault = $true + } + return Add-Member -InputObject $_ 'Default' $isDefault -PassThru + } + + if ($showDetailed) { + $docs | sort 'Name' | format-list -property Name,Alias,Description,@{Label="Depends On";Expression={$_.DependsOn -join ', '}},Default + } else { + $docs | sort 'Name' | format-table -autoSize -wrap -property Name,Alias,@{Label="Depends On";Expression={$_.DependsOn -join ', '}},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 -FileName messages.psd1 -ErrorAction $script:IgnoreError + +$scriptDir = Split-Path $MyInvocation.MyCommand.Path +$manifestPath = Join-Path $scriptDir psake.psd1 +$manifest = Test-ModuleManifest -Path $manifestPath -WarningAction SilentlyContinue + +$script:psake = @{} + +$psake.version = $manifest.Version.ToString() +$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, Get-PSakeScriptTasks, Task, Properties, Include, FormatTaskName, TaskSetup, TaskTearDown, Framework, Assert, Exec -variable psake
