ItemGroup With Custom Metadata regarding files

msbuild

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.

Best Answer

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>
Related Topic