1
votes

I have a bunch of files x.txt in various directories throughout my project. As part of my build step, I would like to collect these and place them in a single folder (without needing to declare each one). I can detect them by using:

<ItemGroup>
  <MyFiles Include="$(SRCROOT)\**\x.txt"/>
</ItemGroup>

However, if I copy these to a single folder - they all overwrite each other. I have tried using a transform where I append a GUID to each file name, but the GUID is only created once, and then re-used for each transform (thus they overwrite each over). Is there a way of generating unique names in MSBuild when copying an ItemGroup with identically named files? The end naming scheme is not important, as long as all the files end up in that folder.

1

1 Answers

1
votes

The transform works but you have to 'force' it to generate new data on each iteration. It took me a while to figure that out and it makes sense now but I couldn't find any documentation explaining this. But it works simply by referencing other existing metadata: msbuild sees that has to be evaluated on every iteration so it will happily evaluate anything part of the new metadata. Example, simply using %(FileName):

<Target Name="CreateUniqueNames">
  <ItemGroup>
    <MyFiles Include="$(SRCROOT)\**\x.txt"/>
    <MyFiles>
      <Dest>%(Filename)$([System.Guid]::NewGuid())%(FileName)</Dest>
    </MyFiles>
  </ItemGroup>
  <Message Text="%(MyFiles.Identity) -> %(MyFiles.Dest)"/>
</Target>

Alternatively you can make use of the unique metadata you already have namely RecursiveDir:

<Target Name="CreateUniqueNames">
  <ItemGroup>
    <MyFiles Include="$(SRCROOT)\**\x.txt"/>
    <MyFiles>
      <Dest>x_$([System.String]::Copy('%(RecursiveDir)').Replace('\', '_')).txt</Dest>
    </MyFiles>
  </ItemGroup>
  <Message Text="%(MyFiles.Identity) -> %(MyFiles.Dest)"/>
</Target>