I'm parsing a number of items that we're getting from our Visual Studio project file and need to run a command line utility on a number of these files. The parameters I need to use are based on a collection of ancillary files that are often stored as semicolon delimited lists, stored as item metadata within the project file:
<ItemGroup>
<Content Include="js\main.js">
<Concatenate>True</Concatenate>
<MoreFiles>path\to\file-1.js;path\to\file-2.js;path\to-another\file-3.js;path\to-yet-another\file-4.js</MoreFiles>
</Content>
<Content Include="js\another.js">
<Concatenate>True</Concatenate>
<MoreFiles>path\to\file-5.js;path\to\file-6.js;path\to\file-7.js;path\to-another\file-8.js</MoreFiles>
</Content>
</ItemGroup>
I'm currently retrieving these using a property, JSFiles
, which I build from @(Content)
, thus:
<ItemGroup>
<JSFiles Include="@(Content)" KeepMetadata="Concatenate;MoreFiles" Condition="'%(Content.Extension)' = '.js' AND '%(Content.Concatenate)' == 'true'" />
</ItemGroup>
I then use a secondary target, which uses @(JSFiles)
as its input:
<Target Name="ConcatenateJS" Inputs="@(JSFiles)" Outputs="%(JSFiles.Identity).concatenatetemp">
<Message Importance="high" Text=" %(JSFiles.Identity):" />
<PropertyGroup>
<MoreFiles>%(JSFiles.MoreFiles)</MoreFiles>
</PropertyGroup>
<ItemGroup>
<MoreFilesArray Include="$(MoreFiles.Split(';'))" />
</ItemGroup>
<Message Importance="high" Text=" MoreFiles: %(MoreFilesArray.Identity)" />
</Target>
So far, so good. By this point, I can use a <Message />
task to output the contents of the Split
operation, which gives me what I would expect:
ConcatenateJS:
js\main.js:
MoreFiles: path\to\file-1.js
MoreFiles: path\to\file-2.js
MoreFiles: path\to-another\file-3.js
MoreFiles: path\to-yet-another\file-4.js
ConcatenateJS:
js\another.js:
MoreFiles: path\to\file-5.js
MoreFiles: path\to\file-6.js
MoreFiles: path\to\file-7.js
MoreFiles: path\to-another\file-8.js
However, in order to pass these files to the command line utility correctly, they need to be full paths, so I need to prepend all the items in $(MoreFiles)
with $(MSBuildProjectDirectory)
.
I've tried using a batching operation (using $(MSBuildProjectDirectory)\%(MoreFilesArray.Identity)
and even $([System.IO.Path]::Combine($(MSBuildProjectDirectory), %(MoreFilesArray.Identity))
to no avail), and I've tried using <CreateItem>
using the AdditionalMetadata
attribute, but that didn't seem to work too well for me (though I'm not sure I was using it correctly).
How can I do this so that the output of my build process looks like this:
ConcatenateJS:
js\main.js:
MoreFiles: C:\full\path\to\file-1.js
MoreFiles: C:\full\path\to\file-2.js
MoreFiles: C:\full\path\to-another\file-3.js
MoreFiles: C:\full\path\to-yet-another\file-4.js
ConcatenateJS:
js\another.js:
MoreFiles: C:\full\path\to\file-5.js
MoreFiles: C:\full\path\to\file-6.js
MoreFiles: C:\full\path\to\file-7.js
MoreFiles: C:\full\path\to-another\file-8.js
Thanks!
MsBuild items has a well-known metadata called 'FullPath' that would display the full path of an item.
<Message Importance="high" Text=" MoreFiles: %(MoreFilesArray.FullPath)" />