【问题标题】:Using robocopy with Visual Studio 2010 Post-build and Pre-build events将 robocopy 与 Visual Studio 2010 生成后和生成前事件一起使用
【发布时间】:2011-07-25 03:47:11
【问题描述】:

Robocopy 在成功时输出 1,这与大多数在成功时以 0 退出的程序不同。 Visual Studio(和 MSBUILD)将退出代码 1 解释为错误。

如何在 Visual Studio 构建后和构建前事件中使用 Robocopy,以便构建环境正确识别其失败和成功?

注意:这或多或少是 this post 的转贴。

【问题讨论】:

    标签: visual-studio-2010 batch-file msbuild robocopy


    【解决方案1】:

    分别是复制源和目标,是robocopy选项:

    robocopy <opt> <src> <tgt>
    set rce=%errorlevel%
    if not %rce%==1 exit %rce% else exit 0
    

    例如,如果我们想将项目目标复制到 c:\temp,不重试并且包含所有子目录(是否为空),我们会使用:

    robocopy /R:0 /E $(TargetDir) c:\temp
    set rce=%errorlevel%
    if not %rce%==1 exit %rce% else exit 0
    

    【讨论】:

    • 你也可以简单地使用if errorlevel 1 exit 0 else exit %errorlevel%
    • @mafutrct:Wunderbar!如果您将评论添加为答案,我会赞成。
    • @mafutrct 不! if errorlevel 1 ... 表示“如果错误大于或等于 1”。换句话说,这会捕获所有错误,但不会捕获“不需要复制”(robocopy 的 0 退出代码)。但是我认为你需要if %errorlevel% leq 1 exit 0 else exit %errorlevel%
    • 其实只有大于 7(8 及以上)的值表示失败,请看下面我的回答
    【解决方案2】:

    MSBuild extensionpack 包含一个 Robocopy 任务,您可以在构建过程中使用它。
    这可以成为您的解决方案,而不是 VS 构建前/构建后事件吗?

    如果是这样,您可以 extend the Visual Studio Build Process 通过覆盖 BeforeBuild、AfterBuild 目标并调用 Robocopy 任务(如果它们更适合您的需求,您也可以覆盖其他目标,请参阅链接的 MSDN 页面中的列表)
    所以实际上你应该下载并安装 MSBuild 扩展包,而不是打开项目的 csproj/vbproj 文件并编辑以下方式:

    为导入 MSBuild 扩展包的 Robocopy 任务添加以下条目

    <PropertyGroup>
        <TPath>$(MSBuildExtensionsPath32)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</TPath>        
    </PropertyGroup>
    <Import Project="$(TPath)"/>
    

    覆盖 BeforeBuild、AfterBuild 并执行 Robocopy 任务

    <Target Name="BeforeBuild">
    <Message Text="Beforebuild" />
      <MSBuild.ExtensionPack.FileSystem.RoboCopy Source="C:\temp\robo_src1" Destination="C:\temp\robo_dest1" Files="*.*" Options="/MIR">
          <Output TaskParameter="ExitCode" PropertyName="Exit" />
          <Output TaskParameter="ReturnCode" PropertyName="Return" />
      </MSBuild.ExtensionPack.FileSystem.RoboCopy>
      <Message Text="ExitCode = $(Exit)"/>
      <Message Text="ReturnCode = $(Return)"/>
    </Target>
    <Target Name="AfterBuild">
      <MSBuild.ExtensionPack.FileSystem.RoboCopy Source="C:\temp\robo_src2" Destination="C:\temp\robo_dest2" Files="*.*" Options="/MIR">
          <Output TaskParameter="ExitCode" PropertyName="Exit" />
          <Output TaskParameter="ReturnCode" PropertyName="Return" />
      </MSBuild.ExtensionPack.FileSystem.RoboCopy>
      <Message Text="ExitCode = $(Exit)"/>
      <Message Text="ReturnCode = $(Return)"/>
    </Target>
    

    【讨论】:

    • 能否请您在回答中解释如何添加它。它的目的是一样的吗?
    • 对不起,代码被截断了我对编辑器不是很熟悉..我正在整理如何正确添加代码
    • 好的,同时我终于想通了。希望这会有所帮助,如果您需要更多信息,请告诉我
    【解决方案3】:

    根据请求添加此答案。基于 Asaf 的解决方案,并添加 skrebbel 的评论。

    您可以将检查简化为:

    robocopy <opt> <src> <tgt>
    if %errorlevel% leq 1 exit 0 else exit %errorlevel%
    

    正如 cmets 中所提到的,您可能需要调整“1”:这取决于您的操作应将什么视为错误。看看the meaning of the bits that in combination make up the number returned by robocopy

    0×10 严重错误。 Robocopy 没有复制任何文件。这要么是 使用错误或由于访问权限不足而导致的错误 源或目标目录。

    0×08 某些文件或目录无法复制(复制错误 发生并且超出了重试限制)。检查这些错误 进一步。

    0×04 检测到一些不匹配的文件或目录。检查 输出日志。家政服务可能是必要的。

    0×02 检测到一些额外的文件或目录。检查输出 日志。可能需要一些家务。

    0×01 一个或多个文件复制成功(即新文件 已经到了)。

    0×00 没有发生错误,也没有进行复制。来源和 目标目录树完全同步。

    【讨论】:

    • 其实只有大于 7(8 及以上)的值表示失败,请看下面我的回答
    • 谢谢@OhadSchneider,我已经编辑了答案以澄清这一点
    【解决方案4】:

    仅检查退出代码 1 是不正确的,如 any exit code below 8 is non-erroneous

    任何大于 8 的值都表示至少有一次失败 在复制操作期间。

    (澄清一下,退出代码 8 也是一个错误:Several files did not copy

    那么,正确的代码应该如下所示:

    IF %ERRORLEVEL% GEQ 8 exit 1
    exit 0
    

    【讨论】:

      【解决方案5】:

      从语法上讲,这是一个每命令一行的版本,直接在 PreBuild 步骤中工作:

      (robocopy "$(ProjectDir)..\Dir1" "$(ProjectDir)Dir1" "Match.*" /a+:R) ^& IF %ERRORLEVEL% GEQ 8 exit 1
      (robocopy "$(ProjectDir)..\Dir2" "$(ProjectDir)Dir2" "Match.*" /a+:R) ^& IF %ERRORLEVEL% GEQ 8 exit 1
      exit 0
      

      参考文献:

      【讨论】:

        【解决方案6】:

        我发现启动 robocopy 比尝试在 Visual Studio 中调用它要容易得多。这种方式 Visual Studio 不关心来自 robocopy 的返回码。

        start robocopy . ..\latestbuild
        

        我能看到的唯一区别是您将看到一个命令提示符出现和消失以执行 robocopy 命令。

        使用 call 而不是 start 实际上不会打开命令提示符,甚至更好地将输出从 robocopy 重定向到 Visual Studio 输出窗口。

        call robocopy . ..\latestbuild
        

        由于某种原因,这种方法仅在预构建事件命令行中使用时才有效。

        【讨论】:

        • start 只是在 CMD 的新实例中生成命令,当前 CMD 默认不会检查,因此对于这种用例它永远不会失败,并且可能不应该依赖。
        【解决方案7】:

        接受的答案是过度杀伤 IMO。 Robocopy 已经有了它的exit codes defined,所以我们通常可以假设8 或以下的任何值都表明事情进展顺利。

        “任何大于 8 的值都表示在复制操作过程中至少有一次失败。”

        假设您的命令是ROBOCOPY $(Source) $(Dest) *.*,我将其简称为$(RobocopyBinCommand)

        在 Visual Studio 中为您的 Pre-Build 或 Post-Build 事件单击下拉菜单并选择 &lt;Edit...&gt;

        在您的命令下方创建一个新行,并放置IF %ERRORLEVEL% LEQ 8 EXIT 0,然后应用并关闭“属性”窗口,例如:

        高级退出代码要求

        假设您只希望在 ROBOCOPY 返回13 时通过构建。上面的 if-check 甚至不允许您使用 CMD.exe 支持的类似OR 的行为来解决问题。您可以通过多种方式解决此限制,但我认为这是最简洁的方法之一。

        if %errorlevel% LEQ 3 echo %errorlevel%|findstr "1 3"

        单线解释

        基本上,我们将错误级别回显的结果传送到findstr,它正在寻找 1 或 3。我们不必担心其中包含 3 或 1 的值,例如 @ 987654334@ 或 16 因为第一次评估确保该值为 3 或更小。一旦评估通过,如果确实通过了,则将 errorlevel 传递给findstr,然后将 errorlevel 与13 进行比较。如果 findstr 检测到任何一个,findstr 将退出 0,否则不会。如果 errorlevel 不是 3 或更低,errorlevel 将保持不变,并且构建任务将照常退出 1,不再使用 ROBOCOPY。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-07
          • 1970-01-01
          相关资源
          最近更新 更多