- | rssFeed | My book on MSBuild and Team Build | Archives and Categories Tuesday, August 29, 2006

MSBuild Batching 2

A twist on the previous entry. Here’s a very similar, but different scenario. You have a set of files, that you want to push to a set of folders. But you have to “discover” these folders. In this scenario there are really 2 different situations you can be in.

1.       Each folder contains a file that you are able to identify by file name

2.       Each folder contains no files, but you are able to identify the folder by its name

For 2) you’ll have to rely on a custom task to get locate these folders. This is because if the folder is empty then you are not able to put these in an Item the normal way. I’ve previously written a task FindUnder that you can use for this purpose. You can find this task, and a handful of others at http://www.codeplex.com/Wiki/View.aspx?ProjectName=Sedodream. Let’s go over scenario 2 because I think it’s a little more straight forward.

Here is the directory structure that you have to work with:

   AssemblyInfo.cs

   DeploySample.proj

   Other1.cs

   Other2.cs

├───Deploy

   ├───five.control

   ├───four.control

   ├───one.control

   ├───six.control

   ├───six.something

   ├───three.control

   ├───three.something

   └───two.control

In this example the folders that you want to copy into end with .control, and the files you want to copy include AssemblyInfo.cs, Other1.cs and Other2.cs. In this situation we want to find all folders under Deploy that end with control. So our search pattern will be *control under the Deploy folder. Here’s how we find those folders using the FindUnder task, and copy the files into them.

   <PropertyGroup>

      <DeployRoot>Deploy</DeployRoot>

      <SearchPath>*.control</SearchPath>

   </PropertyGroup>

   <ItemGroup>

      <FilesToCopy Include="AssemblyInfo.cs;Other1.cs;Other2.cs"/>

   </ItemGroup>

   <Target Name="Deploy">

      <Copy SourceFiles="" DestinationFolder=""/>

      <!-- Find all the folders we need to place the AssemblyInfo.cs file in -->

      <FindUnder Path="$(DeployRoot)" FindDirectories="true" SearchPattern="$(SearchPath)">

         <Output ItemName="DeployFolders" TaskParameter="FoundItems"/>

      </FindUnder>

     

      <Message Text="Found items: @(DeployFolders,'%0d%0a')" Importance="high"/>

      <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="%(DeployFolders.FullPath)"/>

   </Target>

Let’s talk about the Copy task above. This shows how we can copy a set of folders to a set of different folders. This is possible through batching which was discussed in more detail in the previous post. As you use batching keep in mind that batching isn’t limited to custom meta-data. But can also be used with Well-known item metadata. That is what we are doing in this example.

Now let’s see how can we handle situation 1). To review, this is the situation that we have files in a set of directories that we can identify. In this example let’s say that file is named app.config. So we want to find all folders under a given location that have a file named app.config inside of it. So here is your directory structure

   AssemblyInfo.cs

   DeploySample.proj

   Other1.cs

   Other2.cs

└───Deploy2

      ├───five.control

             app.config

      ├───four.control

             app.config

      ├───one.control

             app.config

      ├───six.control

             app.config

      ├───six.something

      ├───three.control

             app.config

      ├───three.something

      └───two.control

            app.config

So the result should actually be the same as the previous example. This is how to achieve that.

   <PropertyGroup>

      <DeployRoot2>Deploy2</DeployRoot2>

   </PropertyGroup>

  

   <ItemGroup>

      <KeyFiles Include=".\$(Deploy2)\**\app.config"/>

   </ItemGroup>

 

   <Target Name="Deploy2">

      <Message Text="Folders to deploy to:%0d%0a@(KeyFiles->'%(RecursiveDir)','%0d%0a')"/>

 

      <!-- Now copy each file to each destination -->

      <Copy SourceFiles="@(FilesToCopy)" DestinationFolder=".\%(KeyFiles.RecursiveDir)"/>

   </Target>

 

So the in this example I’m using the KeyFiles item to determine which folders to copy all the files to. From the Deploy2 target you can see that I’m using batching to copy all the FilesToCopy into each of the locations determined by the KeyFiles item. The directory that contains each KeyFile is determined by the RecursiveDir well-known meta-data value.

 

You can download the entire sample at: www.sedodream.com/content/binary/BatchingSample.zip

Or you can have a look at the project file at:  www.sedodream.com/content/binary/DeploySample.proj.txt

 

Sayed Ibrahim Hashimi

msbuild | Visual Studio Tuesday, August 29, 2006 3:17:46 AM (GMT Daylight Time, UTC+01:00)  #     | 
Tuesday, August 15, 2006

MSBuild batching

Today someone was telling me about a co-worker who was having issues with MSBuild. He told me that he was trying to copy a set of files to a set of different servers. But the issue was that he didn’t know how to achieve this without performing multiple Copy task invocations. I told him that he could achieve this using MSBuild Batching. Batching is a process of performing a task (or target) on a set of items (batches) at a time. A batch can also include a single item. So in this scenario we need to perform the copy one time for each server that he wanted to deploy to. I’ve created a simple msbuild file which demonstrates this in two different ways. The first way uses task batching, which can bee seen in the Test target. And the other uses Target batching which can be seen in the DoItCore target. I've also created a clean target, which has nothing to do with batching.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Test">

     

      <ItemGroup>

            <SourceFiles Include="*.txt"/>

            <Dest Include="One;Two;Three;Four;Five"/>

      </ItemGroup>

     

      <Target Name="Test">

            <Copy SourceFiles ="@(SourceFiles)" DestinationFolder="%(Dest.FullPath)"/>

            <Message Text="Fullpath: %(Dest.FullPath)"/>

      </Target>

 

      <!-- These targets demonstrate target batching -->

      <Target Name="DoIt" DependsOnTargets="DoItCore"/>

      <Target Name="DoItCore" Inputs="@(SourceFiles)" Outputs="%(Dest.FullPath)">

            <Copy SourceFiles="@(SourceFiles)" DestinationFolder="%(Dest.FullPath)"/>

      </Target>

 

      <!-- This will clean up the files -->

      <Target Name="Clean">

            <CreateItem Include="%(Dest.FullPath)\**\*">

                  <Output ItemName="FilesToDelete" TaskParameter="Include"/>

            </CreateItem>

            <Delete Files="@(FilesToDelete)"/>

      </Target>

</Project>

Batching is an advanced topic of MSBuild, and is defintely neglected. I have to admit I’m guilty of not writing about it enough myself. There are some good batching resources, they are listed below.

MSBuild Batching

How To : Batch Targets with Item Metadata

Batching Brainteaser Explained

Channel 9 : Batching Examples

Channel 9 : How does MSBuild’s Batching Algorigth Work?

 

Sayed Ibrahim Hashimi

msbuild | Visual Studio Tuesday, August 15, 2006 4:59:32 AM (GMT Daylight Time, UTC+01:00)  #     | 
Wednesday, August 09, 2006

MSDN Library free to download!

In case you haven't already heard the MSDN Library is now free to download! You can download the May 2006 version at: http://www.microsoft.com/downloads/details.aspx?FamilyId=373930CB-A3D7-4EA5-B421-DD6818DC7C41&displaylang=en

Previously you could only get the MSDN Library if you were an MSDN Subscriber. I think its great that Microsoft made the MSDN Library free to download. It's a great resource and contains all kinds of goodies for .NET developers.

Sayed Ibrahim Hashimi

Visual Studio Wednesday, August 09, 2006 5:32:45 AM (GMT Daylight Time, UTC+01:00)  #     |