Переходите от ручного создания компонентов к сбору урожая с помощью задачи HeatDirectory

Я использую WiX 3.8 для создания проекта, который устанавливает продукт. Инсталлятор в основном готов. Одна из программ, устанавливаемых пакетом, зависит от сторонних библиотек DLL, которые часто обновляются. Как ни странно, номер версии dll регулярно меняется. При первом написании проекта установщика я не рассматривал возможность включения поддержки изменения имен файлов и писал каждый компонент вручную.

Это поведение должно быть изменено в будущем. Если я правильно понимаю, генерировать компоненты для файлов автоматически можно с помощью Задача HeatDirectory. Теперь я создал пример проекта, используя задачу HeatDirectory, которая работает. Но есть некоторое несоответствие в выходных данных задачи HeatDirectory и созданных вручную компонентов, которые я использовал в прошлом.

Я хотел бы, чтобы задача HeatDirectory производила тот же результат, что и мой ручной подход, насколько это возможно. Ниже приведен код двух компонентов, сначала созданных вручную, а затем созданных задачей HeatDirectory:

Компоненты, созданные вручную:

<ComponentGroup Id="ThirdParty.v13.2" Directory="INSTALLFOLDER">
<Component 
  Id="CMP_ThirdParty.v13.2.dll" 
  Guid="AC5E00F0-B458-4272-B132-F13594ED4916">
  <File 
    Id="ThirdParty.v13.2.dll" 
    Name="ThirdParty.v13.2.dll" 
    Source="ComponentsDir\ThirdParty\ThirdParty.v13.2.dll" 
    KeyPath="yes" 
    Assembly=".net" 
    AssemblyApplication="ThirdParty.v13.2.dll" 
    AssemblyManifest="ThirdParty.v13.2.dll" 
    Compressed="no" 
    DiskId="$(var.ThirdPartyDiskId)"/>
</Component>
<Component 
  Id="CMP_ThirdParty.v13.2.xml" 
  Guid="64AC3F5F-38E9-41EC-B714-636F5D9C0CB4">
  <File 
    Id="ThirdParty.v13.2.xml" 
    Name="ThirdParty.v13.2.xml" 
    Source="Source="ComponentsDir\ThirdParty\ThirdParty.v13.2.xml" 
    KeyPath="yes" 
    Compressed="no" 
    DiskId="$(var.ThirdPartyDiskId)"/>
</Component>
</ComponentGroup>

Сгенерированный код задачи HeatDirectory:

<ComponentGroup Id="Files">
<Component 
  Id="cmp9D064A733360960E07277CFD9AB84AF1" 
  Directory="INSTALLFOLDER" 
  Guid="*">
  <File 
    Id="filD5DCB6E091D2D12303E2E80B0B767438" 
    KeyPath="yes" 
    Source="$(var.Path)\ThirdParty.v13.2.dll"/>
</Component>
<Component 
  Id="cmpA8681A63A8A4991D18824BA17E4CA4BF" 
  Directory="INSTALLFOLDER" 
  Guid="*">
  <File 
    Id="fil17554B3CD0E576337AEC758831009938" 
    KeyPath="yes" 
    Source="$(var.Path)\ThirdParty.v13.2.xml"/>
</Component>
</ComponentGroup>

Код, выдающий приведенный выше вывод, выглядит следующим образом:

<Target Name="BeforeBuild">
<HeatDirectory 
  DirectoryRefId="INSTALLFOLDER" 
  OutputFile="Files.wxs" 
  Directory="S:\omePath" 
  SuppressRootDirectory="true" 
  ToolPath="$(WixToolPath)" 
  AutogenerateGuids="true" 
  ComponentGroupName="Files" 
  PreprocessorVariable="var.Path">
</HeatDirectory>
</Target>

Теперь я запишу характеристики сгенерированного кода задачи HeatDirectory, который я хотел бы изменить:

  1. Каждый компонент в группе компонентов имеет атрибут Directory. Я хочу, чтобы родительский элемент ComponentGroup имел атрибут Directory и опускал его в каждом дочернем компоненте.
  2. Мне нужны статические направляющие.
  3. Я хочу, чтобы атрибут Id компонента состоял из префикса CMP, за которым следует имя файла. Я понимаю, что в проекте не может быть двух файлов с одинаковым именем, но я знаю, что это не так. Мне не нужен загадочный идентификатор, сгенерированный задачей.
  4. Дочерний элемент File компонента слишком спартанский. Я хочу, чтобы задача HeatDirectoy создавала атрибут Name для каждого файла, который является текущим именем файла. Затем к атрибуту Compressed нужно добавить значение no, а к DiksId добавить значение переменной, которое можно как-то указать в задаче.
  5. Если собранный файл является dll, задача должна добавить атрибуты Asssembly со значением .net, AssemblyApplication с именем собранного файла в качестве значения и AssemblyManifest также с именем собранного файла в качестве значения.

Можно ли добиться этого с помощью задачи HeatDirectory?


person BdN3504    schedule 10.03.2014    source источник
comment
Для сравнения попробуйте запустить wixcop для файлов, созданных вручную, и посмотрите, какие различия остались. (Конечно, сначала сделайте резервную копию.) Вы можете обнаружить, что многие из ваших требований не являются требованиями.   -  person Tom Blodget    schedule 11.03.2014
comment
Тепловая мощность может быть изменена с помощью XSL-преобразований. Кроме того, по тепловым расширениям.   -  person Tom Blodget    schedule 11.03.2014
comment
Я также наткнулся на раздел XSL-преобразования в руководстве, но, честно говоря, я не понимаю, как работает XSLT. Например, я не могу просто добавить атрибут к Componentgroup, например. Применение ‹xsl:template match=/Wix/Fragment/ComponentGroup› ‹xsl:attribute name=Directory› ‹xsl:text›INSTALLFOLDER‹/xsl:text› ‹/xsl:attribute› ‹xsl:apply-templates /› ‹/ xsl:template› не действует.   -  person BdN3504    schedule 11.03.2014
comment
Теперь я почти добился точного совпадения с XSLT, за исключением статических идентификаторов GUID. Если кто-нибудь может сказать мне, как этого добиться, я с радостью отвечу на свой вопрос.   -  person BdN3504    schedule 11.03.2014
comment
Рад, что у вас работает XSLT. Я не уверен насчет GUID. (Я всегда делаю основное обновление. поэтому все компоненты являются новыми, даже для одинаковых файлов.) Вы уверены, что будете следовать Правила компонентов с вашими статическими идентификаторами GUID?.   -  person Tom Blodget    schedule 12.03.2014
comment
Спасибо, что напомнили мне о правилах компонентов. Я строго помещаю один файл в каждый компонент.   -  person BdN3504    schedule 12.03.2014


Ответы (1)


Ответом на манипулирование выводом задачи HeatDirectory является использование XSLT. В задаче HeatDirectory можно указать атрибут с именем Transforms, который указывает на файл, содержащий XSLT-инструкции. Чтобы получить результат, о котором я просил, можно использовать следующий код XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  exclude-result-prefixes="msxsl">

  <xsl:output
    method="xml"
    indent="yes"/>
  <xsl:variable name="ComponentGroup-Id" select="//wix:ComponentGroup/@Id"/>
  <xsl:variable name="DestinationFolder" select="//wix:Component[1]/@Directory"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select ="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:Directory">
    <xsl:variable name="DirName" select="@Name" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:value-of select="$ComponentGroup-Id"/>
        <xsl:text>_</xsl:text>
        <xsl:value-of select="$DirName"/>
      </xsl:attribute>
      <xsl:attribute name="Name">
        <xsl:value-of select="$DirName"/>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:ComponentGroup">
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:value-of select="$ComponentGroup-Id"/>
      </xsl:attribute>
      <xsl:attribute name="Directory">
        <xsl:value-of select="$DestinationFolder"/>
      </xsl:attribute>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:Component">
    <xsl:variable name="FilePath" select="current()/wix:File/@Source" />
    <xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
    <xsl:variable name="Guid" select="@Guid" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:text>CMP_</xsl:text>
        <xsl:choose>
          <xsl:when test="contains($FileName,'\')">
            <xsl:value-of select="substring-after($FileName,'\')"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$FileName"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:attribute name="Guid">
        <xsl:value-of select="$Guid"/>
      </xsl:attribute>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//wix:File">
    <xsl:variable name="FilePath" select="@Source" />
    <xsl:variable name="FileName" select="substring-after($FilePath,'\')" />
    <xsl:copy>
      <xsl:attribute name="Id">
        <xsl:choose>
          <xsl:when test="contains($FileName,'\')">
            <xsl:value-of select="substring-after($FileName,'\')"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$FileName"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:attribute>
      <xsl:attribute name="KeyPath">
        <xsl:text>yes</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="Source">
        <xsl:value-of select="$FilePath"/>
      </xsl:attribute>
      <xsl:if test="contains($FileName,'.dll')">
        <xsl:attribute name="Assembly">.net</xsl:attribute>
        <xsl:attribute name="AssemblyApplication">
          <xsl:choose>
            <xsl:when test="contains($FileName,'\')">
              <xsl:value-of select="substring-after($FileName,'\')"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$FileName"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
        <xsl:attribute name="AssemblyManifest">
          <xsl:choose>
            <xsl:when test="contains($FileName,'\')">
              <xsl:value-of select="substring-after($FileName,'\')"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$FileName"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
      </xsl:if>
      <xsl:attribute name="Compressed">
        <xsl:text>no</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="DiskId">
        <xsl:text>$(var.SomeDiskID)</xsl:text>
      </xsl:attribute>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
person BdN3504    schedule 12.03.2014