views:

730

answers:

4

I got a directory I want to copy to a number of locations.

Say I have

  • home.aspx

I want to copy it to

  • abc/home.aspx
  • def/home.aspx
  • ghi/home.aspx

so two questions for me:

  • How do I define the list abc, def, ghi?
  • How do I execute my Copy task with each element of this list?
A: 

You really are best off doing this yourself as a learning exercise, rather than treating MSBUILD as a magic box. This article from Patrick Smacchia gives you most of the techniques involved.

Ruben Bartelink
I am actually trying to familiarize myself with MSBuild by trying to automate several tasks I have been doing manually untill today. I have read several tutorials similar to the one you refer to (it seems it's a copy paste galore). By doing so I'm trying to familiarize myself with the syntax and built-in posibilities. Could you please elaborate on how I'm treating it like a magic box and how your refered article can enlighten me?
borisCallens
Hey Boris, I didnt mean the 'treating it like a black box' as you being lazy. I was mainly thinking back to my time learning msbuild - I used to try to understand a task at a time, but not the overall picture. I genuinely found the Smacchia article to be something I wished I had a week before I got it - As the author of NDepend he's no cut and paste merchant. In terms of defining the list, I imagine a [xml list] property would work for the list, and then you'd use the Copy task with the list looping/wildcarding facility to walk the list. I havent done it myself- otherwise would paste sample.
Ruben Bartelink
Thanks for your reply. I will have a second thorough look at the article.
borisCallens
A: 

Have an itemgroup where you build up this list of destinations ("<Destination>abc</Destionation>..., etc). Then invoke the copy task with this list (@Destination).

I'm sure you'll find plenty of examples if you search for it. http://keithhill.spaces.live.com/?_c11_BlogPart_BlogPart=blogview&amp;_c=BlogPart&amp;partqs=cat%3dMSBuild

gokult
+1  A: 

Hi, The concept that you should be interested in is known as Batching.

I've covered this exact scenario on my blog at http://www.sedodream.com/PermaLink,guid,5f1e0445-ce3d-4052-ba80-42fd19512d42.aspx

Here is the text of that blog entry, you can download the mentioned files at the link above.


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.


Here are some other batching related blog entries that I've posted.

Thanks, Sayed Ibrahim Hashimi

Sayed Ibrahim Hashimi
If I understand the convention to separate them with ';' makes the parameter a list rather then a single item.I will check this out after work hours. Thanks
borisCallens
+2  A: 

Here is an actual example that I put together that shows what you were looking for:

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

  <!--Declare an ItemGroup that points to your file you want to copy.-->
  <ItemGroup>
    <ItemToCopy Include=".\Home.aspx" />
  </ItemGroup>

  <!--Declare an ItemGroup that points to your destination Locations-->
  <ItemGroup>
    <DestLocations Include=".\abc\home.aspx" />
    <DestLocations Include=".\def\home.aspx" />
    <DestLocations Include=".\ghi\home.aspx" />
  </ItemGroup>

  <Target Name="CopyFiles">
    <!--Run the copy command to copy the item to your dest locations-->
    <!--This is where the magic happens.  The % sign before the DestLocations reference says to use
    Batching.  So Copy will be run for each unique FullPath MetaData in the DestLocations ItemGroup.-->
    <Copy SourceFiles="@(ItemToCopy)" DestinationFolder="%(DestLocations.FullPath)" />
  </Target>
</Project>
Vaccano
Great. Thanks, the comments make it verry clear.I know I might sound a little shallow if I'm saying I'm not looking to become an MSBuild guru, rather just solve my problem here.I have noticed that through using a technology case by case there is this point in a learning curve where you have enough scattered knowledge that an all-out study from scratch is much easier and puts everything in its place. I find this often the more preferable way of learning something.
borisCallens
If you don't need to know it all now, then that works just fine. I fixed an error in the example (sorry about that). You need to call any tasks (like copy) in a target. I put it in a target. You call call MSBuild with that target name (CopyFiles) and it will run the target.
Vaccano