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
отличаются.
В конечном итоге я хочу получить список RemainingFilesA
используя шаблон, сгенерированный таким же образом ExcludeFilesB
генерируется. Можете ли вы предложить способ, или я должен полностью переосмыслить свой подход?
2 ответа
Истинная причина этого была обнаружена случайно, когда пользовательская задача вызвала исключение.
Фактическая стоимость ExcludeFilesA
является TestDir\SampleProj.*;TestDir\SampleLib1.*
как и следовало ожидать. Однако фактическая стоимость ExcludeFilesB
является TestDir\SampleProj.%2a;TestDir\SampleLib1.%2a
,
предположительно Message
освобождает строку перед ее использованием, но Include
а также Exclude
не делайте. Это объясняет, почему строки выглядят одинаково, но ведут себя по-разному.
Между прочим, порядок выполнения, похоже, не имеет к этому никакого отношения, и я почти уверен (после долгих экспериментов), что все выполняется и оценивается точно в том порядке, в котором оно появляется в этом сценарии.
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>