Skip to content

Commit

Permalink
v2.7.4 $Task
Browse files Browse the repository at this point in the history
  • Loading branch information
nightroman committed May 10, 2014
1 parent c6cc4f3 commit 38930b2
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 50 deletions.
1 change: 1 addition & 0 deletions Demo/.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ task TestVariables {
'BuildFile' { 'BuildFile - build script path - ' + $BuildFile }
'BuildRoot' { 'BuildRoot - build script root - ' + $BuildRoot }
'BuildTask' { 'BuildTask - initial task list - ' + $BuildTask }
'Task' { 'Task - the current task' }
'WhatIf' { 'WhatIf - Invoke-Build parameter' }
default { Write-Warning "Unknown variable '$_'." }
}
Expand Down
10 changes: 5 additions & 5 deletions Demo/Events.test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ function Exit-Build {
Set-Location $HOME
}

# Enter-BuildTask is called before each task. It takes one argument - the task.
# Enter-BuildTask is called before each task.
# The scope is new, the parent for the task script jobs.
function Enter-BuildTask($Task) {
function Enter-BuildTask {
'Enter task {0}' -f $Task.Name
assert ($BuildRoot -eq (Get-Location).ProviderPath)
Set-Location $HOME
}

# Exit-BuildTask is called after each task. Arguments and the scope are the
# same as for Enter-BuildTask.
function Exit-BuildTask($Task) {
# Exit-BuildTask is called after each task.
# The scope is the same as for Enter-BuildTask.
function Exit-BuildTask {
'Exit task {0}' -f $Task.Name
assert ($BuildRoot -eq (Get-Location).ProviderPath)
Set-Location $HOME
Expand Down
30 changes: 21 additions & 9 deletions Invoke-Build-Help.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@
$BuildRoot - build script location
$BuildFile - build script path
$BuildTask - initial tasks
$Task - current task
$Task is available for the task script blocks defined by parameters If,
Inputs, Outputs, Jobs and the event functions Enter|Exit-BuildTask and
Enter|Exit-BuildJob.
$Task properties available for reading:
- Name - task name, [string]
- Started - start time, [DateTime]
- In Exit-BuildTask only:
- Error - an error stopped the task
- Elapsed - task duration, [TimeSpan]
NOTE: The special variable $_ may be defined and visible. Scripts and tasks
can use it as their own, that is assign at first. Only in special cases it
Expand Down Expand Up @@ -97,20 +110,19 @@
a good place for heavy initialization, it does not have to care of WhatIf.
Enter-BuildTask and Exit-BuildTask are invoked in the same scope which is
the parent for a task invoked between them. An argument is the task. The
following task properties are available for reading:
the parent for a task invoked between them. An argument is the task.
Name - task name, [string]
Started - start time, [DateTime]
Exit-BuildTask may read two extra properties:
Error - an error stopped the task
Elapsed - task duration, [TimeSpan]
*** OBSOLETE ***
The argument will be removed soon.
Use the variable $Task instead.
Enter-BuildJob and Exit-BuildJob are invoked in the same scope as
*-BuildTask and take two arguments - the task and the job number.
*** OBSOLETE ***
Use the variable $Task instead of the first argument.
The second argument will become first (incoming incompatible change).
Export-Build and Import-Build are used with persistent builds. Export-Build
outputs data to be exported to clixml. Import-Build is called with a single
argument containing the original data imported from clixml. It is called in
Expand Down
66 changes: 32 additions & 34 deletions Invoke-Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -332,9 +332,7 @@ filter *Try($T, $P = [System.Collections.Stack]@()) {
}

function *IO {
${private:**} = $args[0]

if ((${private:*i} = ${**}.Inputs) -is [scriptblock]) {
if ((${private:*i} = $Task.Inputs) -is [scriptblock]) {
*SL
${*i} = @(& ${*i})
}
Expand All @@ -348,8 +346,8 @@ function *IO {
}
if (!${*p}) {return 'Skipping empty input.'}

${private:*o} = ${**}.Outputs
if (${**}.Partial) {
${private:*o} = $Task.Outputs
if ($Task.Partial) {
${*o} = @(
if (${*o} -is [scriptblock]) {
${*p} | & ${*o}
Expand All @@ -362,8 +360,8 @@ function *IO {
if (${*p}.Count -ne ${*o}.Count) {throw "Different input/output: $(${*p}.Count)/$(${*o}.Count)."}

$k = -1
${**}.Inputs = $i = [System.Collections.ArrayList]@()
${**}.Outputs = $o = [System.Collections.ArrayList]@()
$Task.Inputs = $i = [System.Collections.ArrayList]@()
$Task.Outputs = $o = [System.Collections.ArrayList]@()
foreach($_ in ${*i}) {
if ($_.LastWriteTime -gt [System.IO.File]::GetLastWriteTime((*FP ($p = ${*o}[++$k])))) {
$null = $i.Add(${*p}[$k]), $o.Add($p)
Expand All @@ -373,12 +371,12 @@ function *IO {
}
else {
if (${*o} -is [scriptblock]) {
${**}.Outputs = ${*o} = & ${*o}
$Task.Outputs = ${*o} = & ${*o}
*SL
}
if (!${*o}) {throw 'Empty output.'}

${**}.Inputs = ${*p}
$Task.Inputs = ${*p}
$m = (${*i} | .{process{$_.LastWriteTime.Ticks}} | Measure-Object -Maximum).Maximum
foreach($_ in ${*o}) {
if ($m -gt [System.IO.File]::GetLastWriteTime((*FP $_)).Ticks) {return}
Expand All @@ -405,27 +403,27 @@ function *CP {
$_ | Export-Clixml ${*}.Checkpoint
}

function *Task {
${private:**}, ${private:*p} = $args
function *Task($Task) {
${private:*p} = $args

${**} = ${*}.All[${**}]
${*p} = "${*p}/$(${**}.Name)"
if (${**}.Error) {
$Task = ${*}.All[$Task]
${*p} = "${*p}/$($Task.Name)"
if ($Task.Error) {
Write-Build 8 "Task ${*p} failed."
return
}
if (${**}.Elapsed) {
if ($Task.Elapsed) {
Write-Build 8 "Done ${*p}"
return
}

if ((${private:*x} = ${**}.If) -is [scriptblock] -and !$WhatIf) {
if ((${private:*x} = $Task.If) -is [scriptblock] -and !$WhatIf) {
*SL
try {
${*x} = & ${*x}
}
catch {
${**}.Error = $_
$Task.Error = $_
throw
}
}
Expand All @@ -435,11 +433,11 @@ function *Task {
}

${private:*n} = 0
${private:*a} = ${**}.Job
${private:*i} = [int]($null -ne ${**}.Inputs)
${**}.Started = [DateTime]::Now
${private:*a} = $Task.Job
${private:*i} = [int]($null -ne $Task.Inputs)
$Task.Started = [DateTime]::Now
try {
. *UC Enter-BuildTask ${**}
. *UC Enter-BuildTask $Task
foreach(${private:*j} in ${*a}) {
++${*n}
if (${*j} -is [string]) {
Expand All @@ -460,23 +458,23 @@ function *Task {
continue
}

if (1 -eq ${*i}) {${*i} = *IO ${**}}
if (1 -eq ${*i}) {${*i} = *IO}
if (${*i}) {
Write-Build 11 ${*i}
continue
}

try {
*SL
. Enter-BuildJob ${**} ${*n}
. Enter-BuildJob $Task ${*n}
*SL
if (0 -eq ${*i}) {
& ${*j}
}
else {
$Inputs = ${**}.Inputs
$Outputs = ${**}.Outputs
if (${**}.Partial) {
$Inputs = $Task.Inputs
$Outputs = $Task.Outputs
if ($Task.Partial) {
${*x} = 0
$Inputs | .{process{
$2 = $Outputs[${*x}++]
Expand All @@ -489,32 +487,32 @@ function *Task {
}
}
catch {
${**}.Error = $_
$Task.Error = $_
throw
}
finally {
*SL
. Exit-BuildJob ${**} ${*n}
. Exit-BuildJob $Task ${*n}
}
if (${*a}.Count -ge 2) {
Write-Build 11 "Done ${*m}"
}
}
${**}.Elapsed = $_ = [DateTime]::Now - ${**}.Started
$Task.Elapsed = $_ = [DateTime]::Now - $Task.Started
Write-Build 11 "Done ${*p} $_"
if (${*}.Checkpoint) {*CP}
}
catch {
Write-Build 14 (*II ${**})
${**}.Error = $_
${**}.Elapsed = [DateTime]::Now - ${**}.Started
Write-Build 14 (*II $Task)
$Task.Error = $_
$Task.Elapsed = [DateTime]::Now - $Task.Started
${*x} = "ERROR: Task ${*p}: $_"
$null = ${*}.Errors.Add($(if (*My) {${*x}} else {*EI ${*x} $_}))
throw
}
finally {
$null = ${*}.Tasks.Add(${**})
. *UC Exit-BuildTask ${**}
$null = ${*}.Tasks.Add($Task)
. *UC Exit-BuildTask $Task
}
}

Expand Down
32 changes: 30 additions & 2 deletions Release-Notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,42 @@
Invoke-Build Release Notes
==========================

## v2.7.4
## v2.7.4 $Task

**Default script resolution**

The script specified by `$env:InvokeBuildGetFile` (gets a non standard default
build file) is invoked with the full directory path as an argument. It may be
invoked several times during the directory branch search with each path passed
in. Old scripts should work fine but some of them may be simplified.
in. Old scripts should work fine but some of them may be simplified now.

**Automatic variable $Task. Step 1**

A new automatic variable `$Task` represents the current task instance. It is
available for the task script blocks defined by parameters `If`, `Inputs`,
`Outputs`, `Jobs` and the event functions `Enter|Exit-BuildTask` and
`Enter|Exit-BuildJob`.

Why? Some advanced task scripts need this instance (e.g. shared between tasks).
A common variable `$Task` seems to be simpler than use of a parameter in each
of 8 above code pieces. Let's keep parameters available for something else.

**Potentially incompatible**

Build scripts with the parameter `$Task` or script variable `$Task` may fail.
Rename this variable. The parameter `$Task` is not good anyway because it
conflicts with Invoke-Build and cannot be used as the dynamic parameter.

As far as `Enter|Exit-*` are invoked in the scope where `$Task` is defined,
make sure they do not change it. Other task code may change it in its own
scope. But such hiding of the system variable is not recommended.

**Step 2. The next version**

`Enter|Exit-BuildTask` and `Enter|Exit-BuildJob` will not be accepting the task
as the first argument. The new variable `$Task` should be used instead. Most of
scripts may be prepared now. Change of `Enter|Exit-BuildJob` may be breaking,
the second parameter will become first.

## v2.7.2, v2.7.3

Expand Down

0 comments on commit 38930b2

Please sign in to comment.