将 robocopy 与 Visual Studio 2010 构建后和预构建事件结合使用

发布于 2024-10-27 12:48:35 字数 292 浏览 4 评论 0原文

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

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

注意:这或多或少是 此内容的转发发布

Robocopy outputs 1 upon success, unlike most programs that exit with 0 on success. Visual Studio (and MSBUILD) interprets exit code of 1 as an error.

How can Robocopy be used in Visual Studio post- and pre-build events such that its failure and success are correctly identified by the build environment?

Note: this is more or less a repost of this post.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

忆梦 2024-11-03 12:48:35

根据请求添加此答案。基于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 没有发生错误,也没有进行复制。来源和
目标目录树完全同步。

Adding this answer per request. Based on Asaf's solution, and adding skrebbel's comment.

You can simplify the check to:

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

As kindly remarked in the comments, you may want to adjust the '1': It depends on what your operation should treat as an error. Have a look at the meaning of the bits that in combination make up the number returned by robocopy:

0×10 Serious error. Robocopy did not copy any files. This is either a
usage error or an error due to insufficient access privileges on the
source or destination directories.

0×08 Some files or directories could not be copied (copy errors
occurred and the retry limit was exceeded). Check these errors
further.

0×04 Some Mismatched files or directories were detected. Examine the
output log. Housekeeping is probably necessary.

0×02 Some Extra files or directories were detected. Examine the output
log. Some housekeeping may be needed.

0×01 One or more files were copied successfully (that is, new files
have arrived).

0×00 No errors occurred, and no copying was done. The source and
destination directory trees are completely synchronized.

合久必婚 2024-11-03 12:48:35

对于来说,分别作为复制源和目标,并且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

With <src>, <tgt> being the copy source and target respectfully, and <opt> being robocopy options:

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

For instance, if we want to copy the project target to c:\temp, without retries and with all sub-directories (empty or not), we'd use:

robocopy /R:0 /E $(TargetDir) c:\temp
set rce=%errorlevel%
if not %rce%==1 exit %rce% else exit 0
沫离伤花 2024-11-03 12:48:35

仅仅检查退出代码是否为 1 是不正确的,因为任何低于 8 的退出代码都是正确的

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

(澄清一下,退出代码 8 也是一个错误:几个文件未复制

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

IF %ERRORLEVEL% GEQ 8 exit 1
exit 0

Simply checking for an exit code of 1 is incorrect, as any exit code below 8 is non-erroneous:

Any value greater than 8 indicates that there was at least one failure
during the copy operation.

(Just to clarify, an exit code of 8 is an error as well: Several files did not copy)

The proper code, then, should look like this:

IF %ERRORLEVEL% GEQ 8 exit 1
exit 0
时光磨忆 2024-11-03 12:48:35

从语法上讲,这里是一个每命令一行的版本,可以直接在 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

参考文献:

Syntactically here is a one-line-per-command version that works directly within the PreBuild steps:

(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

References:

我纯我任性 2024-11-03 12:48:35

在我看来,公认的答案是矫枉过正。 Robocopy 已经定义了退出代码,因此我们通常可以假设 8 或更少的任何值都表示一切顺利。

“任何大于 8 的值都表示复制操作期间至少发生了一次失败。”

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

在 Visual Studio 中,针对预构建或构建后事件,单击下拉列表并选择

在命令下方创建一个新行,并放置 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 退出 1。

The accepted answer is overkill IMO. Robocopy already has its exit codes defined, so we can usually assume any value of 8 or less indicates things went well.

"Any value greater than 8 indicates that there was at least one failure during the copy operation."

So let's say your command is, ROBOCOPY $(Source) $(Dest) *.*, which I'll just refer to as $(RobocopyBinCommand).

In Visual Studio for your Pre-Build or Post-Build Event, click the dropdown and select <Edit...>

Create a new line below your command, and place IF %ERRORLEVEL% LEQ 8 EXIT 0 then apply and close the Properties window, eg:

example

Advanced Exit Code Requirements

Let's say you only want the build to pass if ROBOCOPY returns 1 or 3. The if-check above won't allow you to even use the OR-like behavior supported by CMD.exe to fix the issue. You can work around this limitation multiple ways but I think this is one of the most concise ways to do it.

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

One-Liner Explanation

Basically, we're piping the result of echoing the errorlevel to findstr which is looking for either a 1 or a 3. We don't have to worry about values that have a 3 or a 1 in them like 23 or 16 because the first evaluation makes sure the value is 3 or less. Once that evaluation passes if it does indeed pass it then pipes the errorlevel to findstr which then compares errorlevel to 1 or 3. If either is detected by findstr, findstr will exit 0, otherwise it will not. If the errorlevel was not 3 or less, errorlevel will remain unchanged and the build task will exit 1 as-usual from using ROBOCOPY.

转瞬即逝 2024-11-03 12:48:35

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

如果是这样,您可以扩展 Visual Studio 构建过程 通过覆盖 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>

MSBuild extensionpack contains a Robocopy task that you can use in your build process.
Can this be a solution for you instead of VS pre/postbuild events?

If so, you can extend the Visual Studio Build Process by overriding the BeforeBuild, AfterBuild targets and calling the Robocopy task (you can override other targets as well if they would suit your needs better, see the list in the linked MSDN page)
So actually you should download and install MSBuild extensionpack than open your project's csproj/vbproj file and edit the following way:

Adding following entries for importing MSBuild extensionpack's Robocopy task

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

Overriding BeforeBuild, AfterBuild and executing the Robocopy task

<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>
深海少女心 2024-11-03 12:48:35

我发现启动 robocopy 比尝试在 Visual Studio 中调用它要容易得多。这样,Visual Studio 就不会关心 robocopy 的返回代码。

start robocopy . ..\latestbuild

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

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

call robocopy . ..\latestbuild

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

I found that it's much easier to start robocopy rather than trying to call it in-line with Visual Studio. This way Visual Studio doesn't care about the return code from robocopy.

start robocopy . ..\latestbuild

The only difference I could see is that you will see a command prompt appear and disappear to execute the robocopy command.

Using call instead of start actually doesn't open the command prompt and, even better, redirects the output from the robocopy to Visual Studio output window.

call robocopy . ..\latestbuild

For some reason this approach only works when used in Pre-build events command line.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文