【问题标题】:How can I use MSBuild Copy Task to Copy To Multiple Destination Folders?如何使用 MSBuild 复制任务复制到多个目标文件夹?
【发布时间】:2011-04-11 00:27:08
【问题描述】:

我正在尝试使用 MSBuild 的复制任务将文件夹递归地复制到 多个 目标文件夹。我看到了以下问题,这给了我一个良好的开端,但我一定遗漏了一些东西:

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

我的构建文件中的一个 sn-p 如下:

<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 还很陌生,所以我觉得我在这里缺少一些非常基本的东西。

任何帮助将不胜感激。

【问题讨论】:

    标签: msbuild msbuild-task


    【解决方案1】:

    难题中最重要的缺失部分似乎是Target 元素上的Outputs 属性,如果没有它,您将始终只为整个列表中的一项执行目标。另一部分是您需要在途中定义的新属性。

    您的问题的解决方案可能如下所示:

    <ItemGroup>
        <DeployPath Include="\\server1\path" />
        <DeployPath Include="\\server2\path" />
    </ItemGroup>
    
    <Target Name="Deploy" Outputs="%(DeployPath.Identity)">
        <PropertyGroup>
            <Destination>%(DeployPath.Identity)</Destination>
        </PropertyGroup>
        <Message Text="Processing: '$(Destination)" />
        <Copy SourceFiles="@(ItemsToCopy)"
              DestinationFolder="%(DeployPath.Identity)\%(RecursiveDir)" />
    </Target>
    

    【讨论】:

      【解决方案2】:

      您在此处处理的内容称为批处理。我已经写了很多关于批处理的博客。您可以在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.
      

      【讨论】:

      • 很好的解释和例子。谢谢!
      • 我可以踢自己 - 有这个解决方案几个小时前开放,但一直在努力让复制到多个目的地工作 - 第三种方法做到了!
      猜你喜欢
      • 1970-01-01
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      相关资源
      最近更新 更多