Свойства проверки MSBuild

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

Две попытки, которые мне почти нравятся:

<?xml version="1.0" encoding="utf-8" ?>
  <Project ToolsVersion="3.5" DefaultTarget="Release" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <Target Name="Release">
    <Error
      Text="Property PropA required"
      Condition="'$(PropA)' == ''"/>
    <Error
      Text="Property PropB required"
      Condition="'$(PropB)' == ''"/>

    <!-- The body of the task -->

  </Target>
</Project>

Вот попытка пакетной обработки. Это уродливо из-за дополнительного параметра "Имя". Возможно ли вместо этого использовать атрибут Include?

<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="3.5" DefaultTarget="Release" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Release">
    <!-- MSBuild BuildInParallel="true" Projects="@(ProjectsToBuild)"/ -->
    <ItemGroup>
      <RequiredProperty Include="PropA"><Name>PropA</Name></RequiredProperty>
      <RequiredProperty Include="PropB"><Name>PropB</Name></RequiredProperty>
      <RequiredProperty Include="PropC"><Name>PropC</Name></RequiredProperty>
    </ItemGroup>

    <Error
      Text="Property %(RequiredProperty.Name) required"
      Condition="'$(%(RequiredProperty.Name))' == ''" />

  </Target>

</Project>

Ответы

Ответ 1

Отличный вопрос! Я подробно написал об этом в book и в сообщении в блоге Элементы многоразовых скриптов MSBuild: проверка. Мой подход будет охватывать свойства и предметы.

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

Свойства

Внутри цели проверки укажите свои свойства следующим образом:

<_RequiredProperties Include="Root">
  <Value>$(Root)</Value>
</_RequiredProperties>

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

Элементы

Внутри целевого места требуются элементы внутри элемента, например:

<_RequiredItems Include="AllConfigurations">
  <RequiredValue>@(AllConfigurations)</RequiredValue>
</_RequiredItems>

Подобно свойствам, внутри include вы помещаете имя элемента, а затем значение, которое нужно проверить внутри метаданных RequiredValue. В этом примере он просто проверяет, чтобы элемент AllConfiguraitons не был пустым. Если вы хотите убедиться, что заданное значение метаданных указано для всех элементов, выполните следующие действия:

<_RequiredItems Include = "AllConfigurations.Configuration">
  <RequiredValue>%(AllConfigurations.Configuration </RequiredValue>
</_RequiredItems>

Если вы хотите убедиться, что файл существует, добавьте дополнительные метаданные RequiredFilePath.

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

Проверка

Вот что вам нужно для выполнения проверки

Полный пример

Вот полный пример

<Target Name="ValidateBuildSettings">
  <ItemGroup>
    <_RequiredProperties Include="Root">
      <Value>$(Root)</Value>
    </_RequiredProperties>

    <_RequiredProperties Include="BuildInstallRoot">
      <Value>$(BuildInstallRoot)</Value>
    </_RequiredProperties>

    <_RequiredProperties Include="SourceRoot">
      <Value>$(SourceRoot)</Value>
    </_RequiredProperties>
    <!-- 
    _RequiredItems is the item where required items should be placed. 
    The following metadata is significant: 
      REQUIRED METADATA: 
      Identity          = This will basically be used to identify the specific required item 
      RequiredValue     = This is the specific value that will be validated to exist 

      OPTIONAL METADATA 
      RequiredFilePath  = Populate this with a path that should exists, if it is not empty 
                            then it will be checked to exist on disk. 
    -->

    <_RequiredItems Include="AllConfigurations">
      <RequiredValue>@(AllConfigurations)</RequiredValue>
    </_RequiredItems>
    <_RequiredItems Include = "AllConfigurations.Configuration">
      <RequiredValue>%(AllConfigurations.Configuration </RequiredValue>
    </_RequiredItems>
    <_RequiredItems Include ="ProjectsToBuild">
      <RequiredValue>%(ProjectsToBuild.Identity)</RequiredValue>
      <RequiredFilePath>%(ProjectsToBuild.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>