2
votes

We have a number of installations built on WIX (Currently 3.9), which we for instance use harvest to gather the different components and it do flows really well. Everything is automated and we take the nightly build when we need the newest installation.

We need, like many other companies to patch one of many of the files in one or many of the installations, but it's really a pain to make sure we find the right file and also the right component in the different installations.

Is it any best practice regarding this scenario as I can't beleave we're alone with this setup? AND we don't wanna do an upgrade for just a few bug fixes.

Here's a scenario to be solved:

Release 2.0 is finally release, and we have a complete system installation together with a couple of different client installations and an optinal package.

And ofcourse we realised a few gliches in the software and the first, say 3 weeks we made some 15 more or less critical bug fixes in different parts of the system.

Now we feel we need to patch the installations out there, and beleave we need to do a patch project for each installation (MSI) which we then build and it gather the differencies and creates the patch to be able to quickly send out to those already installed the different parts.

Below is a snippet from a patch.wxs I did, but can't find a way to do it automated:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <?include "InitDefinitions.wxi"?>
  <Patch  AllowRemoval="no" Manufacturer="$(var.Company)" 
          DisplayName="$(var.InstallerProductName), patch $(var.Build)" 
          Description="Small Update Patch" Classification="Update">
    <Media Id="5000" Cabinet="patch.cab" EmbedCab="yes">
      <PatchBaseline Id="RTM"/>
    </Media>

    <PatchFamilyRef Id="SP-$(var.Build)-Patch"/>
  </Patch>

  <Fragment>
    <PatchFamily Id="SP-$(var.Build)-Patch" 
                 Version="$(var.Major).$(var.Minor).$(var.Build).$(var.Revision)" 
                 Supersede="yes">
      <PropertyRef Id="ProductVersion" />
      <!--  
            As I understand it's here I define the changes, 
            but I like this section to be automatic populated during build, 
            or something
      -->
    </PatchFamily>
  </Fragment>
</Wix>

Are there ways to solve this?

Thanks in advance!

2

2 Answers

5
votes

I blogged about this in a post titled Automated Patch Building with WiX and Visual Studio.

Here are the basic steps:

  1. Create the initial patch file. You did this already with patch.wxs.
  2. Perform admin installations of your released and update msis. Your can copy the released .msi from a server location. I assume you are building your update .msi with some type of automated build.
  3. Generate the differences between the msis using Torch.exe.
  4. Building the patch. Compile it using Candle.exe, link it using Light.exe, and create the final patch using Pyro.exe.

A simple example on how to manually run these steps can be found here at FireGiant.

1
votes

Switch focus from <Patch> to <PatchCreation>, based on this page I got to: http://wixtoolset.org/documentation/manual/v3/patching/patch_building.html

Not sure exactly why there are two ways to make patches in the WIX framework, but never the less I'm going with the PatchCreation now!

Basically, I've changed the content in the Patch.wxs to this instead:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <?include "InitDefinitions.wxi"?>
  <PatchCreation
      Id="{BAF94FD0-924C-4ED6-8BBF-2F6ACF8B3B3D}"
      CleanWorkingFolder="yes"
      OutputPath="patch.pcp"
      WholeFilesOnly="yes"
        >

    <PatchInformation
        Description="Small Update Patch"
        Comments="Small Update Patch"
        ShortNames="no"
        Languages="1033"
        Compressed="yes"
        Manufacturer="$(var.Company)"/>

    <PatchMetadata
        AllowRemoval="no"
        Description="Small Update Patch"
        ManufacturerName="$(var.Company)"
        MoreInfoURL="http://www.company.com"
        TargetProductName="Sample"
        Classification="Update"
        DisplayName="Sample Patch"/>

    <Family DiskId="5000"
        MediaSrcProp="Sample"
        Name="Sample"
        SequenceStart="5000">
      <UpgradeImage SourceFile="C:\Temp\PatchWork\NewMSI\Install\Product.msi" 
                    Id="SampleUpgrade">
        <TargetImage SourceFile="C:\Temp\PatchWork\ReleasedMSI\Install\Product.msi" 
                      Order="2" Id="SampleTarget" IgnoreMissingFiles="no" />
      </UpgradeImage>
    </Family>

    <PatchSequence PatchFamily="SamplePatchFamily"
        Sequence="2.0.0.1"
        Supersede="yes" />

  </PatchCreation>
</Wix>

And also changed the PostBuild Events in my VS project to this:

FOR /D /R "C:\Temp\PatchWork\ReleasedMSI\Install" %%X IN (*.*) DO RD /S /Q "%%X"
FOR /D /R "C:\Temp\PatchWork\NewMSI\Install" %%X IN (*.*) DO RD /S /Q "%%X"
msiexec.exe /a "C:\Temp\PatchWork\ReleasedMSI\Product.msi" /qb TARGETDIR="C:\Temp\PatchWork\ReleasedMSI\Install"
msiexec.exe /a "$(SolutionDir)Installations\Product.Setup\bin\Release\Product.msi" /qb TARGETDIR="C:\Temp\PatchWork\NewMSI\Install"
candle.exe "$(SolutionDir)Installations\Product.Patch\Patch.wxs"
light.exe  "$(TargetDir)Patch.wixobj" -out "$(TargetDir)Patch.pcp"
msimsp.exe -s "$(TargetDir)Patch.pcp" -p "$(TargetDir)Patch.msp" -l "$(TargetDir)Patch.log"

I got a nice looking patch file with content and it seems to be correct at first glance. Need ofcourse some more works and decisions regarding names, descriptions etc. But the baseline seems to be there now! :)

... Next step is to hook this into the bundle/bootstrapper that we uses for some of the msi-installers. Doesn't feels impossible, but it will probably gives me and others some new headaches to deal with... ;)