How do I get an msbuild task to do config transforms on a collection of files?

I am trying to transform all of the web.config files in a project I have, here's a my tree structure:

  • Transform.bat
  • Transforms
    • ConfigTransform.proj
    • Web.Transform.config
  • Website
    • web.config
    • Views
      • web.config

There's more web.config files, but the idea is that this will find all of them and apply the same config transform on them.

I've taken a few hints from a blog post I found but I get stuck in the last step, the actual transformation. Also there's a bit of a rough part in the middle that I don't really like (I don't quite understand what I'm doing and I'm obviously doing it wrong). Here's where I am so far:

<Project ToolsVersion="4.0" DefaultTargets="Transform" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="TransformXml" AssemblyFile="Tools\Microsoft.Web.Publishing.Tasks.dll"/>

    <PropertyGroup>
        <SitePath>..\..\Website</SitePath>
        <WebConfigTransformInputFile>$(SitePath)\Web.config</WebConfigTransformInputFile>
        <WebConfigTransformFile>Web.Transform.config</WebConfigTransformFile>
        <OutDir>..\N\N\</OutDir>

    </PropertyGroup>

    <ItemGroup>
        <_FilesToTransform Include="$(SitePath)\**\web.config"/>
    </ItemGroup>

    <Target Name="Transform">

    <MakeDir Directories="@(_FilesToTransform->'$(OutDir)%(RelativeDir)')" />

    <TransformXml Source="@(_FilesToTransform->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')"
                  Transform="$(WebConfigTransformFile)"
                  Destination="@(_FilesToTransform->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')" />
    </Target>
</Project>

My Transform.bat looks like this:

%systemroot%\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe %CD%\Transforms\ConfigTransform.proj

So when I call the batch, the appropriate directories get created. However, as you can see I've had to be a little creative with the OutDir, making it ..\N\N. For some reason, if I don't do this the OutDir path will be exactly the same as the input directory. So I obviously need to change something in MakeDir but I'm not sure what.

The real problem comes when it starts to do the transforms. I've tried to keep the TransformXml Source parameter like this or like so:

@(_FilesToTransformNotAppConfig->'%(FullPath)')

The latter gives me an error "Could not open Source file: The given path's format is not supported." and the former gives me this output:

Build started 30-4-2012 14:02:48.
Project "D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj" on node 1 (default targets).
Transform:
  Creating directory "..\N\N\..\..\Website\Views\".
  Transforming Source File: ..\N\N\..\..\Website\Views\Web.config;..\N\N\..\..\Website\Web.config
D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj(32,2): error : Could not open Source file: Could not find a part of the path 'D:\Dev\transform\DoTransforms\Website\Views\Web.config;\Website\Web.config'.
  Transformation failed
Done Building Project "D:\Dev\transform\DoTransforms\Transforms\ConfigTransform.proj" (default targets) -- FAILED.

Build FAILED.

To summarize my questions:

  1. How do I avoid the path issue for the OutDir? I've fiddled with multiple paths but I can't get it right.
  2. How do I get the TransformXml task to accept multiple files in the Source attribute?

Answers


I think you were pretty close. I have pasted a sample below which shows how to do this.

In my sample I discover the transform sitting next to the web.config file itself. For your scenario you can just use an MSBuild property pointing to a specific file.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="TransformAll" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
    <OutputFolder Condition=" '$(OutputFolder)'=='' ">C:\temp\transformed-files\</OutputFolder>
  </PropertyGroup>

  <!--
  This target shows how to transform web.config with a specific transform file associated to that specific web.config file.
  -->
  <Target Name="TransformAll">

    <!-- discover the files to transform -->
    <ItemGroup>
      <FilesToTransofm Include="$(MSBuildProjectDirectory)\**\web.config"/>
    </ItemGroup>

    <!-- Ensure all target directories exist -->
    <MakeDir Directories="@(FilesToTransofm->'$(OutputFolder)%(RecursiveDir)')"/>

    <!-- TransformXml only supports single values for source/transform/destination so use %(FilesToTransofm.Identity)
         to sned only 1 value to it -->
    <TransformXml Source="%(FilesToTransofm.Identity)"
                  Transform="@(FilesToTransofm->'%(RecursiveDir)web.$(Configuration).config')"
                  Destination="@(FilesToTransofm->'$(OutputFolder)%(RecursiveDir)web.config')" />    
  </Target>

</Project>

FYI you can download a full sample at https://github.com/sayedihashimi/sayed-samples/tree/master/TransformMultipleWebConfigs.


Need Your Help

Git remove --cached by TortoiseGit

git tortoisegit

I have updated my .gitignore file and now I want to update the index. I want to execute git rm --cached command. But how can I do it by TortoiseGit?

setImageResource Vs setDrawable

android android-layout

When it comes android development and performance, if you have imageview then which one would be faster or better (is there a difference anyways!): setImageResource and setDrawable