Normalization of the list of elements in MSBuild

I am trying to get a list of all unit test assemblies at the root of my project. I can do it like this:

<CreateItem Include="**\bin\**\*.UnitTest.*.dll"> <Output TaskParameter="Include" ItemName="Items"/> </CreateItem> 

However, this will find the same DLLs several times, as they exist in several subdirectories. Is there an easy way for me to normalize based on element metadata (i.e. file name and extension) to get a list of unique unit test DLL files? Or do I need to resort to writing my own task?

+6
unique distinct msbuild normalize
source share
3 answers

The MSBuild Extension Pack contains an MSBuildHelper task that supports the RemoveDuplicateFiles command.

 <CreateItem Include="**\bin\**\*.UnitTest.*.dll"> <Output TaskParameter="Include" ItemName="Items"/> </CreateItem> <MSBuild.ExtensionPack.Framework.MsBuildHelper TaskAction="RemoveDuplicateFiles" InputItems1="@(Items)"> <Output TaskParameter="OutputItems" ItemName="Items"/> </MSBuild.ExtensionPack.Framework.MsBuildHelper> 
+4
source share

Although this is old, I could never get Thomas to work on my own, but I found a workaround using only the built-in commands with v4.0 msbuild:

 <ItemGroup> <TestAssemblies Include="$(SolutionRoot)\**\bin\*.Tests.dll" /> <TestItems Include="%(TestAssemblies.FileName)%(TestAssemblies.Extension)"> <ItemPath>%(TestAssemblies.Identity)</ItemPath> </TestItems> <DistinctTestItems Include="@(TestItems->Distinct())"></DistinctTestItems> </ItemGroup> <Message Text="%(DistinctTestItems.ItemPath)" Importance="high" /> 
+4
source share

I had a good search on the Internet and could not find a way to do this. If anyone knows a clean inline way, please let me know. In the meantime, I wrote a simple task to complete this work. Usage is as follows:

 <NormalizeByMetadata Items="@(ItemsToNormalize)" MetadataName="Filename"> <Output TaskParameter="NormalizedItems" ItemName="MyNormalizedItems"/> </NormalizeByMetadata> 

After completing the above task, MyNormalizedItems will contain only those items from ItemsToNormalize that have a unique value for Filename metadata. If two or more elements have the same value for their Filename metadata, the first match will be included in the output.

MSBuild Task Code:

 public class NormalizeByMetadata : Task { [Required] public ITaskItem[] Items { get; set; } [Required] public string MetadataName { get; set; } [Output] public ITaskItem[] NormalizedItems { get; private set; } public override bool Execute() { NormalizedItems = Items.Distinct(new ItemEqualityComparer(MetadataName)).ToArray(); return true; } private sealed class ItemEqualityComparer : IEqualityComparer<ITaskItem> { private readonly string _metadataName; public ItemEqualityComparer(string metadataName) { Debug.Assert(metadataName != null); _metadataName = metadataName; } public bool Equals(ITaskItem x, ITaskItem y) { if (x == null || y == null) { return x == y; } var xMetadata = x.GetMetadata(_metadataName); var yMetadata = y.GetMetadata(_metadataName); return string.Equals(xMetadata, yMetadata); } public int GetHashCode(ITaskItem obj) { if (obj == null) { return 0; } var objMetadata = obj.GetMetadata(_metadataName); return objMetadata.GetHashCode(); } } } 
+2
source share

All Articles