La normalización de una lista de artículos en MSBuild
Pregunta
Estoy tratando de obtener una lista de todos los conjuntos de pruebas unitarias en la raíz de mi proyecto. Puedo hacer esto de la siguiente manera:
<CreateItem Include="**\bin\**\*.UnitTest.*.dll">
<Output TaskParameter="Include" ItemName="Items"/>
</CreateItem>
Sin embargo, esto va a encontrar los mismos DLL varias veces desde que existen en múltiples sub-directorios. ¿Hay una manera fácil para mí para normalizar la función de los metadatos artículo (es decir. El nombre de archivo y extensión) de modo que consiga una lista de archivos DLL de prueba de unidad única? O tengo que recurrir a escribir mi propia tarea?
Solución
El MSBuild Extension Pack contiene la tarea MSBuildHelper , apoyando el comando RemoveDuplicateFiles .
<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>
Otros consejos
A pesar de que esto es viejo, nunca podría obtener una solución Thomas para trabajar, pero me encontré una especie de solución utilizando sólo comandos integrados con v4.0 de 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" />
Documentación: Funciones artículo
Yo tenía una buena búsqueda en línea y no pude encontrar ninguna manera de hacer esto. Si alguien conoce una forma integrada de limpia, por favor, hágamelo saber. Mientras tanto, escribí una tarea sencilla de hacer el trabajo. El uso es el siguiente:
<NormalizeByMetadata Items="@(ItemsToNormalize)" MetadataName="Filename">
<Output TaskParameter="NormalizedItems" ItemName="MyNormalizedItems"/>
</NormalizeByMetadata>
Después de la tarea anterior se ha ejecutado, MyNormalizedItems
contendrá sólo aquellos elementos de ItemsToNormalize
que tienen un valor único para el Filename
metadatos. Si dos o más elementos tienen el mismo valor para sus metadatos <=>, el primer partido se incluye en el resultado.
El código para la tarea de MSBuild es:
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();
}
}
}