mercurial/debugcommands.py
changeset 30412 945f8229b30d
parent 30411 869d660b8669
child 30510 a87e469201f9
equal deleted inserted replaced
30411:869d660b8669 30412:945f8229b30d
     8 from __future__ import absolute_import
     8 from __future__ import absolute_import
     9 
     9 
    10 import os
    10 import os
    11 
    11 
    12 from .i18n import _
    12 from .i18n import _
       
    13 from .node import (
       
    14     hex,
       
    15 )
    13 from . import (
    16 from . import (
    14     cmdutil,
    17     cmdutil,
    15     commands,
    18     commands,
       
    19     context,
       
    20     dagparser,
    16     error,
    21     error,
       
    22     lock as lockmod,
    17     revlog,
    23     revlog,
    18     scmutil,
    24     scmutil,
       
    25     simplemerge,
    19 )
    26 )
       
    27 
       
    28 release = lockmod.release
    20 
    29 
    21 # We reuse the command table from commands because it is easier than
    30 # We reuse the command table from commands because it is easier than
    22 # teaching dispatch about multiple tables.
    31 # teaching dispatch about multiple tables.
    23 command = cmdutil.command(commands.table)
    32 command = cmdutil.command(commands.table)
    24 
    33 
    38         lookup = repo.lookup
    47         lookup = repo.lookup
    39     else:
    48     else:
    40         raise error.Abort(_('either two or three arguments required'))
    49         raise error.Abort(_('either two or three arguments required'))
    41     a = r.ancestor(lookup(rev1), lookup(rev2))
    50     a = r.ancestor(lookup(rev1), lookup(rev2))
    42     ui.write('%d:%s\n' % (r.rev(a), hex(a)))
    51     ui.write('%d:%s\n' % (r.rev(a), hex(a)))
       
    52 
       
    53 @command('debugbuilddag',
       
    54     [('m', 'mergeable-file', None, _('add single file mergeable changes')),
       
    55     ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
       
    56     ('n', 'new-file', None, _('add new file at each rev'))],
       
    57     _('[OPTION]... [TEXT]'))
       
    58 def debugbuilddag(ui, repo, text=None,
       
    59                   mergeable_file=False,
       
    60                   overwritten_file=False,
       
    61                   new_file=False):
       
    62     """builds a repo with a given DAG from scratch in the current empty repo
       
    63 
       
    64     The description of the DAG is read from stdin if not given on the
       
    65     command line.
       
    66 
       
    67     Elements:
       
    68 
       
    69      - "+n" is a linear run of n nodes based on the current default parent
       
    70      - "." is a single node based on the current default parent
       
    71      - "$" resets the default parent to null (implied at the start);
       
    72            otherwise the default parent is always the last node created
       
    73      - "<p" sets the default parent to the backref p
       
    74      - "*p" is a fork at parent p, which is a backref
       
    75      - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
       
    76      - "/p2" is a merge of the preceding node and p2
       
    77      - ":tag" defines a local tag for the preceding node
       
    78      - "@branch" sets the named branch for subsequent nodes
       
    79      - "#...\\n" is a comment up to the end of the line
       
    80 
       
    81     Whitespace between the above elements is ignored.
       
    82 
       
    83     A backref is either
       
    84 
       
    85      - a number n, which references the node curr-n, where curr is the current
       
    86        node, or
       
    87      - the name of a local tag you placed earlier using ":tag", or
       
    88      - empty to denote the default parent.
       
    89 
       
    90     All string valued-elements are either strictly alphanumeric, or must
       
    91     be enclosed in double quotes ("..."), with "\\" as escape character.
       
    92     """
       
    93 
       
    94     if text is None:
       
    95         ui.status(_("reading DAG from stdin\n"))
       
    96         text = ui.fin.read()
       
    97 
       
    98     cl = repo.changelog
       
    99     if len(cl) > 0:
       
   100         raise error.Abort(_('repository is not empty'))
       
   101 
       
   102     # determine number of revs in DAG
       
   103     total = 0
       
   104     for type, data in dagparser.parsedag(text):
       
   105         if type == 'n':
       
   106             total += 1
       
   107 
       
   108     if mergeable_file:
       
   109         linesperrev = 2
       
   110         # make a file with k lines per rev
       
   111         initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
       
   112         initialmergedlines.append("")
       
   113 
       
   114     tags = []
       
   115 
       
   116     wlock = lock = tr = None
       
   117     try:
       
   118         wlock = repo.wlock()
       
   119         lock = repo.lock()
       
   120         tr = repo.transaction("builddag")
       
   121 
       
   122         at = -1
       
   123         atbranch = 'default'
       
   124         nodeids = []
       
   125         id = 0
       
   126         ui.progress(_('building'), id, unit=_('revisions'), total=total)
       
   127         for type, data in dagparser.parsedag(text):
       
   128             if type == 'n':
       
   129                 ui.note(('node %s\n' % str(data)))
       
   130                 id, ps = data
       
   131 
       
   132                 files = []
       
   133                 fctxs = {}
       
   134 
       
   135                 p2 = None
       
   136                 if mergeable_file:
       
   137                     fn = "mf"
       
   138                     p1 = repo[ps[0]]
       
   139                     if len(ps) > 1:
       
   140                         p2 = repo[ps[1]]
       
   141                         pa = p1.ancestor(p2)
       
   142                         base, local, other = [x[fn].data() for x in (pa, p1,
       
   143                                                                      p2)]
       
   144                         m3 = simplemerge.Merge3Text(base, local, other)
       
   145                         ml = [l.strip() for l in m3.merge_lines()]
       
   146                         ml.append("")
       
   147                     elif at > 0:
       
   148                         ml = p1[fn].data().split("\n")
       
   149                     else:
       
   150                         ml = initialmergedlines
       
   151                     ml[id * linesperrev] += " r%i" % id
       
   152                     mergedtext = "\n".join(ml)
       
   153                     files.append(fn)
       
   154                     fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
       
   155 
       
   156                 if overwritten_file:
       
   157                     fn = "of"
       
   158                     files.append(fn)
       
   159                     fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
       
   160 
       
   161                 if new_file:
       
   162                     fn = "nf%i" % id
       
   163                     files.append(fn)
       
   164                     fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
       
   165                     if len(ps) > 1:
       
   166                         if not p2:
       
   167                             p2 = repo[ps[1]]
       
   168                         for fn in p2:
       
   169                             if fn.startswith("nf"):
       
   170                                 files.append(fn)
       
   171                                 fctxs[fn] = p2[fn]
       
   172 
       
   173                 def fctxfn(repo, cx, path):
       
   174                     return fctxs.get(path)
       
   175 
       
   176                 if len(ps) == 0 or ps[0] < 0:
       
   177                     pars = [None, None]
       
   178                 elif len(ps) == 1:
       
   179                     pars = [nodeids[ps[0]], None]
       
   180                 else:
       
   181                     pars = [nodeids[p] for p in ps]
       
   182                 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
       
   183                                     date=(id, 0),
       
   184                                     user="debugbuilddag",
       
   185                                     extra={'branch': atbranch})
       
   186                 nodeid = repo.commitctx(cx)
       
   187                 nodeids.append(nodeid)
       
   188                 at = id
       
   189             elif type == 'l':
       
   190                 id, name = data
       
   191                 ui.note(('tag %s\n' % name))
       
   192                 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
       
   193             elif type == 'a':
       
   194                 ui.note(('branch %s\n' % data))
       
   195                 atbranch = data
       
   196             ui.progress(_('building'), id, unit=_('revisions'), total=total)
       
   197         tr.close()
       
   198 
       
   199         if tags:
       
   200             repo.vfs.write("localtags", "".join(tags))
       
   201     finally:
       
   202         ui.progress(_('building'), None)
       
   203         release(tr, lock, wlock)