The situation is this:
I can easily solve this by manually adding the nodes for each file. However, I don't want to bother with that (as one of us in the team will always forget to edit the csproj file when he/she adds a new config).
This is what I have now:
<UsingTask
TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="AfterBuild">
<ItemGroup>
<PathToConfigs Include="Configurations\EnvironmentDependent" />
<FilesToTransform Include="*.config"/>
</ItemGroup>
<TransformXml
Source="%(PathToConfigs)\%(FilesToTransform)"
Destination="OutputConfigs\%(FilesToTransform)"
Transform="%(PathToConfigs)\TransformFiles\%(FilesToTransform)" />
I don't get the proper syntax here, so it is not suprising that I get the following error message:
"The item metadata %(PathToConfigs) is being referenced without an item name. Specify the item name by using %(itemname.PathToConfigs)".
As of Nick's answer I came to this solution:
<TransformXml
Source="@(FilesToTransform -> '%(Identity)')"
Destination="@(FilesToTransform -> '%(OutputFile)')"
Transform="@(FilesToTransform -> '%(Transform)')" />
I verified the paths of files as shown in the <Message ... />
-s.
However, I get the following error:
"Could not open Source file: Could not find a part of the path 'C:\fakepath\Configurations\EnvironmentDependent\file1.config;Configurations\EnvironmentDependent\file2.config'."
(I have renamed part of the path to C:\fakepath; otherwise I did not change path after the semi-colon: the first path in the error message is absolute, the second one is relative. The output of the message shows the relative paths of the files).
What did go wrong?
Source problem is fixed with Source="%FilesToTransform.Identity"
. I'm having the same issue with Transform.
Well, you're iterating over the PathToConfigs collection rather than the group of configs.
Use MsBuild properties when referring to a single item, and use MsBuild items when referring to a collection. Lets first change the path variables to properties rather than items.
<PropertyGroup>
<PathToConfigs>Configurations\EnvironmentDependent</PathToConfigs>
<TransformLocation>$(ConfigLocation)\OutputConfigs</TransformLocation>
<Destination>$(PathToConfigs)\TransformationFiles</Destination>
</PropertyGroup>
Next, since we know the transform and output files are based on the structure of the members of the FilesToTransform item group, lets infer those values in the metadata. First create a group comprising the config files, then construct the FilesToTransform using metadata from the @(Configs) group:
<ItemGroup>
<Configs Include="$(PathToConfigs)\*.config" />
<FilesToTransform Include="@(Configs)">
<Transform>$(TransformLocation)\%(FileName)%(Extension)</Transform>
<OutputFile>$(Destination)\%(FileName)%(Extension)</OutputFile>
</FilesToTransform>
</ItemGroup>
Finally, confirm your output in a message task:
<Message Importance="High" Text=" Source @(FilesToTransform ->'%(Identity)')" />
<Message Importance="High" Text=" Destination @(FilesToTransform -> '%(OutputFile)')" />
<Message Importance="High" Text=" Transform @(FilesToTransform -> '%(Transform)')" />