我正在尝试使用MSBuild脚本来构建和提取部署相当大的Web应用程序。 (我们在几十个目录中谈论几千个文件,这里。它几乎是一个继承的遗留代码库,所以我无能为力。)构建本身运行良好,但我似乎无法复制文件到放置位置正常工作。
这是一段代码,展示了构建脚本中的内容:
<PropertyGroup Condition=" '$(UseBuildNumber)' == 'true' ">
<ReleaseDirectory>$(ReleaseBaseDirectory)$(ReleaseName)\$(BuildNumber)</ReleaseDirectory>
</PropertyGroup>
<ItemGroup>
<OutputFiles Include="
$(SourceRoot)**\*.aspx;
$(SourceRoot)**\*.dll;
$(SourceRoot)**\*.gif;
$(SourceRoot)**\*.ascx;
" />
</ItemGroup>
<Message Text="Output files ==> @(OutputFiles)" />
<Copy
SourceFiles="@(OutputFiles)"
DestinationFolder="$(ReleaseDirectory)"
SkipUnchangedFiles="false"
/>
我在其中添加了一些额外的<Message/>
来验证各个路径是否正确扩展,$(SourceRoot)
和$(ReleaseDirectory)
确实都有正确的路径。但是,在输出中,我得到了(完整路径为简洁而省略):
Task "Message"
Output files ==> ...\Requirement1866**\*.aspx;...\Requirement1866**\*.dll;...\Requirement1866**\*.gif;...\Requirement1866**\*.ascx
Done executing task "Message".
显然,尚未执行通配符扩展,然后以下Copy
(可预见地足够)失败。我只包括一个;实际上,对于每个文件名通配符模式(这反过来比我在上面的构建脚本片段中包含的要多得多)会重复这一过程。
Using "Copy" task from assembly "Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".
Task "Copy"
Copying file from "*basedir*\Requirement1866**\*.aspx" to "*targetdir*\Requirement1866\*buildnumber*\*.aspx".
Command:
copy /y "*basedir*\Requirement1866**\*.aspx" "*targetdir*\Requirement1866\*buildnumber*\*.aspx"
d:\Builds\215\BuildType\TFSBuild.proj(120,5): error MSB3021: Unable to copy file "*basedir*\Requirement1866**\*.aspx" to "*targetdir*\Requirement1866\*buildnumber*\*.aspx". Illegal characters in path.
接下来是:
d:\Builds\215\BuildType\TFSBuild.proj(120,5): error MSB3021: Unable to copy file "*basedir*\Requirement1866**\*.aspx" to "*targetdir*\Requirement1866\*buildnumber*\*.aspx". Illegal characters in path.
我在谷歌搜索中遇到的唯一合理相关的打击是Copy Task - Illegal characters in path,但我已经使用了<ItemGroup>
,<CreateItem>
示例(改编)没有什么都不用,早点中止错误,说TaskParameter
未知(对不起,我没有在我面前的确切错误消息)。
作为一种权宜之计,我可以进入并手动将相关文件从构建输出目录复制到我想要的位置,但我希望这个过程能够实现自动化。
然后,我如何使用MSBuild将构建过程中创建的文件复制到输出目录中,同时保留相对目录结构,而不是逐个列出它们?
答案 0 :(得分:21)
基本上,**
是单个路径元素,因此必须在Include
指令中以相应的反斜杠分隔:
<ItemGroup>
<OutputFiles Include="
$(SourceRoot)\**\*.aspx;
$(SourceRoot)\**\*.dll;
$(SourceRoot)\**\*.gif;
$(SourceRoot)\**\*.ascx;
" />
</ItemGroup>
请注意指定例如$(SourceRoot)\**\*.aspx
而非破碎的$(SourceRoot)**\*.aspx
。如果$(SourceRoot)
以\
结尾,那么通配符扩展可能也会起作用。
其次,在<Copy/>
中,使用%(RecursiveDir)
:
<Copy
SourceFiles="@(OutputFiles)"
DestinationFolder="$(ReleaseDirectory)\%(RecursiveDir)"
SkipUnchangedFiles="false"
/>
通过这些更改,它似乎就像我想要的那样工作:文件被复制到目标目标目录,源的目录结构保留在目标位置。
答案 1 :(得分:2)
另一个建议,不是为每种文件类型添加包含,而是添加Excludes。
<ItemGroup>
<OutputFiles Include="$(SourceRoot)**\*.*" Exclude="$(SourceRoot)**\*.cs;$(SourceRoot)**\*.resx" " />
</ItemGroup>
这样输出将包含任何JS,HTML,DHTML和其他所需的文件类型。