msbuild create itemgroup from property group

2019-07-16 07:22发布

问题:

I want to pass a semi-colon separated list of strings.
Each string represents a file name.

    <PropertyGroup>
          <FileNames>Newtonsoft.Json;Reactive</FileNames>
          <PathToOutput>C:/</PathToOutput>
    </PropertyGroup>

Now I want to create an item group which should give me all the files in particular folder excluding list of Filename, something like:

<ItemGroup>
    <ReleaseFiles Include="$(PathToOutput)\**\*.*" Exclude="%(identity)-> identity.contains(%FileNames)"/>
</ItemGroup>

How do I iterate through current folder's files and match each ones name if it contains any one filename in Filenames variable.

回答1:

Pretty sure this is a duplicate but I cannot find it at the moment so here it goes:

  • turning a semicolon-seperated property into an item is just a matter of using Include=$(Property)
  • Exclude only works if you have a list of exact matches, but you need more arbitrary filtering here so you'll need Condition
  • join the two ItemGroups together like a cross-product, by making those FileNames metadata of the ReleaseFiles item. Then you can iterate over each item in ReleaseFiles and have access to the FileNames at the same time
  • Contains is a property function (well, or a System::String method) so won't work as such on metadata, hence we turn metadata into a string first

In code:

<PropertyGroup>
  <FileNames>Newtonsoft.Json;Reactive</FileNames>
  <PathToOutput>C:/</PathToOutput>
</PropertyGroup>

<Target Name="FilterBasedCommaSeperatedProperty">
  <ItemGroup>
    <!-- property -> item -->
    <Excl Include="$(FileNames)"/>
    <!-- list all and add metadata list -->
    <AllReleaseFiles Include="$(PathToOutput)\**\*.*">
      <Excl>%(Excl.Identity)</Excl>
    </AllReleaseFiles >
    <!-- filter to get list of files we don't want -->
    <FilesToExclude Include="@(AllReleaseFiles)"
                    Condition="$([System.String]::Copy('%(FileName)').Contains('%(Excl)'))"/>
    <!-- all but the ones to exclude --> 
    <ReleaseFiles Include="@(AllReleaseFiles)" Exclude="@(FilesToExclude)"/>
  </ItemGroup>
  <Message Text="%(ReleaseFiles.Identity)" />
</Target>


回答2:

Use the standard way to exclude files files from an item group by using the Exclude attribute and referencing another item group. It'll be much easier to understand.

Example:

<PropertyGroup>
  <PathToOutput>C:/</PathToOutput>
</PropertyGroup>

<ItemGroup>
    <FilesToExclude Include="$(PathToOutput)\**\Newtonsoft.Json" />
    <FilesToExclude Include="$(PathToOutput)\**\Reactive" />
    <ReleaseFiles Include="$(PathToOutput)\**\*.*" Exclude="@(FilesToExclude)"/>
</ItemGroup>