3

我有一个脚本,它试图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生成的模式来获取列表。你能建议一种方法,还是我必须完全重新考虑我的方法?

4

2 回答 2

2

当自定义任务引发异常时,意外揭示了真正的原因。

的实际值与人们预期ExcludeFilesA的一样。然而 的实际TestDir\SampleProj.*;TestDir\SampleLib1.*值为。ExcludeFilesBTestDir\SampleProj.%2a;TestDir\SampleLib1.%2a

大概Message在使用它之前对字符串进行转义,但Include不要Exclude。这可以解释为什么字符串看起来相同但行为不同。

顺便说一句,执行顺序似乎与此无关,而且我很确定(经过广泛的实验)所有内容都会完全按照它在此脚本中出现的顺序执行和评估。

于 2009-12-20T15:36:51.687 回答
0

ItemGroups 需要在目标执行之前进行评估,并且PatternedFilenamesItemGroup 是在其目标容器中动态创建的。您可以使用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>
于 2009-12-19T21:27:10.760 回答