MSBuild:星号和奇怪的 ItemGroup 排除行为
我有一个脚本尝试从某个目录中的所有文件构建一个 ItemGroup
,同时排除具有特定名称的文件(无论扩展名如何)。
要排除的文件列表最初包含文件扩展名,我正在使用社区任务的 RegexReplace
将扩展名替换为星号。然后,我在该项目的 Exclude
属性中使用此列表。由于某种原因,即使列表看起来是正确的,文件也没有被正确排除。
为了尝试找到原因,我创建了一个测试脚本(如下),它有两个任务:第一个以两种不同的方式使用文件模式列表初始化两个属性。第二个任务打印这两个属性以及在 Exclude
属性中使用这两个属性所生成的文件。
属性的值看起来相同,但生成的组不同。这怎么可能?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Init;Test" ToolsVersion="3.5">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="Init">
<ItemGroup>
<OriginalFilenames Include="TestDir\SampleProj.exe"/>
<OriginalFilenames Include="TestDir\SampleLib1.dll"/>
</ItemGroup>
<RegexReplace Input="@(OriginalFilenames)" Expression="\.\w+$" Replacement=".*">
<Output TaskParameter="Output" ItemName="PatternedFilenames"/>
</RegexReplace>
<PropertyGroup>
<ExcludeFilesA>TestDir\SampleProj.*;TestDir\SampleLib1.*</ExcludeFilesA>
<ExcludeFilesB>@(PatternedFilenames)</ExcludeFilesB>
</PropertyGroup>
</Target>
<Target Name="Test">
<Message Text='ExcludeFilesA: $(ExcludeFilesA)' />
<Message Text='ExcludeFilesB: $(ExcludeFilesB)' />
<ItemGroup>
<AllFiles Include="TestDir\**"/>
<RemainingFilesA Include="TestDir\**" Exclude="$(ExcludeFilesA)"/>
<RemainingFilesB Include="TestDir\**" Exclude="$(ExcludeFilesB)"/>
</ItemGroup>
<Message Text="
**AllFiles**
@(AllFiles, '
')" />
<Message Text="
**PatternedFilenames**
@(PatternedFilenames, '
')" />
<Message Text="
**RemainingFilesA**
@(RemainingFilesA, '
')" />
<Message Text="
**RemainingFilesB**
@(RemainingFilesB, '
')" />
</Target>
</Project>
输出(为了清晰起见,稍微重新格式化):
ExcludeFilesA: TestDir\SampleProj.*;TestDir\SampleLib1.*
ExcludeFilesB: TestDir\SampleProj.*;TestDir\SampleLib1.*
AllFiles:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
PatternedFilenames:
TestDir\SampleProj.*
TestDir\SampleLib1.*
RemainingFilesA:
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
RemainingFilesB:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
观察到 ExcludeFilesA
和 ExcludeFilesB
看起来相同,但生成的组 RemainingFilesA
和 RemainingFilesB
代码>不同。
最终,我想使用与生成 ExcludeFilesB
相同的方式生成的模式来获取列表 RemainingFilesA
。你能建议一种方法吗,还是我必须完全重新考虑我的方法?
I have a script that attempts to construct an ItemGroup
out of all files in a certain directory while excluding files with certain names (regardless of extension).
The list of files to be excluded initially contains file extensions, and I am using Community Tasks' RegexReplace
to replace the extensions with an asterisk. I then use this list in the item's Exclude
attribute. For some reason the files do not get excluded properly, even though the list appears to be correct.
To try and find the cause I created a test script (below) which has two tasks: first one initialises two properties with the list of file patterns in two different ways. The second task prints both properties and the files resulting from using both these properties in the Exclude
attribute.
The properties' values appear to be identical, however the resulting groups are different. How is this possible?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Init;Test" ToolsVersion="3.5">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="Init">
<ItemGroup>
<OriginalFilenames Include="TestDir\SampleProj.exe"/>
<OriginalFilenames Include="TestDir\SampleLib1.dll"/>
</ItemGroup>
<RegexReplace Input="@(OriginalFilenames)" Expression="\.\w+$" Replacement=".*">
<Output TaskParameter="Output" ItemName="PatternedFilenames"/>
</RegexReplace>
<PropertyGroup>
<ExcludeFilesA>TestDir\SampleProj.*;TestDir\SampleLib1.*</ExcludeFilesA>
<ExcludeFilesB>@(PatternedFilenames)</ExcludeFilesB>
</PropertyGroup>
</Target>
<Target Name="Test">
<Message Text='ExcludeFilesA: $(ExcludeFilesA)' />
<Message Text='ExcludeFilesB: $(ExcludeFilesB)' />
<ItemGroup>
<AllFiles Include="TestDir\**"/>
<RemainingFilesA Include="TestDir\**" Exclude="$(ExcludeFilesA)"/>
<RemainingFilesB Include="TestDir\**" Exclude="$(ExcludeFilesB)"/>
</ItemGroup>
<Message Text="
**AllFiles**
@(AllFiles, '
')" />
<Message Text="
**PatternedFilenames**
@(PatternedFilenames, '
')" />
<Message Text="
**RemainingFilesA**
@(RemainingFilesA, '
')" />
<Message Text="
**RemainingFilesB**
@(RemainingFilesB, '
')" />
</Target>
</Project>
Output (reformatted somewhat for clarity):
ExcludeFilesA: TestDir\SampleProj.*;TestDir\SampleLib1.*
ExcludeFilesB: TestDir\SampleProj.*;TestDir\SampleLib1.*
AllFiles:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
PatternedFilenames:
TestDir\SampleProj.*
TestDir\SampleLib1.*
RemainingFilesA:
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
RemainingFilesB:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
Observe that both ExcludeFilesA
and ExcludeFilesB
look identical, but the resulting groups RemainingFilesA
and RemainingFilesB
differ.
Ultimately I want to obtain the list RemainingFilesA
using the pattern generated the same way ExcludeFilesB
is generated. Can you suggest a way, or do I have to completely rethink my approach?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当自定义任务抛出异常时,意外地揭示了真正的原因。
ExcludeFilesA
的实际值是TestDir\SampleProj.*;TestDir\SampleLib1.*
正如人们所期望的那样。但是ExcludeFilesB
的实际值是TestDir\SampleProj.%2a;TestDir\SampleLib1.%2a
。据推测,
Message
在使用字符串之前会对其进行转义,但Include
和Exclude
不会。这可以解释为什么字符串看起来相同但行为不同。顺便说一句,执行顺序似乎与此无关,并且我非常确定(经过大量实验)所有内容都按照该脚本中出现的顺序准确执行和评估。
The true cause of this was revealed accidentally when a custom task threw an exception.
The actual value of
ExcludeFilesA
isTestDir\SampleProj.*;TestDir\SampleLib1.*
like one might expect. However the actual value ofExcludeFilesB
isTestDir\SampleProj.%2a;TestDir\SampleLib1.%2a
.Presumably
Message
unescapes the string before using it, butInclude
andExclude
do not. That would explain why the strings look the same but behave differently.Incidentally, the execution order doesn't seem to have anything to do with this, and I'm pretty sure (following extensive experimentation) that everything gets executed and evaluated exactly in the order in which it appears in this script.
需要在目标执行之前评估 ItemGroup,并且
PatternedFilenames
ItemGroup 是在其目标容器内动态创建的。您可以使用 CreateItem 任务解决此问题,这将确保 < code>PatternedFilenames 整个执行过程中的范围:
ItemGroups need to be evaluated before targets execution, and the
PatternedFilenames
ItemGroup is being created on the fly within its target container.You could workaround this using the CreateItem task, which will ensure the
PatternedFilenames
scope throughout the execution: