Kopieren Sie alle Dateien und Ordner mit msbuild

92

Ich frage mich nur, ob mir jemand mit einigen msbuild-Skripten helfen könnte, die ich zu schreiben versuche. Ich möchte alle Dateien und Unterordner mit msbuild von einem Ordner in einen anderen Ordner kopieren.

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

Was ich tun muss, ist, alle Dateien und Unterordner aus dem Tools-Ordner in den Debug-Ordner für die Anwendung zu kopieren. Dies ist der Code, den ich bisher habe.

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

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

Das Build-Skript wird ausgeführt, kopiert jedoch keine der Dateien oder Ordner.

Vielen Dank

Nathan W.
quelle

Antworten:

129

Ich habe auch hier nach Hilfe gesucht. Es hat eine Weile gedauert, aber hier ist, was ich getan habe, das hat wirklich gut funktioniert.

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

Diese rekursiv den Inhalt des benannten Ordner kopiert antlrcszu der $(TargetDir).

Rodolfo Neuber
quelle
4
Ja, das ist die beste Antwort. Das gleiche wie hier auf msdn Blog empfohlen: blogs.msdn.com/b/msbuild/archive/2005/11/07/490068.aspx
Karsten
2
Funktioniert gut - danke! Ich frage mich, warum andere kompliziertere Antworten mehr positive Stimmen haben?!
Ivan
17
Der Trick scheint zu sein, dass durch Hinzufügen %(RecursiveDir)zum Zielordner die Verzeichnisstruktur neu erstellt wird. Ansonsten ist der Ausgang flach. Dies ist die beste Antwort.
JB. Mit Monica.
1
Muss am Ende der .fsproj-Datei stehen, sonst dauert es nicht.
Henrik
Der Schlüsselmoment hier, der für mich funktioniert hat, ist das Verschieben der Variablendeklaration ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) Unter AfterBuild-Ziel. In meinem Fall wurde es im äußeren Bereich deklariert und funktionierte nicht.
Shpand
71

Ich denke, das Problem könnte darin liegen, wie Sie Ihre ItemGroup erstellen und die Aufgabe Kopieren aufrufen. Überprüfen Sie, ob dies sinnvoll ist:

<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
quelle
CreateItemAufgabe ist veraltet. Regex hat die Alternative. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng
35

Ich bin ein bisschen neu in MSBuild, aber ich finde die EXEC-Aufgabe praktisch für solche Situationen. Ich bin in meinem Projekt auf die gleiche Herausforderung gestoßen, und das hat bei mir funktioniert und war viel einfacher. Bitte lassen Sie mich wissen, wenn dies keine gute Praxis ist.

<Target Name="CopyToDeployFolder" DependsOnTargets="CompileWebSite">
    <Exec Command="xcopy.exe  $(OutputDirectory) $(DeploymentDirectory) /e" WorkingDirectory="C:\Windows\" />
</Target>
Denzil Brown
quelle
9
Ich wage es, die Frage umgekehrt zu stellen. Gibt es jemals einen Grund, die msbuild-Kopieraufgabe zum Ausfüllen von Protokollen zu verwenden?
Bernd_k
4
Möglicherweise. Wenn Sie eine Buildfarm haben (Jenkins, TeamCity usw.), wird der Agentendienst möglicherweise unter einem anderen Konto ausgeführt, das keine xcopy im Pfad enthält. Sie können Dinge wie% windir% \ system32 im Pfad ausprobieren, aber selbst dies funktioniert manchmal nicht.
Andrew dh
Das ist die Lösung, die bei mir funktioniert hat. Außerdem musste ich das WorkingDirectory nicht einstellen.
Aebsubis
Zu Ihrer Information, ich muss / Y hinzufügen, um die Eingabeaufforderung zum Überschreiben von Dateien / Ordnern zu unterdrücken. Auch wenn $ (DeploymentDirectory) ein Ordner ist, wird durch das Belassen eines "\" nach dem Pfad die Eingabeaufforderung entfernt: "Ziel ist Ordner oder Datei?"
Hoàng Long
6
Ich weiß, dass dieses Problem nicht häufig auftritt, aber mein Hauptgrund, die CopyAufgabe anstelle eines Befehls zu verwenden, ist die Kompatibilität. Ich habe zuvor mit Mono auf Linux gebaut und xcopyfunktioniert dort offensichtlich nicht.
GregRos
11
<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>

\**\*.*Hilfe, um Dateien aus dem gesamten Ordner zu erhalten. RecursiveDir-Hilfe, um die gesamte Datei in den entsprechenden Ordner zu legen ...

amit thakur
quelle
2
Zieldateien beziehen sich auf 1 Elemente und Quelldateien auf 33 Elemente. Sie müssen die gleiche Anzahl von Elementen haben. Ugh .. msbuild kann großartig sein, aber manchmal so ein schlecht dokumentiertes Stück Müll.
Der Muffin-Mann
CreateItemAufgabe ist veraltet. Regex hat die Alternative. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng
4

Haben Sie versucht, ein konkretes Zielverzeichnis anstelle von anzugeben?

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

Ich bin nicht sehr kompetent mit fortgeschrittener MSBuild-Syntax, aber

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

sieht komisch aus für mich. Das Skript sieht gut aus, daher liegt das Problem möglicherweise in den Werten von $(ApplicationDirectory)und$(OutputPath)

BEARBEITEN:

Hier ist ein Blog-Beitrag, der nützlich sein könnte:

Gewusst wie: Rekursives Kopieren von Dateien mithilfe der Aufgabe

aku
quelle
1
+1 für den Link, der prägnanter ist als die akzeptierte Antwort von zXen.
Bernd_k
3

Dies ist das Beispiel, das funktioniert hat:

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

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

PBo
quelle
2

Dies ist eine Kopieraufgabe, die ich in meinem eigenen Projekt verwendet habe. Es funktionierte perfekt für mich, Ordner mit Unterordnern erfolgreich an das Ziel zu kopieren:

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

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

In meinem Fall habe ich den Veröffentlichungsordner eines Projekts in einen anderen Zielordner kopiert. Ich denke, er ähnelt Ihrem Fall.

nzrytmn
quelle
1

Persönlich habe ich CopyFolder verwendet, der Teil der DEZA-Aufgabenbibliothek ist.

http://sdctasks.codeplex.com/

Johan
quelle
0

Der beste Weg, um Dateien mit MSBuild rekursiv von einem Verzeichnis in ein anderes zu kopieren, ist die Verwendung der Aufgabe "Kopieren" mit SourceFiles und DestinationFiles als Parametern. Zum Beispiel - Um alle Dateien aus dem Build-Verzeichnis in das Backup-Verzeichnis zu kopieren, wird

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

Im obigen Kopierbefehl werden nun alle Quellverzeichnisse durchlaufen und Dateien in das Zielverzeichnis kopiert.

Shivinder Thakur
quelle
0

Wenn Sie mit einer typischen C ++ - Toolchain arbeiten, können Sie Ihre Dateien auch in die Standardliste CopyFileToFolders einfügen

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

Dies ist nicht nur einfach, sondern auch ein guter Weg, da die Aufgabe CopyFilesToFolders geeignete Eingaben, Ausgaben und sogar TLog-Dateien generiert und daher sicherstellt, dass Kopiervorgänge nur ausgeführt werden, wenn sich eine der Eingabedateien geändert hat oder eine der Ausgabedateien fehlt. Mit TLog erkennt Visual Studio das Projekt auch ordnungsgemäß als "aktuell" oder nicht (es verwendet dafür einen separaten U2DCheck-Mechanismus).

Sergei Ozerov
quelle