From fc57f75da75a21eabdcc0cfd08bd27efa312c49c Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Thu, 5 Jan 2012 22:22:08 +0000 Subject: [PATCH] WiX now generates a 64-bit MSI when appropriate --- SConstruct | 3 +- site_scons/wxsgen.py | 262 +++++++++++++++++++++++-------------------- 2 files changed, 142 insertions(+), 123 deletions(-) diff --git a/SConstruct b/SConstruct index 5435a7ef0..c9fb24a0d 100644 --- a/SConstruct +++ b/SConstruct @@ -911,7 +911,8 @@ env.Depends(finish_install, installTargets) install_cantera = Alias('install', finish_install) def build_wxs(target, source, env): - wxsgen.make_wxs(env['stage_dir'], str(target[0])) + wxs = wxsgen.WxsGenerator(env['stage_dir'], env['TARGET_ARCH']=='amd64') + wxs.make_wxs(str(target[0])) if 'msi' in COMMAND_LINE_TARGETS: wxs_target = env.Command(pjoin('build', 'wix', 'cantera.wxs'), diff --git a/site_scons/wxsgen.py b/site_scons/wxsgen.py index a72b4d3ad..8d361fd8b 100644 --- a/site_scons/wxsgen.py +++ b/site_scons/wxsgen.py @@ -2,23 +2,147 @@ import os, sys import uuid import xml.etree.ElementTree as et -CANTERA_UUID = uuid.UUID('1B36CAF0-279D-11E1-8979-001FBC085391') +class WxsGenerator(object): + def __init__(self, stageDir, x64=False): + self.prefix = stageDir + self.x64 = x64 -def Directory(parent, Id, Name): - return et.SubElement(parent, 'Directory', - dict(Id=Id, Name=Name)) + # Use separate UUIDs for 64- and 32-bit components + if self.x64: + self.CANTERA_UUID = uuid.UUID('F707EB9E-3723-11E1-A99F-525400631BAF') + self.pfilesName = 'ProgramFiles64Folder' + else: + self.CANTERA_UUID = uuid.UUID('1B36CAF0-279D-11E1-8979-001FBC085391') + self.pfilesName = 'ProgramFilesFolder' -def FileComponent(parent, componentId, fileId, Name, Source, DiskId='1', KeyPath='yes'): - guid = str(uuid.uuid5(CANTERA_UUID, componentId)) - c = et.SubElement(parent, "Component", - dict(Id=componentId, Guid=guid)) - f = et.SubElement(c, "File", - dict(Id=fileId, - Name=Name, - Source=Source, - DiskId=DiskId, - KeyPath=KeyPath)) - return c,f + def Directory(self, parent, Id, Name): + return et.SubElement(parent, 'Directory', + dict(Id=Id, Name=Name)) + + def FileComponent(self, parent, componentId, fileId, Name, Source, + DiskId='1', KeyPath='yes'): + guid = str(uuid.uuid5(self.CANTERA_UUID, componentId)) + + fields = {'Win64': 'yes'} if self.x64 else {} + c = et.SubElement(parent, "Component", + dict(Id=componentId, Guid=guid, **fields)) + + fields = {'ProcessorArchitecture': 'x64'} if self.x64 else {} + f = et.SubElement(c, "File", + dict(Id=fileId, + Name=Name, + Source=Source, + DiskId=DiskId, + KeyPath=KeyPath, + **fields)) + return c,f + + def addDirectoryContents(self, directory, parent, feature): + """ + directory: name of the directory to add + parent: the Element for the parent directory + feature: the Element for the feature to add the files to + """ + #self.prefix: path to the parent directory + directories = {} + + directories[directory] = self.Directory(parent, directory, directory) + for path, dirs, files in os.walk('/'.join((self.prefix, directory))): + path = path.replace(self.prefix + '/', '', 1).replace('\\', '/') + for d in dirs: + dpath = '/'.join((path, d)) + ID = dpath.replace('/', '_') + directories[dpath] = self.Directory(directories[path], ID, d) + + for f in files: + ID = '_'.join((path, f)).replace('/', '_') + self.FileComponent(directories[path], ID, ID, f, + '/'.join((self.prefix, path, f))) + et.SubElement(feature, 'ComponentRef', dict(Id=ID)) + + return directories + + def make_wxs(self, outFile): + wix = et.Element("Wix", {'xmlns': 'http://schemas.microsoft.com/wix/2006/wi'}) + product = et.SubElement(wix, "Product", + dict(Name='Cantera 2.0', + Id=str(self.CANTERA_UUID), + UpgradeCode='2340BEE1-279D-11E1-A4AA-001FBC085391', + Language='1033', + Codepage='1252', + Version='2.0.0', + Manufacturer='Cantera Developers')) + + fields = {'Platform': 'x64'} if self.x64 else {} + package = et.SubElement(product, "Package", + dict(Id='*', + Keywords='Installer', + Description="Cantera 2.0 Installer", + InstallerVersion='310', + Languages='1033', + Compressed='yes', + SummaryCodepage='1252', **fields)) + + # Required boilerplate refering to nonexistent installation media + media = et.SubElement(product, "Media", + dict(Id='1', + Cabinet='cantera.cab', + EmbedCab='yes', + DiskPrompt='CD-ROM #1')) + diskprompt = et.SubElement(product, "Property", + dict(Id='DiskPrompt', + Value="Cantera Installation Disk")) + + # Directories + targetdir = self.Directory(product, 'TARGETDIR', 'SourceDir') + pfiles = self.Directory(targetdir, self.pfilesName, 'PFiles') + instdir = self.Directory(pfiles, 'INSTALLDIR', 'Cantera') + + # Features + core = et.SubElement(product, 'Feature', + dict(Id='Core', Level='1', + Title='Cantera', + Description='Cantera base files', + Display='expand', + ConfigurableDirectory='INSTALLDIR', + AllowAdvertise='no', + Absent='disallow')) + devel = et.SubElement(product, 'Feature', + dict(Id='DevTools', Level='1000', + Title='Develpment Tools', + Description='Header files and static libraries needed to develop applications that use Cantera.', + Display='expand', + AllowAdvertise='no')) + extras = et.SubElement(product, 'Feature', + dict(Id='Extras', Level='1', + Title='Extras', + Description='Demos, tutorials and templates which show you some ways of using Cantera.', + Display='expand', + AllowAdvertise='no')) + + # Files + includes = self.addDirectoryContents('include', instdir, devel) + binaries = self.addDirectoryContents('bin', instdir, core) + lib_dir = self.addDirectoryContents('lib', instdir, devel) + data_dir = self.addDirectoryContents('data', instdir, core) + demos_dir = self.addDirectoryContents('demos', instdir, extras) + templates_dir = self.addDirectoryContents('templates', instdir, extras) + tutorials_dir = self.addDirectoryContents('tutorials', instdir, extras) + + # Wix UI + et.SubElement(product, 'UIRef', dict(Id='WixUI_FeatureTree')) + et.SubElement(product, 'UIRef', dict(Id='WixUI_ErrorProgressText')) + et.SubElement(product, 'Property', dict(Id='WIXUI_INSTALLDIR', + Value='INSTALLDIR')) + + # License + et.SubElement(product, 'WixVariable', + dict(Id='WixUILicenseRtf', Value='platform/windows/License.rtf')) + + # Format and save as XML + indent(wix) + tree = et.ElementTree(wix) + tree.write(outFile) def indent(elem, level=0): @@ -38,112 +162,6 @@ def indent(elem, level=0): elem.tail = i -def addDirectoryContents(prefix, directory, parent, feature): - """ - prefix: path to the parent directory - directory: name of the directory to add - parent: the Element for the parent directory - feature: the Element for the feature to add the files to - """ - directories = {} - - directories[directory] = Directory(parent, directory, directory) - for path, dirs, files in os.walk('/'.join((prefix, directory))): - path = path.replace(prefix + '/', '', 1).replace('\\', '/') - for d in dirs: - dpath = '/'.join((path, d)) - ID = dpath.replace('/', '_') - directories[dpath] = Directory(directories[path], ID, d) - - for f in files: - ID = '_'.join((path, f)).replace('/', '_') - FileComponent(directories[path], ID, ID, f, - '/'.join((prefix, path, f))) - et.SubElement(feature, 'ComponentRef', dict(Id=ID)) - - return directories - - -def make_wxs(stageDir, outFile): - wix = et.Element("Wix", {'xmlns': 'http://schemas.microsoft.com/wix/2006/wi'}) - product = et.SubElement(wix, "Product", - dict(Name='Cantera 2.0', - Id=str(CANTERA_UUID), - UpgradeCode='2340BEE1-279D-11E1-A4AA-001FBC085391', - Language='1033', - Codepage='1252', - Version='2.0.0', - Manufacturer='Cantera Developers')) - - package = et.SubElement(product, "Package", - dict(Id='*', - Keywords='Installer', - Description="Cantera 2.0 Installer", - InstallerVersion='100', - Languages='1033', - Compressed='yes', - SummaryCodepage='1252')) - - # Required boilerplate refering to nonexistent installation media - media = et.SubElement(product, "Media", - dict(Id='1', - Cabinet='cantera.cab', - EmbedCab='yes', - DiskPrompt='CD-ROM #1')) - diskprompt = et.SubElement(product, "Property", - dict(Id='DiskPrompt', - Value="Cantera Installation Disk")) - - # Directories - targetdir = Directory(product, 'TARGETDIR', 'SourceDir') - pfiles = Directory(targetdir, 'ProgramFilesFolder', 'PFiles') - instdir = Directory(pfiles, 'INSTALLDIR', 'Cantera') - - # Features - core = et.SubElement(product, 'Feature', - dict(Id='Core', Level='1', - Title='Cantera', - Description='Cantera base files', - Display='expand', - ConfigurableDirectory='INSTALLDIR', - AllowAdvertise='no', - Absent='disallow')) - devel = et.SubElement(product, 'Feature', - dict(Id='DevTools', Level='1000', - Title='Develpment Tools', - Description='Header files and static libraries needed to develop applications that use Cantera.', - Display='expand', - AllowAdvertise='no')) - extras = et.SubElement(product, 'Feature', - dict(Id='Extras', Level='1', - Title='Extras', - Description='Demos, tutorials and templates which show you some ways of using Cantera.', - Display='expand', - AllowAdvertise='no')) - - # Files - includes = addDirectoryContents(stageDir, 'include', instdir, devel) - binaries = addDirectoryContents(stageDir, 'bin', instdir, core) - lib_dir = addDirectoryContents(stageDir, 'lib', instdir, devel) - data_dir = addDirectoryContents(stageDir, 'data', instdir, core) - demos_dir = addDirectoryContents(stageDir, 'demos', instdir, extras) - templates_dir = addDirectoryContents(stageDir, 'templates', instdir, extras) - tutorials_dir = addDirectoryContents(stageDir, 'tutorials', instdir, extras) - - # Wix UI - et.SubElement(product, 'UIRef', dict(Id='WixUI_FeatureTree')) - et.SubElement(product, 'UIRef', dict(Id='WixUI_ErrorProgressText')) - et.SubElement(product, 'Property', dict(Id='WIXUI_INSTALLDIR', - Value='INSTALLDIR')) - - # License - et.SubElement(product, 'WixVariable', - dict(Id='WixUILicenseRtf', Value='platform/windows/License.rtf')) - - # Format and save as XML - indent(wix) - tree = et.ElementTree(wix) - tree.write(outFile) def usage(): print "Usage: wxsgen " @@ -153,4 +171,4 @@ if __name__ == '__main__': usage() sys.exit() - make_wxs(sys.argv[1], sys.argv[2]) + WxsGenerator(sys.argv[1]).make_wxs(sys.argv[2])