2010-09-11 62 views
13

我试图使用MSBuild的Copy任务递归复制文件夹到多个目标文件夹。我已经看到了这给了我一个良好的开端以下问题,但我必须失去了一些东西:如何使用MSBuild复制任务复制到多个目标文件夹?

Msbuild copy to several locations based on list of destination parameter?

从我的构建文件摘要是如下:

<ItemGroup> 
    <DeployPath Include="\\server1\path" /> 
    <DeployPath Include="\\server2\path" /> 
</Item Group> 

<Target Name="Deploy"> 
    <Message Text="%(DeployPath.Identity)" /> 
    <Copy SourceFiles="@(ItemsToCopy)" DestinationFolder="%(DeployPath.Identity)\%(RecursiveDir)" /> 
</Target> 

当我运行这个,“消息”的任务,因为我所期望的,吐出来的2线:

\\server1\path 
\\server2\path 

的问题是,“复制”的任务似乎只运行一次,并且将文件复制到的根当前硬盘驱动器,而不是指定网络路径:

复制到C:\file1.txt,而不是\\server1\path\file1.txt

我是相当新的MSBuild的,所以我觉得我失去了一些东西基本相当这里。

任何帮助将不胜感激。

回答

22

你在这里处理的是称为配料。关于配料,我已经讨论了很多。你可以在http://sedotech.com/Resources#Batching找到我的博客。批处理是一种在MSBuild中无法做到的循环。您可以将组拆分为具有共同元数据值的值。元数据可以是标识,完整路径,文件名等值,您甚至可以制作自己的元数据。在任何情况下,当你批量超过1个值时,它们彼此独立分批。看看我创建的例子。执行目标的结果显示在脚本之后。

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 

    <ItemGroup> 
    <ItemsToCopy Include="src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt"/> 
    </ItemGroup> 

    <ItemGroup> 
    <DeployPath Include="C:\temp\path01\" /> 
    <DeployPath Include="C:\temp\path02\" /> 
    </ItemGroup> 

    <!-- 
    Target batching is happening here because there is a 
    %() expression inside the Outputs attribute. So that 
    means that this target will be repeated once per 
    uinque batch of %(DeployPath.Identity). Identity is 
    the value that is passed in the Incude= attribute. 
    Since we know there are two values we know that 
    this target will be executed twice, and on each 
    pass the DeployPath item will only look to contain 
    a single value. If there were duplicates then the list 
    could contain more than 1 value. 
    --> 
    <Target Name="Demo" Outputs="%(DeployPath.Identity)"> 
    <Message Text="DeployPath.Identity: %(DeployPath.Identity)" /> 

    <Message Text="======================================" Importance="high"/> 
    <Message Text="ItemsToCopy1: @(ItemsToCopy)|| DeployPath.Identity: %(DeployPath.Identity)" /> 
    <Message Text="======================================" Importance="high"/> 
    <!-- 
     In the next emample you are batching on both the DeployPath item list as well as 
     the ItemsToCopy item. When two batched items are in the same expression they are 
     matched individually, so you ge a value for DeployPath metadata but not ItemsToCopy 
     metadata. That is why your copy only copied to one location. 
    --> 
    <Message Text="ItemsToCopy2: @(ItemsToCopy)|| DeployPath.Identity-RecursiveDir: %(DeployPath.Identity)\%(RecursiveDir)" /> 
    <Message Text="======================================" Importance="high"/> 
    <!-- 
     In this example I create a property and assign it the value of 
     %(DeployPath.Identity). We know there will only be one such 
     value. Because there should only be one value with Identity 
     when this target is executed so it is safe to 
     convert item to property 

     Because we are not batching on both items we will get the values for both vaules 
     to be correct becuase the target is repeated for the other 
     DeployPath values. 
    --> 
    <PropertyGroup> 
     <_DeployPathIdentity>%(DeployPath.Identity)</_DeployPathIdentity> 
    </PropertyGroup> 
    <Message Text="ItemsToCopy3: @(ItemsToCopy)|| _DeployPathIdentity-RecursiveDir: $(_DeployPathIdentity)\%(RecursiveDir)" /> 

    <!-- 
     I've always preferred to use DestinationFiles so my sample 
     below uses that. But you could change the target to use 
     DestinationFolder instead. 
    --> 
    <Copy SourceFiles="@(ItemsToCopy)" 
      DestinationFiles="@(ItemsToCopy->'$(_DeployPathIdentity)%(RecursiveDir)%(Filename)%(Extension)')" /> 
    </Target> 

</Project> 

输出

Build started 9/10/2010 9:31:28 PM. 
Project "I:\Development\My Code\Community\MSBuild\CopyFiles01.proj" on node 1 (default targets). 
Demo: 
    DeployPath.Identity: C:\temp\path01\ 
    ====================================== 
    ItemsToCopy1: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| DeployPath.I 
    dentity: C:\temp\path01\ 
    ====================================== 
    ItemsToCopy2: || DeployPath.Identity-RecursiveDir: C:\temp\path01\\ 
    ItemsToCopy2: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| DeployPath.I 
    dentity-RecursiveDir: \ 
    ====================================== 
    ItemsToCopy3: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| _DeployPathI 
    dentity-RecursiveDir: C:\temp\path01\\ 
    Creating directory "C:\temp\path01". 
    Copying file from "src\0001.txt" to "C:\temp\path01\0001.txt". 
    Copying file from "src\0002.txt" to "C:\temp\path01\0002.txt". 
    Copying file from "src\sub\sub-0001.txt" to "C:\temp\path01\sub-0001.txt". 
    Copying file from "src\sub\sub-0002.txt" to "C:\temp\path01\sub-0002.txt". 
Demo: 
    DeployPath.Identity: C:\temp\path02\ 
    ====================================== 
    ItemsToCopy1: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| DeployPath.I 
    dentity: C:\temp\path02\ 
    ====================================== 
    ItemsToCopy2: || DeployPath.Identity-RecursiveDir: C:\temp\path02\\ 
    ItemsToCopy2: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| DeployPath.I 
    dentity-RecursiveDir: \ 
    ====================================== 
    ItemsToCopy3: src\0001.txt;src\0002.txt;src\sub\sub-0001.txt;src\sub\sub-0002.txt|| _DeployPathI 
    dentity-RecursiveDir: C:\temp\path02\\ 
    Creating directory "C:\temp\path02". 
    Copying file from "src\0001.txt" to "C:\temp\path02\0001.txt". 
    Copying file from "src\0002.txt" to "C:\temp\path02\0002.txt". 
    Copying file from "src\sub\sub-0001.txt" to "C:\temp\path02\sub-0001.txt". 
    Copying file from "src\sub\sub-0002.txt" to "C:\temp\path02\sub-0002.txt". 
Done Building Project "I:\Development\My Code\Community\MSBuild\CopyFiles01.proj" (default targets 
). 


Build succeeded. 
+0

优秀的解释和例子。谢谢! – WayneC 2010-09-12 19:59:29

+0

我可以踢自己 - 这个解决方案几个小时前就开放了,但一直在努力让复制到多个目的地工作 - 第三种方法做到了! – Oliver 2012-12-11 22:03:47

3

在拼图中最重要的缺少的部分似乎是Outputs属性Target元素上,没有这些你永远只执行对目标的一个项目整个列表。另一块是您需要在路上定义的新属性。

你的问题的解决方案是这样的:

<ItemGroup> 
    <DeployPath Include="\\server1\path" /> 
    <DeployPath Include="\\server2\path" /> 
</Item Group> 

<Target Name="Deploy" Outputs="%(DeployPath.Identity)"> 
    <PropertyGroup> 
     <Destination>%(DeployPath.Identity)</Destination> 
    </PropertyGroup> 
    <Message Text="Processing: '$(Destination)" /> 
    <Copy SourceFiles="@(ItemsToCopy)" 
      DestinationFolder="%(DeployPath.Identity)\%(RecursiveDir)" /> 
</Target> 
相关问题