Problema del patrón MSBuild ItemGroup Include/Exclude
(2)
Problema: una matriz ItemGroups no se construye correctamente en función del valor pasado en el atributo de exclusión.
Si ejecuta este scrip crea un archivo de muestra y luego intenta crear un array llamado TheFiles basado en los atributos Include / Exclude, el problema es cuando el Exclude es algo diferente de hardcoded o una propiedad muy simple que lo hace mal.
El objetivo DynamicExcludeList selecciona incorrectamente estos archivos:
. / AFolder / test.cs;. / AFolder / test.txt
El objetivo HardcodedExcludeList selecciona correctamente estos archivos:
. / AFolder / test.txt
Cualquier ayuda muy apreciada, esto me está volviendo loco.
(tenga en cuenta su msbuild v4)
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">
<Target Name="Run" >
<CallTarget Targets="CreateSampleFiles" />
<CallTarget Targets="DynamicExcludeList" />
<CallTarget Targets="HardcodedExcludeList" />
</Target>
<Target Name="CreateSampleFiles" >
<MakeDir Directories="AFolder" />
<WriteLinesToFile Lines="Test" File="AFolder/test.cs" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder/test.txt" Overwrite="true" />
</Target>
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>./DIRECTORY_NAME_TOKEN/**/*.cs</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace(''DIRECTORY_NAME_TOKEN'', ''AFolder''))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<ItemGroup>
<TheFiles
Include="./AFolder/**/*;"
Exclude="$(FinalExcludes)"
/>
</ItemGroup>
<Message Text="TheFiles: @(TheFiles)" />
</Target>
<Target Name="HardcodedExcludeList" >
<PropertyGroup>
<FinalExcludes>./AFolder/**/*.cs</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<ItemGroup>
<TheFilesWithHardcodedExcludes
Include="./AFolder/**/*;"
Exclude="$(FinalExcludes)"
/>
</ItemGroup>
<Message Text="TheFilesWithHardcodedExcludes: @(TheFilesWithHardcodedExcludes)" />
</Target>
</Project>
Este es el resultado, tenga en cuenta las diferencias entre ''TheFiles'' y ''TheFilesWithHardcodedExcludes''
PS C:/SVN/TrunkDeployment/TestMsBuild> msbuild ./Test.build.xml Microsoft (R) Build Engine Version 4.0.30319.1 [Microsoft .NET Framework, Version 4.0.30319.1] Copyright (C) Microsoft Corporation 2007. All rights reserved. Build started 8/10/2010 2:30:42 PM. Project "C:/SVN/TrunkDeployment/TestMsBuild/Test.build.xml" on node 1 (default targets). DynamicExcludeList: FinalExcludes: ./AFolder/**/*.cs TheFiles: ./AFolder/test.cs;./AFolder/test.txt HardcodedExcludeList: FinalExcludes: ./AFolder/**/*.cs TheFilesWithHardcodedExcludes: ./AFolder/test.txt Done Building Project "C:/SVN/TrunkDeployment/TestMsBuild/Test.build.xml" (default targets). Build succeeded. 0 Warning(s) 0 Error(s) Time Elapsed 00:00:00.06
EDITS
He actualizado el script anterior para usar CreateItem, sin embargo, todavía hay un problema cuando la lista de elementos para excluir contiene más de 1 ruta (es decir, el valor de CommonFileExclusion ha cambiado):
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">
<Target Name="Run" >
<CallTarget Targets="CreateSampleFiles" />
<CallTarget Targets="DynamicExcludeList" />
<CallTarget Targets="HardcodedExcludeList" />
</Target>
<Target Name="CreateSampleFiles" >
<MakeDir Directories="AFolder" />
<WriteLinesToFile Lines="Test" File="AFolder/test.cs" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder/test.txt" Overwrite="true" />
<WriteLinesToFile Lines="Test" File="AFolder/test.vb" Overwrite="true" />
</Target>
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>./DIRECTORY_NAME_TOKEN/**/*.cs;./DIRECTORY_NAME_TOKEN/**/*.vb;</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace(''DIRECTORY_NAME_TOKEN'', ''AFolder''))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include="./AFolder/**/*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: @(TheFiles)" />
</Target>
<Target Name="HardcodedExcludeList" >
<PropertyGroup>
<FinalExcludes>./AFolder/**/*.cs;./AFolder/**/*.vb</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include="./AFolder/**/*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFilesWithHardcodedExcludes"/>
</CreateItem>
<Message Text="TheFilesWithHardcodedExcludes: @(TheFilesWithHardcodedExcludes)" />
</Target>
</Project>
En el destino DynamicExcludeList
use la tarea CreateItem
lugar de ItemGroup
para generar dinámicamente su elemento:
<Target Name="DynamicExcludeList" >
<PropertyGroup>
<CommonFileExclusion>./DIRECTORY_NAME_TOKEN/**/*.cs</CommonFileExclusion>
<FinalExcludes>$(CommonFileExclusion.Replace(''DIRECTORY_NAME_TOKEN'', ''AFolder''))</FinalExcludes>
</PropertyGroup>
<Message Text="FinalExcludes: $(FinalExcludes)" />
<CreateItem Include="./AFolder/**/*;"
Exclude="$(FinalExcludes)">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: @(TheFiles)" />
</Target>
Teóricamente ItemGroup
y CreateItem
son equivalentes pero he visto un caso (situación dinámica) como este cuando se debe usar CreateItem
.
Ok, probé un poco y creo que el problema proviene del hecho de que usas una propiedad que representa el valor SCALAR para valores múltiples. Recomendaría el procesamiento por lotes y la transformación (consulte http://scottlaw.knot.org/blog/?p=402 y http://msdn.microsoft.com/en-us/library/ms171476.aspx ). Por ejemplo, el siguiente código está funcionando:
<Target Name="DynamicExcludeList" >
<ItemGroup>
<ExtensionsExcluded Include="cs;vb" />
</ItemGroup>
<CreateItem Include="./AFolder/**/*"
Exclude="@(ExtensionsExcluded->''./AFolder/**/*.%(identity)'')">
<Output TaskParameter="Include" ItemName="TheFiles"/>
</CreateItem>
<Message Text="TheFiles: @(TheFiles)" />
</Target>