Mercurial > hg
changeset 41957:131d0b7c3940
wix: autogenerate wxs file for library files
Currently, dist.wxs contains an enumeration of .pyd and .dll
files staged to dist/lib by py2exe.
Having a manual list of files is error prone, as things can
easily get out of sync (as the previous commit demonstrates).
This is especially an issue for TortoiseHG, which ships a
number of custom modules, which may pull in additional dependencies.
Let's prevent this problem from manifesting by dynamically
generating a .wxs file containing the .pyd and .dll files staged
by py2exe.
Differential Revision: https://phab.mercurial-scm.org/D6139
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 14 Mar 2019 18:11:22 -0700 |
parents | 39f65c506899 |
children | 1fe278aa4ad5 |
files | contrib/packaging/hgpackaging/wix.py contrib/packaging/wix/dist.wxs |
diffstat | 2 files changed, 63 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/packaging/hgpackaging/wix.py Thu Mar 14 17:59:51 2019 -0700 +++ b/contrib/packaging/hgpackaging/wix.py Thu Mar 14 18:11:22 2019 -0700 @@ -11,6 +11,8 @@ import pathlib import re import subprocess +import tempfile +import xml.dom.minidom from .downloads import ( download_entry, @@ -128,6 +130,52 @@ return post_build_sign +LIBRARIES_XML = ''' +<?xml version="1.0" encoding="utf-8"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + + <?include {wix_dir}/guids.wxi ?> + <?include {wix_dir}/defines.wxi ?> + + <Fragment> + <DirectoryRef Id="INSTALLDIR" FileSource="$(var.SourceDir)"> + <Directory Id="libdir" Name="lib" FileSource="$(var.SourceDir)/lib"> + <Component Id="libOutput" Guid="$(var.lib.guid)" Win64='$(var.IsX64)'> + </Component> + </Directory> + </DirectoryRef> + </Fragment> +</Wix> +'''.lstrip() + + +def make_libraries_xml(wix_dir: pathlib.Path, dist_dir: pathlib.Path): + """Make XML data for library components WXS.""" + # We can't use ElementTree because it doesn't handle the + # <?include ?> directives. + doc = xml.dom.minidom.parseString( + LIBRARIES_XML.format(wix_dir=str(wix_dir))) + + component = doc.getElementsByTagName('Component')[0] + + f = doc.createElement('File') + f.setAttribute('Name', 'library.zip') + f.setAttribute('KeyPath', 'yes') + component.appendChild(f) + + lib_dir = dist_dir / 'lib' + + for p in sorted(lib_dir.iterdir()): + if not p.name.endswith(('.dll', '.pyd')): + continue + + f = doc.createElement('File') + f.setAttribute('Name', p.name) + component.appendChild(f) + + return doc.toprettyxml() + + def build_installer(source_dir: pathlib.Path, python_exe: pathlib.Path, msi_name='mercurial', version=None, post_build_fn=None): """Build a WiX MSI installer. @@ -181,6 +229,17 @@ wxs_source_dir = source_dir / rel_path run_candle(wix_path, build_dir, wxs, wxs_source_dir, defines=defines) + # candle.exe doesn't like when we have an open handle on the file. + # So use TemporaryDirectory() instead of NamedTemporaryFile(). + with tempfile.TemporaryDirectory() as td: + td = pathlib.Path(td) + + tf = td / 'library.wxs' + with tf.open('w') as fh: + fh.write(make_libraries_xml(wix_dir, dist_dir)) + + run_candle(wix_path, build_dir, tf, dist_dir, defines=defines) + source = wix_dir / 'mercurial.wxs' defines['Version'] = version defines['Comments'] = 'Installs Mercurial version %s' % version @@ -204,7 +263,10 @@ assert source.endswith('.wxs') args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) - args.append(str(build_dir / 'mercurial.wixobj')) + args.extend([ + str(build_dir / 'library.wixobj'), + str(build_dir / 'mercurial.wixobj'), + ]) subprocess.run(args, cwd=str(source_dir), check=True)
--- a/contrib/packaging/wix/dist.wxs Thu Mar 14 17:59:51 2019 -0700 +++ b/contrib/packaging/wix/dist.wxs Thu Mar 14 18:11:22 2019 -0700 @@ -9,35 +9,6 @@ <Component Id="distOutput" Guid="$(var.dist.guid)" Win64='$(var.IsX64)'> <File Name="python27.dll" KeyPath="yes" /> </Component> - <Directory Id="libdir" Name="lib" FileSource="$(var.SourceDir)/lib"> - <Component Id="libOutput" Guid="$(var.lib.guid)" Win64='$(var.IsX64)'> - <File Name="library.zip" KeyPath="yes" /> - <File Name="mercurial.cext.base85.pyd" /> - <File Name="mercurial.cext.bdiff.pyd" /> - <File Name="mercurial.cext.mpatch.pyd" /> - <File Name="mercurial.cext.osutil.pyd" /> - <File Name="mercurial.cext.parsers.pyd" /> - <File Name="mercurial.thirdparty.zope.interface._zope_interface_coptimizations.pyd" /> - <File Name="mercurial.zstd.pyd" /> - <File Name="hgext.fsmonitor.pywatchman.bser.pyd" /> - <File Name="pyexpat.pyd" /> - <File Name="bz2.pyd" /> - <File Name="select.pyd" /> - <File Name="sqlite3.dll" /> - <File Name="tcl85.dll" /> - <File Name="tk85.dll" /> - <File Name="unicodedata.pyd" /> - <File Name="_ctypes.pyd" /> - <File Name="_elementtree.pyd" /> - <File Name="_testcapi.pyd" /> - <File Name="_hashlib.pyd" /> - <File Name="_multiprocessing.pyd" /> - <File Name="_socket.pyd" /> - <File Name="_sqlite3.pyd" /> - <File Name="_ssl.pyd" /> - <File Name="_tkinter.pyd" /> - </Component> - </Directory> </DirectoryRef> </Fragment>