2010-09-11 96 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> 
相關問題