将 robocopy 与 Visual Studio 2010 构建后和预构建事件结合使用
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
根据请求添加此答案。基于Asaf的解决方案,并添加skrebbel的评论。
您可以将检查简化为:
正如评论中所指出的,您可能需要调整“1”:这取决于您的操作应将什么视为错误。查看组合起来组成 robocopy 返回的数字的各个位的含义 :
Adding this answer per request. Based on Asaf's solution, and adding skrebbel's comment.
You can simplify the check to:
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:
对于、来说,分别作为复制源和目标,并且robocopy 选项:
例如,如果我们想将项目目标复制到 c:\temp,无需重试并且包含所有子目录(空或非空),我们将使用:
With <src>, <tgt> being the copy source and target respectfully, and <opt> being robocopy options:
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:
仅仅检查退出代码是否为 1 是不正确的,因为任何低于 8 的退出代码都是正确的:
(澄清一下,退出代码 8 也是一个错误:
几个文件未复制
)正确的代码应该如下所示:
Simply checking for an exit code of 1 is incorrect, as any exit code below 8 is non-erroneous:
(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:
从语法上讲,这里是一个每命令一行的版本,可以直接在 PreBuild 步骤中运行:
参考文献:
Syntactically here is a one-line-per-command version that works directly within the PreBuild steps:
References:
在我看来,公认的答案是矫枉过正。 Robocopy 已经定义了退出代码,因此我们通常可以假设
8
或更少的任何值都表示一切顺利。因此,假设您的命令是,
ROBOCOPY $(Source) $(Dest) *.*< /code>,我将其称为
$(RobocopyBinCommand)
。在 Visual Studio 中,针对预构建或构建后事件,单击下拉列表并选择
在命令下方创建一个新行,并放置
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 退出 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.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:Advanced Exit Code Requirements
Let's say you only want the build to pass if ROBOCOPY returns
1
or3
. The if-check above won't allow you to even use theOR
-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 like23
or16
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 tofindstr
which then compares errorlevel to1
or3
. 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.MSBuild 扩展包 包含可在构建过程中使用的 Robocopy 任务。
这可以成为您的解决方案,而不是 VS 构建前/构建后事件吗?
如果是这样,您可以扩展 Visual Studio 构建过程 通过覆盖 BeforeBuild、AfterBuild 目标并调用 Robocopy 任务(如果其他目标更适合您的需求,您也可以覆盖其他目标,请参阅链接的 MSDN 页面中的列表)
因此,实际上您应该下载并安装 MSBuild 扩展包,而不是打开项目的 csproj/vbproj 文件并按以下方式进行编辑:
添加以下条目以导入 MSBuild 扩展包的 Robocopy 任务
覆盖 BeforeBuild、AfterBuild 并执行 Robocopy任务
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
Overriding BeforeBuild, AfterBuild and executing the Robocopy task
我发现启动 robocopy 比尝试在 Visual Studio 中调用它要容易得多。这样,Visual Studio 就不会关心 robocopy 的返回代码。
我能看到的唯一区别是,您将看到命令提示符出现并消失以执行 robocopy 命令。
使用 call 而不是 start 实际上不会打开命令提示符,更好的是,将输出从 robocopy 重定向到 Visual Studio 输出窗口。
由于某种原因,此方法仅在预构建事件命令行中使用时才有效。
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.
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.
For some reason this approach only works when used in Pre-build events command line.