Normalizar uma lista de itens em MSBuild
Pergunta
Eu estou tentando obter uma lista de todos os conjuntos de teste de unidade sob a raiz do meu projeto. Eu posso fazer isso da seguinte forma:
<CreateItem Include="**\bin\**\*.UnitTest.*.dll">
<Output TaskParameter="Include" ItemName="Items"/>
</CreateItem>
No entanto, isso vai encontrar as mesmas DLLs várias vezes desde que eles existem em vários sub-diretórios. Existe uma maneira fácil para mim para normalizar com base em metadados item (ie. O nome do arquivo e extensão) para que eu recebo uma lista de DLLs teste de unidade única? Ou eu tenho que recorrer a escrever minha própria tarefa?
Solução
O MSBuild Extension Pack contém a tarefa MSBuildHelper , apoiando o 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>
Outras dicas
Mesmo que isso é velho, eu nunca poderia obter solução Thomas para mim trabalhar, mas eu achei uma espécie de solução usando apenas built-in comandos com 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" />
Documentação: Funções item
Eu tive uma boa pesquisa on-line e não poderia encontrar alguma maneira de fazer isso. Se alguém souber de uma limpeza built-in maneira, então por favor me avise. Nesse meio tempo, eu escrevi uma tarefa simples para fazer o trabalho. Os olhares de uso como este:
<NormalizeByMetadata Items="@(ItemsToNormalize)" MetadataName="Filename">
<Output TaskParameter="NormalizedItems" ItemName="MyNormalizedItems"/>
</NormalizeByMetadata>
Depois que a tarefa anterior tenha executado, MyNormalizedItems
irá conter apenas os itens de ItemsToNormalize
que têm um valor único para os metadados Filename
. Se dois ou mais itens têm o mesmo valor para seus metadados Filename
, o primeiro jogo será incluído na saída.
O código para a tarefa MSBuild é:
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();
}
}
}