2009-12-19 3 views
3

У меня есть сценарий, который пытается построить ItemGroup из всех файлов в определенном каталоге, исключая файлы с определенными именами (независимо от расширения).MSBuild: звездочки и странные 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 

Заметим, что оба ExcludeFilesA и ExcludeFilesB выглядят одинаково, но в результате группы RemainingFilesA и RemainingFilesB различаются.

В конечном счете, я хочу получить список RemainingFilesA, используя шаблон, сгенерированный таким же образом ExcludeFilesB. Можете ли вы предложить способ, или мне нужно полностью переосмыслить мой подход?

ответ

2

Истинная причина этого было обнаружено случайно, когда задача выполняется сгенерировала исключение.

Фактическое значение ExcludeFilesA: TestDir\SampleProj.*;TestDir\SampleLib1.* как можно было бы ожидать. Однако фактическое значение ExcludeFilesB составляет TestDir\SampleProj.%2a;TestDir\SampleLib1.%2a.

Предположительно Message освобождает строку перед ее использованием, но Include и Exclude нет. Это объясняет, почему строки выглядят одинаково, но ведут себя по-другому.

Кстати, порядок выполнения, похоже, не имеет ничего общего с этим, и я уверен (после обширных экспериментов), что все выполняется и оценивается точно в том порядке, в котором оно появляется в этом скрипте.

+0

Отличный улов ... хороший! – KMoraz

+0

Большое спасибо! Я попытался фактически избежать звездочки в '', чтобы позже получить его дословно без файлового глоблирования, и я не смог найти никакой информации об этом. Ваше исследование помогло мне - использование '% 2a' отключилось, а все' @ -> 'преобразования в более поздней команде получили звездочку. – quetzalcoatl

+0

aand сразу после написания этого комментария, я нашел https://docs.microsoft.com/en-us/visualstudio/msbuild/special-characters-to-escape, где явно указано для Include и asterisk, d'oh. – quetzalcoatl

0

Элементы должны быть оценены перед выполнением целей, а элемент ItemGroup PatternedFilenames создается на ходу в своем целевом контейнере. Вы можете обойти это, используя 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> 
+0

Ох ... спасибо за обходной путь, я попробую это. Не могли бы вы объяснить порядок, в котором все происходит более подробно? Очевидно, что 'ExcludeFilesA' инициализируется до создания ItemGroup' RemainingFilesA'; как получилось, что то же самое не происходит для 'RemainingFilesB'? Это почти похоже на порядок: 1. «Init» заканчивается; 2. Элементы группы из «Тест» оцениваются; 3. Вычислено значение RegexReplace; 4. «Тест» начинается и печатает сообщения. Но, конечно, это не так? ... –

+0

Прочтите раздел «Порядок оценки имущества и предметов» здесь: http://msdn.microsoft.com/en-us/library/dd997067(VS.100).aspx Это сообщение связано с вашей проблемой: http://elegantcode.com/2006/12/11/msbuild-items-run-time-evaluation-behavior/ – KMoraz