Двойной цикл в msbuild?
Я пишу script для msbuild, который должен сделать две партии за один шаг.
Пример: 2 группы элементов
<ItemGroup>
<GroupOne Include="1" />
<GroupOne Include="2" />
</ItemGroup>
<ItemGroup>
<GroupTwo Include="A" />
<GroupTwo Include="B" />
</ItemGroup>
Эти две группы должны быть связаны друг с другом:
<Message Text="%(GroupOne.Identity) %(GroupTwo.Identity)" />
Я надеялся, что msbuild сделает результат обеих партий, давая
1 A
2 A
1 B
2 B
.
Но этого не произошло. Вместо этого он возвратил следующее бесполезное дерьмо:
1
2
A
B
Выполняя это так, как блог из приведенной ниже ссылки предлагает (используя локальную группу свойств), например
<PropertyGroup>
<GroupOneStep>%(GroupOne.Identity)</GroupOneStep>
</PropertyGroup>
<Message Text="$(GroupOneStep) %(GroupTwo.Identity)" />
марки
2 A
2 B
Любые подсказки? Я сошел с ума.: - (
PS: Вот блогпост о теме - к сожалению, он не работает, как реквизит там:
http://blogs.msdn.com/b/giuliov/archive/2010/04/30/gotcha-msbuild-nested-loops-double-batching.aspx
Ответы
Ответ 1
Попробуйте создать новую группу ItemGroup, используя идентификатор из группы 1 и присвоив метаданные новой группе элементов из идентификатора (или любых других метаданных) группы 2. Затем используйте пакетную обработку для итерации по новой группе.
<CreateItem Include="@(GroupOne)" AdditionalMetadata="Option1=%(GroupTwo.Identity)">
<Output ItemName="_Group_Merged" TaskParameter="Include"/>
</CreateItem>
<Message Text="%(_Group_Merged.Identity)-%(_Group_Merged.Option1)" />
Если у вас есть более двух групп, вы можете добавить записи CreateItem, чтобы объединить третью группу в _Group_Merged, а затем перебрать эту объединенную группу.
<CreateItem Include="@(_Group_Merged)" AdditionalMetadata="Option2=%(GroupThree.Identity)">
<Output ItemName="_Group_Merged2" TaskParameter="Include"/>
</CreateItem>
<Message Text="%(_Group_Merged2.Identity)-%(_Group_Merged2.Option1)-%(_Group_Merged2.Option2)" />
Ответ 2
Это гораздо более простое решение.
<Target Name="Default">
<ItemGroup>
<Combined Include="@(GroupOne)">
<GroupTwo>%(GroupTwo.Identity)</GroupTwo>
</Combined>
</ItemGroup>
<Message Text="%(Combined.Identity) %(Combined.GroupTwo) " />
</Target>
Использование промежуточной группы элементов Combined
для создания промежуточной группы элементов, в которую входит задача Message.
Если вы ссылаетесь на две группы элементов в одной и той же задаче, Msbuild будет загружаться на них как по отдельности. который НЕ является тем, что вы хотите
Если у вас больше ItemMetaData, вам нужно будет явно это обработать для второй ItemGroup, ItemGroup, включенный в ссылочный символ @, автоматически включает ItemMetaData, поэтому вам просто нужно создать дополнительные метаданные из второй группы ссылки явно. Вот пример:
<ItemGroup>
<GroupOne Include="1">
<Name>One</Name>
</GroupOne>
<GroupOne Include="2">
<Name>Two</Name>
</GroupOne>
</ItemGroup>
<ItemGroup>
<GroupTwo Include="A">
<Name>Andrew</Name>
</GroupTwo>
<GroupTwo Include="B">
<Name>Bob</Name>
</GroupTwo>
</ItemGroup>
<Target Name="Default">
<ItemGroup>
<Combined Include="@(GroupOne)">
<GroupTwo>%(GroupTwo.Identity)</GroupTwo>
<GroupTwoName>%(GroupTwo.Name)</GroupTwoName>
</Combined>
</ItemGroup>
<Message Text="%(Combined.Identity) %(Combined.Name) %(Combined.GroupTwoName) %(Combined.GroupTwo) " />
</Target>
Ответ 3
Можно также создать тройные вложенные циклы, используя технику Dog Ears.
<Target Name="Test">
<ItemGroup>
<Loop1 Include="L11" />
<Loop1 Include="L12" />
<Loop2 Include="L21" />
<Loop2 Include="L22" />
<Loop3 Include="L31" />
<Loop3 Include="L32" />
<Loop12 Include="@(Loop1)">
<!-- Combine Loop1 and Loop2: Inherit each meta data of Loop1 and add some of Loop2. -->
<Loop2Identity>%(Loop2.Identity)</Loop2Identity>
</Loop12>
<Loop123 Include="@(Loop12)">
<!-- Combine Loop12 and Loop3: Inherit each meta data of Loop12 and add some of Loop3. -->
<Loop3Identity>%(Loop3.Identity)</Loop3Identity>
</Loop123>
</ItemGroup>
<!-- Show all entries of Loop1 and Loop2 combined -->
<Message Text="Loop12.Identity=%(Loop12.Identity), Loop12.Value1=%(Loop12.Value1), Loop12.Loop2Identity=%(Loop12.Loop2Identity)"/>
<!-- Show all entries of Loop1, Loop2 and Loop3 combined -->
<Message Text="Loop123.Identity=%(Loop123.Identity), Loop123.Loop2Identity=%(Loop123.Loop2Identity) Loop123.Loop2Identity=%(Loop123.Loop3Identity)"/>
</Target>
Ответ 4
Для двух вложенных циклов это работает:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<GroupOne Include="1" />
<GroupOne Include="2" />
</ItemGroup>
<ItemGroup>
<GroupTwo Include="A" />
<GroupTwo Include="B" />
</ItemGroup>
<Target Name="Exec"
Outputs="%(GroupOne.Identity)">
<Message Text="Building @(GroupOne->'%(Identity)') %(GroupTwo.Identity)"/>
</Target>
</Project>
Результаты в:
Project "D:\tmp\msbuildtest\test.xml" on node 0 (default targets).
Building 1 A
Building 1 B
Exec:
Building 2 A
Building 2 B
Done Building Project "D:\tmp\msbuildtest\test.xml" (default targets).