Use XSLT in wix

时间:2021-12-14 06:20:55

Following content is directly reprinted from https://installpac.wordpress.com/2012/05/07/conflict-management-in-wix/ and it is only meant for knowledge sharing, please go to the original website for more information.

Conflict Management in WiX

So if you haven’t already read my post on conflict management it might be worth reading up on this first.

https://installpac.wordpress.com/2008/04/21/wise-software-mangler-distribution

The documentation on WiX is somewhat obfuscated to the normal reader and not many people have made an attempt to clear up that documentation to well.

There is some pretty good detail here on WiX in general but it doesn’t go too deep into anything if your serious about SDLC packaging.

http://wix.tramontana.co.hu/

So here I will attempt to detail some of the more important aspects of application packaging, particularly when using WiX to generate MSI packages from a Continuous Integration (CI) build.

These days I typically use Continuous Integration (CI) and Continuous Delivery (CD) for most packaging and deployment activities. Often the CD will be delivered into a Platform As A Service (PAAS) cloud. In most instances I will deliver into a VMWare cloud architecture but that is getting a little off topic.

So back to the original post of CMDB within an SDLC packaging setup.

So as many of you will know component rules but here is an excerpt of component rules from the god father himself http://robmensching.com/blog/posts/2003/10/18/Component-Rules-101

So what Rob states is good information but rarely does he go into detail on how to achieve some of this with his uber geek toolset WiX.

So there is two parts to this puzzle.

1.            Creating component guids

2.            Naming components

So the first part is actually pretty easy but its probably the least documented and as such is probably the one that is done incorrectly more often than not.

So using the following command line in heat you get the following .wxs file generated.

heat dir .\<path to gac files> -gg -dr INSTALLDIR -out .\testSample.wxs -sfrag -sreg

Use XSLT in wix

The important part of this call to note is the -gg option. This tells heat to generate component guids immediately. This option is actually not the best choice, my preference is to use the -ag option for components.

heat dir .\<path to gac files> -ag -dr INSTALLDIR -out .\testSample.wxs -sfrag

The -ag option doesn’t appear to be all that much different but the results are actually significantly different.

Use XSLT in wix

Here you can see the component guid attributes are all tagged with “*” . This is actually very good because the result of such an action tells the linker to deterministically create the component codes at link time.

What is actually happening here is very important to understand because it is based on the entire premise conflict management was built on (go figure, I love your work Rob). So what is actually happening here is that during link time the target path of the files is being resolved and then the component codes are generated based on the resolved target path.

This in effect means that a file deliver to path xxx will always generate component code xxx.

For example.

If you have a file targetted to c:\windows\system32\file_xxxx.dll then the component code will be generated exactly the same for every heat call you make that delivers a file to that same path. The end result is that if you compiled 20 different applications that all delivered the file c:\windows\system32\file_xxxx.dll then all 20 packages would have the same component code for that target path.

For those of you who are familiar with standard guid generation this would typically never ever happen. So you might think this is a strange thing to do but this is actually very very smart. Because the entire premise Windows Installer was built on is that files delivered to the same path should use the same component code to ensure reference counting is put into effect.

For those of you that don’t have a full grasp on Windows Installer Conflict Management the long and the short of this result is that if you do this you will not have issues with applications that share files in common areas. The term “Reference Count” ensure applications that share content do not break other shared applications during uninstallation of your products.

So this is a very very good thing to be doing. Unfortunately hardly anyone actually does it correctly or for that matter is even aware of the issue in the first place. Now this is actually only half of the puzzle. For those of you familiar with Wise Package Studio and Installshield this is a pretty big improvement on how these tools handle conflict management. Interestingly enough its a pretty simple mod to their code to fix as well. (so one wonders why they both fail to deliver such a simple technique into setup capture toolsets).

So the next part is somewhat more difficult and requires you have a grasp on some relatively simple XSLT and a little more heat command line action.

So we now need to call an XSLT to transform the output of heat into something a little more useful. The technique I use here is to turn off unique ID’s using the heat -suid option.

Use XSLT in wix

So the effect of using non-unique names causes the componentId and fileId to use the name of the file that has just been harvested (as shown above). Now in an application which is not too complicated this is actually a simple fix. The however does become an issue when you have the same filename in multiple WiX harvested fragments.

For example if you have;

DirectoryA with FileA.dll within it.

DirectoryB with FileA.dll within it.

and each harvest is called from a separate heat call the above method creates a problem of duplicate ComponentId and FileId attributes within your harvest WiX fragments. Obviously this is bad and causes the compiler to create exceptions. So this fix alone is not enough. This is where the XSLT comes into play allowing you to correct this issue.

So using an XSLT I prefix my heat call with the name of the harvested content in the case shown above the results would be as below.

DirectoryA_FileA.dll
DirectoryB_FileA.dll
So my XSLT code looks like this and I use this as a base XSLT for every heat call I make.

Use XSLT in wix

To call the XSLT you simply add the -t option to your heat call.

heat dir .\<path to gac files> -ag -dr INSTALLDIR -out .\testSample.wxs -sfrag -t <path to xslt file>

The result of adding the XSLT call to your heat call is each non unique filename is prefixed with the name of the heat call used.

Components will get a prefix of

Comp_CoreGAC_

Files will get a prefix of

File_CoreGAC_

This naming convention makes it very simple to identify files / components from each harvest (it looks pretty particularly when looking from referencing tables).

The end result is this.

Use XSLT in wix

So there you have it, this is how to conflict manage WiX installations. This is also a pre-requisite phase to patching which I might follow up sometime later.

ps, please keep commenting and I will keep up the posting.

------------------------------

here's the whole content of 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"> <xsl:output method="xml" indent="yes" /> <xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy> </xsl:template> <xsl:template match="wix:Component">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="Id">
<xsl:text>comp_CoreGAC_</xsl:text>
<xsl:value-of select="@Id"/>
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template> <xsl:template match="wix:ComponentRef">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="Id">
<xsl:text>comp_CoreGAC_</xsl:text>
<xsl:value-of select="@Id"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template> <xsl:template match="wix:Directory">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="Id">
<xsl:text>dir_CoreGAC_</xsl:text>
<xsl:value-of select="@Id"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template> <xsl:template match="wix:File">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="Id">
<xsl:text>file_CoreGAC_</xsl:text>
<xsl:value-of select="@Id"/>
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template> </xsl:stylesheet>