2018-03-16
在 msbuild 的 Copy Task 中复制子目录

自从上次用 msbuild 重写了整个项目的构建流程,终于体会到一点 msbuild 的强大了。这回我需要在 CI 流程中把一个目录的文件复制到另外一个目录中去,复制之前需要判断目标目录是否存在,存在的话,要先删除原目录,然后在复制。这涉及到一点编程元素,我十分不愿意写 windows batch 脚本,也不愿意写 powershell 脚本(好吧,其实是不会写😓),唯一剩下的选择似乎只有 msbuild 了。

没问题,我用过 msbuild 的 Copy Task,问题应该不大……然而,真正用它完成我的任务时发现了问题,原先我只是用它复制一个目录下的所有文件,但是现在我也需要复制一个目录下的所有子目录。然而 Copy Task 并没有一个简单直观的方法可以做到。必须使用如下“奇怪”的方式

1
2
3
4
5
6
7
8
9
10
11
12
<Project ToolsVersion="15.0" DefaultTargets="CopyFiles" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SCAdminSourceFolder Include="D:\SCAdmin" />
<SCAdminSourceFiles Include="D:\SCAdmin\**\*.*" />
<SCAdminDestinationFolder Include="E:\SCAdmin" />
</ItemGroup>

<Target Name="CopyFiles">
<RemoveDir Directories="@(SCAdminDestinationFolder)" Condition="Exists('@(SCAdminDestinationFolder)')" />
<Copy SourceFiles="@(SCAdminSourceFiles)" DestinationFolder="E:\SCAdmin\%(RecursiveDir)" />
</Target>
</Project>

以上的例子重点是 Copy Task 的 DestinationFolder 属性,需要注意2点:

  1. %(RecursiveDir) 这是关键,要复制所有文件包括按照原样复制子目录,需要使用这个特定“字符串”,它是固定的。具体解释可以参考这里
  2. DestinationFolder 使用了 %(RecursiveDir) 好像就不能用其它参数了(比如 SCAdminDestinationFolder),不知道为什么……所以没法使用 SCAdminDestinationFolder 参数。
阅读此文