comparison contrib/packaging/hgpackaging/wix.py @ 42048:978b03d5f66e

wix: add support for additional wxs files As with my previous change for an --extra-prebuiild-script, I'm assuming this is predominantly useful in an enterprise environment and am only adding this to wix and not also to inno install scripts. Differential Revision: https://phab.mercurial-scm.org/D6179
author Augie Fackler <raf@durin42.com>
date Mon, 01 Apr 2019 16:21:47 -0400
parents 715d3220ac4f
children 1711f5813a63
comparison
equal deleted inserted replaced
42047:715d3220ac4f 42048:978b03d5f66e
10 import os 10 import os
11 import pathlib 11 import pathlib
12 import re 12 import re
13 import subprocess 13 import subprocess
14 import tempfile 14 import tempfile
15 import typing
15 import xml.dom.minidom 16 import xml.dom.minidom
16 17
17 from .downloads import ( 18 from .downloads import (
18 download_entry, 19 download_entry,
19 ) 20 )
176 return doc.toprettyxml() 177 return doc.toprettyxml()
177 178
178 179
179 def build_installer(source_dir: pathlib.Path, python_exe: pathlib.Path, 180 def build_installer(source_dir: pathlib.Path, python_exe: pathlib.Path,
180 msi_name='mercurial', version=None, post_build_fn=None, 181 msi_name='mercurial', version=None, post_build_fn=None,
181 extra_packages_script=None): 182 extra_packages_script: typing.Optional[str]=None,
183 extra_wxs:typing.Optional[typing.Dict[str,str]]=None):
182 """Build a WiX MSI installer. 184 """Build a WiX MSI installer.
183 185
184 ``source_dir`` is the path to the Mercurial source tree to use. 186 ``source_dir`` is the path to the Mercurial source tree to use.
185 ``arch`` is the target architecture. either ``x86`` or ``x64``. 187 ``arch`` is the target architecture. either ``x86`` or ``x64``.
186 ``python_exe`` is the path to the Python executable to use/bundle. 188 ``python_exe`` is the path to the Python executable to use/bundle.
192 dist directories and the resolved Mercurial version. 194 dist directories and the resolved Mercurial version.
193 ``extra_packages_script`` is a command to be run to inject extra packages 195 ``extra_packages_script`` is a command to be run to inject extra packages
194 into the py2exe binary. It should stage packages into the virtualenv and 196 into the py2exe binary. It should stage packages into the virtualenv and
195 print a null byte followed by a newline-separated list of packages that 197 print a null byte followed by a newline-separated list of packages that
196 should be included in the exe. 198 should be included in the exe.
199 ``extra_wxs`` is a dict of {wxs_name: working_dir_for_wxs_build}.
197 """ 200 """
198 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86' 201 arch = 'x64' if r'\x64' in os.environ.get('LIB', '') else 'x86'
199 202
200 hg_build_dir = source_dir / 'build' 203 hg_build_dir = source_dir / 'build'
201 dist_dir = source_dir / 'dist' 204 dist_dir = source_dir / 'dist'
232 235
233 for wxs, rel_path in SUPPORT_WXS: 236 for wxs, rel_path in SUPPORT_WXS:
234 wxs = wix_dir / wxs 237 wxs = wix_dir / wxs
235 wxs_source_dir = source_dir / rel_path 238 wxs_source_dir = source_dir / rel_path
236 run_candle(wix_path, build_dir, wxs, wxs_source_dir, defines=defines) 239 run_candle(wix_path, build_dir, wxs, wxs_source_dir, defines=defines)
240
241 for source, rel_path in sorted((extra_wxs or {}).items()):
242 run_candle(wix_path, build_dir, source, rel_path, defines=defines)
237 243
238 # candle.exe doesn't like when we have an open handle on the file. 244 # candle.exe doesn't like when we have an open handle on the file.
239 # So use TemporaryDirectory() instead of NamedTemporaryFile(). 245 # So use TemporaryDirectory() instead of NamedTemporaryFile().
240 with tempfile.TemporaryDirectory() as td: 246 with tempfile.TemporaryDirectory() as td:
241 td = pathlib.Path(td) 247 td = pathlib.Path(td)
267 273
268 for source, rel_path in SUPPORT_WXS: 274 for source, rel_path in SUPPORT_WXS:
269 assert source.endswith('.wxs') 275 assert source.endswith('.wxs')
270 args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) 276 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
271 277
278 for source, rel_path in sorted((extra_wxs or {}).items()):
279 assert source.endswith('.wxs')
280 source = os.path.basename(source)
281 args.append(str(build_dir / ('%s.wixobj' % source[:-4])))
282
272 args.extend([ 283 args.extend([
273 str(build_dir / 'library.wixobj'), 284 str(build_dir / 'library.wixobj'),
274 str(build_dir / 'mercurial.wixobj'), 285 str(build_dir / 'mercurial.wixobj'),
275 ]) 286 ])
276 287
284 295
285 296
286 def build_signed_installer(source_dir: pathlib.Path, python_exe: pathlib.Path, 297 def build_signed_installer(source_dir: pathlib.Path, python_exe: pathlib.Path,
287 name: str, version=None, subject_name=None, 298 name: str, version=None, subject_name=None,
288 cert_path=None, cert_password=None, 299 cert_path=None, cert_password=None,
289 timestamp_url=None, extra_packages_script=None): 300 timestamp_url=None, extra_packages_script=None,
301 extra_wxs=None):
290 """Build an installer with signed executables.""" 302 """Build an installer with signed executables."""
291 303
292 post_build_fn = make_post_build_signing_fn( 304 post_build_fn = make_post_build_signing_fn(
293 name, 305 name,
294 subject_name=subject_name, 306 subject_name=subject_name,
297 timestamp_url=timestamp_url) 309 timestamp_url=timestamp_url)
298 310
299 info = build_installer(source_dir, python_exe=python_exe, 311 info = build_installer(source_dir, python_exe=python_exe,
300 msi_name=name.lower(), version=version, 312 msi_name=name.lower(), version=version,
301 post_build_fn=post_build_fn, 313 post_build_fn=post_build_fn,
302 extra_packages_script=extra_packages_script) 314 extra_packages_script=extra_packages_script,
315 extra_wxs=extra_wxs)
303 316
304 description = '%s %s' % (name, version) 317 description = '%s %s' % (name, version)
305 318
306 sign_with_signtool(info['msi_path'], description, 319 sign_with_signtool(info['msi_path'], description,
307 subject_name=subject_name, cert_path=cert_path, 320 subject_name=subject_name, cert_path=cert_path,