MSBuild:星号和奇怪的ItemGroup排除行为

时间:2009-12-19 00:26:27

标签: msbuild msbuildcommunitytasks msbuild-propertygroup

我有一个脚本尝试从某个目录中的所有文件中构造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="&#xA;**AllFiles**&#xA;@(AllFiles, '&#xA;')" />
    <Message Text="&#xA;**PatternedFilenames**&#xA;@(PatternedFilenames, '&#xA;')" />
    <Message Text="&#xA;**RemainingFilesA**&#xA;@(RemainingFilesA, '&#xA;')" />
    <Message Text="&#xA;**RemainingFilesB**&#xA;@(RemainingFilesB, '&#xA;')" />
  </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

观察ExcludeFilesAExcludeFilesB看起来相同,但结果组RemainingFilesARemainingFilesB不同。

最终,我希望使用生成RemainingFilesA的方式生成的模式获取列表ExcludeFilesB。你能提出一个方法,还是我必须彻底重新考虑我的做法?

2 个答案:

答案 0 :(得分:2)

当自定义任务引发异常时,意外泄露了这个原因。

ExcludeFilesA的实际值是TestDir\SampleProj.*;TestDir\SampleLib1.*,就像人们所期望的那样。但是,ExcludeFilesB的实际值为TestDir\SampleProj.%2a;TestDir\SampleLib1.%2a

大概Message在使用之前对字符串进行取景,但IncludeExclude没有。这可以解释为什么字符串看起来相同但表现不同。

顺便说一句,执行顺序似乎与此无关,我很确定(经过大量实验)所有内容都按照它在此脚本中出现的顺序执行和评估。< / p>

答案 1 :(得分:0)

在目标执行之前需要评估ItemGroups,并且在其目标容器中动态创建PatternedFilenames ItemGroup。 您可以使用CreateItem任务解决此问题,这将确保整个执行期间的PatternedFilenames范围:

<RegexReplace Input="@(OriginalFilenames)" Expression="\.\w+$" Replacement=".*">
  <Output TaskParameter="Output" ItemName="PatternedFilenames_tmp"/>
</RegexReplace>
<CreateItem Include="@(PatternedFilenames_tmp)">
  <Output TaskParameter="Include" ItemName="PatternedFilenames"/>
</CreateItem>