Generating a cross-product with MSBuild 1

Have you ever wanted to create a cross-product of two item groups in TeamBuild? Aaron Hallberg has a post in which he explains two possible ways of doing it. I struggled with the same problem a few days ago and found another solution that doesn’t involve creating your own MSBuild Task but still keeps the “collection aspect of batching”.

Aaron has a simple lab example that I will use to explain my approach. The goal is to create a cross product of the Foo and Bar collections and then print out the result. My solution follows:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="PrintFooAndBar"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >

<ItemGroup>
<Foo Include="foo1">
<FooMetadata>1</FooMetadata>
</Foo>
<Foo Include="foo2">
<FooMetadata>2</FooMetadata>
</Foo>
</ItemGroup>

<ItemGroup>
<Bar Include="bar1">
<BarMetadata>a</BarMetadata>
</Bar>
<Bar Include="bar2">
<BarMetadata>b</BarMetadata>
</Bar>
</ItemGroup>

<Target Name="PrintFooAndBar">
<!-- Create a new list of Items that contain the cross product of Bar and Foo -->
<CreateItem Include="@(Bar)"
AdditionalMetadata="FooMetadata=%(Foo.FooMetadata)">
<Output ItemName="InternalBar" TaskParameter="Include"/>
</CreateItem>

<!-- Print the contents of the new list -->
<Message Importance="high"
Text="FooMetadata=%(InternalBar.FooMetadata), BarMetadata=%(InternalBar.BarMetadata)" />
</Target>
</Project>

I simply use the CreateItem task to merge the two collections into a new collection that contains the metadata from both. I then use this new collection to print out the messages!

If more information is needed from the collections (maybe you want to keep the %Identity data from Foo) you can simply add more stuff to the AdditionalMetadata attribute (“Foo=%(Foo.Identity);FooMetadata=%(Foo.FooMetadata)”)

One comment on “Generating a cross-product with MSBuild

Comments are closed.