Copia tutti i file e le cartelle usando msbuild


93

Mi chiedevo solo se qualcuno potesse aiutarmi con alcuni script di msbuild che sto cercando di scrivere. Quello che vorrei fare è copiare tutti i file e le sottocartelle da una cartella a un'altra cartella usando msbuild.

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

Quello che devo essere in grado di fare è copiare tutti i file e le sottocartelle dalla cartella degli strumenti nella cartella di debug dell'applicazione. Questo è il codice che ho finora.

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

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

Lo script di build viene eseguito ma non copia nessuno dei file o delle cartelle.

Grazie

Risposte:


133

Stavo cercando aiuto anche su questo. Mi ci è voluto un po ', ma ecco cosa ho fatto che ha funzionato davvero bene.

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

Ciò ha copiato in modo ricorsivo il contenuto della cartella denominata antlrcsin $(TargetDir).


4
Sì, questa è la risposta migliore. Lo stesso consigliato qui sul blog msdn
Karsten

2
Funziona bene, grazie! Mi chiedo perché altre risposte più complicate abbiano più voti positivi ?!
Ivan

17
Il trucco sembra essere che l'aggiunta %(RecursiveDir)alla cartella di destinazione ricrea la struttura della directory. Altrimenti l'uscita è piatta. Questa è la migliore risposta.
JB. Con Monica.

1
Deve essere messo in fondo al file .fsproj, altrimenti non ci vuole.
Henrik

Il momento chiave qui che ha funzionato per me è stato lo spostamento della dichiarazione della variabile ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) Sotto l'obiettivo AfterBuild. Nel mio caso è stato dichiarato nell'ambito esterno e non ha funzionato.
Shpand

71

Penso che il problema potrebbe essere nel modo in cui stai creando il tuo ItemGroup e chiamando l'attività di copia. Vedi se ha senso:

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

CreateIteml'attività è deprecata. regex ha l'alternativa. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

35

Sono un po 'nuovo in MSBuild, ma trovo utile EXEC Task per situazioni come queste. Mi sono imbattuto nella stessa sfida nel mio progetto e questo ha funzionato per me ed è stato molto più semplice. Qualcuno mi faccia sapere se non è una buona pratica.

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

9
Oserei porre la domanda al contrario. C'è qualche motivo per utilizzare il log che riempie l'attività di copia di msbuild?
bernd_k

4
Potenzialmente. Se hai una build farm (Jenkins, TeamCity ecc.), Il servizio agente potrebbe essere eseguito con un account diverso che non ha xcopy nel percorso. Puoi provare cose come% windir% \ system32 nel percorso, ma anche questo a volte non funziona.
Andrew dh

Questa è la soluzione che ha funzionato per me. Inoltre non avevo bisogno di impostare WorkingDirectory.
Aebsubis

Cordiali saluti, devo aggiungere / Y per sopprimere il prompt di sostituzione di file / cartelle. Inoltre, se $ (DeploymentDirectory) è una cartella, lasciare una "\" dopo il percorso rimuoverà il prompt: "la destinazione è una cartella o un file?"
Hoàng Long,

6
So che questo problema non si presenta spesso, ma il motivo principale per utilizzare l' Copyattività anziché un comando è la compatibilità. Ho già compilato su Linux utilizzando Mono e ovviamente xcopynon funziona lì.
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>

\**\*.*aiuto per ottenere file da tutta la cartella. RecursiveDir aiuta a mettere tutti i file nella rispettiva cartella ...


2
I file di destinazione si riferiscono a 1 elemento e i file di origine si riferiscono a 33 elementi. Devono avere lo stesso numero di articoli. Ugh .. msbuild può essere fantastico, ma a volte è un pezzo di spazzatura così scarsamente documentato.
The Muffin Man

CreateIteml'attività è deprecata. regex ha l'alternativa. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Ray Cheng

4

Hai provato a specificare una directory di destinazione concreta invece di

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

Non sono molto esperto con la sintassi avanzata di MSBuild, ma

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

mi sembra strano. Lo script sembra buono, quindi il problema potrebbe essere nei valori di $(ApplicationDirectory)e$(OutputPath)

MODIFICARE:

Ecco un post sul blog che potrebbe essere utile:

Procedura: copiare i file in modo ricorsivo utilizzando l'attività


1
+1 per il collegamento, che è più conciso della risposta accettata da zXen.
bernd_k

3

Questo è l'esempio che ha funzionato:

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

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


2

Questa è l'attività di copia che ho usato nel mio progetto, funzionava perfettamente per me che copia la cartella con le sottocartelle nella destinazione con successo:

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

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

Nel mio caso ho copiato la cartella di pubblicazione di un progetto in un'altra cartella di destinazione, penso che sia simile al tuo caso.



0

Il modo migliore per copiare in modo ricorsivo i file da una directory a un'altra utilizzando MSBuild è utilizzare l'attività di copia con SourceFiles e DestinationFiles come parametri. Ad esempio: per copiare tutti i file dalla directory di build alla directory di backup sarà

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

Ora nel comando Copia sopra, tutte le directory di origine vengono attraversate ei file vengono copiati nella directory di destinazione.


0

Se stai lavorando con la tipica toolchain C ++, un altro modo per procedere è aggiungere i tuoi file all'elenco standard CopyFileToFolders

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

Oltre ad essere semplice, questo è un bel modo di procedere perché l'attività CopyFilesToFolders genererà input, output e persino file TLog appropriati, quindi assicurandosi che le operazioni di copia vengano eseguite solo quando uno dei file di input è cambiato o uno dei file di output è mancante. Con TLog, Visual Studio riconoscerà anche correttamente il progetto come "aggiornato" o meno (utilizza un meccanismo U2DCheck separato per questo).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.