view tests/fakedirstatewritetime.py @ 41454:d1d3094b54f9

patch: handle 0 context lines (diff.unified=0) when parsing patches Previously, if there were no context lines, we would just keep updating the ranges and the hunk, but not actually storing the hunk (just overwriting it each time). Thus a diff like this: $ hg diff --config diff.unified=0 diff --git a/bar b/bar --- a/bar +++ b/bar @@ -1,0 +2,1 @@ 1 +change1 @@ -3,0 +5,1 @@ 3 +change2 would come out of the parser like this (change1 is lost): bar: @@ -3,0 +5,1 @@ 3 +change2 This had some really weird side effects for things like commit --interactive, split, etc. Differential Revision: https://phab.mercurial-scm.org/D5743
author Kyle Lippincott <spectral@google.com>
date Mon, 28 Jan 2019 18:00:14 -0800
parents c6061cadb400
children fdd4d668ceb5
line wrap: on
line source

# extension to emulate invoking 'dirstate.write()' at the time
# specified by '[fakedirstatewritetime] fakenow', only when
# 'dirstate.write()' is invoked via functions below:
#
#   - 'workingctx._poststatusfixup()' (= 'repo.status()')
#   - 'committablectx.markcommitted()'

from __future__ import absolute_import

from mercurial import (
    context,
    dirstate,
    extensions,
    policy,
    registrar,
)
from mercurial.utils import dateutil

configtable = {}
configitem = registrar.configitem(configtable)

configitem(b'fakedirstatewritetime', b'fakenow',
    default=None,
)

parsers = policy.importmod(r'parsers')

def pack_dirstate(fakenow, orig, dmap, copymap, pl, now):
    # execute what original parsers.pack_dirstate should do actually
    # for consistency
    actualnow = int(now)
    for f, e in dmap.items():
        if e[0] == 'n' and e[3] == actualnow:
            e = parsers.dirstatetuple(e[0], e[1], e[2], -1)
            dmap[f] = e

    return orig(dmap, copymap, pl, fakenow)

def fakewrite(ui, func):
    # fake "now" of 'pack_dirstate' only if it is invoked while 'func'

    fakenow = ui.config(b'fakedirstatewritetime', b'fakenow')
    if not fakenow:
        # Execute original one, if fakenow isn't configured. This is
        # useful to prevent subrepos from executing replaced one,
        # because replacing 'parsers.pack_dirstate' is also effective
        # in subrepos.
        return func()

    # parsing 'fakenow' in YYYYmmddHHMM format makes comparison between
    # 'fakenow' value and 'touch -t YYYYmmddHHMM' argument easy
    fakenow = dateutil.parsedate(fakenow, [b'%Y%m%d%H%M'])[0]

    orig_pack_dirstate = parsers.pack_dirstate
    orig_dirstate_getfsnow = dirstate._getfsnow
    wrapper = lambda *args: pack_dirstate(fakenow, orig_pack_dirstate, *args)

    parsers.pack_dirstate = wrapper
    dirstate._getfsnow = lambda *args: fakenow
    try:
        return func()
    finally:
        parsers.pack_dirstate = orig_pack_dirstate
        dirstate._getfsnow = orig_dirstate_getfsnow

def _poststatusfixup(orig, workingctx, status, fixup):
    ui = workingctx.repo().ui
    return fakewrite(ui, lambda : orig(workingctx, status, fixup))

def markcommitted(orig, committablectx, node):
    ui = committablectx.repo().ui
    return fakewrite(ui, lambda : orig(committablectx, node))

def extsetup(ui):
    extensions.wrapfunction(context.workingctx, '_poststatusfixup',
                            _poststatusfixup)
    extensions.wrapfunction(context.committablectx, 'markcommitted',
                            markcommitted)