如何在msbuild中挑选要复制的文件并保留目录结构?

时间:2012-04-03 15:16:43

标签: msbuild

我有一个我正在使用steal编译的Web应用程序,然后我只想复制生产所需的文件,但我需要保留目录结构。例如,在运行steal的构建(将js / css编译为production.js / css文件)之后,目录看起来像这样:

\WebApp\index.html
\WebApp\app\img\a.png 
\WebApp\app\img\b.png
\WebApp\app\js\foo.js
\WebApp\app\js\bar.js
\WebApp\app\css\base.css
\WebApp\app\css\app.css
\WebApp\app\css\widget1.css
\WebApp\app\production.js
\WebApp\app\production.css
\WebApp\steal\steal.js
\WebApp\steal\README.md
\WebApp\steal\build\build.js

除此之外,我想只将一些特定文件复制到同一个目录结构中:

\artifacts\staging\www\index.html
\artifacts\staging\www\app\img\a.png 
\artifacts\staging\www\app\img\b.png
\artifacts\staging\www\app\production.js
\artifacts\staging\www\app\production.css
\artifacts\staging\www\steal\steal.js

理想情况下,我会有这样的事情:

<PropertyGroup>
  <WorkingDir>WebApp\</WorkingDir> 
  <OutputDir>artifacts\staging\www\</OutputDir>
</PropertyGroup>

...

<ItemGroup>
  <CopyFiles Remove="@(CopyFiles)" /> <!-- clean existing items -->
  <CopyFiles Condition="'$(Configuration)'=='Debug'"
        Include="$(WorkingDir)\**\*.*" 
        Exclude="$(WorkingDir)\**\.svn\**" />
  <CopyFiles Condition="'$(Configuration)'=='Release'"
        Include="$(WorkingDir)\index.html;$(WorkingDir)\app\img\**\*.*;$(WorkingDir)\app\production.*;$(WorkingDir)\steal\steal.js;" 
        Exclude="$(WorkingDir)\**\.svn\**" />
</ItemGroup>

<Copy SourceFiles="@(CopyFiles)" 
    DestinationFolder="@(CopyFiles->'$(OutputDir)\%(RecursiveDir)%(Filename)%(Extension)')" />

问题当然没有保留目录结构,实际上我只是将所有文件都放到没有子目录的$(OutputDir)中。 %(RecursiveDir)**的扩展,但由于我明确指定了大多数路径,因此它实际上并未生效。


现在我知道我可以用一堆copy任务和itemgroup来强制执行此操作,但除了丑陋之外,它还引入了自己的问题。首先,它容易出错,因为如果有人想要添加项目,他们必须确保使用唯一的项目组名称(此构建脚本很大并且执行许多其他任务),并确保多条线路都同步。

必须有比这更好的方法吗?

<ItemGroup>
  <IndexFiles Include="$(WorkingDir)\index.html" />
  <ImgFiles Include="$(WorkingDir)\app\img\**\*.*" />
  <AppFiles Include="$(WorkingDir)\app\production.*" />
  ...
</ItemGroup>

<Copy SourceFiles="@(IndexFiles)" 
    DestinationFolder="@(IndexFiles->'$(OutputDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
<Copy SourceFiles="@(ImgFiles)" 
    DestinationFolder="@(ImgFiles->'$(OutputDir)\app\img\%(RecursiveDir)%(Filename)%(Extension)')" />
<Copy SourceFiles="@(AppFiles)" 
    DestinationFolder="@(AppFiles->'$(OutputDir)\app\%(RecursiveDir)%(Filename)%(Extension)')" />
....

3 个答案:

答案 0 :(得分:2)

我遇到了同样的问题,经过一番挣扎,我成功了。关键是在“**”之后指定要包含的文件夹。

<ItemGroup>
    <CopyFiles Include="$(WorkingDir)\index.html" />
    <CopyFiles Include="$(WorkingDir)\**\app\img\**\*.*" />
    <CopyFiles Include="$(WorkingDir)\**\app\production.*" />
    ...
</ItemGroup>

因此,输出目录将包含所有子目录为“img”的app文件夹,以及名为“production”的所有文件。

作为注释 - “RecursiveDir”部分保持不变。

答案 1 :(得分:1)

只是添加到底池。

您还可以使用“排除某些文件”策略。

以下内容将获取所有* .txt和* .doc文件...但也会排除特定名称的文件。

问题是.....你是否更感兴趣包括某些文件......或.....不包括某些文件。

不时需要两种“技巧”。

<ItemGroup>
    <MyExcludeFiles Include="$(WorkingDir)\**\SuperSecretStuff.txt" />
    <MyExcludeFiles Include="$(WorkingDir)\**\SuperSecretStuff.doc" />
</ItemGroup>

<ItemGroup>
    <MyIncludeFiles Include="$(WorkingDir)\**\*.txt" Exclude="@(MyExcludeFiles)"/>
    <MyIncludeFiles Include="$(WorkingDir)\**\*.doc" Exclude="@(MyExcludeFiles)"/>
</ItemGroup>        


<Copy
SourceFiles="@(MyIncludeFiles)"
DestinationFiles="@(MyIncludeFiles->'$(OutputDir)\%(RecursiveDir)%(Filename)%(Extension)')"
/>  

答案 2 :(得分:0)

您可以稍微改变逻辑并使用{​​{1}}包含所有内容,然后排除您不需要的文件:

**

然后,您可以使用 <CopyFiles Condition="'$(Configuration)'=='Debug'" Include="$(WorkingDir)\**\*.*" Exclude="$(WorkingDir)\**\.svn\**" /> <CopyFiles Condition="'$(Configuration)'=='Release'" Include="$(WorkingDir)\**\*.*" Exclude="$(WorkingDir)\**\.svn\**;$(WorkingDir)\app\css\*.*;$(WorkingDir)\app\js\*.*;$(WorkingDir)\steal\README.md;$(WorkingDir)\steal\build\*.*" /> 属性。