dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.22k stars 1.35k forks source link

How to pass item (ITaskItem) with all metadata into the task? #5877

Open Denis535 opened 3 years ago

Denis535 commented 3 years ago

When you use %(Item.Identity) syntax then MSBuild creates new item with the same Identity. So, all other metadata is lost!

<PrintItem Reference="%(ReferencePath.Identity)" /> // Metadata is lost

<UsingTask TaskName="PrintItem" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
        <Item ParameterType="Microsoft.Build.Framework.ITaskItem" Required="true" />
    </ParameterGroup>
    <Task>
        <Using Namespace="System" />
        <Code Type="Fragment" Language="cs">
            <![CDATA[
            Log.LogMessage( MessageImportance.High, "Item: {0}", Item );
            foreach (var metadata in Item.MetadataNames.Cast<string>()) {
                Log.LogMessage( MessageImportance.High, "Metadata: {0} = {1}", metadata, Item.GetMetadata( metadata ) );
            }
            ]]>
        </Code>
    </Task>
</UsingTask>

<ItemGroup>
    <NewItem Include="%(Item.Identity)" /> // Metadata is lost
</ItemGroup>

Is there a way to avoid losing metadata?

Denis535 commented 3 years ago

This works but looks strange.

<PrintItem Reference="@(ReferencePath)" Condition="%(ReferencePath.Identity) != ''" />
rainersigwald commented 3 years ago

That's the standard idiom.

danmoseley commented 3 years ago

Ideally the task accepts the list and loops over it -- that is why it looks clunky when you have to pass one at a time.