如何在使用MSBuild目标批处理时处理错误?

5

我正在为一个目标使用批处理,并希望能够针对发生错误的迭代进行特定的OnError清理。以下是一个完全泛化的示例:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">

<ItemGroup>
    <Example Include="Item1">
        <Color>Blue</Color>
    </Example>
    <Example Include="Item2">
        <Color>Red</Color>
    </Example>
</ItemGroup>

<Target Name="Build"
    Inputs="@(Example)"
    Outputs="%(Example.Color).txt">
    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
</Target>

<Target Name="HandleErrors">
    <Message Text="Do some cleanup about %(Example.Color)" Importance="high" />
</Target>

</Project>

当颜色为蓝色时,构建目标失败。但是HandleErrors目标会运行两次,每种颜色运行一次。有没有办法只让它在失败期间活动的颜色上运行?

2个回答

10
我认为现在发生的事情并不是很清楚。在回答你的问题之前,让我们通过修改你的 proj 文件来看看正在发生什么。
下面是一个已修改的文件 sample-no-error.proj,其中我删除了错误部分,并只添加了一个 Message 任务。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">

    <Message Text="Inside of Build, color: %(Example.Color)" />
  </Target>  
</Project>

当我从命令行构建时,结果如下图所示。 enter image description here 从这里我们可以看到目标本身被执行了两次。这是因为在目标上使用了Outputs=%(Example.Color).txt修饰符。当您使用%(...)时,将启动MSBuild批处理。有两种批处理方式:目标批处理和任务批处理。目标批处理是指每个批处理都会执行一个完整的目标(这就是您正在进行的操作)。任务批处理是指每个批处理都会执行一个任务。
我有另一个示例,与您的示例完全相同,只是我在Build目标中添加了一个额外的Message语句。
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">

    <Message Text="Inside of Build, color: %(Example.Color)" />

    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
  </Target>

  <Target Name="HandleErrors">
    <Message Text="Inside of the HandleErrors target" />
    <Message Text="Do some cleanup about %(Example.Color)" Importance="high" />
  </Target>
</Project>

当我构建这个时,结果是。 enter image description here 基于此,我们可以看到Build目标被执行了一次,并且出现错误,所以它没有像之前的例子那样第二次被执行。之后HandleErrors目标开始运行。在其中遇到了该元素。
<Message Text="Inside of the HandleErrors target" />

并且该消息已发送给记录器(请注意,这只会被调用一次)。之后便完成了。

<Message Text="Do some cleanup about %(Example.Color)" Importance="high" />

现在会出现两个消息语句。这是因为任务批处理已经开始运行了。该任务每个不同的 %(Example.Color) 批次被调用一次,其中的颜色值为 Red 和 Blue。因此,我们知道目标只被调用了一次(原始错误发生的地方),但你将整个 Example 项目集传递给它。

如果你想知道哪个值导致了错误,你需要在 Build 目标中跟踪它。你可以将当前的颜色放入属性中,然后在 HandleErrors 目标中引用它。例如,请参阅下面的 sample-id-errors.proj。

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">
    <PropertyGroup>
      <_LastUsedColor>%(Example.Color)</_LastUsedColor>
    </PropertyGroup>

    <Message Text="Inside of Build, color: %(Example.Color)" />

    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
  </Target>

  <Target Name="HandleErrors">
    <Message Text="Inside of the HandleErrors target" />
    <Message Text="The color which caused the error was: $(_LastUsedColor)"/>
  </Target>
</Project>

您可以看到,在 Build 内部,我只是设置了 _LastUsedColor 属性的值,然后如果出现错误,我就在该目标内使用相同的属性。当我构建此文件时,结果如下。

enter image description here

我认为这就是你想要实现的。如果你不知道批处理是如何工作的,那么它会非常令人困惑。我在http://sedotech.com/resources#Batching.上有许多关于批处理的在线资源。

啊哈!我错过了,在HandleErrors目标中通过引用%(Example.Color)来执行任务批处理。当然,设置属性正是我所需要的。感谢您快速而详细的回复(以及您不可或缺的书籍:-)。 - Jeff Youngstrom

0

如果我理解正确,您的HandleErrors将被单独分批。

您将使用错误任务,无论是有条件地还是无条件地。在任何情况下,您都应该能够使用MSBuild任务来调用HandleErrors并将%(Example.Color)作为属性传递。类似于:

<MSBuild Targets="HandleErrors" Properties="ErrorColor=%(Example.Color)" />

另一种方法可能是,在出现错误的情况下创建一个属性,并在HandleErrors目标中使用它。虽然上述方法会更加简洁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接