问题
I’m trying to create a “Files” task item group with a metadata attribute called “TargetPath” populated with the relative path to a file.
Example:
For these paths:
D:\Test\Blah.exe
D:\Test\Config\fun.config
D:\Test\en-US\my.resources.dll
The output should be:
File Target = Blah.exe
File Target = Config\fun.config
File Target = en-US\my.resources.dll
Here is my best attempt... hopefully this makes my question clearer:
<ItemGroup>
<Files Include="d:\test\**\*" >
<TargetPath>%(RecursiveDir)%(Filename)%(Extension)</TargetPath>
</Files>
</ItemGroup>
<Message Text="File Target = @(Files->'%(TargetPath)')"/>
I'd like "TargetPath" populated correctly... currently it appears to be null or empty. Anyone know what I'm missing?
Edit:
Yes, I realize I can do this:
<Message Text="File Target = @(Files->'%(RecursiveDir)%(Filename)%(Extension)')"/>
However, I'm building up this ItemGroup to use the ResolveManifestFiles MSBuild task, which requires that I build up a TaskItem with the TargetPath metadata attribute to be able to customize that value.
回答1:
You're trying to assign dynamic metadata to an itemgroup before it's created. In your example there's no need to create custom metadata since this information is already part of the well-known metadata, so you can just do:
<ItemGroup>
<Files Include="d:\test\**\*" ></Files>
</ItemGroup>
<Message Text="File Target = @(Files->'%(RecursiveDir)%(Filename)%(Extension)')"/>
Or:
<Message Text="File Target = %(Files.RecursiveDir)%(Files.Filename)%(Files.Extension)"/>
EDIT:
This example uses CreateItem task to dynamically update the itemgroup:
<ItemGroup>
<Files Include="d:\test\**\*" ></Files>
</ItemGroup>
<CreateItem
Include="@(Files)"
AdditionalMetadata="TargetPath=%(RecursiveDir)%(Filename)%(Extension)">
<Output TaskParameter="Include" ItemName="Files"/>
</CreateItem>
回答2:
Modern MSBuild doesn't require CreateTask (since .NET 3.5).
You can do it like this:
<ItemGroup>
<Files Include="d:\test\**\*" />
<FilesWithMetadata Include="%(Files.Identity)" >
<TargetPath>%(RecursiveDir)%(Filename)%(Extension)</TargetPath>
</FilesWithMetadata>
</ItemGroup>
回答3:
I am liking the CreateItem method to use like this:
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
...
</ItemGroup>
<CreateItem Include="@(Reference)" Condition="'%(Reference.Private)' == 'True'" AdditionalMetadata="TargetPath=$([System.IO.Path]::GetFileName(%(Reference.HintPath)))">
<Output TaskParameter="Include" ItemName="DLLFiles"/>
</CreateItem>
<Message Text="HintPaths: "@(DLLFiles->'$(OutputPath)%(TargetPath)')"" Importance="high" />
I am using Transforms to just get only the file name.
Output:
HintPaths: "bin\Release\log4net.dll;bin\Release\Newtonsoft.Json.dll;bin\Release\RabbitMQ.Client.dll;bin\Release\ReflectSoftware.Insight.dll"
来源:https://stackoverflow.com/questions/2010655/itemgroup-with-custom-metadata-regarding-files