使用HeatDirectory任务从手动组件创建转移到收获

时间:2014-03-10 14:24:36

标签: wix components heat

我正在使用WiX 3.8来构建一个安装产品的项目。安装程序基本完成。由软件包安装的程序之一是依赖于第三方的dll,它经常更新。特别是dll的版本号定期更改。在第一次编写安装程序项目时,我没有考虑支持更改文件名并手动编写每个组件。

将来应该更改此行为。如果我理解正确,可以在HeatDirectory Task的帮助下自动生成文件组件。我现在使用HeatDirectory Task创建了一个示例项目。但是HeatDirectory Task产生的输出与我过去使用的手动编写的组件之间存在一些差异。

我希望HeatDirectory Task尽可能好地生成与我的手动方法相同的输出。以下是两个组件的代码,首先手动创建,然后由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. 我想要静态guids。
  3. 我希望组件的Id属性由前缀CMP后跟文件名组成。据我所知,项目中不能有两个文件名相同的文件,但我知道情况并非如此。我不想要任务生成的神秘标识符。
  4. 组件的File子项太过于简单。我希望HeatDirectoy Task为每个文件创建一个Name属性,该文件是文件的当前名称。然后,Compressed属性应添加值noDiksId应添加变量值,可以在某种程度上在任务中指定。
  5. 如果收集的文件是dll,则任务应将属性Asssembly附加值.netAssemblyApplication,并将已获取文件的名称作为其值&amp; AssemblyManifest也将已获取文件的名称作为其值。
  6. 是否可以通过HeatDirectory任务实现这一目标?

1 个答案:

答案 0 :(得分: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>