Copiez tous les fichiers et dossiers à l'aide de msbuild

93

Je me demandais simplement si quelqu'un pouvait m'aider avec certains scripts msbuild que j'essaie d'écrire. Ce que je voudrais faire, c'est copier tous les fichiers et sous-dossiers d'un dossier vers un autre dossier à l'aide de msbuild.

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

Ce que je dois pouvoir faire est de copier tous les fichiers et sous-dossiers du dossier tools dans le dossier de débogage de l'application. C'est le code que j'ai jusqu'à présent.

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

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

Le script de construction s'exécute mais ne copie aucun des fichiers ou des dossiers.

Merci

Nathan W
la source

Réponses:

133

Je cherchais de l'aide à ce sujet aussi. Cela m'a pris du temps, mais voici ce que j'ai fait qui a très bien fonctionné.

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

Cela copiait récursivement le contenu du dossier nommé antlrcsdans le fichier $(TargetDir).

Rodolfo Neuber
la source
4
Oui, c'est la meilleure réponse. Le même que recommandé ici sur le blog msdn
Karsten
2
Fonctionne bien - merci! Je me demande pourquoi d'autres réponses plus compliquées ont plus de votes positifs?!
Ivan le
17
L'astuce semble être que l'ajout %(RecursiveDir)au dossier de destination recréera la structure du répertoire. Sinon, la sortie est plate. C'est la meilleure réponse.
JB. Avec Monica.
1
Doit être placé au bas du fichier .fsproj, sinon cela ne prend pas.
Henrik
Le moment clé ici qui a fonctionné pour moi est le déplacement de la déclaration de variable ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) Sous la cible AfterBuild. Dans mon cas, il a été déclaré dans le champ d'application externe et n'a pas fonctionné.
Shpand
71

Je pense que le problème peut être dans la façon dont vous créez votre ItemGroup et appelez la tâche de copie. Voyez si cela a du sens:

<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>
brock.holum
la source
CreateItemLa tâche est obsolète. regex a l'alternative. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng
35

Je suis un peu nouveau dans MSBuild mais je trouve la tâche EXEC pratique pour de telles situations. J'ai rencontré le même défi dans mon projet et cela a fonctionné pour moi et a été beaucoup plus simple. Quelqu'un s'il vous plaît laissez-moi savoir si ce n'est pas une bonne pratique.

<Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
    <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
</Target>
Denzil Brown
la source
9
J'ose poser la question dans l'autre sens. Y a-t-il une raison d'utiliser la tâche de copie de msbuild de remplissage de journal?
bernd_k
4
Potentiellement. Si vous avez une batterie de construction (Jenkins, TeamCity, etc.), le service d'agent peut s'exécuter sous un autre compte qui n'a pas xcopy dans le chemin. Vous pouvez essayer des choses comme% windir% \ system32 dans le chemin, mais même cela ne fonctionne pas parfois.
Andrew dh
C'est la solution qui a fonctionné pour moi. Je n'avais pas non plus besoin de définir le WorkingDirectory.
Aebsubis
FYI, je dois ajouter / Y pour supprimer l'invite de remplacement de fichier / dossier. De plus, si $ (DeploymentDirectory) est un dossier, laisser un "\" après le chemin supprimera l'invite: "la destination est un dossier ou un fichier?"
Hoàng Long le
6
Je sais que ce problème ne se pose pas souvent, mais ma principale raison d'utiliser la Copytâche au lieu d'une commande est la compatibilité. J'ai déjà construit sur Linux en utilisant Mono et ne xcopyfonctionne évidemment pas là-bas.
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>

\**\*.*aide à obtenir des fichiers de tout le dossier. RecursiveDir aide à mettre tout le fichier dans le dossier respectif ...

amit thakur
la source
2
Les fichiers de destination font référence à 1 éléments et les fichiers source à 33 éléments. Ils doivent avoir le même nombre d'articles. Ugh .. msbuild peut être génial, mais parfois un morceau d'ordure si mal documenté.
The Muffin Man
CreateItemLa tâche est obsolète. regex a l'alternative. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng
4

Avez-vous essayé de spécifier un répertoire de destination concret au lieu de

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

Je ne maîtrise pas très bien la syntaxe avancée de MSBuild, mais

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

me semble bizarre. Le script semble bon, donc le problème peut être dans les valeurs de $(ApplicationDirectory)et$(OutputPath)

ÉDITER:

Voici un article de blog qui pourrait être utile:

Comment: copier récursivement des fichiers à l'aide de la tâche

aku
la source
1
+1 pour le lien, qui est plus concis que la réponse acceptée de zXen.
bernd_k
3

Voici l'exemple qui a fonctionné:

<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>

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

PBo
la source
2

Il s'agit d'une tâche de copie que j'ai utilisée dans mon propre projet, cela fonctionnait parfaitement pour moi qui copie le dossier avec les sous-dossiers vers la destination avec succès:

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

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

Dans mon cas, j'ai copié le dossier de publication d'un projet dans un autre dossier de destination, je pense que c'est similaire à votre cas.

nzrytmn
la source
1

Personnellement, j'ai utilisé CopyFolder qui fait partie de la bibliothèque de tâches SDC.

http://sdctasks.codeplex.com/

Johan
la source
0

La meilleure façon de copier récursivement des fichiers d'un répertoire à un autre à l'aide de MSBuild consiste à utiliser la tâche de copie avec SourceFiles et DestinationFiles comme paramètres. Par exemple - Pour copier tous les fichiers du répertoire de construction vers le répertoire de sauvegarde sera

<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>

Maintenant, dans la commande Copy ci-dessus, tous les répertoires source sont parcourus et les fichiers sont copiés dans le répertoire de destination.

shivinder thakur
la source
0

Si vous travaillez avec une chaîne d'outils C ++ typique, une autre façon de procéder consiste à ajouter vos fichiers dans la liste standard CopyFileToFolders

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

En plus d'être simple, c'est une bonne façon de procéder car la tâche CopyFilesToFolders générera des entrées, des sorties et même des fichiers TLog appropriés, garantissant ainsi que les opérations de copie ne s'exécuteront que lorsqu'un des fichiers d'entrée a changé ou que l'un des fichiers de sortie est manquant. Avec TLog, Visual Studio reconnaîtra également correctement le projet comme "à jour" ou non (il utilise un mécanisme U2DCheck distinct pour cela).

Sergueï Ozerov
la source