我需要编写我的构建脚本。我正在使用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>
答案 0 :(得分:13)
我们在调试MSBuild问题时发现了一个宝石:
http://blog.scrappydog.com/2008/06/subtle-msbuild-bug-feature.html
在Targets之前解析ItemGroups,因此当沿着脚本进一步引用ItemGroup时,将不会拾取任何创建新文件的目标(例如编译!)。
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>
很多人对他赞不绝口!
答案 1 :(得分: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)')" />
复制任务将获取SourceFiles集合中的每个项目,并通过使用$(DropPath)替换源项目规范中的**之前的部分来转换其路径。
有人可能会说DestinationFolder属性应该被写为以下转换的快捷方式:
<Copy SourceFiles="@(Compile)" DestinationFiles="@(Compile->'$(DestinationFolder)%(Identity)')" />
唉,这会阻止你试图避免的深拷贝到平面文件夹场景,但其他人可能会在他们的构建过程中使用。
答案 2 :(得分:5)
以递归方式复制目录内容和结构的非常简单的示例:
<Copy SourceFiles="@(Compile)" DestinationFolder="c:\foocopy\%(Compile.RecursiveDir)"></Copy>
@(编译)是要复制的所有文件的ItemGroup。可能是这样的:
<ItemGroup>
<Compile Include=".\**\*.dll" />
</ItemGroup>
复制任务会将所有文件复制到c:\ foocopy中,就像xcopy一样。
答案 3 :(得分:4)
我在MSDN中的一个例子中找到了这个例子。我不明白它,但会在stackoverflow中为我的其他travlers留下一个例子。以下是上述迁移目标的固定版本:
<Target Name="migrate" DependsOnTargets="Clean">
<Copy DestinationFiles="@(SourceDir->'$(DeployPath)\%(RecursiveDir)%(Filename)%(Extension)')" SourceFiles="@(SourceDir)" />
</Target>
如果有人真正了解这个例子,请解释。祝你好运!