contrib/packaging/hgpackaging/wix.py
author Manuel Jacob <me@manueljacob.de>
Thu, 15 Sep 2022 01:48:38 +0200
changeset 49494 c96ed4029fda
parent 48848 17d5e25b8e78
permissions -rw-r--r--
templates: add filter to reverse list The filter supports only lists because for lists, it’s straightforward to implement. Reversing text doesn’t seem very useful and is hard to implement. Reversing the bytes would break multi-bytes encodings. Reversing the code points would break characters consisting of multiple code points. Reversing graphemes is non-trivial without using a library not included in the standard library.

# wix.py - WiX installer functionality
#
# Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

# no-check-code because Python 3 native.

import json
import os
import pathlib
import shutil
import typing

from .pyoxidizer import (
    build_docs_html,
    run_pyoxidizer,
)


def build_installer_pyoxidizer(
    source_dir: pathlib.Path,
    target_triple: str,
    msi_name='mercurial',
    version=None,
    extra_wxs: typing.Optional[typing.Dict[str, str]] = None,
    extra_features: typing.Optional[typing.List[str]] = None,
    signing_info: typing.Optional[typing.Dict[str, str]] = None,
    extra_pyoxidizer_vars=None,
):
    """Build a WiX MSI installer using PyOxidizer."""
    hg_build_dir = source_dir / "build"
    build_dir = hg_build_dir / ("wix-%s" % target_triple)

    build_dir.mkdir(parents=True, exist_ok=True)

    # Need to ensure docs HTML is built because this isn't done as part of
    # `pip install Mercurial`.
    build_docs_html(source_dir)

    build_vars = {}

    if msi_name:
        build_vars["MSI_NAME"] = msi_name

    if version:
        build_vars["VERSION"] = version

    if extra_features:
        build_vars["EXTRA_MSI_FEATURES"] = ";".join(extra_features)

    if signing_info:
        if signing_info["cert_path"]:
            build_vars["SIGNING_PFX_PATH"] = signing_info["cert_path"]
        if signing_info["cert_password"]:
            build_vars["SIGNING_PFX_PASSWORD"] = signing_info["cert_password"]
        if signing_info["subject_name"]:
            build_vars["SIGNING_SUBJECT_NAME"] = signing_info["subject_name"]
        if signing_info["timestamp_url"]:
            build_vars["TIME_STAMP_SERVER_URL"] = signing_info["timestamp_url"]

    if extra_pyoxidizer_vars:
        build_vars.update(json.loads(extra_pyoxidizer_vars))

    if extra_wxs:
        raise Exception(
            "support for extra .wxs files has been temporarily dropped"
        )

    out_dir = run_pyoxidizer(
        source_dir,
        build_dir,
        target_triple,
        build_vars=build_vars,
        target="msi",
    )

    msi_dir = out_dir / "msi"
    msi_files = [f for f in os.listdir(msi_dir) if f.endswith(".msi")]

    if len(msi_files) != 1:
        raise Exception("expected exactly 1 .msi file; got %d" % len(msi_files))

    msi_filename = msi_files[0]

    msi_path = msi_dir / msi_filename
    dist_path = source_dir / "dist" / msi_filename

    dist_path.parent.mkdir(parents=True, exist_ok=True)

    shutil.copyfile(msi_path, dist_path)

    return {
        "msi_path": dist_path,
    }