Copie todos los archivos y carpetas usando msbuild


93

Me pregunto si alguien podría ayudarme con algunos scripts de msbuild que estoy tratando de escribir. Lo que me gustaría hacer es copiar todos los archivos y subcarpetas de una carpeta a otra usando msbuild.

{ProjectName}
      |----->Source
      |----->Tools
              |----->Viewer
                       |-----{about 5 sub dirs}

Lo que necesito poder hacer es copiar todos los archivos y subcarpetas de la carpeta de herramientas a la carpeta de depuración de la aplicación. Este es el código que tengo hasta ahora.

 <ItemGroup>
<Viewer Include="..\$(ApplicationDirectory)\Tools\viewer\**\*.*" />
 </ItemGroup>

<Target Name="BeforeBuild">
        <Copy SourceFiles="@(Viewer)" DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" />
  </Target>

El script de compilación se ejecuta pero no copia ninguno de los archivos o carpetas.

Gracias

Respuestas:


133

También estaba buscando ayuda en esto. Me tomó un tiempo, pero esto es lo que hice que funcionó muy bien.

<Target Name="AfterBuild">
    <ItemGroup>
        <ANTLR Include="..\Data\antlrcs\**\*.*" />
    </ItemGroup>
    <Copy SourceFiles="@(ANTLR)" DestinationFolder="$(TargetDir)\%(RecursiveDir)" SkipUnchangedFiles="true" />
</Target>

Esto copió de forma recursiva el contenido de la carpeta nombrada antlrcsen $(TargetDir).


4
Si, esta es la mejor respuesta. Lo mismo que se recomienda aquí en el blog de msdn
— Karsten

2
Funciona bien, ¡gracias! Me pregunto por qué otras respuestas más complicadas tienen más votos a favor.
— Ivan

17
El truco parece ser que agregar %(RecursiveDir)a la carpeta de destino recreará la estructura del directorio. De lo contrario, la salida es plana. Esta es la mejor respuesta.
— JB. Con Monica.

1
Debe colocarse al final del archivo .fsproj, o no se necesita.
— Henrik

El momento clave aquí que funcionó para mí es mover la declaración de variable ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) En el objetivo de AfterBuild. En mi caso, se declaró en el ámbito externo y no funcionó.
— Envío el

71

Creo que el problema podría estar en cómo está creando su ItemGroup y llamando a la tarea Copiar. Vea si esto tiene sentido:

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="@(YourFilesToCopy->'$(YourDestinationDirectory)\%(RecursiveDir)%(Filename)%(Extension)')" />
    </Target>
</Project>

CreateItemla tarea está en desuso. regex tiene la alternativa. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
— Ray Cheng

35

Soy un poco nuevo en MSBuild, pero encuentro que la tarea EXEC es útil para situaciones como estas. Me encontré con el mismo desafío en mi proyecto y esto funcionó para mí y fue mucho más simple. Alguien, por favor, avíseme si no es una buena práctica.

<Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
    <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
</Target>

9
Me atrevo a hacer la pregunta al revés. ¿Hay alguna razón para usar la tarea de copia de msbuild de llenado de registros?
— bernd_k

4
Potencialmente. Si tiene una granja de compilación (Jenkins, TeamCity, etc.), el servicio del agente puede ejecutarse con una cuenta diferente que no tenga xcopy en la ruta. Puede probar cosas como% windir% \ system32 en la ruta, pero incluso esto no funciona algunas veces.
— Andrew dh

Esa es la solución que funcionó para mí. Además, no necesitaba configurar WorkingDirectory.
— Aebsubis

FYI, necesito agregar / Y para suprimir el mensaje de anulación de archivo / carpeta. Además, si $ (DeploymentDirectory) es una carpeta, dejar un "\" después de la ruta eliminará el mensaje: "¿el destino es una carpeta o un archivo?"
— Hoàng Long

6
Sé que este problema no surge con frecuencia, pero mi principal razón para usar la Copytarea en lugar de un comando es la compatibilidad. He construido en Linux usando Mono antes, y obviamente xcopyno funciona allí.
— GregRos

12
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <PropertyGroup>
        <YourDestinationDirectory>..\SomeDestinationDirectory</YourDestinationDirectory>
        <YourSourceDirectory>..\SomeSourceDirectory</YourSourceDirectory>
    </PropertyGroup>

    <Target Name="BeforeBuild">
        <CreateItem Include="$(YourSourceDirectory)\**\*.*">
            <Output TaskParameter="Include" ItemName="YourFilesToCopy" />
        </CreateItem>

        <Copy SourceFiles="@(YourFilesToCopy)"
                DestinationFiles="$(YourFilesToCopy)\%(RecursiveDir)" />
    </Target>
</Project>

\**\*.*ayuda a obtener archivos de toda la carpeta. RecursiveDir ayuda a poner todo el archivo en la carpeta respectiva ...


2
Los archivos de destino se refieren a 1 elementos y los archivos de origen se refieren a 33 elementos. Deben tener la misma cantidad de elementos. Ugh ... msbuild puede ser increíble, pero a veces es una basura tan mal documentada.
— The Muffin Man

CreateItemla tarea está en desuso. regex tiene la alternativa. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
— Ray Cheng

4

¿Intentó especificar un directorio de destino concreto en lugar de

DestinationFolder="@(Viewer->'$(OutputPath)\\Tools')" ? 

No soy muy competente con la sintaxis avanzada de MSBuild, pero

@(Viewer->'$(OutputPath)\\Tools') 

me parece extraño. El script se ve bien, por lo que el problema puede estar en los valores de $(ApplicationDirectory)y$(OutputPath)

EDITAR:

Aquí hay una publicación de blog que podría ser útil:

Cómo: copiar archivos de forma recursiva mediante la tarea


1
+1 para el enlace, que es más conciso que la respuesta aceptada de zXen.
— bernd_k

3

Este es el ejemplo que funcionó:

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

   <ItemGroup>
      <MySourceFiles Include="c:\MySourceTree\**\*.*"/>
   </ItemGroup>

   <Target Name="CopyFiles">
      <Copy
        SourceFiles="@(MySourceFiles)"
        DestinationFiles="@(MySourceFiles->'c:\MyDestinationTree\%(RecursiveDir)%(Filename)%(Extension)')"
       />
    </Target>

</Project>

fuente: https://msdn.microsoft.com/en-us/library/3e54c37h.aspx


2

Esta es la tarea de copia que utilicé en mi propio proyecto, funcionó perfectamente para mí que copia la carpeta con subcarpetas al destino con éxito:

<ItemGroup >
<MyProjectSource Include="$(OutputRoot)/MySource/**/*.*" />
</ItemGroup>

<Target Name="AfterCopy" AfterTargets="WebPublish">
<Copy SourceFiles="@(MyProjectSource)" 
 OverwriteReadOnlyFiles="true" DestinationFolder="$(PublishFolder)api/% (RecursiveDir)"/>

En mi caso, copié la carpeta de publicación de un proyecto en otra carpeta de destino, creo que es similar a su caso.



0

La mejor manera de copiar archivos de forma recursiva de un directorio a otro usando MSBuild es usando la tarea Copiar con SourceFiles y DestinationFiles como parámetros. Por ejemplo: copiar todos los archivos del directorio de compilación al directorio de respaldo será

<PropertyGroup>
<BuildDirectory Condition="'$(BuildDirectory)' == ''">Build</BuildDirectory>
<BackupDirectory Condition="'$(BackupDiretory)' == ''">Backup</BackupDirectory>
</PropertyGroup>

<ItemGroup>
<AllFiles Include="$(MSBuildProjectDirectory)/$(BuildDirectory)/**/*.*" />
</ItemGroup>

<Target Name="Backup">
<Exec Command="if not exist $(BackupDirectory) md $(BackupDirectory)" />
<Copy SourceFiles="@(AllFiles)" DestinationFiles="@(AllFiles-> 
'$(MSBuildProjectDirectory)/$(BackupDirectory)/%(RecursiveDir)/%(Filename)% 
(Extension)')" />
</Target>

Ahora, en el comando Copiar anterior, todos los directorios de origen se recorren y los archivos se copian en el directorio de destino.


0

Si está trabajando con una cadena de herramientas típica de C ++, otra forma de hacerlo es agregar sus archivos a la lista estándar CopyFileToFolders

<ItemGroup>
  <CopyFileToFolders Include="materials\**\*">
    <DestinationFolders>$(MainOutputDirectory)\Resources\materials\%(RecursiveDir)</DestinationFolders>
  </CopyFileToFolders>
</ItemGroup>

Además de ser simple, esta es una buena manera de hacerlo porque la tarea CopyFilesToFolders generará entradas, salidas e incluso archivos TLog adecuados, por lo que se asegurará de que las operaciones de copia se ejecuten solo cuando uno de los archivos de entrada haya cambiado o falta uno de los archivos de salida. Con TLog, Visual Studio también reconocerá correctamente el proyecto como "actualizado" o no (utiliza un mecanismo U2DCheck separado para eso).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.