view mercurial/diffhelper.py @ 47205:603efb3845ba

pyoxidizer: support producing MSI installers Newer versions of PyOxidizer have support for building WiX MSI installers "natively." Essentially, you can script the definition of your WiX installer via Starlark and PyOxidizer can invoke WiX tools to produce the installer. This commit teaches our PyOxidizer config file to produce MSI installers similarly to how `contrib/packaging/packging.py wix` would do it. We had to make a very minor change to `mercurial.wxs` to reflect different paths depending on who builds. This is because when PyOxidizer builds WiX installers, it does so from an isolated directory, not Mercurial's source directory. We simply copy the files into the build environment so they are accessible. After this change, running `pyoxidizer build msi` produces a nearly identical install layout to what the previous method produces. When I applied this series on top of the 5.8 tag, here is the list of differences and explanations: * docs/*.html files are missing from the new installer because the Python build environment doesn't have docutils. * .pyd and .exe files differ, likely because I'm using a different Visual Studio toolchain on my local computer than the official build environment. * Various .dist-info/ directories have different names. This is because older versions of PyOxidizer had buggy behavior and weren't properly normalizing package names in .dist-info/ directories. e.g. we went from `cached-property-1.5.2.dist-info` to `cached_property-1.5.2.dist-info`. * Translations (.mo files) may be missing if gettext isn't in %Path%. This is because the packaging.py code installs gettext and ensures it can be found. * Some *.dist-info/RECORD files vary due to SHA-256 content digest divergence due to build environment differences. (This should be harmless.) * The new install layout ships a python3.dll because newer versions of PyOxidizer ship this file. * The new install layout has a different vcruntime140.dll and also a vcruntime140_1.dll because newer versions of PyOxidizer ship a newer version of the Visual C++ Redistributable Runtime. The new PyOxidizer functionality is not yet integrated with packaging.py. This will come in a subsequent commit. So for now, the new functionality introduced here is unused. Differential Revision: https://phab.mercurial-scm.org/D10683
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 06 May 2021 16:03:43 -0700
parents d4ba4d51f85f
children 6000f5b25c9b
line wrap: on
line source

# diffhelper.py - helper routines for patch
#
# Copyright 2009 Olivia Mackall <olivia@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import absolute_import

from .i18n import _

from . import (
    error,
    pycompat,
)

MISSING_NEWLINE_MARKER = b'\\ No newline at end of file\n'


def addlines(fp, hunk, lena, lenb, a, b):
    """Read lines from fp into the hunk

    The hunk is parsed into two arrays, a and b. a gets the old state of
    the text, b gets the new state. The control char from the hunk is saved
    when inserting into a, but not b (for performance while deleting files.)
    """
    while True:
        todoa = lena - len(a)
        todob = lenb - len(b)
        num = max(todoa, todob)
        if num == 0:
            break
        for i in pycompat.xrange(num):
            s = fp.readline()
            if not s:
                raise error.ParseError(_(b'incomplete hunk'))
            if s == MISSING_NEWLINE_MARKER:
                fixnewline(hunk, a, b)
                continue
            if s == b'\n' or s == b'\r\n':
                # Some patches may be missing the control char
                # on empty lines. Supply a leading space.
                s = b' ' + s
            hunk.append(s)
            if s.startswith(b'+'):
                b.append(s[1:])
            elif s.startswith(b'-'):
                a.append(s)
            else:
                b.append(s[1:])
                a.append(s)


def fixnewline(hunk, a, b):
    """Fix up the last lines of a and b when the patch has no newline at EOF"""
    l = hunk[-1]
    # tolerate CRLF in last line
    if l.endswith(b'\r\n'):
        hline = l[:-2]
    else:
        hline = l[:-1]

    if hline.startswith((b' ', b'+')):
        b[-1] = hline[1:]
    if hline.startswith((b' ', b'-')):
        a[-1] = hline
    hunk[-1] = hline


def testhunk(a, b, bstart):
    """Compare the lines in a with the lines in b

    a is assumed to have a control char at the start of each line, this char
    is ignored in the compare.
    """
    alen = len(a)
    blen = len(b)
    if alen > blen - bstart or bstart < 0:
        return False
    for i in pycompat.xrange(alen):
        if a[i][1:] != b[i + bstart]:
            return False
    return True