在Visual Studio 2010后期构建和预构建事件中使用robocopy

时间:2011-03-29 10:04:40

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

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

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

注意:这或多或少是this post的重新发布。

7 个答案:

答案 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,然后应用并关闭“属性”窗口,例如:

example

高级退出代码要求

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

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

单行说明

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