Robocopy成功后输出1,与大多数成功退出0的程序不同。 Visual Studio(和MSBUILD)将退出代码1解释为错误。
如何在Visual Studio后期和预构建事件中使用Robocopy,以便构建环境正确识别其失败和成功?
注意:这或多或少是this post的重新发布。
答案 0 :(得分:21)
根据请求添加此答案。基于Asaf的解决方案,并添加skrebbel的评论。
您可以将检查简化为:
robocopy <opt> <src> <tgt>
if %errorlevel% leq 1 exit 0 else exit %errorlevel%
正如评论中所说的那样,您可能需要调整“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没有发生错误,也没有复制。来源和 目标目录树完全同步。
答案 1 :(得分:19)
使用&lt; src&gt;,&lt; tgt&gt;恭敬地成为复制源和目标,并且&lt; opt&gt;是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
答案 2 :(得分:9)
只需检查退出代码1是不正确的,如any exit code below 8 is non-erroneous:
任何大于8的值表示至少有一次失败 在复制操作期间。
(只是澄清一下,退出代码8也是错误:Several files did not copy
)
然后,正确的代码应如下所示:
IF %ERRORLEVEL% GEQ 8 exit 1
exit 0
答案 3 :(得分:4)
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>
答案 4 :(得分:4)
这里的语法是一个单行命令版本,可直接在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
参考文献:
答案 5 :(得分:0)
我发现启动 robocopy要比使用Visual Studio在线调用它更容易。这样,Visual Studio就不会关心robocopy的返回代码。
start robocopy . ..\latestbuild
我能看到的唯一区别是你会看到一个命令提示符出现并消失以执行robocopy命令。
使用调用而不是启动实际上并没有打开命令提示符,更好的是,将robocopy的输出重定向到Visual Studio输出窗口。 / p>
call robocopy . ..\latestbuild
出于某种原因,此方法仅在预构建事件命令行中使用时才有效。
答案 6 :(得分:0)
公认的答案是过度使用IMO。 Robocopy已经有了它的exit codes defined,因此我们通常可以假设8
等于或小于任何值表示一切顺利。
“任何大于8的值都表示在复制操作期间至少存在一次故障。”
因此,假设您的命令是ROBOCOPY $(Source) $(Dest) *.*
,我将其简称为$(RobocopyBinCommand)
。
在Visual Studio中,针对您的构建前或构建后事件,单击下拉列表,然后选择<Edit...>
在命令下方创建新行,然后放置IF %ERRORLEVEL% LEQ 8 EXIT 0
,然后应用并关闭“属性”窗口,例如:
假设您仅希望ROBOCOPY返回1
或3
的构建通过。上面的if-check甚至不允许您使用CMD.exe支持的类似OR
的行为来解决此问题。您可以通过多种方法解决此限制,但我认为这是最简洁的方法之一。
if %errorlevel% LEQ 3 echo %errorlevel%|findstr "1 3"
基本上,我们正在将错误级别回显到findstr
的结果中,后者正在寻找1或3。我们不必担心其中包含3或1的值。像23
或16
一样,因为第一次评估可确保该值等于或小于3。一旦评估通过,如果确实通过,则将错误级别传递到findstr
,然后将错误级别与1
或3
进行比较。如果findstr检测到任何一个,则findstr将退出0,否则将不会退出。如果错误级别不是3或更小,则错误级别将保持不变,并且构建任务将正常退出使用ROBOCOPY的状态。