summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Jennings <stephen.g.jennings@gmail.com>2014-03-19 00:26:16 -0700
committerStephen Jennings <stephen.g.jennings@gmail.com>2014-03-19 00:26:16 -0700
commit5628d3e932b2240487e34092e401c2ec8197ab94 (patch)
tree033ba5ce79eaeca33dc7e2df99668380e39df5c4
parent35fcb69d0989108aca4f977f38cb9438755d647c (diff)
downloadOATH.Net-5628d3e932b2240487e34092e401c2ec8197ab94.zip
OATH.Net-5628d3e932b2240487e34092e401c2ec8197ab94.tar.gz
OATH.Net-5628d3e932b2240487e34092e401c2ec8197ab94.tar.bz2
Add Psake build script
-rw-r--r--.nuget/packages.config4
-rw-r--r--Build.cmd11
-rw-r--r--OATH.Net.sln6
-rw-r--r--Psake.cmd3
-rw-r--r--Psake.psm1846
-rw-r--r--README.md15
-rw-r--r--Test.cmd6
-rw-r--r--default.ps181
8 files changed, 955 insertions, 17 deletions
diff --git a/.nuget/packages.config b/.nuget/packages.config
new file mode 100644
index 0000000..7025a72
--- /dev/null
+++ b/.nuget/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="NUnit.Runners" version="2.6.3" />
+</packages> \ No newline at end of file
diff --git a/Build.cmd b/Build.cmd
deleted file mode 100644
index 1f4f0e8..0000000
--- a/Build.cmd
+++ /dev/null
@@ -1,11 +0,0 @@
-@echo off
-setlocal
-
-set CONFIGURATION=%~1
-
-if "%CONFIGURATION%"=="" set CONFIGURATION=Debug
-
-"%WINDIR%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" ^
- %~dp0OATH.Net.sln ^
- /target:Clean;Build ^
- /property:Configuration=%CONFIGURATION%
diff --git a/OATH.Net.sln b/OATH.Net.sln
index 93e0e07..937d545 100644
--- a/OATH.Net.sln
+++ b/OATH.Net.sln
@@ -8,9 +8,15 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4C63D6DA-A2F5-4711-84AD-1318F3625B3E}"
ProjectSection(SolutionItems) = preProject
NOTICE.md = NOTICE.md
+ OATH.Net.nuspec = OATH.Net.nuspec
README.md = README.md
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D7006C7B-F53C-419A-B5FB-E90AF78EB7B0}"
+ ProjectSection(SolutionItems) = preProject
+ .nuget\packages.config = .nuget\packages.config
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
diff --git a/Psake.cmd b/Psake.cmd
new file mode 100644
index 0000000..3f85b36
--- /dev/null
+++ b/Psake.cmd
@@ -0,0 +1,3 @@
+@echo off
+
+powershell -NoProfile -NoExit -ExecutionPolicy Bypass -Command "Import-Module '%~dp0\psake.psm1'"
diff --git a/Psake.psm1 b/Psake.psm1
new file mode 100644
index 0000000..882d216
--- /dev/null
+++ b/Psake.psm1
@@ -0,0 +1,846 @@
+# 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)
+ }
+
+ Exec $task.Action `
+ -maxRetries $task.MaxRetries `
+ -retryTriggerErrorPattern $task.RetryTriggerErrorPattern
+
+ 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
+}
+
+# .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
+ )
+ try {
+ if (-not $nologo) {
+ "psake version {0}`nCopyright (c) 2010 James Kovacs`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) {
+ WriteDocumentation
+ 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
+ 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')
+ }
+ '4.5.1' {
+ $versions = @('v4.0.30319')
+ $buildToolsVersions = @('12.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)
+ }
+ }
+ }
+ if ($buildToolsVersions -ne $null) {
+ $frameworkDirs = @($buildToolsVersions | foreach { (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\$_" -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 {
+ $currentContext = $psake.context.Peek()
+
+ if ($currentContext.tasks.default) {
+ $defaultTaskDependencies = $currentContext.tasks.default.DependsOn
+ } else {
+ $defaultTaskDependencies = @()
+ }
+
+ $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 }
+ }
+ } | sort 'Name' | format-table -autoSize -wrap -property Name,Alias,"Depends On",Default,Description
+}
+
+function WriteTaskTimeSummary($invokePsakeDuration) {
+ "-" * 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.3.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
diff --git a/README.md b/README.md
index e4b5ebe..22f5213 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,21 @@ OATH.Net is a .NET library to perform OATH authentication.
}
+## Building ##
+
+Visual Studio should build the project correctly with no effort.
+
+A [Psake](https://github.com/psake/psake) build script is included for running
+tests and creating NuGet packages. To use Psake:
+
+1. Open Psake by importing `Psake.psm1` into a PowerShell session, or run
+ `Psake.cmd` to create a session with Psake already imported.
+
+2. Run `Invoke-psake build` to build the project.
+
+3. Run `Invoke-psake test` to run all unit tests.
+
+
## Source Code
OATH.Net is on GitHub:
diff --git a/Test.cmd b/Test.cmd
deleted file mode 100644
index c461e08..0000000
--- a/Test.cmd
+++ /dev/null
@@ -1,6 +0,0 @@
-@echo off
-setlocal
-
-call "%~dp0Build.cmd" Debug
-
-start "NUnit" "%~dp0packages\NUnit.2.5.10.11092\tools\nunit.exe" "%~dp0OATH.Net.sln"
diff --git a/default.ps1 b/default.ps1
new file mode 100644
index 0000000..7545dc1
--- /dev/null
+++ b/default.ps1
@@ -0,0 +1,81 @@
+# OATH.NET Psake build script
+
+## Primary Build Tasks ##
+
+Task Build -Depend BuildSolution -Description "Builds the project"
+Task Test -Depend Build, TestSolution -Description "Runs all unit tests"
+Task Package -Depend Test, CreateNuPkg -Description "Creates the NuGet package"
+Task Clean -Depend CleanSolution -Description "Deletes all build artifacts"
+Task Default -Depend Test
+
+
+## Build Process ##
+
+Framework "4.0"
+
+Properties {
+ if (!$Configuration) { $Configuration = "Release" }
+
+ $workingTree = Resolve-Path .
+ $solution = "$workingTree\OATH.Net.sln"
+ $nuspec = "$workingTree\OATH.Net.nuspec"
+
+ $nunit = "$workingTree\packages\NUnit.Runners.2.6.3\tools\nunit-console.exe"
+ $testAssembly = "$workingTree\OATH.Net.Test\bin\$Configuration\OATH.Net.Test.dll"
+
+ $nuget = GetNuGetPath
+}
+
+Task RestoreNuGetPackages {
+ Status "Restoring NuGet packages"
+ Exec { & $nuget restore $solution -NonInteractive }
+}
+
+Task BuildSolution -Depend RestoreNuGetPackages {
+ Exec { msbuild /target:build $solution /p:Configuration=$configuration }
+}
+
+Task TestSolution {
+ Exec { & $nunit "$testAssembly" /framework=net-4.0 /nologo }
+}
+
+Task CleanSolution {
+ Exec { msbuild /target:clean $solution /p:Configuration=$Configuration }
+ del -ErrorAction Ignore *.nupkg
+ del -ErrorAction Ignore TestResult.xml
+}
+
+Task CreateNuPkg {
+ Exec { & $nuget pack $nuspec }
+}
+
+
+## Helpers ##
+
+function GetNuGetPath {
+ if (Get-Command "nuget" -ErrorAction SilentlyContinue) {
+ $nuget = "nuget.exe"
+ } else {
+ $temp = [System.IO.Path]::GetTempPath()
+ $nuget = "${temp}nuget.exe"
+ if (!(Test-Path $nuget)) {
+ Status "Downloading nuget.exe to $nuget"
+ (New-Object System.Net.WebClient).DownloadFile("http://nuget.org/nuget.exe", $nuget)
+ }
+ }
+ return $nuget
+}
+
+FormatTaskName {
+ param($taskName)
+ Write-Output ("=" * 72)
+ Write-Output "Running task '$taskName'"
+ Write-Output ("=" * 72)
+}
+
+function Status {
+ param($text)
+ Write-Output ("-" * 72)
+ Write-Output " $text"
+ Write-Output ("-" * 72)
+}