Skopiuj wszystkie pliki i foldery za pomocą msbuild


94

Zastanawiam się tylko, czy ktoś mógłby mi pomóc z kilkoma skryptami msbuild, które próbuję napisać. To, co chciałbym zrobić, to skopiować wszystkie pliki i podfoldery z folderu do innego folderu za pomocą msbuild.

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

To, co muszę zrobić, to skopiować wszystkie pliki i podfoldery z folderu narzędzi do folderu debugowania aplikacji. To jest kod, który mam do tej pory.

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

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

Skrypt kompilacji działa, ale nie kopiuje żadnych plików ani folderów.

Dzięki

Odpowiedzi:


136

W tym też szukałem pomocy. Zajęło mi to trochę czasu, ale oto, co zrobiłem, że zadziałało naprawdę dobrze.

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

To rekurencyjnie skopiowało zawartość folderu o nazwie antlrcsdo $(TargetDir).


4
Tak, to najlepsza odpowiedź. To samo, co zalecane tutaj na blogu msdn
— Karsten

18
Wydaje się, że sztuczka polega na tym, że dodanie %(RecursiveDir)do folderu docelowego odtworzy strukturę katalogów. W przeciwnym razie wyjście jest płaskie. To jest najlepsza odpowiedź.
— JB. Z Monicą.

1
Należy umieścić na dole pliku .fsproj lub nie zajmuje.
— Henrik,

Kluczowym momentem, który zadziałał dla mnie, jest przeniesienie deklaracji zmiennej ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) W ramach celu AfterBuild. W moim przypadku zostało to zadeklarowane w zakresie zewnętrznym i nie zadziałało.
— Shpand

To świetny pomysł! Znalazłem %(RecursiveDir)w MSBuild dobrze znane metadane elementu : docs.microsoft.com/en-us/visualstudio/msbuild/ ...
— kenjiuno

72

Myślę, że problem może tkwić w tym, jak tworzysz ItemGroup i wywołujesz zadanie kopiowania. Sprawdź, czy to ma 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>

CreateItemzadanie jest przestarzałe. regex ma alternatywę. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
— Ray Cheng

35

Jestem trochę nowy w MSBuild, ale uważam, że zadanie EXEC jest przydatne w takich sytuacjach. Spotkałem się z tym samym wyzwaniem w moim projekcie i to zadziałało i było znacznie prostsze. Niech ktoś mi powie, jeśli to nie jest dobra praktyka.

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

9
Odważę się zadać to pytanie w drugą stronę. Czy jest jakiś powód, aby kiedykolwiek używać zadania kopiowania MSBuild wypełniającego dziennik?
— bernd_k

4
Potencjalnie. Jeśli masz farmę kompilacji (Jenkins, TeamCity itp.), Usługa agenta może działać na innym koncie, które nie ma xcopy w ścieżce. Możesz wypróbować na ścieżce rzeczy takie jak% windir% \ system32, ale nawet to czasami nie działa.
— Andrew dh

To rozwiązanie zadziałało dla mnie. Nie musiałem też ustawiać katalogu roboczego.
— Aebsubis

FYI, muszę dodać / Y, aby pominąć monit o zastąpienie pliku / folderu. Również jeśli $ (DeploymentDirectory) jest folderem, pozostawienie znaku „\” po ścieżce usunie monit: „miejsce docelowe to folder czy plik?”
— Hoàng Long

6
Wiem, że ten problem nie pojawia się często, ale moim głównym powodem, dla którego używam Copyzadania zamiast polecenia, jest kompatybilność. Wcześniej budowałem na Linuksie przy użyciu Mono i oczywiście xcopytam nie działa.
— GregRos

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

\**\*.*pomóc pobrać pliki z całego folderu. RecursiveDir pomaga umieścić cały plik w odpowiednim folderze ...


2
Pliki docelowe odnoszą się do 1 pozycji, a pliki źródłowe do 33 pozycji. Muszą mieć taką samą liczbę elementów. Ugh… msbuild może być niesamowity, ale czasami taki słabo udokumentowany kawałek śmieci.
— The Muffin Man

CreateItemzadanie jest przestarzałe. regex ma alternatywę. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
— Ray Cheng

4

Czy próbowałeś określić konkretny katalog docelowy zamiast

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

Nie jestem biegły w zaawansowanej składni MSBuild, ale

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

wygląda dla mnie dziwnie. Skrypt wygląda dobrze, więc problem może dotyczyć wartości $(ApplicationDirectory)i$(OutputPath)

EDYTOWAĆ:

Oto post na blogu, który może być przydatny:

Instrukcje: rekurencyjne kopiowanie plików za pomocą zadania


1
+1 dla linku, który jest bardziej zwięzły niż zaakceptowana odpowiedź od zXen.
— bernd_k

3

Oto przykład, który zadziałał:

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

źródło: https://msdn.microsoft.com/en-us/library/3e54c37h.aspx


2

To jest zadanie kopiowania, którego użyłem w moim własnym projekcie, działało idealnie dla mnie, pomyślnie kopiując folder z podfolderami do miejsca docelowego:

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

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

W moim przypadku skopiowałem folder publikacji projektu do innego folderu docelowego, myślę, że jest to podobne do twojego przypadku.



0

Najlepszym sposobem rekurencyjnego kopiowania plików z jednego katalogu do innego przy użyciu programu MSBuild jest użycie zadania kopiowania z parametrami SourceFiles i DestinationFiles. Na przykład - Aby skopiować wszystkie pliki z katalogu kompilacji do katalogu kopii zapasowej, będzie

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

Teraz w powyższym poleceniu Kopiuj przechodzą wszystkie katalogi źródłowe, a pliki są kopiowane do katalogu docelowego.


0

Jeśli pracujesz z typowym łańcuchem narzędzi C ++, innym sposobem jest dodanie plików do standardowej listy CopyFileToFolders

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

Poza tym, że jest to proste, jest to przyjemny sposób, ponieważ zadanie CopyFilesToFolders wygeneruje odpowiednie dane wejściowe, wyjściowe, a nawet pliki TLog, dzięki czemu operacje kopiowania będą wykonywane tylko wtedy, gdy jeden z plików wejściowych ulegnie zmianie lub brakuje jednego z plików wyjściowych. Z TLog, Visual Studio również poprawnie rozpozna projekt jako „aktualny” lub nie (używa do tego oddzielnego mechanizmu U2DCheck).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.