subcarpetas - ¿Cómo puedo usar la tarea de copia de MSBuild para copiar en varias carpetas de destino?
robocopy copiar carpetas y subcarpetas (2)
Intento copiar una carpeta de forma recursiva en varias carpetas de destino utilizando la tarea Copiar de MSBuild. He visto la siguiente pregunta que me dio un buen comienzo, pero me falta algo:
¿Copiar Msbuild a varias ubicaciones según la lista de parámetros de destino?
Un fragmento de mi archivo de compilación está a continuación:
<ItemGroup>
<DeployPath Include="//server1/path" />
<DeployPath Include="//server2/path" />
</Item Group>
<Target Name="Deploy">
<Message Text="%(DeployPath.Identity)" />
<Copy SourceFiles="@(ItemsToCopy)" DestinationFolder="%(DeployPath.Identity)/%(RecursiveDir)" />
</Target>
Cuando ejecuto esto, la tarea "Mensaje", como era de esperar, escupe 2 líneas:
//server1/path
//server2/path
El problema es que la tarea "Copiar" parece ejecutarse solo una vez y copia los archivos en la raíz del disco duro actual y no en las rutas de red especificadas:
Copia en C:/file1.txt
lugar de //server1/path/file1.txt
Soy bastante nuevo en MSBuild, así que me siento como si me estuviera perdiendo algo bastante básico aquí.
Cualquier ayuda sería muy apreciada.
La pieza faltante más importante en el rompecabezas parece ser el atributo Outputs
en el elemento Target
sin el cual siempre solo ejecutará el objetivo para un elemento de la lista completa. La otra pieza es la nueva propiedad que necesita definir en el camino.
La solución a su problema sería así:
<ItemGroup>
<DeployPath Include="//server1/path" />
<DeployPath Include="//server2/path" />
</Item Group>
<Target Name="Deploy" Outputs="%(DeployPath.Identity)">
<PropertyGroup>
<Destination>%(DeployPath.Identity)</Destination>
</PropertyGroup>
<Message Text="Processing: ''$(Destination)" />
<Copy SourceFiles="@(ItemsToCopy)"
DestinationFolder="%(DeployPath.Identity)/%(RecursiveDir)" />
</Target>
Lo que está tratando aquí se conoce como procesamiento por lotes. He blogueado bastante sobre lotes. Puede encontrar mis blogs listados en http://sedotech.com/Resources#Batching . El procesamiento por lotes es una forma de hacer un ciclo sin realmente hacer uno en MSBuild. Puede dividir grupos en valores con un valor de metadato común. Los metadatos pueden ser valores como Identity, FullPath, Filename, etc. Incluso puedes crear tus propios metadatos. En cualquier caso, cuando haces un lote con más de 1 valor, se agrupan por lotes independientemente el uno del otro. Echa un vistazo al ejemplo que creé. El resultado de ejecutar el objetivo se muestra después del script.
<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ItemsToCopy Include="src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt"/>
</ItemGroup>
<ItemGroup>
<DeployPath Include="C:/temp/path01/" />
<DeployPath Include="C:/temp/path02/" />
</ItemGroup>
<!--
Target batching is happening here because there is a
%() expression inside the Outputs attribute. So that
means that this target will be repeated once per
uinque batch of %(DeployPath.Identity). Identity is
the value that is passed in the Incude= attribute.
Since we know there are two values we know that
this target will be executed twice, and on each
pass the DeployPath item will only look to contain
a single value. If there were duplicates then the list
could contain more than 1 value.
-->
<Target Name="Demo" Outputs="%(DeployPath.Identity)">
<Message Text="DeployPath.Identity: %(DeployPath.Identity)" />
<Message Text="======================================" Importance="high"/>
<Message Text="ItemsToCopy1: @(ItemsToCopy)|| DeployPath.Identity: %(DeployPath.Identity)" />
<Message Text="======================================" Importance="high"/>
<!--
In the next emample you are batching on both the DeployPath item list as well as
the ItemsToCopy item. When two batched items are in the same expression they are
matched individually, so you ge a value for DeployPath metadata but not ItemsToCopy
metadata. That is why your copy only copied to one location.
-->
<Message Text="ItemsToCopy2: @(ItemsToCopy)|| DeployPath.Identity-RecursiveDir: %(DeployPath.Identity)/%(RecursiveDir)" />
<Message Text="======================================" Importance="high"/>
<!--
In this example I create a property and assign it the value of
%(DeployPath.Identity). We know there will only be one such
value. Because there should only be one value with Identity
when this target is executed so it is safe to
convert item to property
Because we are not batching on both items we will get the values for both vaules
to be correct becuase the target is repeated for the other
DeployPath values.
-->
<PropertyGroup>
<_DeployPathIdentity>%(DeployPath.Identity)</_DeployPathIdentity>
</PropertyGroup>
<Message Text="ItemsToCopy3: @(ItemsToCopy)|| _DeployPathIdentity-RecursiveDir: $(_DeployPathIdentity)/%(RecursiveDir)" />
<!--
I''ve always preferred to use DestinationFiles so my sample
below uses that. But you could change the target to use
DestinationFolder instead.
-->
<Copy SourceFiles="@(ItemsToCopy)"
DestinationFiles="@(ItemsToCopy->''$(_DeployPathIdentity)%(RecursiveDir)%(Filename)%(Extension)'')" />
</Target>
</Project>
Salida
Build started 9/10/2010 9:31:28 PM.
Project "I:/Development/My Code/Community/MSBuild/CopyFiles01.proj" on node 1 (default targets).
Demo:
DeployPath.Identity: C:/temp/path01/
======================================
ItemsToCopy1: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| DeployPath.I
dentity: C:/temp/path01/
======================================
ItemsToCopy2: || DeployPath.Identity-RecursiveDir: C:/temp/path01//
ItemsToCopy2: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| DeployPath.I
dentity-RecursiveDir: /
======================================
ItemsToCopy3: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| _DeployPathI
dentity-RecursiveDir: C:/temp/path01//
Creating directory "C:/temp/path01".
Copying file from "src/0001.txt" to "C:/temp/path01/0001.txt".
Copying file from "src/0002.txt" to "C:/temp/path01/0002.txt".
Copying file from "src/sub/sub-0001.txt" to "C:/temp/path01/sub-0001.txt".
Copying file from "src/sub/sub-0002.txt" to "C:/temp/path01/sub-0002.txt".
Demo:
DeployPath.Identity: C:/temp/path02/
======================================
ItemsToCopy1: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| DeployPath.I
dentity: C:/temp/path02/
======================================
ItemsToCopy2: || DeployPath.Identity-RecursiveDir: C:/temp/path02//
ItemsToCopy2: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| DeployPath.I
dentity-RecursiveDir: /
======================================
ItemsToCopy3: src/0001.txt;src/0002.txt;src/sub/sub-0001.txt;src/sub/sub-0002.txt|| _DeployPathI
dentity-RecursiveDir: C:/temp/path02//
Creating directory "C:/temp/path02".
Copying file from "src/0001.txt" to "C:/temp/path02/0001.txt".
Copying file from "src/0002.txt" to "C:/temp/path02/0002.txt".
Copying file from "src/sub/sub-0001.txt" to "C:/temp/path02/sub-0001.txt".
Copying file from "src/sub/sub-0002.txt" to "C:/temp/path02/sub-0002.txt".
Done Building Project "I:/Development/My Code/Community/MSBuild/CopyFiles01.proj" (default targets
).
Build succeeded.