How can I use %(RecursiveDir) and task batching together

I thought this would be simple, but I can't figure out how to recursively copy items to multiple directories.

<ItemGroup>
<Host Include="localhost">
<
Hostname>localhost</Hostname>
<
Domain>$(NamDMZ)</Domain>
</
Host>

<!-- Development servers-->

<Host Include="DevServer1">
<
Domain>$(NSRoot)</Domain>
<
Hostname>DevServer1</Hostname>
<
Description>Development server</Description>
</
Host>

---

<ItemGroup>
<
HTMLPublishFiles Include="$(SourceRel)Customer\Data\html\company\**\*.*" />
<
HTMLPublishFiles Include="$(SourceRel)Customer\Data\html\shared\**\*.*" />
<
HTMLPublishFiles Include="$(SourceRel)Customer\Data\html\company_$(AssemblyName)\**\*.*" />
</
ItemGroup>

<Copy SourceFiles="@(HTMLPublishFiles)"
DestinationFolder="$(PublishDir)%(Host.Hostname)\%(RecursiveDir)\" />

Here's the problem, instead of copying to

$(PublishDir)localhost\%(RecursiveDir)\ and

$(PublishDir)DevServer1\%(RecursiveDir)\

it just copies to

$(PublishDir)\%(RecursiveDir)\, which is not what is needed. How can I do this




Answer this question

How can I use %(RecursiveDir) and task batching together

  • Exellon

    Neil,

    Sorry, I missed your post. Your solution works, and it's shorter!

    --Scott



  • 50322899

    That didn't work either, but if I split the CreateItem into two, then it works, like so:

    <CreateItem AdditionalMetadata="RealRecDir=%(FilesToCopy.RecursiveDir)" Include="@(FilesToCopy)">
    <Output ItemName="TestEx1" TaskParameter ="Include"/>
    </CreateItem>

    <CreateItem AdditionalMetadata="Hostname=%(Host.HostName" Include="@(TextEx1)">
    <Output ItemName="TestEx2" TaskParameter ="Include"/>
    </CreateItem>

    <Copy SourceFiles="@(TestEx2)" DestinationFiles="@(TestEx2->'$(PublishDir)%(HostName)%(RealRecDir)%(Filename)')"/>

    Thanks for the help.



  • Joe Butler

    Scott,

    I think your case the problem is you have a $(Host.HostName) in there, and your %(RecursiveDir) isn't qualified. Try changing the %(RecursiveDir) to %(HTMLPublishFiles.RecursiveDir) and see if that does the trick. Also, I assume you have a <Target> around this that actually batches on the Host ItemGroup

    Neil



  • tachikoma

    Now that I'm thinking about it my use of the RelativeDir may not function properly. Here is a more correct technique I think.

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

    <ItemGroup>

    <Host Include="localhost">

    <Hostname>localhost</Hostname>

    <Domain>$(NamDMZ)</Domain>

    </Host>

    <!-- Development servers-->

    <Host Include="DevServer1">

    <Domain>$(NSRoot)</Domain>

    <Hostname>DevServer1</Hostname>

    <Description>Development server</Description>

    </Host>

    </ItemGroup>

    <ItemGroup>

    <FilesToCopy Include="Source\Ibr\**\*"/>

    </ItemGroup>

    <PropertyGroup>

    <PublishDir>C:\pub\</PublishDir>

    </PropertyGroup>

    <Target Name="PrintFiles">

    <CreateItem AdditionalMetadata="Hostname=%(Host.HostName);RealRecDir=%(FilesToCopy.RecursiveDir)" Include="@(FilesToCopy)">

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

    </CreateItem>

    <Copy SourceFiles="@(Test)" DestinationFiles="@(Test->'$(PublishDir)%(HostName)%(RealRecDir)%(FileName)')"/>

    </Target>

    </Project>

    Sayed Ibrahim Hashimi
    www.sedodream.com


  • Jon Limjap

    Ok, I messed around with this some tonight and I'm as confused as you, Scott. I sent mail to our whole MSBuild team to see if they can shed some light. Faisal's up on IM right now scratching his head, too. When I hear back, I'll let you know :)

    Neil



  • Mark Watkin

    Scott,

    Did the CreateProperty method work for you as well It's quite a bit simpler to parse for future maintainers of your build script.

    Neil



  • Geze

    Scott,

    I have an even better one for you :) Rajeev, master of all things batching, gave this supremely simple version that doesn't require CreateProperty:

    <Target Name="Build" Outputs="%(Host.Identity)">

    <Message Text="$(PublishDir)@(Host)\%(HTMLPublishFiles.Identity) "/>

    </Target>

    (Obvously, you can replace the Message task with the Copy task and get the same result)

    Neil



  • DaveKoch

    What about this approach:

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

    <ItemGroup>

    <Host Include="localhost">

    <Hostname>localhost</Hostname>

    <Domain>$(NamDMZ)</Domain>

    </Host>

    <!-- Development servers-->

    <Host Include="DevServer1">

    <Domain>$(NSRoot)</Domain>

    <Hostname>DevServer1</Hostname>

    <Description>Development server</Description>

    </Host>

    </ItemGroup>

    <ItemGroup>

    <FilesToCopy Include="**\*"/>

    </ItemGroup>

    <PropertyGroup>

    <PublishDir>C:\pub\</PublishDir>

    </PropertyGroup>

    <Target Name="CopyFiles">

    <CreateItem AdditionalMetadata="Hostname=%(Host.HostName)" Include="@(FilesToCopy)">

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

    </CreateItem>

    <Copy SourceFiles="@(Test)" DestinationFiles="@(Test->'$(PublishDir)%(HostName)\%(RelativeDir)%(FileName)')"/>

    </Target>

    </Project>

    Sayed Ibrahim Hashimi
    www.sedodream.com


  • Jeff Schindler

    You're close, Sayed, but there's an easier way without having to use a funky transform. Just do a CreateProperty (rather than CreateItem) to put the hostname into a property. Then when you do the Copy command it only has to batch on one thing:

    <Target Name="Build" Outputs="%(Host.Identity)">
    <
    CreateProperty Value="%(Host.HostName)">
    <
    Output PropertyName="Hostname" TaskParameter="Value"/>
    </
    CreateProperty>

    <
    Copy SourceFiles="@(HTMLPublishFiles)" DestinationFolder="$(PublishDir)\$(Hostname)\%(HTMLPublishFiles.RecursiveDir)"/>
    </
    Target>

    Also note that you have to make sure that every Include that's used to create HTMLPublishFiles has a ** in it. In the original example, one of them didn't, which will make the recursion work incorrectly.

    Neil



  • How can I use %(RecursiveDir) and task batching together