如何为批处理任务的每次执行获取 MSBuild 输出参数?
How to get MSBuild output parameter for each execution of a batched task?
我有一个 MSBuild 目标,它 运行 是针对多个项目的 Exec 任务。我如何获得它们每个的退出代码?
只有当输入文件自上次 运行(即增量构建)后发生更改时,我才能使用它来获取所有退出代码和 运行:
<ItemGroup>
<TestItem Include="MyFile1" />
<TestItem Include="MyFile2" />
<TestItem Include="MyFile10" />
</ItemGroup>
<Target Name="PrepareItemTest">
<ItemGroup>
<TestItem>
<!-- The timestamp of the "done file" is used below to detect if this target has been run since the inputs have been modified. -->
<DoneFilePath>%(TestItem.RelativeDir)%(TestItem.Filename).done/DoneFilePath>
</TestItem>
</ItemGroup>
</Target>
<Target Name="ItemTest"
DependsOnTargets="PrepareItemTest"
Inputs="@(TestItem);@(OtherInputs)"
Outputs="%(TestItem.DoneFilePath)">
<Exec Command="ECHO Running on %(TestItem.Identity) |findstr 1" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
</Exec>
<Error Condition=" '$(TestExitCode)' != '0' " Text="Error $TestExitCode" />
<WriteLinesToFile Condition=" '$(TestExitCode)' == '0' " File="%(TestItem.DoneFilePath)" Lines="Ran successfully on %(TestItem.Filename)%(TestItem.Extension)" />
</Target>
输出:
Ran ItemTest. Exit code=0
Ran ItemTest. Exit code=1
所以这会打印返回的所有不同退出代码,但不会将它们与输入项相关联,所以我不知道哪些输入已成功处理,哪些未成功处理。
完成此任务的最简单方法是 batch 完成 目标 而不是任务本身。那实际上 "moves the loop up a level",来自(伪代码):
target PrepareItemTest {
foreach item in TestItem {
TestExitCode.append(exec().result))
}
warn("exit codes: " + TestExitCode)
}
到
target PrepareItemTest {
foreach item in TestItem {
TestExitCode.append(exec().result))
warn("exit code: " item + " " + TestExitCode)
}
}
如果项目代表产生输出的文件,这很简单,您应该在 Inputs
属性中进行批处理(并定义 Outputs
以获得正确的增量行为)。
对于您给出的示例,它有点令人困惑,因为目标没有生成一组输出文件。这意味着您必须滥用目标的 Outputs
属性才能获得批处理行为。你可以这样做:
<Target Name="ItemTest" Outputs="%(TestItem.Identity)">
<Exec Command="ECHO Running on @(TestItem->'%(Identity)') |findstr 1" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
</Exec>
<Warning Text="Ran ItemTest for @(TestItem). Exit code=$(TestExitCode)" />
</Target>
产生
Project "D:\work\batch-over-target.proj" on node 1 (default targets).
ItemTest:
ECHO Running on MyItem1 |findstr 1
Running on MyItem1
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem1. Exit code=0
ItemTest:
ECHO Running on MyItem2 |findstr 1
The command "ECHO Running on MyItem2 |findstr 1" exited with code 1.
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem2. Exit code=1
ItemTest:
ECHO Running on MyItem10 |findstr 1
Running on MyItem10
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem10. Exit code=0
Done Building Project "D:\work\batch-over-target.proj" (default targets).
这样做的原因是,在一个批次中,使用 @(ItemName)
访问的项目包括 仅适合该批次 的结果。如果您仔细确保每个批次只有一个项目,您可以将输出与输入相关联。
我有一个 MSBuild 目标,它 运行 是针对多个项目的 Exec 任务。我如何获得它们每个的退出代码?
只有当输入文件自上次 运行(即增量构建)后发生更改时,我才能使用它来获取所有退出代码和 运行:
<ItemGroup>
<TestItem Include="MyFile1" />
<TestItem Include="MyFile2" />
<TestItem Include="MyFile10" />
</ItemGroup>
<Target Name="PrepareItemTest">
<ItemGroup>
<TestItem>
<!-- The timestamp of the "done file" is used below to detect if this target has been run since the inputs have been modified. -->
<DoneFilePath>%(TestItem.RelativeDir)%(TestItem.Filename).done/DoneFilePath>
</TestItem>
</ItemGroup>
</Target>
<Target Name="ItemTest"
DependsOnTargets="PrepareItemTest"
Inputs="@(TestItem);@(OtherInputs)"
Outputs="%(TestItem.DoneFilePath)">
<Exec Command="ECHO Running on %(TestItem.Identity) |findstr 1" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
</Exec>
<Error Condition=" '$(TestExitCode)' != '0' " Text="Error $TestExitCode" />
<WriteLinesToFile Condition=" '$(TestExitCode)' == '0' " File="%(TestItem.DoneFilePath)" Lines="Ran successfully on %(TestItem.Filename)%(TestItem.Extension)" />
</Target>
输出:
Ran ItemTest. Exit code=0
Ran ItemTest. Exit code=1
所以这会打印返回的所有不同退出代码,但不会将它们与输入项相关联,所以我不知道哪些输入已成功处理,哪些未成功处理。
完成此任务的最简单方法是 batch 完成 目标 而不是任务本身。那实际上 "moves the loop up a level",来自(伪代码):
target PrepareItemTest {
foreach item in TestItem {
TestExitCode.append(exec().result))
}
warn("exit codes: " + TestExitCode)
}
到
target PrepareItemTest {
foreach item in TestItem {
TestExitCode.append(exec().result))
warn("exit code: " item + " " + TestExitCode)
}
}
如果项目代表产生输出的文件,这很简单,您应该在 Inputs
属性中进行批处理(并定义 Outputs
以获得正确的增量行为)。
对于您给出的示例,它有点令人困惑,因为目标没有生成一组输出文件。这意味着您必须滥用目标的 Outputs
属性才能获得批处理行为。你可以这样做:
<Target Name="ItemTest" Outputs="%(TestItem.Identity)">
<Exec Command="ECHO Running on @(TestItem->'%(Identity)') |findstr 1" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
</Exec>
<Warning Text="Ran ItemTest for @(TestItem). Exit code=$(TestExitCode)" />
</Target>
产生
Project "D:\work\batch-over-target.proj" on node 1 (default targets).
ItemTest:
ECHO Running on MyItem1 |findstr 1
Running on MyItem1
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem1. Exit code=0
ItemTest:
ECHO Running on MyItem2 |findstr 1
The command "ECHO Running on MyItem2 |findstr 1" exited with code 1.
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem2. Exit code=1
ItemTest:
ECHO Running on MyItem10 |findstr 1
Running on MyItem10
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem10. Exit code=0
Done Building Project "D:\work\batch-over-target.proj" (default targets).
这样做的原因是,在一个批次中,使用 @(ItemName)
访问的项目包括 仅适合该批次 的结果。如果您仔细确保每个批次只有一个项目,您可以将输出与输入相关联。