Скопіюйте всі файли та папки за допомогою msbuild


93

Просто цікаво, чи може хтось допомогти мені з якимись сценаріями msbuild, які я намагаюся написати. Що я хотів би зробити, це скопіювати всі файли та підпапки з папки в іншу папку за допомогою msbuild.

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

Що мені потрібно вміти, це скопіювати всі файли та підпапки з папки інструментів у папку налагодження для програми. Це код, який я маю досі.

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

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

Сценарій збірки виконується, але не копіює жоден файл або папку.

Дякую

Відповіді:


132

Я також шукав допомогу щодо цього. Це зайняло у мене трохи часу, але ось що я зробив, що спрацювало дуже добре.

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

Це рекурсивно скопіювало вміст папки з іменем antlrcsдо $(TargetDir).


4
Так, це найкраща відповідь. Те саме, що рекомендується тут у блозі msdn
Карстен,

2
Чудово працює - дякую! Цікаво, чому інші складніші відповіді мають більше голосів ?!
Іван

17
Здається, фокус полягає в тому, що додавання %(RecursiveDir)до цільової папки відтворить структуру каталогів. В іншому випадку вихід є рівним. Це найкраща відповідь.
JB. З Монікою.

1
Потрібно розмістити внизу файлу .fsproj, інакше це не потрібно.
Генрік

Ключовим моментом, який тут спрацював, є переміщення декларації змінної ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) Під ціллю AfterBuild. У моєму випадку це було оголошено у зовнішній області і не працювало.
Шпанд

71

Я думаю, що проблема може полягати в тому, як ви створюєте свою групу предметів і викликаєте завдання копіювання. Подивіться, чи це має сенс:

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

CreateItemзавдання застаріле. регулярний вираз має альтернативу. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Рей Ченг

35

Я якось новачок у MSBuild, але я вважаю, що завдання EXEC зручна для такої ситуації. Я зіткнувся з тим самим викликом у своєму проекті, і це спрацювало для мене і було набагато простіше. Хтось, будь ласка, дайте мені знати, якщо це не є доброю практикою.

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

9
Я наважуся поставити питання навпаки. Чи є коли-небудь причина використовувати завдання заповнення журналу msbuild copy?
bernd_k

4
Потенційно. Якщо у вас є ферма збірки (Jenkins, TeamCity тощо), служба агента може працювати під іншим обліковим записом, який не має xcopy у шляху. Ви можете спробувати такі речі, як% windir% \ system32, але навіть це не спрацьовує кілька разів.
Andrew dh

Це рішення, яке працювало для мене. Також мені не потрібно було встановлювати робочий каталог.
Aebsubis

FYI, мені потрібно додати / Y, щоб придушити запит заміни файлу / папки. Також якщо $ (DeploymentDirectory) є папкою, залишаючи "\" після того, як шлях видалить запит: "призначення - це папка або файл?"
Хоанг Лонг,

6
Я знаю, що ця проблема виникає не часто, але моя головна причина використовувати Copyзавдання замість команди - це сумісність. Я xcopyпрацював на Linux за допомогою Mono раніше, і, очевидно, там не працює.
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>

\**\*.*допоможе отримати файли з усієї папки. Довідка RecursiveDir помістити весь файл у відповідну папку ...


2
Файли призначення посилаються на 1 елемент, а вихідні - на 33 елементи. Вони повинні мати однакову кількість предметів. Тьфу .. msbuild може бути приголомшливим, але іноді такий погано задокументований шматок.
The Muffin Man

CreateItemзавдання застаріле. регулярний вираз має альтернативу. msdn.microsoft.com/en-us/library/s2y3e43x.aspx
Рей Ченг

4

Ви намагалися вказати конкретний каталог призначення замість

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

Я не дуже добре володію розширеним синтаксисом MSBuild, але

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

мені здається дивним. Сценарій виглядає добре, тому проблема може бути у значеннях $(ApplicationDirectory)і$(OutputPath)

РЕДАГУВАТИ:

Ось допис у блозі, який може бути корисним:

Як: рекурсивно копіювати файли за допомогою завдання


1
+1 за посилання, що є більш стислим, ніж прийнята відповідь від zXen.
bernd_k

3

Ось приклад, який спрацював:

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

джерело: https://msdn.microsoft.com/en-us/library/3e54c37h.aspx


2

Це завдання копіювання, яке я використовував у своєму власному проекті, для мене це прекрасно працювало, що успішно копіює папку з підпапками до місця призначення:

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

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

У моєму випадку я скопіював папку публікації проекту в іншу папку призначення, я думаю, це схоже на ваш випадок.



0

Найкращим способом рекурсивного копіювання файлів з одного каталогу в інший за допомогою MSBuild є використання завдання копіювання з параметрами SourceFiles та DestinationFiles. Наприклад - Скопіювати всі файли з каталогу побудови буде резервне копіювання каталогу

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

Тепер у вищевказаній команді Копіювати обходять усі вихідні каталоги, а файли копіюють у каталог призначення.


0

Якщо ви працюєте з типовою ланцюжком інструментів для C ++, іншим способом є додавання файлів у стандартний список CopyFileToFolders

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

Окрім простоти, це приємний спосіб, оскільки завдання CopyFilesToFolders буде генерувати відповідні вхідні дані, вихідні дані та навіть файли TLog, тому переконайтесь, що операції копіювання будуть виконуватися лише тоді, коли один із вхідних файлів змінився або один із вихідних файлів відсутній. За допомогою TLog Visual Studio також правильно розпізнає проект як "оновлений" чи ні (для цього використовується окремий механізм U2DCheck).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.