Замените .sln на MSBuild и заверните содержащиеся проекты в целевые объекты

Я хотел бы создать проект MSBuild, который отражает зависимости проекта в решении и обертывает проекты VS внутри повторно используемых целей.

Проблема, которую мне нравится решать, заключается в svn-export, сборке и развертывании конкретной сборки (и ее зависимостей) в приложении BizTalk.

Мой вопрос: как я могу сделать цели для svn-экспорта, создания и развертывания многоразового использования, а также повторно использовать завернутые проекты, когда они созданы для разных зависимостей?

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

Детали

Проект, который мне нравится развернуть

<Project DefaultTargets="Deploy" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <ExportRoot Condition="'$(Export)'==''">Export</ExportRoot>
    </PropertyGroup>

    <Target Name="Clean_Export">
        <RemoveDir Directories="$(ExportRoot)\My.Project.Dir" />
    </Target>

    <Target Name="Export_MyProject">
        <Exec Command="svn export svn://xxx/trunk/Biztalk2009/MyProject.btproj --force" WorkingDirectory="$(ExportRoot)" />
    </Target>

    <Target Name="Build_MyProject" DependsOnTargets="Export_MyProject">
        <MSBuild Projects="$(ExportRoot)\My.Project.Dir\MyProject.btproj" Targets="Build" Properties="Configuration=Release"></MSBuild>
    </Target>

    <Target Name="Deploy_MyProject" DependsOnTargets="Build_MyProject">
        <Exec Command="BTSTask AddResource -ApplicationName:CORE -Source:MyProject.dll" />
    </Target>
</Project>

Проекты, от которых он зависит, выглядят почти так же (другие .btproj и .csproj).

Ответ 1

Вау, это загруженный вопрос для сообщения в форуме. Я написал около 20 страниц о создании многоразовых файлов .targets в моей книге, но я расскажу вам об этом здесь. Я считаю, что ключом к созданию сценариев многократной сборки (т.е..targets) является три элемента:

  • Поместите поведение (например, цели) в отдельные файлы
  • Поместите данные (т.е. свойства и элементы, они называются .proj файлами) в свои собственные файлы.
  • расширяемость
  • .targets файлы должны проверять допущения

Идея состоит в том, что вы хотите поместить все свои цели в отдельные файлы, а затем эти файлы будут импортированы файлами, которые будут управлять процессом сборки. Это файлы, содержащие данные. Поскольку вы импортируете файлы .targets, вы получаете все цели, как если бы они были определены внутри. Будет заключен тихий контракт между файлами .proj и .targets. Этот контракт определяется в свойствах и элементах, которые оба используются. Это то, что нужно проверить.

Идея здесь не нова. За этим шаблоном следует .csproj(и другие проекты, созданные Visual Studio). Если вы посмотрите на ваш .csproj файл, вы не найдете ни одной цели, просто свойства и элементы. Затем в нижней части файла он импортирует Microsoft.csharp.targets(может отличаться в зависимости от типа проекта). Этот файл проекта (вместе с другими, который он импортирует) содержит все цели, которые фактически выполняют сборку.

Так оно и сложилось так:

  • SharedBuild.targets
  • MyProduct.proj

Где MyProdcut.proj может выглядеть так:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- This uses a .targets file to off load performing the build -->
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
    <OutputPath Condition=" '$(OutputPath)'=='' ">$(MSBuildProjectDirectory)\BuildArtifacts\bin\</OutputPath>
  </PropertyGroup>

  <ItemGroup>
    <Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary1\ClassLibrary1.csproj"/>
    <Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary2\ClassLibrary2.csproj"/>
    <Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary3\ClassLibrary3.csproj"/>
    <Projects Include="$(MSBuildProjectDirectory)\..\WindowsFormsApplication1\WindowsFormsApplication1.csproj"/>
  </ItemGroup>

  <Import Project="SharedBuild.targets"/>
</Project>

И SharedBuild.targets может выглядеть так:

<Project  DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- This represents a re-usable build file -->
  <Target Name="SharedBuild_Validate">
    <!-- See http://sedodream.com/2009/06/30/ElementsOfReusableMSBuildScriptsValidation.aspx for more info
         about this validation pattern
    -->
    <ItemGroup>
      <_RequiredProperties Include ="Configuration">
          <Value>$(Configuration)</Value>
      </_RequiredProperties>    
      <_RequiredProperties Include ="OutputPath">
          <Value>$(OutputPath)</Value>
      </_RequiredProperties>

      <_RequiredItems Include="Projects">
        <RequiredValue>%(Projects.Identity)</RequiredValue>
        <RequiredFilePath>%(Projects.Identity)</RequiredFilePath>
      </_RequiredItems>
    </ItemGroup>

    <!-- Raise an error if any value in _RequiredProperties is missing -->
    <Error Condition="'%(_RequiredProperties.Value)'==''"
           Text="Missing required property [%(_RequiredProperties.Identity)]"/>

    <!-- Raise an error if any value in _RequiredItems is empty -->
    <Error Condition="'%(_RequiredItems.RequiredValue)'==''"
           Text="Missing required item value [%(_RequiredItems.Identity)]" />

    <!-- Validate any file/directory that should exist -->
    <Error Condition="'%(_RequiredItems.RequiredFilePath)' != '' and !Exists('%(_RequiredItems.RequiredFilePath)')"
           Text="Unable to find expeceted path [%(_RequiredItems.RequiredFilePath)] on item [%(_RequiredItems.Identity)]" />
  </Target>

  <PropertyGroup>
    <BuildDependsOn>
      SharedBuild_Validate;
      BeforeBuild;
      CoreBuild;
      AfterBuild;
    </BuildDependsOn>
  </PropertyGroup>
  <Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
  <Target Name="BeforeBuild"/>
  <Target Name="AfterBuild"/>
  <Target Name="CoreBuild">
    <!-- Make sure output folder exists -->
    <PropertyGroup>
      <_FullOutputPath>$(OutputPath)$(Configuration)\</_FullOutputPath>
    </PropertyGroup>
    <MakeDir Directories="$(_FullOutputPath)"/>
    <MSBuild Projects="@(Projects)"
             BuildInParallel="true"
             Properties="OutputPath=$(_FullOutputPath)"/>
  </Target>
</Project>

Не смотрите слишком много на цель SharedBuild_Validate. Я положил это на полноту, но не сосредоточился на этом. Вы можете найти дополнительную информацию об этом в моем блоге в http://sedodream.com/2009/06/30/ElementsOfReusableMSBuildScriptsValidation.aspx.

Важными частями, которые нужно заметить, являются точки расширяемости. Несмотря на то, что это очень простой файл, он содержит все компоненты многоразового файла .targets. Вы можете настроить его поведение, передав разные свойства и элементы для сборки. Вы можете расширить его поведение, переопределив цель (BeforeBuild, AfterBuild или даже CoreBuild), и вы можете ввести свои собственные цели в сборку с помощью:

<Project ...>
   ...
  <Import Project="SharedBuild.targets"/>
  <PropertyGroup>
    <BuildDependsOn>
      $(BuildDependsOn);
      CustomAfterBuild
    </BuildDependsOn>
  </PropertyGroup>
  <Target Name="CustomAfterBuild">
    <!-- Insert stuff here -->
  </Target>
</Project>

В вашем случае я бы создал файл SvnExport.targets, который использует требуемые свойства:

  • SvnExportRoot
  • SvnUrl
  • SvnWorkingDirectory Вы будете использовать эти свойства для экспорта.

Затем создайте еще один для сборки и развертывания Biztalk. Вы можете разделить его на 2, если необходимо.

Затем внутри вашего .proj файла вы просто импортируете оба и устанавливаете цели для сборки в правильном порядке, а ваш выключен.

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

UPDATE:

Добавлено в блог на http://sedodream.com/2010/03/19/ReplacingSolutionFilesWithMSBuildFiles.aspx