8

我需要编写我的构建脚本。我正在使用 MSBUILD,因为它与 VS.net 集成。我正在尝试将一些文件从构建环境复制到部署文件夹。我正在使用 MSBuild 的复制任务。但不是像我期望的那样复制目录树。它将所有内容复制到一个文件夹中。我重复目录树中的所有文件,最终都放在一个文件夹中。我需要它将文件夹和目录树复制到目标文件夹中。有什么我想念的吗?

这是我的构建脚本的相关部分:

<PropertyGroup>
    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
    <Source>outputfolder</Source>
    <DestEnv>x</DestEnv>
    <DeployPath>\\networkpath\$(DestEnv)</DeployPath>
</PropertyGroup>
<ItemGroup>
    <TargetDir Include="$(DeployPath)\**\*" Exclude="**\web.config"></TargetDir>
    <SourceDir Include="$(Source)\**\*" />
</ItemGroup>    
<Target Name="Clean" >
    <!-- clean detail ... -->
</Target>
<Target Name="migrate" DependsOnTargets="Clean">
    <Copy DestinationFolder="$(DeployPath)" SourceFiles="@(SourceDir)" />
</Target>
4

4 回答 4

15

只是我们在调试有关复制的 MSBuild 问题时发现的一个宝石:

http://blog.scrappydog.com/2008/06/subtle-msbuild-bug-feature.html

ItemGroups 在 Targets 之前被解析,因此当在脚本中进一步引用 ItemGroup 时,不会拾取任何创建新文件(例如编译!)的 Targets。

Eric Bowen 还描述了这个“功能”的变通方法,即CreateItem任务:

<Target Name="Copy" >
    <CreateItem Include="..\Source\**\bin\**\*.exe"
        Exclude="..\Source\**\bin\**\*.vshost.exe">
        <Output TaskParameter="Include" ItemName="CompileOutput" />
    </CreateItem>
    <Copy SourceFiles="@(CompileOutput)" 
        DestinationFolder="$(OutputDirectory)"></Copy>
</Target>

给他很多赞!

于 2009-01-12T07:53:53.047 回答
12

当您为 Copy 任务指定 DestinationFolder 时,它会从 SourceFiles 集合中获取所有项目并将它们复制到 DestinationFolder。这是意料之中的,因为复制任务无法确定每个项目路径的哪一部分需要替换为 DestinationFolder 以保持树结构。例如,如果您的 SourceDir 集合定义如下:

<ItemGroup>
    <SourceDir Include="$(Source)\**\*" />
    <SourceDir Include="E:\ExternalDependencies\**\*" />
    <SourceDir Include="\\sharedlibraries\gdiplus\*.h" />
</ItemGroup>

您希望目标文件夹树是什么样的?

要保留树,您需要进行身份转换并为 SourceFiles 集合中的每个项目生成一个目标项目。这是一个例子:

<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'$(DropPath)%(Identity)')" />

Copy 任务将获取 SourceFiles 集合中的每个项目,并将通过将源项目规范中 ** 之前的部分替换为 $(DropPath) 来转换其路径。

有人可能会争辩说 DestinationFolder 属性应该被编写为以下转换的快捷方式:

<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'$(DestinationFolder)%(Identity)')" />

唉,这将阻止您试图避免的深度复制到平面文件夹的情况,但其他人可能会在他们的构建过程中使用。

于 2008-11-05T23:15:48.207 回答
5

递归复制目录内容和结构的非常简单的示例:

<Copy SourceFiles="@(Compile)" DestinationFolder="c:\foocopy\%(Compile.RecursiveDir)"></Copy>

@(Compile) 是您要复制的所有文件的 ItemGroup。可能是这样的:

   <ItemGroup>
      <Compile Include=".\**\*.dll" /> 
   </ItemGroup>

Copy 任务会将所有文件复制到 c:\foocopy 中,就像 xcopy 一样。

于 2008-11-08T17:36:27.080 回答
4

我在MSDN中的一个示例中找到了该示例,我不明白,但会在 stackoverflow 中为我的同行留下一个示例。这是上面迁移目标的固定版本:

<Target Name="migrate" DependsOnTargets="Clean">
    <Copy DestinationFiles="@(SourceDir->'$(DeployPath)\%(RecursiveDir)%(Filename)%(Extension)')" SourceFiles="@(SourceDir)" />
</Target>

如果有人真正理解这个例子,请解释一下。祝你好运!

于 2008-11-05T23:07:26.210 回答