36

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

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

注意:这或多或少是这篇文章的转贴

4

7 回答 7

29

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

您可以将检查简化为:

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

正如评论中所提到的,您可能需要调整“1”:这取决于您的操作应将什么视为错误。看一下组成 robocopy 返回的数字的位的含义

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

0×08 部分文件或目录无法复制(复制出错,超出重试限制)。进一步检查这些错误。

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

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

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

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

于 2012-10-31T17:17:21.967 回答
19

<src>, <tgt> 分别是复制源和目标,<opt> 是 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
于 2011-03-29T10:07:38.470 回答
11

简单地检查退出代码 1 是不正确的,因为任何低于 8 的退出代码都是非错误的

任何大于 8 的值都表示在复制操作期间至少发生了一次故障。

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

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

IF %ERRORLEVEL% GEQ 8 exit 1
exit 0
于 2014-10-25T15:58:43.573 回答
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

参考:

于 2015-11-10T21:44:34.640 回答
4

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

如果是这样,您可以通过覆盖 BeforeBuild、AfterBuild 目标和调用 Robocopy 任务来扩展 Visual Studio 构建过程(如果它们更适合您的需要,您也可以覆盖其他目标,请参阅链接的 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>
于 2011-03-29T10:20:47.800 回答
4

接受的答案是过度杀伤国际海事组织。Robocopy 已经定义了它的退出代码,所以我们通常可以假设任何值8或更少都表明事情进展顺利。

“任何大于 8 的值都表示在复制操作过程中至少出现了一次故障。”

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

在 Visual Studio 中为您的 Pre-Build 或 Post-Build 事件,单击下拉菜单并选择<Edit...>

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

例子

高级退出代码要求

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

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

单线解释

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

于 2019-01-03T00:32:15.160 回答
0

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

start robocopy . ..\latestbuild

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

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

call robocopy . ..\latestbuild

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

于 2018-04-09T08:44:31.493 回答