hgext/absorb.py
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Mon, 08 Oct 2018 10:30:59 +0900
changeset 40205 89ba51c3e4f1
parent 40190 31dfa7dac4c9
child 40210 8f192f2c4a1e
permissions -rw-r--r--
tests: use NO_CHECK_EOF for fragments having intentional error Some test scripts are excluded in test-check-module-imports.t, because import-checker.py reports that code fragments embedded in these test scripts have syntax error. But these syntax error is intentional. This patch uses NO_CHECK_EOF instead of EOF as heredoc limit mark for such fragments, in order to make import-checker.py ignore them. NO_CHECK_EOF limit mark tells import-checker.py that this code fragment should be ignored, via testparseutil.py.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     1
# absorb.py
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     2
#
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     3
# Copyright 2016 Facebook, Inc.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     4
#
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     7
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     8
"""apply working directory changes to changesets (EXPERIMENTAL)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
     9
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    10
The absorb extension provides a command to use annotate information to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    11
amend modified chunks into the corresponding non-public changesets.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    12
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    13
::
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    14
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    15
    [absorb]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    16
    # only check 50 recent non-public changesets at most
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    17
    max-stack-size = 50
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    18
    # whether to add noise to new commits to avoid obsolescence cycle
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    19
    add-noise = 1
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    20
    # make `amend --correlated` a shortcut to the main command
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    21
    amend-flag = correlated
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    22
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    23
    [color]
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
    24
    absorb.description = yellow
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    25
    absorb.node = blue bold
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    26
    absorb.path = bold
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    27
"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    28
38922
ec0697f4f9c9 absorb: note some TODOs from the code review
Augie Fackler <augie@google.com>
parents: 38921
diff changeset
    29
# TODO:
ec0697f4f9c9 absorb: note some TODOs from the code review
Augie Fackler <augie@google.com>
parents: 38921
diff changeset
    30
#  * Rename config items to [commands] namespace
ec0697f4f9c9 absorb: note some TODOs from the code review
Augie Fackler <augie@google.com>
parents: 38921
diff changeset
    31
#  * Converge getdraftstack() with other code in core
ec0697f4f9c9 absorb: note some TODOs from the code review
Augie Fackler <augie@google.com>
parents: 38921
diff changeset
    32
#  * move many attributes on fixupstate to be private
ec0697f4f9c9 absorb: note some TODOs from the code review
Augie Fackler <augie@google.com>
parents: 38921
diff changeset
    33
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    34
from __future__ import absolute_import
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    35
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    36
import collections
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    37
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    38
from mercurial.i18n import _
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    39
from mercurial import (
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    40
    cmdutil,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    41
    commands,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    42
    context,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    43
    crecord,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    44
    error,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    45
    linelog,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    46
    mdiff,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    47
    node,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    48
    obsolete,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    49
    patch,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    50
    phases,
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
    51
    pycompat,
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    52
    registrar,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    53
    repair,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    54
    scmutil,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    55
    util,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    56
)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    57
from mercurial.utils import (
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    58
    stringutil,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    59
)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    60
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    61
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    62
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    63
# be specifying the version(s) of Mercurial they are tested with, or
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    64
# leave the attribute unspecified.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    65
testedwith = 'ships-with-hg-core'
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    66
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    67
cmdtable = {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    68
command = registrar.command(cmdtable)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    69
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    70
configtable = {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    71
configitem = registrar.configitem(configtable)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    72
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    73
configitem('absorb', 'add-noise', default=True)
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    74
configitem('absorb', 'amend-flag', default=None)
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
    75
configitem('absorb', 'max-stack-size', default=50)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    76
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    77
colortable = {
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
    78
    'absorb.description': 'yellow',
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    79
    'absorb.node': 'blue bold',
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    80
    'absorb.path': 'bold',
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    81
}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    82
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    83
defaultdict = collections.defaultdict
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    84
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    85
class nullui(object):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    86
    """blank ui object doing nothing"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    87
    debugflag = False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    88
    verbose = False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    89
    quiet = True
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    90
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    91
    def __getitem__(name):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    92
        def nullfunc(*args, **kwds):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    93
            return
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    94
        return nullfunc
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    95
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    96
class emptyfilecontext(object):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    97
    """minimal filecontext representing an empty file"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    98
    def data(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
    99
        return ''
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   100
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   101
    def node(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   102
        return node.nullid
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   103
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   104
def uniq(lst):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   105
    """list -> list. remove duplicated items without changing the order"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   106
    seen = set()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   107
    result = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   108
    for x in lst:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   109
        if x not in seen:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   110
            seen.add(x)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   111
            result.append(x)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   112
    return result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   113
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   114
def getdraftstack(headctx, limit=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   115
    """(ctx, int?) -> [ctx]. get a linear stack of non-public changesets.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   116
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   117
    changesets are sorted in topo order, oldest first.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   118
    return at most limit items, if limit is a positive number.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   119
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   120
    merges are considered as non-draft as well. i.e. every commit
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   121
    returned has and only has 1 parent.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   122
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   123
    ctx = headctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   124
    result = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   125
    while ctx.phase() != phases.public:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   126
        if limit and len(result) >= limit:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   127
            break
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   128
        parents = ctx.parents()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   129
        if len(parents) != 1:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   130
            break
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   131
        result.append(ctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   132
        ctx = parents[0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   133
    result.reverse()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   134
    return result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   135
38918
2ac40e86f604 absorb: avoid mutable default arg
Augie Fackler <augie@google.com>
parents: 38917
diff changeset
   136
def getfilestack(stack, path, seenfctxs=None):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   137
    """([ctx], str, set) -> [fctx], {ctx: fctx}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   138
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   139
    stack is a list of contexts, from old to new. usually they are what
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   140
    "getdraftstack" returns.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   141
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   142
    follows renames, but not copies.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   143
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   144
    seenfctxs is a set of filecontexts that will be considered "immutable".
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   145
    they are usually what this function returned in earlier calls, useful
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   146
    to avoid issues that a file was "moved" to multiple places and was then
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   147
    modified differently, like: "a" was copied to "b", "a" was also copied to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   148
    "c" and then "a" was deleted, then both "b" and "c" were "moved" from "a"
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   149
    and we enforce only one of them to be able to affect "a"'s content.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   150
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   151
    return an empty list and an empty dict, if the specified path does not
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   152
    exist in stack[-1] (the top of the stack).
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   153
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   154
    otherwise, return a list of de-duplicated filecontexts, and the map to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   155
    convert ctx in the stack to fctx, for possible mutable fctxs. the first item
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   156
    of the list would be outside the stack and should be considered immutable.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   157
    the remaining items are within the stack.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   158
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   159
    for example, given the following changelog and corresponding filelog
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   160
    revisions:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   161
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   162
      changelog: 3----4----5----6----7
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   163
      filelog:   x    0----1----1----2 (x: no such file yet)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   164
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   165
    - if stack = [5, 6, 7], returns ([0, 1, 2], {5: 1, 6: 1, 7: 2})
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   166
    - if stack = [3, 4, 5], returns ([e, 0, 1], {4: 0, 5: 1}), where "e" is a
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   167
      dummy empty filecontext.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   168
    - if stack = [2], returns ([], {})
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   169
    - if stack = [7], returns ([1, 2], {7: 2})
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   170
    - if stack = [6, 7], returns ([1, 2], {6: 1, 7: 2}), although {6: 1} can be
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   171
      removed, since 1 is immutable.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   172
    """
38918
2ac40e86f604 absorb: avoid mutable default arg
Augie Fackler <augie@google.com>
parents: 38917
diff changeset
   173
    if seenfctxs is None:
2ac40e86f604 absorb: avoid mutable default arg
Augie Fackler <augie@google.com>
parents: 38917
diff changeset
   174
        seenfctxs = set()
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   175
    assert stack
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   176
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   177
    if path not in stack[-1]:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   178
        return [], {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   179
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   180
    fctxs = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   181
    fctxmap = {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   182
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   183
    pctx = stack[0].p1() # the public (immutable) ctx we stop at
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   184
    for ctx in reversed(stack):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   185
        if path not in ctx: # the file is added in the next commit
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   186
            pctx = ctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   187
            break
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   188
        fctx = ctx[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   189
        fctxs.append(fctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   190
        if fctx in seenfctxs: # treat fctx as the immutable one
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   191
            pctx = None # do not add another immutable fctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   192
            break
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   193
        fctxmap[ctx] = fctx # only for mutable fctxs
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   194
        renamed = fctx.renamed()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   195
        if renamed:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   196
            path = renamed[0] # follow rename
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   197
            if path in ctx: # but do not follow copy
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   198
                pctx = ctx.p1()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   199
                break
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   200
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   201
    if pctx is not None: # need an extra immutable fctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   202
        if path in pctx:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   203
            fctxs.append(pctx[path])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   204
        else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   205
            fctxs.append(emptyfilecontext())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   206
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   207
    fctxs.reverse()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   208
    # note: we rely on a property of hg: filerev is not reused for linear
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   209
    # history. i.e. it's impossible to have:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   210
    #   changelog:  4----5----6 (linear, no merges)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   211
    #   filelog:    1----2----1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   212
    #                         ^ reuse filerev (impossible)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   213
    # because parents are part of the hash. if that's not true, we need to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   214
    # remove uniq and find a different way to identify fctxs.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   215
    return uniq(fctxs), fctxmap
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   216
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   217
class overlaystore(patch.filestore):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   218
    """read-only, hybrid store based on a dict and ctx.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   219
    memworkingcopy: {path: content}, overrides file contents.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   220
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   221
    def __init__(self, basectx, memworkingcopy):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   222
        self.basectx = basectx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   223
        self.memworkingcopy = memworkingcopy
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   224
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   225
    def getfile(self, path):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   226
        """comply with mercurial.patch.filestore.getfile"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   227
        if path not in self.basectx:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   228
            return None, None, None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   229
        fctx = self.basectx[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   230
        if path in self.memworkingcopy:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   231
            content = self.memworkingcopy[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   232
        else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   233
            content = fctx.data()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   234
        mode = (fctx.islink(), fctx.isexec())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   235
        renamed = fctx.renamed() # False or (path, node)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   236
        return content, mode, (renamed and renamed[0])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   237
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   238
def overlaycontext(memworkingcopy, ctx, parents=None, extra=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   239
    """({path: content}, ctx, (p1node, p2node)?, {}?) -> memctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   240
    memworkingcopy overrides file contents.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   241
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   242
    # parents must contain 2 items: (node1, node2)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   243
    if parents is None:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   244
        parents = ctx.repo().changelog.parents(ctx.node())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   245
    if extra is None:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   246
        extra = ctx.extra()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   247
    date = ctx.date()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   248
    desc = ctx.description()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   249
    user = ctx.user()
38987
9204445ad54c absorb: port partway to Python 3
Augie Fackler <augie@google.com>
parents: 38961
diff changeset
   250
    files = set(ctx.files()).union(memworkingcopy)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   251
    store = overlaystore(ctx, memworkingcopy)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   252
    return context.memctx(
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   253
        repo=ctx.repo(), parents=parents, text=desc,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   254
        files=files, filectxfn=store, user=user, date=date,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   255
        branch=None, extra=extra)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   256
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   257
class filefixupstate(object):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   258
    """state needed to apply fixups to a single file
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   259
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   260
    internally, it keeps file contents of several revisions and a linelog.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   261
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   262
    the linelog uses odd revision numbers for original contents (fctxs passed
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   263
    to __init__), and even revision numbers for fixups, like:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   264
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   265
        linelog rev 1: self.fctxs[0] (from an immutable "public" changeset)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   266
        linelog rev 2: fixups made to self.fctxs[0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   267
        linelog rev 3: self.fctxs[1] (a child of fctxs[0])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   268
        linelog rev 4: fixups made to self.fctxs[1]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   269
        ...
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   270
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   271
    a typical use is like:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   272
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   273
        1. call diffwith, to calculate self.fixups
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   274
        2. (optionally), present self.fixups to the user, or change it
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   275
        3. call apply, to apply changes
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   276
        4. read results from "finalcontents", or call getfinalcontent
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   277
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   278
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   279
    def __init__(self, fctxs, path, ui=None, opts=None):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   280
        """([fctx], ui or None) -> None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   281
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   282
        fctxs should be linear, and sorted by topo order - oldest first.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   283
        fctxs[0] will be considered as "immutable" and will not be changed.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   284
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   285
        self.fctxs = fctxs
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   286
        self.path = path
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   287
        self.ui = ui or nullui()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   288
        self.opts = opts or {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   289
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   290
        # following fields are built from fctxs. they exist for perf reason
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   291
        self.contents = [f.data() for f in fctxs]
38987
9204445ad54c absorb: port partway to Python 3
Augie Fackler <augie@google.com>
parents: 38961
diff changeset
   292
        self.contentlines = pycompat.maplist(mdiff.splitnewlines, self.contents)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   293
        self.linelog = self._buildlinelog()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   294
        if self.ui.debugflag:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   295
            assert self._checkoutlinelog() == self.contents
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   296
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   297
        # following fields will be filled later
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   298
        self.chunkstats = [0, 0] # [adopted, total : int]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   299
        self.targetlines = [] # [str]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   300
        self.fixups = [] # [(linelog rev, a1, a2, b1, b2)]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   301
        self.finalcontents = [] # [str]
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   302
        self.ctxaffected = set()
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   303
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   304
    def diffwith(self, targetfctx, fm=None):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   305
        """calculate fixups needed by examining the differences between
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   306
        self.fctxs[-1] and targetfctx, chunk by chunk.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   307
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   308
        targetfctx is the target state we move towards. we may or may not be
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   309
        able to get there because not all modified chunks can be amended into
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   310
        a non-public fctx unambiguously.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   311
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   312
        call this only once, before apply().
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   313
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   314
        update self.fixups, self.chunkstats, and self.targetlines.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   315
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   316
        a = self.contents[-1]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   317
        alines = self.contentlines[-1]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   318
        b = targetfctx.data()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   319
        blines = mdiff.splitnewlines(b)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   320
        self.targetlines = blines
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   321
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   322
        self.linelog.annotate(self.linelog.maxrev)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   323
        annotated = self.linelog.annotateresult # [(linelog rev, linenum)]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   324
        assert len(annotated) == len(alines)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   325
        # add a dummy end line to make insertion at the end easier
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   326
        if annotated:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   327
            dummyendline = (annotated[-1][0], annotated[-1][1] + 1)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   328
            annotated.append(dummyendline)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   329
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   330
        # analyse diff blocks
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   331
        for chunk in self._alldiffchunks(a, b, alines, blines):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   332
            newfixups = self._analysediffchunk(chunk, annotated)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   333
            self.chunkstats[0] += bool(newfixups) # 1 or 0
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   334
            self.chunkstats[1] += 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   335
            self.fixups += newfixups
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   336
            if fm is not None:
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   337
                self._showchanges(fm, alines, blines, chunk, newfixups)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   338
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   339
    def apply(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   340
        """apply self.fixups. update self.linelog, self.finalcontents.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   341
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   342
        call this only once, before getfinalcontent(), after diffwith().
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   343
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   344
        # the following is unnecessary, as it's done by "diffwith":
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   345
        #   self.linelog.annotate(self.linelog.maxrev)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   346
        for rev, a1, a2, b1, b2 in reversed(self.fixups):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   347
            blines = self.targetlines[b1:b2]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   348
            if self.ui.debugflag:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   349
                idx = (max(rev - 1, 0)) // 2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   350
                self.ui.write(_('%s: chunk %d:%d -> %d lines\n')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   351
                              % (node.short(self.fctxs[idx].node()),
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   352
                                 a1, a2, len(blines)))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   353
            self.linelog.replacelines(rev, a1, a2, b1, b2)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   354
        if self.opts.get('edit_lines', False):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   355
            self.finalcontents = self._checkoutlinelogwithedits()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   356
        else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   357
            self.finalcontents = self._checkoutlinelog()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   358
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   359
    def getfinalcontent(self, fctx):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   360
        """(fctx) -> str. get modified file content for a given filecontext"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   361
        idx = self.fctxs.index(fctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   362
        return self.finalcontents[idx]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   363
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   364
    def _analysediffchunk(self, chunk, annotated):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   365
        """analyse a different chunk and return new fixups found
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   366
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   367
        return [] if no lines from the chunk can be safely applied.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   368
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   369
        the chunk (or lines) cannot be safely applied, if, for example:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   370
          - the modified (deleted) lines belong to a public changeset
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   371
            (self.fctxs[0])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   372
          - the chunk is a pure insertion and the adjacent lines (at most 2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   373
            lines) belong to different non-public changesets, or do not belong
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   374
            to any non-public changesets.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   375
          - the chunk is modifying lines from different changesets.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   376
            in this case, if the number of lines deleted equals to the number
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   377
            of lines added, assume it's a simple 1:1 map (could be wrong).
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   378
            otherwise, give up.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   379
          - the chunk is modifying lines from a single non-public changeset,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   380
            but other revisions touch the area as well. i.e. the lines are
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   381
            not continuous as seen from the linelog.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   382
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   383
        a1, a2, b1, b2 = chunk
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   384
        # find involved indexes from annotate result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   385
        involved = annotated[a1:a2]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   386
        if not involved and annotated: # a1 == a2 and a is not empty
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   387
            # pure insertion, check nearby lines. ignore lines belong
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   388
            # to the public (first) changeset (i.e. annotated[i][0] == 1)
38919
dc4750b2a04e absorb: use set literal to avoid intermediate list
Augie Fackler <augie@google.com>
parents: 38918
diff changeset
   389
            nearbylinenums = {a2, max(0, a1 - 1)}
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   390
            involved = [annotated[i]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   391
                        for i in nearbylinenums if annotated[i][0] != 1]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   392
        involvedrevs = list(set(r for r, l in involved))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   393
        newfixups = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   394
        if len(involvedrevs) == 1 and self._iscontinuous(a1, a2 - 1, True):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   395
            # chunk belongs to a single revision
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   396
            rev = involvedrevs[0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   397
            if rev > 1:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   398
                fixuprev = rev + 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   399
                newfixups.append((fixuprev, a1, a2, b1, b2))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   400
        elif a2 - a1 == b2 - b1 or b1 == b2:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   401
            # 1:1 line mapping, or chunk was deleted
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
   402
            for i in pycompat.xrange(a1, a2):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   403
                rev, linenum = annotated[i]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   404
                if rev > 1:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   405
                    if b1 == b2: # deletion, simply remove that single line
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   406
                        nb1 = nb2 = 0
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   407
                    else: # 1:1 line mapping, change the corresponding rev
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   408
                        nb1 = b1 + i - a1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   409
                        nb2 = nb1 + 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   410
                    fixuprev = rev + 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   411
                    newfixups.append((fixuprev, i, i + 1, nb1, nb2))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   412
        return self._optimizefixups(newfixups)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   413
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   414
    @staticmethod
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   415
    def _alldiffchunks(a, b, alines, blines):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   416
        """like mdiff.allblocks, but only care about differences"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   417
        blocks = mdiff.allblocks(a, b, lines1=alines, lines2=blines)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   418
        for chunk, btype in blocks:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   419
            if btype != '!':
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   420
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   421
            yield chunk
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   422
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   423
    def _buildlinelog(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   424
        """calculate the initial linelog based on self.content{,line}s.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   425
        this is similar to running a partial "annotate".
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   426
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   427
        llog = linelog.linelog()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   428
        a, alines = '', []
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
   429
        for i in pycompat.xrange(len(self.contents)):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   430
            b, blines = self.contents[i], self.contentlines[i]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   431
            llrev = i * 2 + 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   432
            chunks = self._alldiffchunks(a, b, alines, blines)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   433
            for a1, a2, b1, b2 in reversed(list(chunks)):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   434
                llog.replacelines(llrev, a1, a2, b1, b2)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   435
            a, alines = b, blines
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   436
        return llog
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   437
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   438
    def _checkoutlinelog(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   439
        """() -> [str]. check out file contents from linelog"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   440
        contents = []
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
   441
        for i in pycompat.xrange(len(self.contents)):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   442
            rev = (i + 1) * 2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   443
            self.linelog.annotate(rev)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   444
            content = ''.join(map(self._getline, self.linelog.annotateresult))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   445
            contents.append(content)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   446
        return contents
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   447
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   448
    def _checkoutlinelogwithedits(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   449
        """() -> [str]. prompt all lines for edit"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   450
        alllines = self.linelog.getalllines()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   451
        # header
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   452
        editortext = (_('HG: editing %s\nHG: "y" means the line to the right '
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   453
                        'exists in the changeset to the top\nHG:\n')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   454
                      % self.fctxs[-1].path())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   455
        # [(idx, fctx)]. hide the dummy emptyfilecontext
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   456
        visiblefctxs = [(i, f)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   457
                        for i, f in enumerate(self.fctxs)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   458
                        if not isinstance(f, emptyfilecontext)]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   459
        for i, (j, f) in enumerate(visiblefctxs):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   460
            editortext += (_('HG: %s/%s %s %s\n') %
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   461
                           ('|' * i, '-' * (len(visiblefctxs) - i + 1),
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   462
                            node.short(f.node()),
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   463
                            f.description().split('\n',1)[0]))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   464
        editortext += _('HG: %s\n') % ('|' * len(visiblefctxs))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   465
        # figure out the lifetime of a line, this is relatively inefficient,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   466
        # but probably fine
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   467
        lineset = defaultdict(lambda: set()) # {(llrev, linenum): {llrev}}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   468
        for i, f in visiblefctxs:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   469
            self.linelog.annotate((i + 1) * 2)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   470
            for l in self.linelog.annotateresult:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   471
                lineset[l].add(i)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   472
        # append lines
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   473
        for l in alllines:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   474
            editortext += ('    %s : %s' %
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   475
                           (''.join([('y' if i in lineset[l] else ' ')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   476
                                     for i, _f in visiblefctxs]),
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   477
                            self._getline(l)))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   478
        # run editor
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   479
        editedtext = self.ui.edit(editortext, '', action='absorb')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   480
        if not editedtext:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   481
            raise error.Abort(_('empty editor text'))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   482
        # parse edited result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   483
        contents = ['' for i in self.fctxs]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   484
        leftpadpos = 4
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   485
        colonpos = leftpadpos + len(visiblefctxs) + 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   486
        for l in mdiff.splitnewlines(editedtext):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   487
            if l.startswith('HG:'):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   488
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   489
            if l[colonpos - 1:colonpos + 2] != ' : ':
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   490
                raise error.Abort(_('malformed line: %s') % l)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   491
            linecontent = l[colonpos + 2:]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   492
            for i, ch in enumerate(l[leftpadpos:colonpos - 1]):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   493
                if ch == 'y':
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   494
                    contents[visiblefctxs[i][0]] += linecontent
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   495
        # chunkstats is hard to calculate if anything changes, therefore
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   496
        # set them to just a simple value (1, 1).
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   497
        if editedtext != editortext:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   498
            self.chunkstats = [1, 1]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   499
        return contents
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   500
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   501
    def _getline(self, lineinfo):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   502
        """((rev, linenum)) -> str. convert rev+line number to line content"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   503
        rev, linenum = lineinfo
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   504
        if rev & 1: # odd: original line taken from fctxs
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   505
            return self.contentlines[rev // 2][linenum]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   506
        else: # even: fixup line from targetfctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   507
            return self.targetlines[linenum]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   508
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   509
    def _iscontinuous(self, a1, a2, closedinterval=False):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   510
        """(a1, a2 : int) -> bool
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   511
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   512
        check if these lines are continuous. i.e. no other insertions or
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   513
        deletions (from other revisions) among these lines.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   514
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   515
        closedinterval decides whether a2 should be included or not. i.e. is
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   516
        it [a1, a2), or [a1, a2] ?
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   517
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   518
        if a1 >= a2:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   519
            return True
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   520
        llog = self.linelog
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   521
        offset1 = llog.getoffset(a1)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   522
        offset2 = llog.getoffset(a2) + int(closedinterval)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   523
        linesinbetween = llog.getalllines(offset1, offset2)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   524
        return len(linesinbetween) == a2 - a1 + int(closedinterval)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   525
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   526
    def _optimizefixups(self, fixups):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   527
        """[(rev, a1, a2, b1, b2)] -> [(rev, a1, a2, b1, b2)].
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   528
        merge adjacent fixups to make them less fragmented.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   529
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   530
        result = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   531
        pcurrentchunk = [[-1, -1, -1, -1, -1]]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   532
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   533
        def pushchunk():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   534
            if pcurrentchunk[0][0] != -1:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   535
                result.append(tuple(pcurrentchunk[0]))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   536
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   537
        for i, chunk in enumerate(fixups):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   538
            rev, a1, a2, b1, b2 = chunk
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   539
            lastrev = pcurrentchunk[0][0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   540
            lasta2 = pcurrentchunk[0][2]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   541
            lastb2 = pcurrentchunk[0][4]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   542
            if (a1 == lasta2 and b1 == lastb2 and rev == lastrev and
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   543
                    self._iscontinuous(max(a1 - 1, 0), a1)):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   544
                # merge into currentchunk
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   545
                pcurrentchunk[0][2] = a2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   546
                pcurrentchunk[0][4] = b2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   547
            else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   548
                pushchunk()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   549
                pcurrentchunk[0] = list(chunk)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   550
        pushchunk()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   551
        return result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   552
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   553
    def _showchanges(self, fm, alines, blines, chunk, fixups):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   554
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   555
        def trim(line):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   556
            if line.endswith('\n'):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   557
                line = line[:-1]
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   558
            return line
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   559
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   560
        # this is not optimized for perf but _showchanges only gets executed
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   561
        # with an extra command-line flag.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   562
        a1, a2, b1, b2 = chunk
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   563
        aidxs, bidxs = [0] * (a2 - a1), [0] * (b2 - b1)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   564
        for idx, fa1, fa2, fb1, fb2 in fixups:
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
   565
            for i in pycompat.xrange(fa1, fa2):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   566
                aidxs[i - a1] = (max(idx, 1) - 1) // 2
38920
a5c8c5476339 absorb: use pycompat to get xrange
Augie Fackler <augie@google.com>
parents: 38919
diff changeset
   567
            for i in pycompat.xrange(fb1, fb2):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   568
                bidxs[i - b1] = (max(idx, 1) - 1) // 2
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   569
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   570
        fm.startitem()
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   571
        fm.write('hunk', '        %s\n',
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   572
                 '@@ -%d,%d +%d,%d @@'
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   573
                 % (a1, a2 - a1, b1, b2 - b1), label='diff.hunk')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   574
        fm.data(path=self.path, linetype='hunk')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   575
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   576
        def writeline(idx, diffchar, line, linetype, linelabel):
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   577
            fm.startitem()
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   578
            node = ''
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   579
            if idx:
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   580
                ctx = self.fctxs[idx]
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   581
                fm.context(fctx=ctx)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   582
                node = ctx.hex()
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   583
                self.ctxaffected.add(ctx.changectx())
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   584
            fm.write('node', '%-7.7s ', node, label='absorb.node')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   585
            fm.write('diffchar ' + linetype, '%s%s\n', diffchar, line,
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   586
                     label=linelabel)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   587
            fm.data(path=self.path, linetype=linetype)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   588
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   589
        for i in pycompat.xrange(a1, a2):
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   590
            writeline(aidxs[i - a1], '-', trim(alines[i]), 'deleted',
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   591
                      'diff.deleted')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   592
        for i in pycompat.xrange(b1, b2):
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   593
            writeline(bidxs[i - b1], '+', trim(blines[i]), 'inserted',
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   594
                      'diff.inserted')
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   595
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   596
class fixupstate(object):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   597
    """state needed to run absorb
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   598
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   599
    internally, it keeps paths and filefixupstates.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   600
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   601
    a typical use is like filefixupstates:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   602
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   603
        1. call diffwith, to calculate fixups
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   604
        2. (optionally), present fixups to the user, or edit fixups
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   605
        3. call apply, to apply changes to memory
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   606
        4. call commit, to commit changes to hg database
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   607
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   608
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   609
    def __init__(self, stack, ui=None, opts=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   610
        """([ctx], ui or None) -> None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   611
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   612
        stack: should be linear, and sorted by topo order - oldest first.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   613
        all commits in stack are considered mutable.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   614
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   615
        assert stack
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   616
        self.ui = ui or nullui()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   617
        self.opts = opts or {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   618
        self.stack = stack
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   619
        self.repo = stack[-1].repo().unfiltered()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   620
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   621
        # following fields will be filled later
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   622
        self.paths = [] # [str]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   623
        self.status = None # ctx.status output
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   624
        self.fctxmap = {} # {path: {ctx: fctx}}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   625
        self.fixupmap = {} # {path: filefixupstate}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   626
        self.replacemap = {} # {oldnode: newnode or None}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   627
        self.finalnode = None # head after all fixups
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   628
        self.ctxaffected = set() # ctx that will be absorbed into
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   629
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   630
    def diffwith(self, targetctx, match=None, fm=None):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   631
        """diff and prepare fixups. update self.fixupmap, self.paths"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   632
        # only care about modified files
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   633
        self.status = self.stack[-1].status(targetctx, match)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   634
        self.paths = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   635
        # but if --edit-lines is used, the user may want to edit files
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   636
        # even if they are not modified
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   637
        editopt = self.opts.get('edit_lines')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   638
        if not self.status.modified and editopt and match:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   639
            interestingpaths = match.files()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   640
        else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   641
            interestingpaths = self.status.modified
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   642
        # prepare the filefixupstate
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   643
        seenfctxs = set()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   644
        # sorting is necessary to eliminate ambiguity for the "double move"
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   645
        # case: "hg cp A B; hg cp A C; hg rm A", then only "B" can affect "A".
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   646
        for path in sorted(interestingpaths):
38921
e930df0f9a55 absorb: use ui.debug() instead of open-coding it
Augie Fackler <augie@google.com>
parents: 38920
diff changeset
   647
            self.ui.debug('calculating fixups for %s\n' % path)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   648
            targetfctx = targetctx[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   649
            fctxs, ctx2fctx = getfilestack(self.stack, path, seenfctxs)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   650
            # ignore symbolic links or binary, or unchanged files
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   651
            if any(f.islink() or stringutil.binary(f.data())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   652
                   for f in [targetfctx] + fctxs
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   653
                   if not isinstance(f, emptyfilecontext)):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   654
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   655
            if targetfctx.data() == fctxs[-1].data() and not editopt:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   656
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   657
            seenfctxs.update(fctxs[1:])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   658
            self.fctxmap[path] = ctx2fctx
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   659
            fstate = filefixupstate(fctxs, path, ui=self.ui, opts=self.opts)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   660
            if fm is not None:
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   661
                fm.startitem()
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   662
                fm.plain('showing changes for ')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   663
                fm.write('path', '%s\n', path, label='absorb.path')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   664
                fm.data(linetype='path')
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   665
            fstate.diffwith(targetfctx, fm)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   666
            self.fixupmap[path] = fstate
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   667
            self.paths.append(path)
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   668
            self.ctxaffected.update(fstate.ctxaffected)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   669
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   670
    def apply(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   671
        """apply fixups to individual filefixupstates"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   672
        for path, state in self.fixupmap.iteritems():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   673
            if self.ui.debugflag:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   674
                self.ui.write(_('applying fixups to %s\n') % path)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   675
            state.apply()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   676
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   677
    @property
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   678
    def chunkstats(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   679
        """-> {path: chunkstats}. collect chunkstats from filefixupstates"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   680
        return dict((path, state.chunkstats)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   681
                    for path, state in self.fixupmap.iteritems())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   682
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   683
    def commit(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   684
        """commit changes. update self.finalnode, self.replacemap"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   685
        with self.repo.wlock(), self.repo.lock():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   686
            with self.repo.transaction('absorb') as tr:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   687
                self._commitstack()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   688
                self._movebookmarks(tr)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   689
                if self.repo['.'].node() in self.replacemap:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   690
                    self._moveworkingdirectoryparent()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   691
                if self._useobsolete:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   692
                    self._obsoleteoldcommits()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   693
            if not self._useobsolete: # strip must be outside transactions
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   694
                self._stripoldcommits()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   695
        return self.finalnode
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   696
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   697
    def printchunkstats(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   698
        """print things like '1 of 2 chunk(s) applied'"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   699
        ui = self.ui
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   700
        chunkstats = self.chunkstats
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   701
        if ui.verbose:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   702
            # chunkstats for each file
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   703
            for path, stat in chunkstats.iteritems():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   704
                if stat[0]:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   705
                    ui.write(_('%s: %d of %d chunk(s) applied\n')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   706
                             % (path, stat[0], stat[1]))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   707
        elif not ui.quiet:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   708
            # a summary for all files
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   709
            stats = chunkstats.values()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   710
            applied, total = (sum(s[i] for s in stats) for i in (0, 1))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   711
            ui.write(_('%d of %d chunk(s) applied\n') % (applied, total))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   712
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   713
    def _commitstack(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   714
        """make new commits. update self.finalnode, self.replacemap.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   715
        it is splitted from "commit" to avoid too much indentation.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   716
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   717
        # last node (20-char) committed by us
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   718
        lastcommitted = None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   719
        # p1 which overrides the parent of the next commit, "None" means use
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   720
        # the original parent unchanged
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   721
        nextp1 = None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   722
        for ctx in self.stack:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   723
            memworkingcopy = self._getnewfilecontents(ctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   724
            if not memworkingcopy and not lastcommitted:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   725
                # nothing changed, nothing commited
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   726
                nextp1 = ctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   727
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   728
            msg = ''
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   729
            if self._willbecomenoop(memworkingcopy, ctx, nextp1):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   730
                # changeset is no longer necessary
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   731
                self.replacemap[ctx.node()] = None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   732
                msg = _('became empty and was dropped')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   733
            else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   734
                # changeset needs re-commit
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   735
                nodestr = self._commitsingle(memworkingcopy, ctx, p1=nextp1)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   736
                lastcommitted = self.repo[nodestr]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   737
                nextp1 = lastcommitted
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   738
                self.replacemap[ctx.node()] = lastcommitted.node()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   739
                if memworkingcopy:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   740
                    msg = _('%d file(s) changed, became %s') % (
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   741
                        len(memworkingcopy), self._ctx2str(lastcommitted))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   742
                else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   743
                    msg = _('became %s') % self._ctx2str(lastcommitted)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   744
            if self.ui.verbose and msg:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   745
                self.ui.write(_('%s: %s\n') % (self._ctx2str(ctx), msg))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   746
        self.finalnode = lastcommitted and lastcommitted.node()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   747
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   748
    def _ctx2str(self, ctx):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   749
        if self.ui.debugflag:
40150
1be1689d9ce9 absorb: print '{rev}:' as a prefix to the hash
Matt Harbison <matt_harbison@yahoo.com>
parents: 39786
diff changeset
   750
            return '%d:%s' % (ctx.rev(), ctx.hex())
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   751
        else:
40150
1be1689d9ce9 absorb: print '{rev}:' as a prefix to the hash
Matt Harbison <matt_harbison@yahoo.com>
parents: 39786
diff changeset
   752
            return '%d:%s' % (ctx.rev(), node.short(ctx.node()))
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   753
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   754
    def _getnewfilecontents(self, ctx):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   755
        """(ctx) -> {path: str}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   756
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   757
        fetch file contents from filefixupstates.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   758
        return the working copy overrides - files different from ctx.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   759
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   760
        result = {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   761
        for path in self.paths:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   762
            ctx2fctx = self.fctxmap[path] # {ctx: fctx}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   763
            if ctx not in ctx2fctx:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   764
                continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   765
            fctx = ctx2fctx[ctx]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   766
            content = fctx.data()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   767
            newcontent = self.fixupmap[path].getfinalcontent(fctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   768
            if content != newcontent:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   769
                result[fctx.path()] = newcontent
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   770
        return result
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   771
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   772
    def _movebookmarks(self, tr):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   773
        repo = self.repo
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   774
        needupdate = [(name, self.replacemap[hsh])
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   775
                      for name, hsh in repo._bookmarks.iteritems()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   776
                      if hsh in self.replacemap]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   777
        changes = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   778
        for name, hsh in needupdate:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   779
            if hsh:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   780
                changes.append((name, hsh))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   781
                if self.ui.verbose:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   782
                    self.ui.write(_('moving bookmark %s to %s\n')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   783
                                  % (name, node.hex(hsh)))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   784
            else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   785
                changes.append((name, None))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   786
                if self.ui.verbose:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   787
                    self.ui.write(_('deleting bookmark %s\n') % name)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   788
        repo._bookmarks.applychanges(repo, tr, changes)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   789
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   790
    def _moveworkingdirectoryparent(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   791
        if not self.finalnode:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   792
            # Find the latest not-{obsoleted,stripped} parent.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   793
            revs = self.repo.revs('max(::. - %ln)', self.replacemap.keys())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   794
            ctx = self.repo[revs.first()]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   795
            self.finalnode = ctx.node()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   796
        else:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   797
            ctx = self.repo[self.finalnode]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   798
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   799
        dirstate = self.repo.dirstate
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   800
        # dirstate.rebuild invalidates fsmonitorstate, causing "hg status" to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   801
        # be slow. in absorb's case, no need to invalidate fsmonitorstate.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   802
        noop = lambda: 0
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   803
        restore = noop
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   804
        if util.safehasattr(dirstate, '_fsmonitorstate'):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   805
            bak = dirstate._fsmonitorstate.invalidate
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   806
            def restore():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   807
                dirstate._fsmonitorstate.invalidate = bak
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   808
            dirstate._fsmonitorstate.invalidate = noop
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   809
        try:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   810
            with dirstate.parentchange():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   811
                dirstate.rebuild(ctx.node(), ctx.manifest(), self.paths)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   812
        finally:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   813
            restore()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   814
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   815
    @staticmethod
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   816
    def _willbecomenoop(memworkingcopy, ctx, pctx=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   817
        """({path: content}, ctx, ctx) -> bool. test if a commit will be noop
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   818
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   819
        if it will become an empty commit (does not change anything, after the
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   820
        memworkingcopy overrides), return True. otherwise return False.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   821
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   822
        if not pctx:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   823
            parents = ctx.parents()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   824
            if len(parents) != 1:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   825
                return False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   826
            pctx = parents[0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   827
        # ctx changes more files (not a subset of memworkingcopy)
38987
9204445ad54c absorb: port partway to Python 3
Augie Fackler <augie@google.com>
parents: 38961
diff changeset
   828
        if not set(ctx.files()).issubset(set(memworkingcopy)):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   829
            return False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   830
        for path, content in memworkingcopy.iteritems():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   831
            if path not in pctx or path not in ctx:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   832
                return False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   833
            fctx = ctx[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   834
            pfctx = pctx[path]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   835
            if pfctx.flags() != fctx.flags():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   836
                return False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   837
            if pfctx.data() != content:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   838
                return False
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   839
        return True
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   840
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   841
    def _commitsingle(self, memworkingcopy, ctx, p1=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   842
        """(ctx, {path: content}, node) -> node. make a single commit
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   843
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   844
        the commit is a clone from ctx, with a (optionally) different p1, and
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   845
        different file contents replaced by memworkingcopy.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   846
        """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   847
        parents = p1 and (p1, node.nullid)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   848
        extra = ctx.extra()
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
   849
        if self._useobsolete and self.ui.configbool('absorb', 'add-noise'):
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   850
            extra['absorb_source'] = ctx.hex()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   851
        mctx = overlaycontext(memworkingcopy, ctx, parents, extra=extra)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   852
        # preserve phase
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   853
        with mctx.repo().ui.configoverride({
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   854
            ('phases', 'new-commit'): ctx.phase()}):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   855
            return mctx.commit()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   856
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   857
    @util.propertycache
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   858
    def _useobsolete(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   859
        """() -> bool"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   860
        return obsolete.isenabled(self.repo, obsolete.createmarkersopt)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   861
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   862
    def _obsoleteoldcommits(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   863
        relations = [(self.repo[k], v and (self.repo[v],) or ())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   864
                     for k, v in self.replacemap.iteritems()]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   865
        if relations:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   866
            obsolete.createmarkers(self.repo, relations)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   867
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   868
    def _stripoldcommits(self):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   869
        nodelist = self.replacemap.keys()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   870
        # make sure we don't strip innocent children
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   871
        revs = self.repo.revs('%ln - (::(heads(%ln::)-%ln))', nodelist,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   872
                              nodelist, nodelist)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   873
        tonode = self.repo.changelog.node
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   874
        nodelist = [tonode(r) for r in revs]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   875
        if nodelist:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   876
            repair.strip(self.repo.ui, self.repo, nodelist)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   877
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   878
def _parsechunk(hunk):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   879
    """(crecord.uihunk or patch.recordhunk) -> (path, (a1, a2, [bline]))"""
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   880
    if type(hunk) not in (crecord.uihunk, patch.recordhunk):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   881
        return None, None
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   882
    path = hunk.header.filename()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   883
    a1 = hunk.fromline + len(hunk.before) - 1
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   884
    # remove before and after context
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   885
    hunk.before = hunk.after = []
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   886
    buf = util.stringio()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   887
    hunk.write(buf)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   888
    patchlines = mdiff.splitnewlines(buf.getvalue())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   889
    # hunk.prettystr() will update hunk.removed
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   890
    a2 = a1 + hunk.removed
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   891
    blines = [l[1:] for l in patchlines[1:] if l[0] != '-']
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   892
    return path, (a1, a2, blines)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   893
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   894
def overlaydiffcontext(ctx, chunks):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   895
    """(ctx, [crecord.uihunk]) -> memctx
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   896
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   897
    return a memctx with some [1] patches (chunks) applied to ctx.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   898
    [1]: modifications are handled. renames, mode changes, etc. are ignored.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   899
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   900
    # sadly the applying-patch logic is hardly reusable, and messy:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   901
    # 1. the core logic "_applydiff" is too heavy - it writes .rej files, it
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   902
    #    needs a file stream of a patch and will re-parse it, while we have
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   903
    #    structured hunk objects at hand.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   904
    # 2. a lot of different implementations about "chunk" (patch.hunk,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   905
    #    patch.recordhunk, crecord.uihunk)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   906
    # as we only care about applying changes to modified files, no mode
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   907
    # change, no binary diff, and no renames, it's probably okay to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   908
    # re-invent the logic using much simpler code here.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   909
    memworkingcopy = {} # {path: content}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   910
    patchmap = defaultdict(lambda: []) # {path: [(a1, a2, [bline])]}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   911
    for path, info in map(_parsechunk, chunks):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   912
        if not path or not info:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   913
            continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   914
        patchmap[path].append(info)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   915
    for path, patches in patchmap.iteritems():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   916
        if path not in ctx or not patches:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   917
            continue
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   918
        patches.sort(reverse=True)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   919
        lines = mdiff.splitnewlines(ctx[path].data())
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   920
        for a1, a2, blines in patches:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   921
            lines[a1:a2] = blines
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   922
        memworkingcopy[path] = ''.join(lines)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   923
    return overlaycontext(memworkingcopy, ctx)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   924
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   925
def absorb(ui, repo, stack=None, targetctx=None, pats=None, opts=None):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   926
    """pick fixup chunks from targetctx, apply them to stack.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   927
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   928
    if targetctx is None, the working copy context will be used.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   929
    if stack is None, the current draft stack will be used.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   930
    return fixupstate.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   931
    """
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   932
    if stack is None:
38961
19344143b3e1 absorb: following UI conventions
David Demelier <markand@malikania.fr>
parents: 38932
diff changeset
   933
        limit = ui.configint('absorb', 'max-stack-size')
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   934
        stack = getdraftstack(repo['.'], limit)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   935
        if limit and len(stack) >= limit:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   936
            ui.warn(_('absorb: only the recent %d changesets will '
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   937
                      'be analysed\n')
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   938
                    % limit)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   939
    if not stack:
39453
ab452995eaff absorb: clarify the reason for not finding changesets to modify
Matt Harbison <matt_harbison@yahoo.com>
parents: 38987
diff changeset
   940
        raise error.Abort(_('no mutable changeset to change'))
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   941
    if targetctx is None: # default to working copy
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   942
        targetctx = repo[None]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   943
    if pats is None:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   944
        pats = ()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   945
    if opts is None:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   946
        opts = {}
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   947
    state = fixupstate(stack, ui=ui, opts=opts)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   948
    matcher = scmutil.match(targetctx, pats, opts)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   949
    if opts.get('interactive'):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   950
        diff = patch.diff(repo, stack[-1].node(), targetctx.node(), matcher)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   951
        origchunks = patch.parsepatch(diff)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   952
        chunks = cmdutil.recordfilter(ui, origchunks)[0]
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   953
        targetctx = overlaydiffcontext(stack[-1], chunks)
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   954
    fm = None
40190
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   955
    if opts.get('print_changes') or not opts.get('apply_changes'):
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   956
        fm = ui.formatter('absorb', opts)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   957
    state.diffwith(targetctx, matcher, fm)
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   958
    if fm is not None:
40188
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   959
        fm.startitem()
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   960
        fm.write("count", "\n%d changesets affected\n", len(state.ctxaffected))
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   961
        fm.data(linetype='summary')
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   962
        for ctx in reversed(stack):
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   963
            if ctx not in state.ctxaffected:
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   964
                continue
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   965
            fm.startitem()
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   966
            fm.context(ctx=ctx)
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   967
            fm.data(linetype='changeset')
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   968
            fm.write('node', '%-7.7s ', ctx.hex(), label='absorb.node')
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   969
            descfirstline = ctx.description().splitlines()[0]
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   970
            fm.write('descfirstline', '%s\n', descfirstline,
2c5316796f45 absorb: print summary of changesets affected
Mark Thomas <mbthomas@fb.com>
parents: 40187
diff changeset
   971
                     label='absorb.description')
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   972
        fm.end()
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   973
    if not opts.get('dry_run'):
40190
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   974
        if not opts.get('apply_changes'):
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   975
            if ui.promptchoice("apply changes (yn)? $$ &Yes $$ &No", default=1):
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   976
                raise error.Abort(_('absorb cancelled\n'))
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   977
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   978
        state.apply()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   979
        if state.commit():
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   980
            state.printchunkstats()
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   981
        elif not ui.quiet:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   982
            ui.write(_('nothing applied\n'))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   983
    return state
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   984
38932
205efbf656c2 absorb: remove sf alias for command
Gregory Szorc <gregory.szorc@gmail.com>
parents: 38923
diff changeset
   985
@command('^absorb',
40190
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   986
         [('a', 'apply-changes', None,
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   987
           _('apply changes without prompting for confirmation')),
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   988
          ('p', 'print-changes', None,
31dfa7dac4c9 absorb: prompt user to accept absorb changes by default
Mark Thomas <mbthomas@fb.com>
parents: 40188
diff changeset
   989
           _('just print which changesets are modified by which changes')),
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   990
          ('i', 'interactive', None,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   991
           _('interactively select which chunks to apply (EXPERIMENTAL)')),
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   992
          ('e', 'edit-lines', None,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   993
           _('edit what lines belong to which changesets before commit '
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   994
             '(EXPERIMENTAL)')),
40187
dcda50856843 absorb: use a formatter to generate output
Mark Thomas <mbthomas@fb.com>
parents: 40150
diff changeset
   995
         ] + commands.dryrunopts + commands.templateopts + commands.walkopts,
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   996
         _('hg absorb [OPTION] [FILE]...'))
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   997
def absorbcmd(ui, repo, *pats, **opts):
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   998
    """incorporate corrections into the stack of draft changesets
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
   999
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1000
    absorb analyzes each change in your working directory and attempts to
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1001
    amend the changed lines into the changesets in your stack that first
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1002
    introduced those lines.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1003
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1004
    If absorb cannot find an unambiguous changeset to amend for a change,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1005
    that change will be left in the working directory, untouched. They can be
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1006
    observed by :hg:`status` or :hg:`diff` afterwards. In other words,
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1007
    absorb does not write to the working directory.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1008
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1009
    Changesets outside the revset `::. and not public() and not merge()` will
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1010
    not be changed.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1011
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1012
    Changesets that become empty after applying the changes will be deleted.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1013
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1014
    If in doubt, run :hg:`absorb -pn` to preview what changesets will
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1015
    be amended by what changed lines, without actually changing anything.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1016
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1017
    Returns 0 on success, 1 if all chunks were ignored and nothing amended.
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1018
    """
39786
d50125dec2c1 py3: fix kwargs handling in hgext/absorb.py
Pulkit Goyal <pulkit@yandex-team.ru>
parents: 39453
diff changeset
  1019
    opts = pycompat.byteskwargs(opts)
38917
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1020
    state = absorb(ui, repo, pats=pats, opts=opts)
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1021
    if sum(s[0] for s in state.chunkstats.values()) == 0:
5111d11b8719 absorb: import extension from Facebook's hg-experimental
Augie Fackler <augie@google.com>
parents:
diff changeset
  1022
        return 1