Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double-Loop in msbuild?

I'm writing a script for msbuild which should make two batches in one step.
Example: 2 ItemGroups

<ItemGroup>
 <GroupOne Include="1" />
 <GroupOne Include="2" />
</ItemGroup>

<ItemGroup>
 <GroupTwo Include="A" />
 <GroupTwo Include="B" />
</ItemGroup>

These two groups should be looped within each other:

<Message Text="%(GroupOne.Identity) %(GroupTwo.Identity)" />

I hoped that msbuild makes the result up of both batches giving

1 A  
2 A  
1 B  
2 B  

as result.
But that didn't happen. Instead, it returned the following useless crap:

1  
2  
  A  
  B  

Doing it the way the blog from the link below proposes (using a local propertygroup) like

<PropertyGroup>
  <GroupOneStep>%(GroupOne.Identity)</GroupOneStep>
</PropertyGroup>
<Message Text="$(GroupOneStep) %(GroupTwo.Identity)" />

makes

2 A   
2 B

Any hints? I'm going mad. :-(

PS: Here's a blogpost about the topic - unfortunately it doesn't work as propsed there: http://blogs.msdn.com/b/giuliov/archive/2010/04/30/gotcha-msbuild-nested-loops-double-batching.aspx

like image 391
Sascha Avatar asked Jan 24 '11 19:01

Sascha


2 Answers

This is a much simpler solution.

<Target Name="Default">
    <ItemGroup>
        <Combined Include="@(GroupOne)">
            <GroupTwo>%(GroupTwo.Identity)</GroupTwo>
        </Combined>
    </ItemGroup>

    <Message Text="%(Combined.Identity) %(Combined.GroupTwo) " />
</Target>

Using an intermediate Item group Combined to create an intermediate item group that the Message task batches on.

If you reference two Item groups in the same task, Msbuild will batch on them both separately. which is NOT what you want

If you have more ItemMetaData you'll need to handle that explicitly for the second ItemGroup, The ItemGroup included with the reference symbol @ automatically includes the ItemMetaData, so you'll just need to create the additional MetaData from the second group by referencing explicitly. Here's an example:

<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>
like image 58
Dog Ears Avatar answered Oct 20 '22 13:10

Dog Ears


Try this to create a new ItemGroup using the identity from group 1 and assigning metadata to the new item group from the identity (or any other metadata) of group 2. Then use batching to iterate over the new group.

<CreateItem Include="@(GroupOne)" AdditionalMetadata="Option1=%(GroupTwo.Identity)">
    <Output ItemName="_Group_Merged" TaskParameter="Include"/>
</CreateItem>

<Message Text="%(_Group_Merged.Identity)-%(_Group_Merged.Option1)" />

If you have more than two groups you can add CreateItem entries to merge the third group into _Group_Merged and then iterate over that combined group.

<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)" />
like image 12
Brian Walker Avatar answered Oct 20 '22 12:10

Brian Walker