comparison mercurial/debugcommands.py @ 30412:945f8229b30d

debugcommands: move debugbuilddag And we drop some now unused imports from commands.py.
author Gregory Szorc <gregory.szorc@gmail.com>
date Thu, 10 Nov 2016 09:45:42 -0800
parents 869d660b8669
children a87e469201f9
comparison
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)