MSBuild metadata in related product groups

I have two groups of elements that I want to join:

<ItemGroup> <ServerTypeA Include="ServerA;ServerB;"> <MetaDataA>A</MetaDataA> </ServerTypeA> </ItemGroup> <ItemGroup> <ServerTypeB Include="ServerB;ServerC;"> <MetaDataB>B</MetaDataB> </ServerTypeB> </ItemGroup> 

Using a regular join, you will get a collection with 4 elements:

 ServerA with Metadata A; ServerB with Metadata A; ServerB with Metadata B; ServerC with Metadata B; 

How to create the following collection:

 ServerA with Metadata A ServerB with Metadata A & B ServerC with Metadata B 
+4
source share
1 answer

It is possible. You must manually connect.

Here is an example of how to do this (msbuild 3.5 or higher is required):

 <ItemGroup> <ServerTypeA Include="ServerA;ServerB;"> <MetaDataA>A</MetaDataA> </ServerTypeA> <ServerTypeB Include="ServerB;ServerC;"> <MetaDataB>B</MetaDataB> </ServerTypeB> </ItemGroup> <Target Name="JoinServers" DependsOnTargets="ProcessServerTypeA;ProcessServerTypeB"> <Message Text="%(Joined.Identity) Metadata: %(Joined.MetaDataA)%(Joined.MetaDataB)"/> </Target> <!--Create --> <Target Name="ProcessServerTypeA"> <ItemGroup> <Joined Include="%(ServerTypeA.Identity)"> <MetaDataA>%(ServerTypeA.MetaDataA)</MetaDataA> </Joined> </ItemGroup> </Target> <!--Need to batch at the target level for this to work--> <Target Name="ProcessServerTypeB" Inputs="@(ServerTypeB)" Outputs="%(ServerTypeB.Identity)'"> <PropertyGroup> <!--Create Temporary Properties for the Item Metadata--> <TempItemName>%(ServerTypeB.Identity)</TempItemName> <TempMetaDataB>%(ServerTypeB.MetaDataB)</TempMetaDataB> <!--Does the current item already exist?--> <TempIsDuplicate Condition="'%(Joined.Identity)' == '$(TempItemName)'">True</TempIsDuplicate> </PropertyGroup> <ItemGroup> <!--Update the existing item metadata if this is a duplicate--> <!--Don't provide the include attribute. This will allow you to update existing items metadata--> <!--Have to reference %(Joined.Identity) in the condtion to ensure we only update the correct item--> <!--You cannot directly reference metadata from ServerTypeB here. Hence the need for the temp Properties--> <Joined Condition="'%(Joined.Identity)' == '$(TempItemName)'"> <MetaDataB>$(TempMetaDataB)</MetaDataB> </Joined> <!--Create a new item if current item is not a duplicate--> <Joined Include="$(TempItemName)" Condition="'$(TempIsDuplicate)' != 'True'"> <MetaDataB>$(TempMetaDataB)</MetaDataB> </Joined> </ItemGroup> </Target> 

Running the JoinServers target will result in the following output:

 ServerA Metadata: A ServerB Metadata: AB ServerC Metadata: B 

Update with best answer.

This question pointed me to a much simpler solution.

Basically you use Transform modifiers with %(Identity) to make the connection.

You can replace all 3 goals from above with the following to get the same result.

 <Target Name="JoinServers"> <ItemGroup> <Joined Include="%(Identity)"> <MetaDataA>@(ServerTypeA->'%(MetaDataA)')</MetaDataA> <MetaDataB>@(ServerTypeB->'%(MetaDataB)')</MetaDataB> </Joined> </ItemGroup> <Message Text="%(Joined.Identity) Metadata: %(Joined.MetaDataA)%(Joined.MetaDataB)"/> </Target> 
+8
source

Source: https://habr.com/ru/post/1335949/


All Articles