How to create dynamic build tasks with Invoke-Buil

2019-07-22 11:19发布

问题:

Using Invoke-Build I am trying to create dynamic build tasks, an example of the approach is below. Where, in a similar fashion to the classic UNIX make facility an output file will be generated for each input file iff the input file is newer than the output file.

It accomplishes this by dynamically generating a set of incremental tasks and then calling the tasks.

The generation of the incremental tasks is outlined below:

    $Jobs = Foreach($_ in $Conf ) {
        $SourceFile = Get-Item $_
        $FileName = $SourceFile.Name
        $ObjectName = $FileName -replace '^Thing-(.*)\.conf\.ps1$','$1'
        $TaskName = "Task-$ObjectName"
        $OutFile = "Thing-$ObjectName.ps1"
        # Import the script, overwriting the "$MetaData" variable    
        $MetaData = . $SourceFile

    $TaskCode = @'
.\BuildThing.ps1
BuildThing -MetaData $MetaData
'@
        Write-Verbose "$SourceFile $OutFile"
        $SBInputs = [scriptblock]::Create(  { $SourceFile } ).GetNewClosure()
        $SBOutputs = [scriptblock]::Create( { $OutFile } ).GetNewClosure()
        $SBMain = [scriptblock]::Create($TaskCode).GetNewClosure()
        Task "$TaskName" -Inputs $SBInputs -Outputs $SBOutputs ($SBMain)

        Write-Output $TaskName
    }

This does appear to work well apart from the scoping of required other functions. No matter where I try to source the BuildThing.ps1 script when the task Task-Thing- is executed Invoke-Build complains that BuildThing is not recognized as:

"the name of a cmdlet, function, script file or operable program."

If I dot source the relevant files before running Invoke-Build everything works as desired.

This seems like a scoping problem - but it's not clear how to resolve it in a straightforward manner.

If I try to include BuildThing.ps1 outside of the loop in a static way, it does seem to be called, as confirmed by debugging, but does not appear to be in scope to be executed by the dynamic task.

回答1:

With regard to the above, the appropriate approach appears to be to modify the definition of $TaskCode to dot source the file.

If we assume .\BuildThing.ps1 contains a function - e.g.

function BuildThing {
param(...)
...
}

Then the dynamic task code needs to dot source this code. This seems inefficient for a large set of similar build tasks, however it does resolve the issue.

$TaskCode = @'
. .\BuildThing.ps1
BuildThing -MetaData $MetaData
'@