Thursday, September 18, 2008

Recursive Copy in TFS MSBuild

In working with TFS I just discovered the Well-Known Item Metadata (bad name in my opinion as I don't they they are really all that "Well-known") which can be used in MSBuild. One of these is %(RecursiveDir) .

From MSDN:

If the Include attribute contains the wildcard **, this metadata specifies the path to the file, beginning at the location of the wildcard. For more information on wildcards, see How to: Use Wildcards to Build All Files in a Directory. 
This example has no RecursiveDir metadata, but if the following example was used to include this item, the item would contain a RecursiveDir value of MyProject\Source\. 
 
<ItemGroup> 
    <MyItem Include="C:\**\Program.cs" /> 
</ItemGroup> 
 
If the following example was used to include this item, the RecursiveDir value of the item would remain MyProject\Source\. 
 
<ItemGroup> 
    <MyItem Include="C:\**\Source\Program.cs" /> 
</ItemGroup> 

This gives a lot of flexibility when using MSBuild. It allows you to create a ItemGroup element which can include and exclude files in a directory recursively and then copy those files recursively to another directory!

This allowed me to do the following to copy the build out put of a web site (which naturally has a lot of sub-folders) easily up to the server.

<Target Name="AfterDropBuild" >
  <Message Text="AfterDropBuild being fired" />
  <ItemGroup>
    <Compile Include="$(DropLocation)\$(BuildNumber)\Mixed Platforms\Release\_PublishedWebsites\User Interface\**\*.*"
             Exclude="$(DropLocation)\$(BuildNumber)\Mixed Platforms\Release\_PublishedWebsites\User Interface\connectionStrings.config"/>
  </ItemGroup>
 
  <Copy SourceFiles="@(Compile)" DestinationFolder="\\ServerName\MyFolder\%(RecursiveDir)"></Copy>
  <Message Text="Completed coping files" />
</Target>

MSBuild takes awhile to learn all the tricks, but the more tricks I learn the more I like it.