1# bruterebase.py - brute force rebase testing
2#
3# Copyright 2017 Facebook, Inc.
4#
5# This software may be used and distributed according to the terms of the
6# GNU General Public License version 2 or any later version.
7
8from __future__ import absolute_import
9
10from mercurial import (
11    error,
12    registrar,
13    revsetlang,
14)
15
16from hgext import rebase
17
18try:
19    xrange
20except NameError:
21    xrange = range
22
23cmdtable = {}
24command = registrar.command(cmdtable)
25
26
27@command(b'debugbruterebase')
28def debugbruterebase(ui, repo, source, dest):
29    """for every non-empty subset of source, run rebase -r subset -d dest
30
31    Print one line summary for each subset. Assume obsstore is enabled.
32    """
33    srevs = list(repo.revs(source))
34
35    with repo.wlock(), repo.lock():
36        repolen = len(repo)
37        cl = repo.changelog
38
39        def getdesc(rev):
40            result = cl.changelogrevision(rev).description
41            if rev >= repolen:
42                result += b"'"
43            return result
44
45        for i in xrange(1, 2 ** len(srevs)):
46            subset = [rev for j, rev in enumerate(srevs) if i & (1 << j) != 0]
47            spec = revsetlang.formatspec(b'%ld', subset)
48            tr = repo.transaction(b'rebase')
49            tr._report = lambda x: 0  # hide "transaction abort"
50
51            with ui.silent():
52                try:
53                    rebase.rebase(ui, repo, dest=dest, rev=[spec])
54                except error.Abort as ex:
55                    summary = b'ABORT: %s' % ex.message
56                except Exception as ex:
57                    summary = b'CRASH: %s' % ex
58                else:
59                    # short summary about new nodes
60                    cl = repo.changelog
61                    descs = []
62                    for rev in xrange(repolen, len(repo)):
63                        desc = b'%s:' % getdesc(rev)
64                        for prev in cl.parentrevs(rev):
65                            if prev > -1:
66                                desc += getdesc(prev)
67                        descs.append(desc)
68                    descs.sort()
69                    summary = b' '.join(descs)
70            repo.vfs.tryunlink(b'rebasestate')
71
72            subsetdesc = b''.join(getdesc(rev) for rev in subset)
73            ui.write(b'%s: %s\n' % (subsetdesc.rjust(len(srevs)), summary))
74            tr.abort()
75