Скопируйте все файлы и папки с помощью msbuild

94

Просто интересно, может ли кто-нибудь помочь мне с некоторыми скриптами 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>

Сценарий сборки запускается, но не копирует никакие файлы или папки.

Благодарность

Натан В
источник

Ответы:

136

Я тоже искал помощи по этому поводу. Это заняло у меня время, но вот то, что я сделал, сработало очень хорошо.

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

Это рекурсивно копируется содержимое в папку с именем antlrcsв $(TargetDir).

Родольфо Нойбер
источник
4
Да, это лучший ответ. То же, что рекомендовано здесь, в блоге msdn
Карстен,
18
Уловка, похоже, заключается в том, что добавление %(RecursiveDir)в папку назначения воссоздает структуру каталогов. В противном случае результат будет плоским. Это лучший ответ.
JB. С Моникой.
1
Нужно положить в нижней части файла .fsproj, или он не принимает.
Henrik
Ключевым моментом, который сработал для меня, является перемещение объявления переменной ( <ANTLR Include = ".. \ Data \ antlrcs ***. *" /> ) В цель AfterBuild. В моем случае он был объявлен во внешней области видимости и не работал.
Шпанд
Отличная идея! Я нашел %(RecursiveDir)в MSBuild метаданные хорошо известных элементов : docs.microsoft.com/en-us/visualstudio/msbuild/…
kenjiuno
72

Я думаю, проблема может заключаться в том, как вы создаете свою ItemGroup и вызываете задачу копирования. Посмотрите, имеет ли это смысл:

<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
источник
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 для заполнения журнала?
bernd_k
4
Потенциально. Если у вас есть ферма сборки (Jenkins, TeamCity и т. Д.), Служба агента может работать под другой учетной записью, в пути которой нет xcopy. Вы можете попробовать что-то вроде% windir% \ system32 в пути, но даже это иногда не работает.
Andrew dh
Это решение, которое сработало для меня. Также мне не нужно было устанавливать рабочий каталог.
Aebsubis,
К вашему сведению, мне нужно добавить / Y, чтобы подавить запрос переопределения файла / папки. Также, если $ (DeploymentDirectory) - это папка, оставление символа «\» после пути приведет к удалению запроса: «Место назначения - папка или файл?»
Hoàng Long,
6
Я знаю, что эта проблема возникает не часто, но моя основная причина использовать Copyзадачу вместо команды - совместимость. Я раньше строил Linux с использованием Mono и, очевидно, xcopyтам не работал.
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>

\**\*.*Помогите получить файлы из всей папки. 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

PBo
источник
2

Это задача копирования, которую я использовал в своем собственном проекте, она отлично работала для меня, успешно копируя папку с подпапками в место назначения:

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

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

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

nzrytmn
источник
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).

Сергей Озеров
источник