Question

The situation is this:

  • I have multiple config files in one folder
  • I have transformation files with the same name in a different folder
  • I want to output the transformed files with the same name to a third folder after the build

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)".

Update

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?

Update 2

Source problem is fixed with Source="%FilesToTransform.Identity". I'm having the same issue with Transform.

Was it helpful?

Solution

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)')" />

OTHER TIPS

I needed to figure out the rest after Nick has pointed to the right direction. You have to play with it for the proper syntax:

This is the one that works as intended:

<PropertyGroup>
  <PathToConfigs>Configurations\EnvironmentDependent</PathToConfigs>
  <TransformLocation>Configurations\TransformFilesFor\Environment1</TransformLocation>
  <Destination>$(PathToConfigs)\TransformedConfigs</Destination>
</PropertyGroup>

<ItemGroup>
  <FilesToTransform Include="$(PathToConfigs)\*.config" />
</ItemGroup>

<!-- you can check the path of files here -->

<Message Importance="High" 
     Text=" Source files: %(FilesToTransform.Identity)" />
<Message Importance="High" 
     Text=" Destination files: $(Destination)\%(FilesToTransform.Filename)%(FilesToTransform.Extension)" />
<Message Importance="High" 
     Text=" Transform files: $(TransformLocation)\%(FilesToTransform.Filename)%(FilesToTransform.Extension)" />

<!--
 1>   Source files: Configurations\EnvironmentDependent\config1.config
 1>   Source files: Configurations\EnvironmentDependent\config2.config
 1>   Destination files: Configurations\EnvironmentDependent\TransformedConfigs\config1.config
 1>   Destination files: Configurations\EnvironmentDependent\TransformedConfigs\config2.config
 1>   Transform files: Configurations\TransformFilesFor\Environment1\config1.config
 1>   Transform files: Configurations\TransformFilesFor\Environment1\config2.config
 -->

<TransformXml 
    Source="%(FilesToTransform.Identity)" 
    Destination="$(Destination)\%(FilesToTransform.Filename)%(FilesToTransform.Extension)" 
    Transform="$(TransformLocation)\%(FilesToTransform.Filename)%(FilesToTransform.Extension)" />

Any help on a shorter syntax is appreciated, though!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top