##// END OF EJS Templates
Refactor log ui buffering and patch display
Matt Mackall -
r3645:b984dcb1 default
parent child Browse files
Show More
@@ -1,524 +1,585 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), 'os sys')
11 demandload(globals(), 'os sys')
12 demandload(globals(), 'mdiff util templater cStringIO')
12 demandload(globals(), 'mdiff util templater cStringIO patch')
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 def revpair(ui, repo, revs):
16 def revpair(ui, repo, revs):
17 '''return pair of nodes, given list of revisions. second item can
17 '''return pair of nodes, given list of revisions. second item can
18 be None, meaning use working dir.'''
18 be None, meaning use working dir.'''
19
19
20 def revfix(repo, val, defval):
20 def revfix(repo, val, defval):
21 if not val and val != 0:
21 if not val and val != 0:
22 val = defval
22 val = defval
23 return repo.lookup(val)
23 return repo.lookup(val)
24
24
25 if not revs:
25 if not revs:
26 return repo.dirstate.parents()[0], None
26 return repo.dirstate.parents()[0], None
27 end = None
27 end = None
28 if len(revs) == 1:
28 if len(revs) == 1:
29 if revrangesep in revs[0]:
29 if revrangesep in revs[0]:
30 start, end = revs[0].split(revrangesep, 1)
30 start, end = revs[0].split(revrangesep, 1)
31 start = revfix(repo, start, 0)
31 start = revfix(repo, start, 0)
32 end = revfix(repo, end, repo.changelog.count() - 1)
32 end = revfix(repo, end, repo.changelog.count() - 1)
33 else:
33 else:
34 start = revfix(repo, revs[0], None)
34 start = revfix(repo, revs[0], None)
35 elif len(revs) == 2:
35 elif len(revs) == 2:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
37 raise util.Abort(_('too many revisions specified'))
37 raise util.Abort(_('too many revisions specified'))
38 start = revfix(repo, revs[0], None)
38 start = revfix(repo, revs[0], None)
39 end = revfix(repo, revs[1], None)
39 end = revfix(repo, revs[1], None)
40 else:
40 else:
41 raise util.Abort(_('too many revisions specified'))
41 raise util.Abort(_('too many revisions specified'))
42 return start, end
42 return start, end
43
43
44 def revrange(ui, repo, revs):
44 def revrange(ui, repo, revs):
45 """Yield revision as strings from a list of revision specifications."""
45 """Yield revision as strings from a list of revision specifications."""
46
46
47 def revfix(repo, val, defval):
47 def revfix(repo, val, defval):
48 if not val and val != 0:
48 if not val and val != 0:
49 return defval
49 return defval
50 return repo.changelog.rev(repo.lookup(val))
50 return repo.changelog.rev(repo.lookup(val))
51
51
52 seen, l = {}, []
52 seen, l = {}, []
53 for spec in revs:
53 for spec in revs:
54 if revrangesep in spec:
54 if revrangesep in spec:
55 start, end = spec.split(revrangesep, 1)
55 start, end = spec.split(revrangesep, 1)
56 start = revfix(repo, start, 0)
56 start = revfix(repo, start, 0)
57 end = revfix(repo, end, repo.changelog.count() - 1)
57 end = revfix(repo, end, repo.changelog.count() - 1)
58 step = start > end and -1 or 1
58 step = start > end and -1 or 1
59 for rev in xrange(start, end+step, step):
59 for rev in xrange(start, end+step, step):
60 if rev in seen:
60 if rev in seen:
61 continue
61 continue
62 seen[rev] = 1
62 seen[rev] = 1
63 l.append(rev)
63 l.append(rev)
64 else:
64 else:
65 rev = revfix(repo, spec, None)
65 rev = revfix(repo, spec, None)
66 if rev in seen:
66 if rev in seen:
67 continue
67 continue
68 seen[rev] = 1
68 seen[rev] = 1
69 l.append(rev)
69 l.append(rev)
70
70
71 return l
71 return l
72
72
73 def make_filename(repo, pat, node,
73 def make_filename(repo, pat, node,
74 total=None, seqno=None, revwidth=None, pathname=None):
74 total=None, seqno=None, revwidth=None, pathname=None):
75 node_expander = {
75 node_expander = {
76 'H': lambda: hex(node),
76 'H': lambda: hex(node),
77 'R': lambda: str(repo.changelog.rev(node)),
77 'R': lambda: str(repo.changelog.rev(node)),
78 'h': lambda: short(node),
78 'h': lambda: short(node),
79 }
79 }
80 expander = {
80 expander = {
81 '%': lambda: '%',
81 '%': lambda: '%',
82 'b': lambda: os.path.basename(repo.root),
82 'b': lambda: os.path.basename(repo.root),
83 }
83 }
84
84
85 try:
85 try:
86 if node:
86 if node:
87 expander.update(node_expander)
87 expander.update(node_expander)
88 if node and revwidth is not None:
88 if node and revwidth is not None:
89 expander['r'] = (lambda:
89 expander['r'] = (lambda:
90 str(repo.changelog.rev(node)).zfill(revwidth))
90 str(repo.changelog.rev(node)).zfill(revwidth))
91 if total is not None:
91 if total is not None:
92 expander['N'] = lambda: str(total)
92 expander['N'] = lambda: str(total)
93 if seqno is not None:
93 if seqno is not None:
94 expander['n'] = lambda: str(seqno)
94 expander['n'] = lambda: str(seqno)
95 if total is not None and seqno is not None:
95 if total is not None and seqno is not None:
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
97 if pathname is not None:
97 if pathname is not None:
98 expander['s'] = lambda: os.path.basename(pathname)
98 expander['s'] = lambda: os.path.basename(pathname)
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
100 expander['p'] = lambda: pathname
100 expander['p'] = lambda: pathname
101
101
102 newname = []
102 newname = []
103 patlen = len(pat)
103 patlen = len(pat)
104 i = 0
104 i = 0
105 while i < patlen:
105 while i < patlen:
106 c = pat[i]
106 c = pat[i]
107 if c == '%':
107 if c == '%':
108 i += 1
108 i += 1
109 c = pat[i]
109 c = pat[i]
110 c = expander[c]()
110 c = expander[c]()
111 newname.append(c)
111 newname.append(c)
112 i += 1
112 i += 1
113 return ''.join(newname)
113 return ''.join(newname)
114 except KeyError, inst:
114 except KeyError, inst:
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
116 inst.args[0])
116 inst.args[0])
117
117
118 def make_file(repo, pat, node=None,
118 def make_file(repo, pat, node=None,
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
120 if not pat or pat == '-':
120 if not pat or pat == '-':
121 return 'w' in mode and sys.stdout or sys.stdin
121 return 'w' in mode and sys.stdout or sys.stdin
122 if hasattr(pat, 'write') and 'w' in mode:
122 if hasattr(pat, 'write') and 'w' in mode:
123 return pat
123 return pat
124 if hasattr(pat, 'read') and 'r' in mode:
124 if hasattr(pat, 'read') and 'r' in mode:
125 return pat
125 return pat
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
127 pathname),
127 pathname),
128 mode)
128 mode)
129
129
130 def matchpats(repo, pats=[], opts={}, head=''):
130 def matchpats(repo, pats=[], opts={}, head=''):
131 cwd = repo.getcwd()
131 cwd = repo.getcwd()
132 if not pats and cwd:
132 if not pats and cwd:
133 opts['include'] = [os.path.join(cwd, i)
133 opts['include'] = [os.path.join(cwd, i)
134 for i in opts.get('include', [])]
134 for i in opts.get('include', [])]
135 opts['exclude'] = [os.path.join(cwd, x)
135 opts['exclude'] = [os.path.join(cwd, x)
136 for x in opts.get('exclude', [])]
136 for x in opts.get('exclude', [])]
137 cwd = ''
137 cwd = ''
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
139 opts.get('exclude'), head)
139 opts.get('exclude'), head)
140
140
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
143 exact = dict.fromkeys(files)
143 exact = dict.fromkeys(files)
144 for src, fn in repo.walk(node=node, files=files, match=matchfn,
144 for src, fn in repo.walk(node=node, files=files, match=matchfn,
145 badmatch=badmatch):
145 badmatch=badmatch):
146 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
146 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
147
147
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
149 if added is None or removed is None:
149 if added is None or removed is None:
150 added, removed = repo.status()[1:3]
150 added, removed = repo.status()[1:3]
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
152 mf = repo.manifest.read(changes[0])
152 mf = repo.manifest.read(changes[0])
153 for a in added:
153 for a in added:
154 aa = repo.wread(a)
154 aa = repo.wread(a)
155 bestscore, bestname = None, None
155 bestscore, bestname = None, None
156 for r in removed:
156 for r in removed:
157 rr = repo.file(r).read(mf[r])
157 rr = repo.file(r).read(mf[r])
158 delta = mdiff.textdiff(aa, rr)
158 delta = mdiff.textdiff(aa, rr)
159 if len(delta) < len(aa):
159 if len(delta) < len(aa):
160 myscore = 1.0 - (float(len(delta)) / len(aa))
160 myscore = 1.0 - (float(len(delta)) / len(aa))
161 if bestscore is None or myscore > bestscore:
161 if bestscore is None or myscore > bestscore:
162 bestscore, bestname = myscore, r
162 bestscore, bestname = myscore, r
163 if bestname and bestscore >= threshold:
163 if bestname and bestscore >= threshold:
164 yield bestname, a, bestscore
164 yield bestname, a, bestscore
165
165
166 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
166 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
167 similarity=None):
167 similarity=None):
168 if dry_run is None:
168 if dry_run is None:
169 dry_run = opts.get('dry_run')
169 dry_run = opts.get('dry_run')
170 if similarity is None:
170 if similarity is None:
171 similarity = float(opts.get('similarity') or 0)
171 similarity = float(opts.get('similarity') or 0)
172 add, remove = [], []
172 add, remove = [], []
173 mapping = {}
173 mapping = {}
174 for src, abs, rel, exact in walk(repo, pats, opts):
174 for src, abs, rel, exact in walk(repo, pats, opts):
175 if src == 'f' and repo.dirstate.state(abs) == '?':
175 if src == 'f' and repo.dirstate.state(abs) == '?':
176 add.append(abs)
176 add.append(abs)
177 mapping[abs] = rel, exact
177 mapping[abs] = rel, exact
178 if repo.ui.verbose or not exact:
178 if repo.ui.verbose or not exact:
179 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
179 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
180 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
180 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
181 remove.append(abs)
181 remove.append(abs)
182 mapping[abs] = rel, exact
182 mapping[abs] = rel, exact
183 if repo.ui.verbose or not exact:
183 if repo.ui.verbose or not exact:
184 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
184 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
185 if not dry_run:
185 if not dry_run:
186 repo.add(add, wlock=wlock)
186 repo.add(add, wlock=wlock)
187 repo.remove(remove, wlock=wlock)
187 repo.remove(remove, wlock=wlock)
188 if similarity > 0:
188 if similarity > 0:
189 for old, new, score in findrenames(repo, add, remove, similarity):
189 for old, new, score in findrenames(repo, add, remove, similarity):
190 oldrel, oldexact = mapping[old]
190 oldrel, oldexact = mapping[old]
191 newrel, newexact = mapping[new]
191 newrel, newexact = mapping[new]
192 if repo.ui.verbose or not oldexact or not newexact:
192 if repo.ui.verbose or not oldexact or not newexact:
193 repo.ui.status(_('recording removal of %s as rename to %s '
193 repo.ui.status(_('recording removal of %s as rename to %s '
194 '(%d%% similar)\n') %
194 '(%d%% similar)\n') %
195 (oldrel, newrel, score * 100))
195 (oldrel, newrel, score * 100))
196 if not dry_run:
196 if not dry_run:
197 repo.copy(old, new, wlock=wlock)
197 repo.copy(old, new, wlock=wlock)
198
198
199 class uibuffer(object):
200 # Implement and delegate some ui protocol. Save hunks of
201 # output for later display in the desired order.
202 def __init__(self, ui):
203 self.ui = ui
204 self.hunk = {}
205 self.header = {}
206 self.quiet = ui.quiet
207 self.verbose = ui.verbose
208 self.debugflag = ui.debugflag
209 self.lastheader = None
210 def note(self, *args):
211 if self.verbose:
212 self.write(*args)
213 def status(self, *args):
214 if not self.quiet:
215 self.write(*args)
216 def debug(self, *args):
217 if self.debugflag:
218 self.write(*args)
219 def write(self, *args):
220 self.hunk.setdefault(self.rev, []).extend(args)
221 def write_header(self, *args):
222 self.header.setdefault(self.rev, []).extend(args)
223 def mark(self, rev):
224 self.rev = rev
225 def flush(self, rev):
226 if rev in self.header:
227 h = "".join(self.header[rev])
228 if h != self.lastheader:
229 self.lastheader = h
230 self.ui.write(h)
231 del self.header[rev]
232 if rev in self.hunk:
233 self.ui.write("".join(self.hunk[rev]))
234 del self.hunk[rev]
235 return 1
236 return 0
237
199 class changeset_printer(object):
238 class changeset_printer(object):
200 '''show changeset information when templating not requested.'''
239 '''show changeset information when templating not requested.'''
201
240
202 def __init__(self, ui, repo):
241 def __init__(self, ui, repo, patch, buffered):
203 self.ui = ui
242 self.ui = ui
204 self.repo = repo
243 self.repo = repo
244 self.buffered = buffered
245 self.patch = patch
246 if buffered:
247 self.ui = uibuffer(ui)
248
249 def flush(self, rev):
250 return self.ui.flush(rev)
205
251
206 def show(self, rev=0, changenode=None, brinfo=None, copies=None):
252 def show(self, rev=0, changenode=None, brinfo=None, copies=None):
207 '''show a single changeset or file revision'''
253 '''show a single changeset or file revision'''
254 if self.buffered:
255 self.ui.mark(rev)
208 log = self.repo.changelog
256 log = self.repo.changelog
209 if changenode is None:
257 if changenode is None:
210 changenode = log.node(rev)
258 changenode = log.node(rev)
211 elif not rev:
259 elif not rev:
212 rev = log.rev(changenode)
260 rev = log.rev(changenode)
213
261
214 if self.ui.quiet:
262 if self.ui.quiet:
215 self.ui.write("%d:%s\n" % (rev, short(changenode)))
263 self.ui.write("%d:%s\n" % (rev, short(changenode)))
216 return
264 return
217
265
218 changes = log.read(changenode)
266 changes = log.read(changenode)
219 date = util.datestr(changes[2])
267 date = util.datestr(changes[2])
220 extra = changes[5]
268 extra = changes[5]
221 branch = extra.get("branch")
269 branch = extra.get("branch")
222
270
223 hexfunc = self.ui.debugflag and hex or short
271 hexfunc = self.ui.debugflag and hex or short
224
272
225 parents = log.parentrevs(rev)
273 parents = log.parentrevs(rev)
226 if not self.ui.debugflag:
274 if not self.ui.debugflag:
227 if parents[1] == nullrev:
275 if parents[1] == nullrev:
228 if parents[0] >= rev - 1:
276 if parents[0] >= rev - 1:
229 parents = []
277 parents = []
230 else:
278 else:
231 parents = [parents[0]]
279 parents = [parents[0]]
232 parents = [(p, hexfunc(log.node(p))) for p in parents]
280 parents = [(p, hexfunc(log.node(p))) for p in parents]
233
281
234 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
282 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
235
283
236 if branch:
284 if branch:
237 self.ui.write(_("branch: %s\n") % branch)
285 self.ui.write(_("branch: %s\n") % branch)
238 for tag in self.repo.nodetags(changenode):
286 for tag in self.repo.nodetags(changenode):
239 self.ui.write(_("tag: %s\n") % tag)
287 self.ui.write(_("tag: %s\n") % tag)
240 for parent in parents:
288 for parent in parents:
241 self.ui.write(_("parent: %d:%s\n") % parent)
289 self.ui.write(_("parent: %d:%s\n") % parent)
242
290
243 if brinfo and changenode in brinfo:
291 if brinfo and changenode in brinfo:
244 br = brinfo[changenode]
292 br = brinfo[changenode]
245 self.ui.write(_("branch: %s\n") % " ".join(br))
293 self.ui.write(_("branch: %s\n") % " ".join(br))
246
294
247 if self.ui.debugflag:
295 if self.ui.debugflag:
248 self.ui.write(_("manifest: %d:%s\n") %
296 self.ui.write(_("manifest: %d:%s\n") %
249 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
297 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
250 self.ui.write(_("user: %s\n") % changes[1])
298 self.ui.write(_("user: %s\n") % changes[1])
251 self.ui.write(_("date: %s\n") % date)
299 self.ui.write(_("date: %s\n") % date)
252
300
253 if self.ui.debugflag:
301 if self.ui.debugflag:
254 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
302 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
255 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
303 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
256 files):
304 files):
257 if value:
305 if value:
258 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
306 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
259 elif changes[3] and self.ui.verbose:
307 elif changes[3] and self.ui.verbose:
260 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
308 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
261 if copies and self.ui.verbose:
309 if copies and self.ui.verbose:
262 copies = ['%s (%s)' % c for c in copies]
310 copies = ['%s (%s)' % c for c in copies]
263 self.ui.write(_("copies: %s\n") % ' '.join(copies))
311 self.ui.write(_("copies: %s\n") % ' '.join(copies))
264
312
265 if extra and self.ui.debugflag:
313 if extra and self.ui.debugflag:
266 extraitems = extra.items()
314 extraitems = extra.items()
267 extraitems.sort()
315 extraitems.sort()
268 for key, value in extraitems:
316 for key, value in extraitems:
269 self.ui.write(_("extra: %s=%s\n")
317 self.ui.write(_("extra: %s=%s\n")
270 % (key, value.encode('string_escape')))
318 % (key, value.encode('string_escape')))
271
319
272 description = changes[4].strip()
320 description = changes[4].strip()
273 if description:
321 if description:
274 if self.ui.verbose:
322 if self.ui.verbose:
275 self.ui.write(_("description:\n"))
323 self.ui.write(_("description:\n"))
276 self.ui.write(description)
324 self.ui.write(description)
277 self.ui.write("\n\n")
325 self.ui.write("\n\n")
278 else:
326 else:
279 self.ui.write(_("summary: %s\n") %
327 self.ui.write(_("summary: %s\n") %
280 description.splitlines()[0])
328 description.splitlines()[0])
281 self.ui.write("\n")
329 self.ui.write("\n")
282
330
283 class changeset_templater(object):
331 self.showpatch(changenode)
332
333 def showpatch(self, node):
334 if self.patch:
335 prev = self.repo.changelog.parents(node)[0]
336 patch.diff(self.repo, prev, node, fp=self.ui)
337 self.ui.write("\n")
338
339 class changeset_templater(changeset_printer):
284 '''format changeset information.'''
340 '''format changeset information.'''
285
341
286 def __init__(self, ui, repo, mapfile, dest=None):
342 def __init__(self, ui, repo, patch, mapfile, buffered):
343 changeset_printer.__init__(self, ui, repo, patch, buffered)
287 self.t = templater.templater(mapfile, templater.common_filters,
344 self.t = templater.templater(mapfile, templater.common_filters,
288 cache={'parent': '{rev}:{node|short} ',
345 cache={'parent': '{rev}:{node|short} ',
289 'manifest': '{rev}:{node|short}',
346 'manifest': '{rev}:{node|short}',
290 'filecopy': '{name} ({source})'})
347 'filecopy': '{name} ({source})'})
291 self.ui = ui
292 self.dest = dest
293 self.repo = repo
294
348
295 def use_template(self, t):
349 def use_template(self, t):
296 '''set template string to use'''
350 '''set template string to use'''
297 self.t.cache['changeset'] = t
351 self.t.cache['changeset'] = t
298
352
299 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
353 def show(self, rev=0, changenode=None, brinfo=None, copies=[], **props):
300 '''show a single changeset or file revision'''
354 '''show a single changeset or file revision'''
355 if self.buffered:
356 self.ui.mark(rev)
301 log = self.repo.changelog
357 log = self.repo.changelog
302 if changenode is None:
358 if changenode is None:
303 changenode = log.node(rev)
359 changenode = log.node(rev)
304 elif not rev:
360 elif not rev:
305 rev = log.rev(changenode)
361 rev = log.rev(changenode)
306
362
307 changes = log.read(changenode)
363 changes = log.read(changenode)
308
364
309 def showlist(name, values, plural=None, **args):
365 def showlist(name, values, plural=None, **args):
310 '''expand set of values.
366 '''expand set of values.
311 name is name of key in template map.
367 name is name of key in template map.
312 values is list of strings or dicts.
368 values is list of strings or dicts.
313 plural is plural of name, if not simply name + 's'.
369 plural is plural of name, if not simply name + 's'.
314
370
315 expansion works like this, given name 'foo'.
371 expansion works like this, given name 'foo'.
316
372
317 if values is empty, expand 'no_foos'.
373 if values is empty, expand 'no_foos'.
318
374
319 if 'foo' not in template map, return values as a string,
375 if 'foo' not in template map, return values as a string,
320 joined by space.
376 joined by space.
321
377
322 expand 'start_foos'.
378 expand 'start_foos'.
323
379
324 for each value, expand 'foo'. if 'last_foo' in template
380 for each value, expand 'foo'. if 'last_foo' in template
325 map, expand it instead of 'foo' for last key.
381 map, expand it instead of 'foo' for last key.
326
382
327 expand 'end_foos'.
383 expand 'end_foos'.
328 '''
384 '''
329 if plural: names = plural
385 if plural: names = plural
330 else: names = name + 's'
386 else: names = name + 's'
331 if not values:
387 if not values:
332 noname = 'no_' + names
388 noname = 'no_' + names
333 if noname in self.t:
389 if noname in self.t:
334 yield self.t(noname, **args)
390 yield self.t(noname, **args)
335 return
391 return
336 if name not in self.t:
392 if name not in self.t:
337 if isinstance(values[0], str):
393 if isinstance(values[0], str):
338 yield ' '.join(values)
394 yield ' '.join(values)
339 else:
395 else:
340 for v in values:
396 for v in values:
341 yield dict(v, **args)
397 yield dict(v, **args)
342 return
398 return
343 startname = 'start_' + names
399 startname = 'start_' + names
344 if startname in self.t:
400 if startname in self.t:
345 yield self.t(startname, **args)
401 yield self.t(startname, **args)
346 vargs = args.copy()
402 vargs = args.copy()
347 def one(v, tag=name):
403 def one(v, tag=name):
348 try:
404 try:
349 vargs.update(v)
405 vargs.update(v)
350 except (AttributeError, ValueError):
406 except (AttributeError, ValueError):
351 try:
407 try:
352 for a, b in v:
408 for a, b in v:
353 vargs[a] = b
409 vargs[a] = b
354 except ValueError:
410 except ValueError:
355 vargs[name] = v
411 vargs[name] = v
356 return self.t(tag, **vargs)
412 return self.t(tag, **vargs)
357 lastname = 'last_' + name
413 lastname = 'last_' + name
358 if lastname in self.t:
414 if lastname in self.t:
359 last = values.pop()
415 last = values.pop()
360 else:
416 else:
361 last = None
417 last = None
362 for v in values:
418 for v in values:
363 yield one(v)
419 yield one(v)
364 if last is not None:
420 if last is not None:
365 yield one(last, tag=lastname)
421 yield one(last, tag=lastname)
366 endname = 'end_' + names
422 endname = 'end_' + names
367 if endname in self.t:
423 if endname in self.t:
368 yield self.t(endname, **args)
424 yield self.t(endname, **args)
369
425
370 def showbranches(**args):
426 def showbranches(**args):
371 branch = changes[5].get("branch")
427 branch = changes[5].get("branch")
372 if branch:
428 if branch:
373 yield showlist('branch', [branch], plural='branches', **args)
429 yield showlist('branch', [branch], plural='branches', **args)
374 # add old style branches if requested
430 # add old style branches if requested
375 if brinfo and changenode in brinfo:
431 if brinfo and changenode in brinfo:
376 yield showlist('branch', brinfo[changenode],
432 yield showlist('branch', brinfo[changenode],
377 plural='branches', **args)
433 plural='branches', **args)
378
434
379 def showparents(**args):
435 def showparents(**args):
380 parents = [[('rev', log.rev(p)), ('node', hex(p))]
436 parents = [[('rev', log.rev(p)), ('node', hex(p))]
381 for p in log.parents(changenode)
437 for p in log.parents(changenode)
382 if self.ui.debugflag or p != nullid]
438 if self.ui.debugflag or p != nullid]
383 if (not self.ui.debugflag and len(parents) == 1 and
439 if (not self.ui.debugflag and len(parents) == 1 and
384 parents[0][0][1] == rev - 1):
440 parents[0][0][1] == rev - 1):
385 return
441 return
386 return showlist('parent', parents, **args)
442 return showlist('parent', parents, **args)
387
443
388 def showtags(**args):
444 def showtags(**args):
389 return showlist('tag', self.repo.nodetags(changenode), **args)
445 return showlist('tag', self.repo.nodetags(changenode), **args)
390
446
391 def showextras(**args):
447 def showextras(**args):
392 extras = changes[5].items()
448 extras = changes[5].items()
393 extras.sort()
449 extras.sort()
394 for key, value in extras:
450 for key, value in extras:
395 args = args.copy()
451 args = args.copy()
396 args.update(dict(key=key, value=value))
452 args.update(dict(key=key, value=value))
397 yield self.t('extra', **args)
453 yield self.t('extra', **args)
398
454
399 def showcopies(**args):
455 def showcopies(**args):
400 c = [{'name': x[0], 'source': x[1]} for x in copies]
456 c = [{'name': x[0], 'source': x[1]} for x in copies]
401 return showlist('file_copy', c, plural='file_copies', **args)
457 return showlist('file_copy', c, plural='file_copies', **args)
402
458
403 if self.ui.debugflag:
459 if self.ui.debugflag:
404 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
460 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
405 def showfiles(**args):
461 def showfiles(**args):
406 return showlist('file', files[0], **args)
462 return showlist('file', files[0], **args)
407 def showadds(**args):
463 def showadds(**args):
408 return showlist('file_add', files[1], **args)
464 return showlist('file_add', files[1], **args)
409 def showdels(**args):
465 def showdels(**args):
410 return showlist('file_del', files[2], **args)
466 return showlist('file_del', files[2], **args)
411 def showmanifest(**args):
467 def showmanifest(**args):
412 args = args.copy()
468 args = args.copy()
413 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
469 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
414 node=hex(changes[0])))
470 node=hex(changes[0])))
415 return self.t('manifest', **args)
471 return self.t('manifest', **args)
416 else:
472 else:
417 def showfiles(**args):
473 def showfiles(**args):
418 yield showlist('file', changes[3], **args)
474 yield showlist('file', changes[3], **args)
419 showadds = ''
475 showadds = ''
420 showdels = ''
476 showdels = ''
421 showmanifest = ''
477 showmanifest = ''
422
478
423 defprops = {
479 defprops = {
424 'author': changes[1],
480 'author': changes[1],
425 'branches': showbranches,
481 'branches': showbranches,
426 'date': changes[2],
482 'date': changes[2],
427 'desc': changes[4],
483 'desc': changes[4],
428 'file_adds': showadds,
484 'file_adds': showadds,
429 'file_dels': showdels,
485 'file_dels': showdels,
430 'files': showfiles,
486 'files': showfiles,
431 'file_copies': showcopies,
487 'file_copies': showcopies,
432 'manifest': showmanifest,
488 'manifest': showmanifest,
433 'node': hex(changenode),
489 'node': hex(changenode),
434 'parents': showparents,
490 'parents': showparents,
435 'rev': rev,
491 'rev': rev,
436 'tags': showtags,
492 'tags': showtags,
437 'extras': showextras,
493 'extras': showextras,
438 }
494 }
439 props = props.copy()
495 props = props.copy()
440 props.update(defprops)
496 props.update(defprops)
441
497
442 try:
498 try:
443 dest = self.dest or self.ui
444 if self.ui.debugflag and 'header_debug' in self.t:
499 if self.ui.debugflag and 'header_debug' in self.t:
445 key = 'header_debug'
500 key = 'header_debug'
446 elif self.ui.quiet and 'header_quiet' in self.t:
501 elif self.ui.quiet and 'header_quiet' in self.t:
447 key = 'header_quiet'
502 key = 'header_quiet'
448 elif self.ui.verbose and 'header_verbose' in self.t:
503 elif self.ui.verbose and 'header_verbose' in self.t:
449 key = 'header_verbose'
504 key = 'header_verbose'
450 elif 'header' in self.t:
505 elif 'header' in self.t:
451 key = 'header'
506 key = 'header'
452 else:
507 else:
453 key = ''
508 key = ''
454 if key:
509 if key:
455 dest.write_header(templater.stringify(self.t(key, **props)))
510 h = templater.stringify(self.t(key, **props))
511 if self.buffered:
512 self.ui.write_header(h)
513 else:
514 self.ui.write(h)
456 if self.ui.debugflag and 'changeset_debug' in self.t:
515 if self.ui.debugflag and 'changeset_debug' in self.t:
457 key = 'changeset_debug'
516 key = 'changeset_debug'
458 elif self.ui.quiet and 'changeset_quiet' in self.t:
517 elif self.ui.quiet and 'changeset_quiet' in self.t:
459 key = 'changeset_quiet'
518 key = 'changeset_quiet'
460 elif self.ui.verbose and 'changeset_verbose' in self.t:
519 elif self.ui.verbose and 'changeset_verbose' in self.t:
461 key = 'changeset_verbose'
520 key = 'changeset_verbose'
462 else:
521 else:
463 key = 'changeset'
522 key = 'changeset'
464 dest.write(templater.stringify(self.t(key, **props)))
523 self.ui.write(templater.stringify(self.t(key, **props)))
524 self.showpatch(changenode)
465 except KeyError, inst:
525 except KeyError, inst:
466 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
526 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
467 inst.args[0]))
527 inst.args[0]))
468 except SyntaxError, inst:
528 except SyntaxError, inst:
469 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
529 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
470
530
471 class stringio(object):
531 class stringio(object):
472 '''wrap cStringIO for use by changeset_templater.'''
532 '''wrap cStringIO for use by changeset_templater.'''
473 def __init__(self):
533 def __init__(self):
474 self.fp = cStringIO.StringIO()
534 self.fp = cStringIO.StringIO()
475
535
476 def write(self, *args):
536 def write(self, *args):
477 for a in args:
537 for a in args:
478 self.fp.write(a)
538 self.fp.write(a)
479
539
480 write_header = write
540 write_header = write
481
541
482 def __getattr__(self, key):
542 def __getattr__(self, key):
483 return getattr(self.fp, key)
543 return getattr(self.fp, key)
484
544
485 def show_changeset(ui, repo, opts):
545 def show_changeset(ui, repo, opts, buffered=False):
486 """show one changeset using template or regular display.
546 """show one changeset using template or regular display.
487
547
488 Display format will be the first non-empty hit of:
548 Display format will be the first non-empty hit of:
489 1. option 'template'
549 1. option 'template'
490 2. option 'style'
550 2. option 'style'
491 3. [ui] setting 'logtemplate'
551 3. [ui] setting 'logtemplate'
492 4. [ui] setting 'style'
552 4. [ui] setting 'style'
493 If all of these values are either the unset or the empty string,
553 If all of these values are either the unset or the empty string,
494 regular display via changeset_printer() is done.
554 regular display via changeset_printer() is done.
495 """
555 """
496 # options
556 # options
557 patch = opts.get('patch')
497 tmpl = opts.get('template')
558 tmpl = opts.get('template')
498 mapfile = None
559 mapfile = None
499 if tmpl:
560 if tmpl:
500 tmpl = templater.parsestring(tmpl, quoted=False)
561 tmpl = templater.parsestring(tmpl, quoted=False)
501 else:
562 else:
502 mapfile = opts.get('style')
563 mapfile = opts.get('style')
503 # ui settings
564 # ui settings
504 if not mapfile:
565 if not mapfile:
505 tmpl = ui.config('ui', 'logtemplate')
566 tmpl = ui.config('ui', 'logtemplate')
506 if tmpl:
567 if tmpl:
507 tmpl = templater.parsestring(tmpl)
568 tmpl = templater.parsestring(tmpl)
508 else:
569 else:
509 mapfile = ui.config('ui', 'style')
570 mapfile = ui.config('ui', 'style')
510
571
511 if tmpl or mapfile:
572 if tmpl or mapfile:
512 if mapfile:
573 if mapfile:
513 if not os.path.split(mapfile)[0]:
574 if not os.path.split(mapfile)[0]:
514 mapname = (templater.templatepath('map-cmdline.' + mapfile)
575 mapname = (templater.templatepath('map-cmdline.' + mapfile)
515 or templater.templatepath(mapfile))
576 or templater.templatepath(mapfile))
516 if mapname: mapfile = mapname
577 if mapname: mapfile = mapname
517 try:
578 try:
518 t = changeset_templater(ui, repo, mapfile)
579 t = changeset_templater(ui, repo, patch, mapfile, buffered)
519 except SyntaxError, inst:
580 except SyntaxError, inst:
520 raise util.Abort(inst.args[0])
581 raise util.Abort(inst.args[0])
521 if tmpl: t.use_template(tmpl)
582 if tmpl: t.use_template(tmpl)
522 return t
583 return t
523 return changeset_printer(ui, repo)
584 return changeset_printer(ui, repo, patch, buffered)
524
585
@@ -1,3413 +1,3359 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal imp urllib pdb shlex")
11 demandload(globals(), "os re sys signal imp urllib pdb shlex")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog bundlerepo")
13 demandload(globals(), "difflib patch tempfile time")
13 demandload(globals(), "difflib patch tempfile time")
14 demandload(globals(), "traceback errno version atexit bz2")
14 demandload(globals(), "traceback errno version atexit bz2")
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
15 demandload(globals(), "archival changegroup cmdutil hgweb.server sshserver")
16
16
17 class UnknownCommand(Exception):
17 class UnknownCommand(Exception):
18 """Exception raised if command is not in the command table."""
18 """Exception raised if command is not in the command table."""
19 class AmbiguousCommand(Exception):
19 class AmbiguousCommand(Exception):
20 """Exception raised if command shortcut matches more than one command."""
20 """Exception raised if command shortcut matches more than one command."""
21
21
22 def bail_if_changed(repo):
22 def bail_if_changed(repo):
23 modified, added, removed, deleted = repo.status()[:4]
23 modified, added, removed, deleted = repo.status()[:4]
24 if modified or added or removed or deleted:
24 if modified or added or removed or deleted:
25 raise util.Abort(_("outstanding uncommitted changes"))
25 raise util.Abort(_("outstanding uncommitted changes"))
26
26
27 def relpath(repo, args):
27 def relpath(repo, args):
28 cwd = repo.getcwd()
28 cwd = repo.getcwd()
29 if cwd:
29 if cwd:
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
30 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return args
31 return args
32
32
33 def logmessage(opts):
33 def logmessage(opts):
34 """ get the log message according to -m and -l option """
34 """ get the log message according to -m and -l option """
35 message = opts['message']
35 message = opts['message']
36 logfile = opts['logfile']
36 logfile = opts['logfile']
37
37
38 if message and logfile:
38 if message and logfile:
39 raise util.Abort(_('options --message and --logfile are mutually '
39 raise util.Abort(_('options --message and --logfile are mutually '
40 'exclusive'))
40 'exclusive'))
41 if not message and logfile:
41 if not message and logfile:
42 try:
42 try:
43 if logfile == '-':
43 if logfile == '-':
44 message = sys.stdin.read()
44 message = sys.stdin.read()
45 else:
45 else:
46 message = open(logfile).read()
46 message = open(logfile).read()
47 except IOError, inst:
47 except IOError, inst:
48 raise util.Abort(_("can't read commit message '%s': %s") %
48 raise util.Abort(_("can't read commit message '%s': %s") %
49 (logfile, inst.strerror))
49 (logfile, inst.strerror))
50 return message
50 return message
51
51
52 def walkchangerevs(ui, repo, pats, change, opts):
52 def walkchangerevs(ui, repo, pats, change, opts):
53 '''Iterate over files and the revs they changed in.
53 '''Iterate over files and the revs they changed in.
54
54
55 Callers most commonly need to iterate backwards over the history
55 Callers most commonly need to iterate backwards over the history
56 it is interested in. Doing so has awful (quadratic-looking)
56 it is interested in. Doing so has awful (quadratic-looking)
57 performance, so we use iterators in a "windowed" way.
57 performance, so we use iterators in a "windowed" way.
58
58
59 We walk a window of revisions in the desired order. Within the
59 We walk a window of revisions in the desired order. Within the
60 window, we first walk forwards to gather data, then in the desired
60 window, we first walk forwards to gather data, then in the desired
61 order (usually backwards) to display it.
61 order (usually backwards) to display it.
62
62
63 This function returns an (iterator, matchfn) tuple. The iterator
63 This function returns an (iterator, matchfn) tuple. The iterator
64 yields 3-tuples. They will be of one of the following forms:
64 yields 3-tuples. They will be of one of the following forms:
65
65
66 "window", incrementing, lastrev: stepping through a window,
66 "window", incrementing, lastrev: stepping through a window,
67 positive if walking forwards through revs, last rev in the
67 positive if walking forwards through revs, last rev in the
68 sequence iterated over - use to reset state for the current window
68 sequence iterated over - use to reset state for the current window
69
69
70 "add", rev, fns: out-of-order traversal of the given file names
70 "add", rev, fns: out-of-order traversal of the given file names
71 fns, which changed during revision rev - use to gather data for
71 fns, which changed during revision rev - use to gather data for
72 possible display
72 possible display
73
73
74 "iter", rev, None: in-order traversal of the revs earlier iterated
74 "iter", rev, None: in-order traversal of the revs earlier iterated
75 over with "add" - use to display data'''
75 over with "add" - use to display data'''
76
76
77 def increasing_windows(start, end, windowsize=8, sizelimit=512):
77 def increasing_windows(start, end, windowsize=8, sizelimit=512):
78 if start < end:
78 if start < end:
79 while start < end:
79 while start < end:
80 yield start, min(windowsize, end-start)
80 yield start, min(windowsize, end-start)
81 start += windowsize
81 start += windowsize
82 if windowsize < sizelimit:
82 if windowsize < sizelimit:
83 windowsize *= 2
83 windowsize *= 2
84 else:
84 else:
85 while start > end:
85 while start > end:
86 yield start, min(windowsize, start-end-1)
86 yield start, min(windowsize, start-end-1)
87 start -= windowsize
87 start -= windowsize
88 if windowsize < sizelimit:
88 if windowsize < sizelimit:
89 windowsize *= 2
89 windowsize *= 2
90
90
91 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
91 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
92 follow = opts.get('follow') or opts.get('follow_first')
92 follow = opts.get('follow') or opts.get('follow_first')
93
93
94 if repo.changelog.count() == 0:
94 if repo.changelog.count() == 0:
95 return [], matchfn
95 return [], matchfn
96
96
97 if follow:
97 if follow:
98 defrange = '%s:0' % repo.changectx().rev()
98 defrange = '%s:0' % repo.changectx().rev()
99 else:
99 else:
100 defrange = 'tip:0'
100 defrange = 'tip:0'
101 revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
101 revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
102 wanted = {}
102 wanted = {}
103 slowpath = anypats
103 slowpath = anypats
104 fncache = {}
104 fncache = {}
105
105
106 if not slowpath and not files:
106 if not slowpath and not files:
107 # No files, no patterns. Display all revs.
107 # No files, no patterns. Display all revs.
108 wanted = dict.fromkeys(revs)
108 wanted = dict.fromkeys(revs)
109 copies = []
109 copies = []
110 if not slowpath:
110 if not slowpath:
111 # Only files, no patterns. Check the history of each file.
111 # Only files, no patterns. Check the history of each file.
112 def filerevgen(filelog, node):
112 def filerevgen(filelog, node):
113 cl_count = repo.changelog.count()
113 cl_count = repo.changelog.count()
114 if node is None:
114 if node is None:
115 last = filelog.count() - 1
115 last = filelog.count() - 1
116 else:
116 else:
117 last = filelog.rev(node)
117 last = filelog.rev(node)
118 for i, window in increasing_windows(last, nullrev):
118 for i, window in increasing_windows(last, nullrev):
119 revs = []
119 revs = []
120 for j in xrange(i - window, i + 1):
120 for j in xrange(i - window, i + 1):
121 n = filelog.node(j)
121 n = filelog.node(j)
122 revs.append((filelog.linkrev(n),
122 revs.append((filelog.linkrev(n),
123 follow and filelog.renamed(n)))
123 follow and filelog.renamed(n)))
124 revs.reverse()
124 revs.reverse()
125 for rev in revs:
125 for rev in revs:
126 # only yield rev for which we have the changelog, it can
126 # only yield rev for which we have the changelog, it can
127 # happen while doing "hg log" during a pull or commit
127 # happen while doing "hg log" during a pull or commit
128 if rev[0] < cl_count:
128 if rev[0] < cl_count:
129 yield rev
129 yield rev
130 def iterfiles():
130 def iterfiles():
131 for filename in files:
131 for filename in files:
132 yield filename, None
132 yield filename, None
133 for filename_node in copies:
133 for filename_node in copies:
134 yield filename_node
134 yield filename_node
135 minrev, maxrev = min(revs), max(revs)
135 minrev, maxrev = min(revs), max(revs)
136 for file_, node in iterfiles():
136 for file_, node in iterfiles():
137 filelog = repo.file(file_)
137 filelog = repo.file(file_)
138 # A zero count may be a directory or deleted file, so
138 # A zero count may be a directory or deleted file, so
139 # try to find matching entries on the slow path.
139 # try to find matching entries on the slow path.
140 if filelog.count() == 0:
140 if filelog.count() == 0:
141 slowpath = True
141 slowpath = True
142 break
142 break
143 for rev, copied in filerevgen(filelog, node):
143 for rev, copied in filerevgen(filelog, node):
144 if rev <= maxrev:
144 if rev <= maxrev:
145 if rev < minrev:
145 if rev < minrev:
146 break
146 break
147 fncache.setdefault(rev, [])
147 fncache.setdefault(rev, [])
148 fncache[rev].append(file_)
148 fncache[rev].append(file_)
149 wanted[rev] = 1
149 wanted[rev] = 1
150 if follow and copied:
150 if follow and copied:
151 copies.append(copied)
151 copies.append(copied)
152 if slowpath:
152 if slowpath:
153 if follow:
153 if follow:
154 raise util.Abort(_('can only follow copies/renames for explicit '
154 raise util.Abort(_('can only follow copies/renames for explicit '
155 'file names'))
155 'file names'))
156
156
157 # The slow path checks files modified in every changeset.
157 # The slow path checks files modified in every changeset.
158 def changerevgen():
158 def changerevgen():
159 for i, window in increasing_windows(repo.changelog.count()-1,
159 for i, window in increasing_windows(repo.changelog.count()-1,
160 nullrev):
160 nullrev):
161 for j in xrange(i - window, i + 1):
161 for j in xrange(i - window, i + 1):
162 yield j, change(j)[3]
162 yield j, change(j)[3]
163
163
164 for rev, changefiles in changerevgen():
164 for rev, changefiles in changerevgen():
165 matches = filter(matchfn, changefiles)
165 matches = filter(matchfn, changefiles)
166 if matches:
166 if matches:
167 fncache[rev] = matches
167 fncache[rev] = matches
168 wanted[rev] = 1
168 wanted[rev] = 1
169
169
170 class followfilter:
170 class followfilter:
171 def __init__(self, onlyfirst=False):
171 def __init__(self, onlyfirst=False):
172 self.startrev = nullrev
172 self.startrev = nullrev
173 self.roots = []
173 self.roots = []
174 self.onlyfirst = onlyfirst
174 self.onlyfirst = onlyfirst
175
175
176 def match(self, rev):
176 def match(self, rev):
177 def realparents(rev):
177 def realparents(rev):
178 if self.onlyfirst:
178 if self.onlyfirst:
179 return repo.changelog.parentrevs(rev)[0:1]
179 return repo.changelog.parentrevs(rev)[0:1]
180 else:
180 else:
181 return filter(lambda x: x != nullrev,
181 return filter(lambda x: x != nullrev,
182 repo.changelog.parentrevs(rev))
182 repo.changelog.parentrevs(rev))
183
183
184 if self.startrev == nullrev:
184 if self.startrev == nullrev:
185 self.startrev = rev
185 self.startrev = rev
186 return True
186 return True
187
187
188 if rev > self.startrev:
188 if rev > self.startrev:
189 # forward: all descendants
189 # forward: all descendants
190 if not self.roots:
190 if not self.roots:
191 self.roots.append(self.startrev)
191 self.roots.append(self.startrev)
192 for parent in realparents(rev):
192 for parent in realparents(rev):
193 if parent in self.roots:
193 if parent in self.roots:
194 self.roots.append(rev)
194 self.roots.append(rev)
195 return True
195 return True
196 else:
196 else:
197 # backwards: all parents
197 # backwards: all parents
198 if not self.roots:
198 if not self.roots:
199 self.roots.extend(realparents(self.startrev))
199 self.roots.extend(realparents(self.startrev))
200 if rev in self.roots:
200 if rev in self.roots:
201 self.roots.remove(rev)
201 self.roots.remove(rev)
202 self.roots.extend(realparents(rev))
202 self.roots.extend(realparents(rev))
203 return True
203 return True
204
204
205 return False
205 return False
206
206
207 # it might be worthwhile to do this in the iterator if the rev range
207 # it might be worthwhile to do this in the iterator if the rev range
208 # is descending and the prune args are all within that range
208 # is descending and the prune args are all within that range
209 for rev in opts.get('prune', ()):
209 for rev in opts.get('prune', ()):
210 rev = repo.changelog.rev(repo.lookup(rev))
210 rev = repo.changelog.rev(repo.lookup(rev))
211 ff = followfilter()
211 ff = followfilter()
212 stop = min(revs[0], revs[-1])
212 stop = min(revs[0], revs[-1])
213 for x in xrange(rev, stop-1, -1):
213 for x in xrange(rev, stop-1, -1):
214 if ff.match(x) and x in wanted:
214 if ff.match(x) and x in wanted:
215 del wanted[x]
215 del wanted[x]
216
216
217 def iterate():
217 def iterate():
218 if follow and not files:
218 if follow and not files:
219 ff = followfilter(onlyfirst=opts.get('follow_first'))
219 ff = followfilter(onlyfirst=opts.get('follow_first'))
220 def want(rev):
220 def want(rev):
221 if ff.match(rev) and rev in wanted:
221 if ff.match(rev) and rev in wanted:
222 return True
222 return True
223 return False
223 return False
224 else:
224 else:
225 def want(rev):
225 def want(rev):
226 return rev in wanted
226 return rev in wanted
227
227
228 for i, window in increasing_windows(0, len(revs)):
228 for i, window in increasing_windows(0, len(revs)):
229 yield 'window', revs[0] < revs[-1], revs[-1]
229 yield 'window', revs[0] < revs[-1], revs[-1]
230 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
230 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
231 srevs = list(nrevs)
231 srevs = list(nrevs)
232 srevs.sort()
232 srevs.sort()
233 for rev in srevs:
233 for rev in srevs:
234 fns = fncache.get(rev)
234 fns = fncache.get(rev)
235 if not fns:
235 if not fns:
236 def fns_generator():
236 def fns_generator():
237 for f in change(rev)[3]:
237 for f in change(rev)[3]:
238 if matchfn(f):
238 if matchfn(f):
239 yield f
239 yield f
240 fns = fns_generator()
240 fns = fns_generator()
241 yield 'add', rev, fns
241 yield 'add', rev, fns
242 for rev in nrevs:
242 for rev in nrevs:
243 yield 'iter', rev, None
243 yield 'iter', rev, None
244 return iterate(), matchfn
244 return iterate(), matchfn
245
245
246 def write_bundle(cg, filename=None, compress=True):
246 def write_bundle(cg, filename=None, compress=True):
247 """Write a bundle file and return its filename.
247 """Write a bundle file and return its filename.
248
248
249 Existing files will not be overwritten.
249 Existing files will not be overwritten.
250 If no filename is specified, a temporary file is created.
250 If no filename is specified, a temporary file is created.
251 bz2 compression can be turned off.
251 bz2 compression can be turned off.
252 The bundle file will be deleted in case of errors.
252 The bundle file will be deleted in case of errors.
253 """
253 """
254 class nocompress(object):
254 class nocompress(object):
255 def compress(self, x):
255 def compress(self, x):
256 return x
256 return x
257 def flush(self):
257 def flush(self):
258 return ""
258 return ""
259
259
260 fh = None
260 fh = None
261 cleanup = None
261 cleanup = None
262 try:
262 try:
263 if filename:
263 if filename:
264 if os.path.exists(filename):
264 if os.path.exists(filename):
265 raise util.Abort(_("file '%s' already exists") % filename)
265 raise util.Abort(_("file '%s' already exists") % filename)
266 fh = open(filename, "wb")
266 fh = open(filename, "wb")
267 else:
267 else:
268 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
268 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
269 fh = os.fdopen(fd, "wb")
269 fh = os.fdopen(fd, "wb")
270 cleanup = filename
270 cleanup = filename
271
271
272 if compress:
272 if compress:
273 fh.write("HG10")
273 fh.write("HG10")
274 z = bz2.BZ2Compressor(9)
274 z = bz2.BZ2Compressor(9)
275 else:
275 else:
276 fh.write("HG10UN")
276 fh.write("HG10UN")
277 z = nocompress()
277 z = nocompress()
278 # parse the changegroup data, otherwise we will block
278 # parse the changegroup data, otherwise we will block
279 # in case of sshrepo because we don't know the end of the stream
279 # in case of sshrepo because we don't know the end of the stream
280
280
281 # an empty chunkiter is the end of the changegroup
281 # an empty chunkiter is the end of the changegroup
282 empty = False
282 empty = False
283 while not empty:
283 while not empty:
284 empty = True
284 empty = True
285 for chunk in changegroup.chunkiter(cg):
285 for chunk in changegroup.chunkiter(cg):
286 empty = False
286 empty = False
287 fh.write(z.compress(changegroup.genchunk(chunk)))
287 fh.write(z.compress(changegroup.genchunk(chunk)))
288 fh.write(z.compress(changegroup.closechunk()))
288 fh.write(z.compress(changegroup.closechunk()))
289 fh.write(z.flush())
289 fh.write(z.flush())
290 cleanup = None
290 cleanup = None
291 return filename
291 return filename
292 finally:
292 finally:
293 if fh is not None:
293 if fh is not None:
294 fh.close()
294 fh.close()
295 if cleanup is not None:
295 if cleanup is not None:
296 os.unlink(cleanup)
296 os.unlink(cleanup)
297
297
298 def setremoteconfig(ui, opts):
298 def setremoteconfig(ui, opts):
299 "copy remote options to ui tree"
299 "copy remote options to ui tree"
300 if opts.get('ssh'):
300 if opts.get('ssh'):
301 ui.setconfig("ui", "ssh", opts['ssh'])
301 ui.setconfig("ui", "ssh", opts['ssh'])
302 if opts.get('remotecmd'):
302 if opts.get('remotecmd'):
303 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
303 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
304
304
305 def show_version(ui):
305 def show_version(ui):
306 """output version and copyright information"""
306 """output version and copyright information"""
307 ui.write(_("Mercurial Distributed SCM (version %s)\n")
307 ui.write(_("Mercurial Distributed SCM (version %s)\n")
308 % version.get_version())
308 % version.get_version())
309 ui.status(_(
309 ui.status(_(
310 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
310 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
311 "This is free software; see the source for copying conditions. "
311 "This is free software; see the source for copying conditions. "
312 "There is NO\nwarranty; "
312 "There is NO\nwarranty; "
313 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
313 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
314 ))
314 ))
315
315
316 def help_(ui, name=None, with_version=False):
316 def help_(ui, name=None, with_version=False):
317 """show help for a command, extension, or list of commands
317 """show help for a command, extension, or list of commands
318
318
319 With no arguments, print a list of commands and short help.
319 With no arguments, print a list of commands and short help.
320
320
321 Given a command name, print help for that command.
321 Given a command name, print help for that command.
322
322
323 Given an extension name, print help for that extension, and the
323 Given an extension name, print help for that extension, and the
324 commands it provides."""
324 commands it provides."""
325 option_lists = []
325 option_lists = []
326
326
327 def helpcmd(name):
327 def helpcmd(name):
328 if with_version:
328 if with_version:
329 show_version(ui)
329 show_version(ui)
330 ui.write('\n')
330 ui.write('\n')
331 aliases, i = findcmd(ui, name)
331 aliases, i = findcmd(ui, name)
332 # synopsis
332 # synopsis
333 ui.write("%s\n\n" % i[2])
333 ui.write("%s\n\n" % i[2])
334
334
335 # description
335 # description
336 doc = i[0].__doc__
336 doc = i[0].__doc__
337 if not doc:
337 if not doc:
338 doc = _("(No help text available)")
338 doc = _("(No help text available)")
339 if ui.quiet:
339 if ui.quiet:
340 doc = doc.splitlines(0)[0]
340 doc = doc.splitlines(0)[0]
341 ui.write("%s\n" % doc.rstrip())
341 ui.write("%s\n" % doc.rstrip())
342
342
343 if not ui.quiet:
343 if not ui.quiet:
344 # aliases
344 # aliases
345 if len(aliases) > 1:
345 if len(aliases) > 1:
346 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
346 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
347
347
348 # options
348 # options
349 if i[1]:
349 if i[1]:
350 option_lists.append(("options", i[1]))
350 option_lists.append(("options", i[1]))
351
351
352 def helplist(select=None):
352 def helplist(select=None):
353 h = {}
353 h = {}
354 cmds = {}
354 cmds = {}
355 for c, e in table.items():
355 for c, e in table.items():
356 f = c.split("|", 1)[0]
356 f = c.split("|", 1)[0]
357 if select and not select(f):
357 if select and not select(f):
358 continue
358 continue
359 if name == "shortlist" and not f.startswith("^"):
359 if name == "shortlist" and not f.startswith("^"):
360 continue
360 continue
361 f = f.lstrip("^")
361 f = f.lstrip("^")
362 if not ui.debugflag and f.startswith("debug"):
362 if not ui.debugflag and f.startswith("debug"):
363 continue
363 continue
364 doc = e[0].__doc__
364 doc = e[0].__doc__
365 if not doc:
365 if not doc:
366 doc = _("(No help text available)")
366 doc = _("(No help text available)")
367 h[f] = doc.splitlines(0)[0].rstrip()
367 h[f] = doc.splitlines(0)[0].rstrip()
368 cmds[f] = c.lstrip("^")
368 cmds[f] = c.lstrip("^")
369
369
370 fns = h.keys()
370 fns = h.keys()
371 fns.sort()
371 fns.sort()
372 m = max(map(len, fns))
372 m = max(map(len, fns))
373 for f in fns:
373 for f in fns:
374 if ui.verbose:
374 if ui.verbose:
375 commands = cmds[f].replace("|",", ")
375 commands = cmds[f].replace("|",", ")
376 ui.write(" %s:\n %s\n"%(commands, h[f]))
376 ui.write(" %s:\n %s\n"%(commands, h[f]))
377 else:
377 else:
378 ui.write(' %-*s %s\n' % (m, f, h[f]))
378 ui.write(' %-*s %s\n' % (m, f, h[f]))
379
379
380 def helpext(name):
380 def helpext(name):
381 try:
381 try:
382 mod = findext(name)
382 mod = findext(name)
383 except KeyError:
383 except KeyError:
384 raise UnknownCommand(name)
384 raise UnknownCommand(name)
385
385
386 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
386 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
387 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
387 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
388 for d in doc[1:]:
388 for d in doc[1:]:
389 ui.write(d, '\n')
389 ui.write(d, '\n')
390
390
391 ui.status('\n')
391 ui.status('\n')
392 if ui.verbose:
392 if ui.verbose:
393 ui.status(_('list of commands:\n\n'))
393 ui.status(_('list of commands:\n\n'))
394 else:
394 else:
395 ui.status(_('list of commands (use "hg help -v %s" '
395 ui.status(_('list of commands (use "hg help -v %s" '
396 'to show aliases and global options):\n\n') % name)
396 'to show aliases and global options):\n\n') % name)
397
397
398 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
398 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in mod.cmdtable])
399 helplist(modcmds.has_key)
399 helplist(modcmds.has_key)
400
400
401 if name and name != 'shortlist':
401 if name and name != 'shortlist':
402 try:
402 try:
403 helpcmd(name)
403 helpcmd(name)
404 except UnknownCommand:
404 except UnknownCommand:
405 helpext(name)
405 helpext(name)
406
406
407 else:
407 else:
408 # program name
408 # program name
409 if ui.verbose or with_version:
409 if ui.verbose or with_version:
410 show_version(ui)
410 show_version(ui)
411 else:
411 else:
412 ui.status(_("Mercurial Distributed SCM\n"))
412 ui.status(_("Mercurial Distributed SCM\n"))
413 ui.status('\n')
413 ui.status('\n')
414
414
415 # list of commands
415 # list of commands
416 if name == "shortlist":
416 if name == "shortlist":
417 ui.status(_('basic commands (use "hg help" '
417 ui.status(_('basic commands (use "hg help" '
418 'for the full list or option "-v" for details):\n\n'))
418 'for the full list or option "-v" for details):\n\n'))
419 elif ui.verbose:
419 elif ui.verbose:
420 ui.status(_('list of commands:\n\n'))
420 ui.status(_('list of commands:\n\n'))
421 else:
421 else:
422 ui.status(_('list of commands (use "hg help -v" '
422 ui.status(_('list of commands (use "hg help -v" '
423 'to show aliases and global options):\n\n'))
423 'to show aliases and global options):\n\n'))
424
424
425 helplist()
425 helplist()
426
426
427 # global options
427 # global options
428 if ui.verbose:
428 if ui.verbose:
429 option_lists.append(("global options", globalopts))
429 option_lists.append(("global options", globalopts))
430
430
431 # list all option lists
431 # list all option lists
432 opt_output = []
432 opt_output = []
433 for title, options in option_lists:
433 for title, options in option_lists:
434 opt_output.append(("\n%s:\n" % title, None))
434 opt_output.append(("\n%s:\n" % title, None))
435 for shortopt, longopt, default, desc in options:
435 for shortopt, longopt, default, desc in options:
436 if "DEPRECATED" in desc and not ui.verbose: continue
436 if "DEPRECATED" in desc and not ui.verbose: continue
437 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
437 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
438 longopt and " --%s" % longopt),
438 longopt and " --%s" % longopt),
439 "%s%s" % (desc,
439 "%s%s" % (desc,
440 default
440 default
441 and _(" (default: %s)") % default
441 and _(" (default: %s)") % default
442 or "")))
442 or "")))
443
443
444 if opt_output:
444 if opt_output:
445 opts_len = max([len(line[0]) for line in opt_output if line[1]])
445 opts_len = max([len(line[0]) for line in opt_output if line[1]])
446 for first, second in opt_output:
446 for first, second in opt_output:
447 if second:
447 if second:
448 ui.write(" %-*s %s\n" % (opts_len, first, second))
448 ui.write(" %-*s %s\n" % (opts_len, first, second))
449 else:
449 else:
450 ui.write("%s\n" % first)
450 ui.write("%s\n" % first)
451
451
452 # Commands start here, listed alphabetically
452 # Commands start here, listed alphabetically
453
453
454 def add(ui, repo, *pats, **opts):
454 def add(ui, repo, *pats, **opts):
455 """add the specified files on the next commit
455 """add the specified files on the next commit
456
456
457 Schedule files to be version controlled and added to the repository.
457 Schedule files to be version controlled and added to the repository.
458
458
459 The files will be added to the repository at the next commit.
459 The files will be added to the repository at the next commit.
460
460
461 If no names are given, add all files in the repository.
461 If no names are given, add all files in the repository.
462 """
462 """
463
463
464 names = []
464 names = []
465 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
465 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
466 if exact:
466 if exact:
467 if ui.verbose:
467 if ui.verbose:
468 ui.status(_('adding %s\n') % rel)
468 ui.status(_('adding %s\n') % rel)
469 names.append(abs)
469 names.append(abs)
470 elif repo.dirstate.state(abs) == '?':
470 elif repo.dirstate.state(abs) == '?':
471 ui.status(_('adding %s\n') % rel)
471 ui.status(_('adding %s\n') % rel)
472 names.append(abs)
472 names.append(abs)
473 if not opts.get('dry_run'):
473 if not opts.get('dry_run'):
474 repo.add(names)
474 repo.add(names)
475
475
476 def addremove(ui, repo, *pats, **opts):
476 def addremove(ui, repo, *pats, **opts):
477 """add all new files, delete all missing files
477 """add all new files, delete all missing files
478
478
479 Add all new files and remove all missing files from the repository.
479 Add all new files and remove all missing files from the repository.
480
480
481 New files are ignored if they match any of the patterns in .hgignore. As
481 New files are ignored if they match any of the patterns in .hgignore. As
482 with add, these changes take effect at the next commit.
482 with add, these changes take effect at the next commit.
483
483
484 Use the -s option to detect renamed files. With a parameter > 0,
484 Use the -s option to detect renamed files. With a parameter > 0,
485 this compares every removed file with every added file and records
485 this compares every removed file with every added file and records
486 those similar enough as renames. This option takes a percentage
486 those similar enough as renames. This option takes a percentage
487 between 0 (disabled) and 100 (files must be identical) as its
487 between 0 (disabled) and 100 (files must be identical) as its
488 parameter. Detecting renamed files this way can be expensive.
488 parameter. Detecting renamed files this way can be expensive.
489 """
489 """
490 sim = float(opts.get('similarity') or 0)
490 sim = float(opts.get('similarity') or 0)
491 if sim < 0 or sim > 100:
491 if sim < 0 or sim > 100:
492 raise util.Abort(_('similarity must be between 0 and 100'))
492 raise util.Abort(_('similarity must be between 0 and 100'))
493 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
493 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
494
494
495 def annotate(ui, repo, *pats, **opts):
495 def annotate(ui, repo, *pats, **opts):
496 """show changeset information per file line
496 """show changeset information per file line
497
497
498 List changes in files, showing the revision id responsible for each line
498 List changes in files, showing the revision id responsible for each line
499
499
500 This command is useful to discover who did a change or when a change took
500 This command is useful to discover who did a change or when a change took
501 place.
501 place.
502
502
503 Without the -a option, annotate will avoid processing files it
503 Without the -a option, annotate will avoid processing files it
504 detects as binary. With -a, annotate will generate an annotation
504 detects as binary. With -a, annotate will generate an annotation
505 anyway, probably with undesirable results.
505 anyway, probably with undesirable results.
506 """
506 """
507 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
507 getdate = util.cachefunc(lambda x: util.datestr(x.date()))
508
508
509 if not pats:
509 if not pats:
510 raise util.Abort(_('at least one file name or pattern required'))
510 raise util.Abort(_('at least one file name or pattern required'))
511
511
512 opmap = [['user', lambda x: ui.shortuser(x.user())],
512 opmap = [['user', lambda x: ui.shortuser(x.user())],
513 ['number', lambda x: str(x.rev())],
513 ['number', lambda x: str(x.rev())],
514 ['changeset', lambda x: short(x.node())],
514 ['changeset', lambda x: short(x.node())],
515 ['date', getdate], ['follow', lambda x: x.path()]]
515 ['date', getdate], ['follow', lambda x: x.path()]]
516 if (not opts['user'] and not opts['changeset'] and not opts['date']
516 if (not opts['user'] and not opts['changeset'] and not opts['date']
517 and not opts['follow']):
517 and not opts['follow']):
518 opts['number'] = 1
518 opts['number'] = 1
519
519
520 ctx = repo.changectx(opts['rev'])
520 ctx = repo.changectx(opts['rev'])
521
521
522 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
522 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
523 node=ctx.node()):
523 node=ctx.node()):
524 fctx = ctx.filectx(abs)
524 fctx = ctx.filectx(abs)
525 if not opts['text'] and util.binary(fctx.data()):
525 if not opts['text'] and util.binary(fctx.data()):
526 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
526 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
527 continue
527 continue
528
528
529 lines = fctx.annotate(follow=opts.get('follow'))
529 lines = fctx.annotate(follow=opts.get('follow'))
530 pieces = []
530 pieces = []
531
531
532 for o, f in opmap:
532 for o, f in opmap:
533 if opts[o]:
533 if opts[o]:
534 l = [f(n) for n, dummy in lines]
534 l = [f(n) for n, dummy in lines]
535 if l:
535 if l:
536 m = max(map(len, l))
536 m = max(map(len, l))
537 pieces.append(["%*s" % (m, x) for x in l])
537 pieces.append(["%*s" % (m, x) for x in l])
538
538
539 if pieces:
539 if pieces:
540 for p, l in zip(zip(*pieces), lines):
540 for p, l in zip(zip(*pieces), lines):
541 ui.write("%s: %s" % (" ".join(p), l[1]))
541 ui.write("%s: %s" % (" ".join(p), l[1]))
542
542
543 def archive(ui, repo, dest, **opts):
543 def archive(ui, repo, dest, **opts):
544 '''create unversioned archive of a repository revision
544 '''create unversioned archive of a repository revision
545
545
546 By default, the revision used is the parent of the working
546 By default, the revision used is the parent of the working
547 directory; use "-r" to specify a different revision.
547 directory; use "-r" to specify a different revision.
548
548
549 To specify the type of archive to create, use "-t". Valid
549 To specify the type of archive to create, use "-t". Valid
550 types are:
550 types are:
551
551
552 "files" (default): a directory full of files
552 "files" (default): a directory full of files
553 "tar": tar archive, uncompressed
553 "tar": tar archive, uncompressed
554 "tbz2": tar archive, compressed using bzip2
554 "tbz2": tar archive, compressed using bzip2
555 "tgz": tar archive, compressed using gzip
555 "tgz": tar archive, compressed using gzip
556 "uzip": zip archive, uncompressed
556 "uzip": zip archive, uncompressed
557 "zip": zip archive, compressed using deflate
557 "zip": zip archive, compressed using deflate
558
558
559 The exact name of the destination archive or directory is given
559 The exact name of the destination archive or directory is given
560 using a format string; see "hg help export" for details.
560 using a format string; see "hg help export" for details.
561
561
562 Each member added to an archive file has a directory prefix
562 Each member added to an archive file has a directory prefix
563 prepended. Use "-p" to specify a format string for the prefix.
563 prepended. Use "-p" to specify a format string for the prefix.
564 The default is the basename of the archive, with suffixes removed.
564 The default is the basename of the archive, with suffixes removed.
565 '''
565 '''
566
566
567 node = repo.changectx(opts['rev']).node()
567 node = repo.changectx(opts['rev']).node()
568 dest = cmdutil.make_filename(repo, dest, node)
568 dest = cmdutil.make_filename(repo, dest, node)
569 if os.path.realpath(dest) == repo.root:
569 if os.path.realpath(dest) == repo.root:
570 raise util.Abort(_('repository root cannot be destination'))
570 raise util.Abort(_('repository root cannot be destination'))
571 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
571 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts)
572 kind = opts.get('type') or 'files'
572 kind = opts.get('type') or 'files'
573 prefix = opts['prefix']
573 prefix = opts['prefix']
574 if dest == '-':
574 if dest == '-':
575 if kind == 'files':
575 if kind == 'files':
576 raise util.Abort(_('cannot archive plain files to stdout'))
576 raise util.Abort(_('cannot archive plain files to stdout'))
577 dest = sys.stdout
577 dest = sys.stdout
578 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
578 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
579 prefix = cmdutil.make_filename(repo, prefix, node)
579 prefix = cmdutil.make_filename(repo, prefix, node)
580 archival.archive(repo, dest, node, kind, not opts['no_decode'],
580 archival.archive(repo, dest, node, kind, not opts['no_decode'],
581 matchfn, prefix)
581 matchfn, prefix)
582
582
583 def backout(ui, repo, rev, **opts):
583 def backout(ui, repo, rev, **opts):
584 '''reverse effect of earlier changeset
584 '''reverse effect of earlier changeset
585
585
586 Commit the backed out changes as a new changeset. The new
586 Commit the backed out changes as a new changeset. The new
587 changeset is a child of the backed out changeset.
587 changeset is a child of the backed out changeset.
588
588
589 If you back out a changeset other than the tip, a new head is
589 If you back out a changeset other than the tip, a new head is
590 created. This head is the parent of the working directory. If
590 created. This head is the parent of the working directory. If
591 you back out an old changeset, your working directory will appear
591 you back out an old changeset, your working directory will appear
592 old after the backout. You should merge the backout changeset
592 old after the backout. You should merge the backout changeset
593 with another head.
593 with another head.
594
594
595 The --merge option remembers the parent of the working directory
595 The --merge option remembers the parent of the working directory
596 before starting the backout, then merges the new head with that
596 before starting the backout, then merges the new head with that
597 changeset afterwards. This saves you from doing the merge by
597 changeset afterwards. This saves you from doing the merge by
598 hand. The result of this merge is not committed, as for a normal
598 hand. The result of this merge is not committed, as for a normal
599 merge.'''
599 merge.'''
600
600
601 bail_if_changed(repo)
601 bail_if_changed(repo)
602 op1, op2 = repo.dirstate.parents()
602 op1, op2 = repo.dirstate.parents()
603 if op2 != nullid:
603 if op2 != nullid:
604 raise util.Abort(_('outstanding uncommitted merge'))
604 raise util.Abort(_('outstanding uncommitted merge'))
605 node = repo.lookup(rev)
605 node = repo.lookup(rev)
606 p1, p2 = repo.changelog.parents(node)
606 p1, p2 = repo.changelog.parents(node)
607 if p1 == nullid:
607 if p1 == nullid:
608 raise util.Abort(_('cannot back out a change with no parents'))
608 raise util.Abort(_('cannot back out a change with no parents'))
609 if p2 != nullid:
609 if p2 != nullid:
610 if not opts['parent']:
610 if not opts['parent']:
611 raise util.Abort(_('cannot back out a merge changeset without '
611 raise util.Abort(_('cannot back out a merge changeset without '
612 '--parent'))
612 '--parent'))
613 p = repo.lookup(opts['parent'])
613 p = repo.lookup(opts['parent'])
614 if p not in (p1, p2):
614 if p not in (p1, p2):
615 raise util.Abort(_('%s is not a parent of %s' %
615 raise util.Abort(_('%s is not a parent of %s' %
616 (short(p), short(node))))
616 (short(p), short(node))))
617 parent = p
617 parent = p
618 else:
618 else:
619 if opts['parent']:
619 if opts['parent']:
620 raise util.Abort(_('cannot use --parent on non-merge changeset'))
620 raise util.Abort(_('cannot use --parent on non-merge changeset'))
621 parent = p1
621 parent = p1
622 hg.clean(repo, node, show_stats=False)
622 hg.clean(repo, node, show_stats=False)
623 revert_opts = opts.copy()
623 revert_opts = opts.copy()
624 revert_opts['all'] = True
624 revert_opts['all'] = True
625 revert_opts['rev'] = hex(parent)
625 revert_opts['rev'] = hex(parent)
626 revert(ui, repo, **revert_opts)
626 revert(ui, repo, **revert_opts)
627 commit_opts = opts.copy()
627 commit_opts = opts.copy()
628 commit_opts['addremove'] = False
628 commit_opts['addremove'] = False
629 if not commit_opts['message'] and not commit_opts['logfile']:
629 if not commit_opts['message'] and not commit_opts['logfile']:
630 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
630 commit_opts['message'] = _("Backed out changeset %s") % (hex(node))
631 commit_opts['force_editor'] = True
631 commit_opts['force_editor'] = True
632 commit(ui, repo, **commit_opts)
632 commit(ui, repo, **commit_opts)
633 def nice(node):
633 def nice(node):
634 return '%d:%s' % (repo.changelog.rev(node), short(node))
634 return '%d:%s' % (repo.changelog.rev(node), short(node))
635 ui.status(_('changeset %s backs out changeset %s\n') %
635 ui.status(_('changeset %s backs out changeset %s\n') %
636 (nice(repo.changelog.tip()), nice(node)))
636 (nice(repo.changelog.tip()), nice(node)))
637 if op1 != node:
637 if op1 != node:
638 if opts['merge']:
638 if opts['merge']:
639 ui.status(_('merging with changeset %s\n') % nice(op1))
639 ui.status(_('merging with changeset %s\n') % nice(op1))
640 n = _lookup(repo, hex(op1))
640 n = _lookup(repo, hex(op1))
641 hg.merge(repo, n)
641 hg.merge(repo, n)
642 else:
642 else:
643 ui.status(_('the backout changeset is a new head - '
643 ui.status(_('the backout changeset is a new head - '
644 'do not forget to merge\n'))
644 'do not forget to merge\n'))
645 ui.status(_('(use "backout --merge" '
645 ui.status(_('(use "backout --merge" '
646 'if you want to auto-merge)\n'))
646 'if you want to auto-merge)\n'))
647
647
648 def branch(ui, repo, label=None):
648 def branch(ui, repo, label=None):
649 """set or show the current branch name
649 """set or show the current branch name
650
650
651 With <name>, set the current branch name. Otherwise, show the
651 With <name>, set the current branch name. Otherwise, show the
652 current branch name.
652 current branch name.
653 """
653 """
654
654
655 if label is not None:
655 if label is not None:
656 repo.opener("branch", "w").write(label)
656 repo.opener("branch", "w").write(label)
657 else:
657 else:
658 b = repo.workingctx().branch()
658 b = repo.workingctx().branch()
659 if b:
659 if b:
660 ui.write("%s\n" % b)
660 ui.write("%s\n" % b)
661
661
662 def branches(ui, repo):
662 def branches(ui, repo):
663 """list repository named branches
663 """list repository named branches
664
664
665 List the repository's named branches.
665 List the repository's named branches.
666 """
666 """
667 b = repo.branchtags()
667 b = repo.branchtags()
668 l = [(-repo.changelog.rev(n), n, t) for t,n in b.items()]
668 l = [(-repo.changelog.rev(n), n, t) for t,n in b.items()]
669 l.sort()
669 l.sort()
670 for r, n, t in l:
670 for r, n, t in l:
671 hexfunc = ui.debugflag and hex or short
671 hexfunc = ui.debugflag and hex or short
672 if ui.quiet:
672 if ui.quiet:
673 ui.write("%s\n" % t)
673 ui.write("%s\n" % t)
674 else:
674 else:
675 ui.write("%-30s %s:%s\n" % (t, -r, hexfunc(n)))
675 ui.write("%-30s %s:%s\n" % (t, -r, hexfunc(n)))
676
676
677 def bundle(ui, repo, fname, dest=None, **opts):
677 def bundle(ui, repo, fname, dest=None, **opts):
678 """create a changegroup file
678 """create a changegroup file
679
679
680 Generate a compressed changegroup file collecting changesets not
680 Generate a compressed changegroup file collecting changesets not
681 found in the other repository.
681 found in the other repository.
682
682
683 If no destination repository is specified the destination is assumed
683 If no destination repository is specified the destination is assumed
684 to have all the nodes specified by one or more --base parameters.
684 to have all the nodes specified by one or more --base parameters.
685
685
686 The bundle file can then be transferred using conventional means and
686 The bundle file can then be transferred using conventional means and
687 applied to another repository with the unbundle or pull command.
687 applied to another repository with the unbundle or pull command.
688 This is useful when direct push and pull are not available or when
688 This is useful when direct push and pull are not available or when
689 exporting an entire repository is undesirable.
689 exporting an entire repository is undesirable.
690
690
691 Applying bundles preserves all changeset contents including
691 Applying bundles preserves all changeset contents including
692 permissions, copy/rename information, and revision history.
692 permissions, copy/rename information, and revision history.
693 """
693 """
694 revs = opts.get('rev') or None
694 revs = opts.get('rev') or None
695 if revs:
695 if revs:
696 revs = [repo.lookup(rev) for rev in revs]
696 revs = [repo.lookup(rev) for rev in revs]
697 base = opts.get('base')
697 base = opts.get('base')
698 if base:
698 if base:
699 if dest:
699 if dest:
700 raise util.Abort(_("--base is incompatible with specifiying "
700 raise util.Abort(_("--base is incompatible with specifiying "
701 "a destination"))
701 "a destination"))
702 base = [repo.lookup(rev) for rev in base]
702 base = [repo.lookup(rev) for rev in base]
703 # create the right base
703 # create the right base
704 # XXX: nodesbetween / changegroup* should be "fixed" instead
704 # XXX: nodesbetween / changegroup* should be "fixed" instead
705 o = []
705 o = []
706 has = {nullid: None}
706 has = {nullid: None}
707 for n in base:
707 for n in base:
708 has.update(repo.changelog.reachable(n))
708 has.update(repo.changelog.reachable(n))
709 if revs:
709 if revs:
710 visit = list(revs)
710 visit = list(revs)
711 else:
711 else:
712 visit = repo.changelog.heads()
712 visit = repo.changelog.heads()
713 seen = {}
713 seen = {}
714 while visit:
714 while visit:
715 n = visit.pop(0)
715 n = visit.pop(0)
716 parents = [p for p in repo.changelog.parents(n) if p not in has]
716 parents = [p for p in repo.changelog.parents(n) if p not in has]
717 if len(parents) == 0:
717 if len(parents) == 0:
718 o.insert(0, n)
718 o.insert(0, n)
719 else:
719 else:
720 for p in parents:
720 for p in parents:
721 if p not in seen:
721 if p not in seen:
722 seen[p] = 1
722 seen[p] = 1
723 visit.append(p)
723 visit.append(p)
724 else:
724 else:
725 setremoteconfig(ui, opts)
725 setremoteconfig(ui, opts)
726 dest = ui.expandpath(dest or 'default-push', dest or 'default')
726 dest = ui.expandpath(dest or 'default-push', dest or 'default')
727 other = hg.repository(ui, dest)
727 other = hg.repository(ui, dest)
728 o = repo.findoutgoing(other, force=opts['force'])
728 o = repo.findoutgoing(other, force=opts['force'])
729
729
730 if revs:
730 if revs:
731 cg = repo.changegroupsubset(o, revs, 'bundle')
731 cg = repo.changegroupsubset(o, revs, 'bundle')
732 else:
732 else:
733 cg = repo.changegroup(o, 'bundle')
733 cg = repo.changegroup(o, 'bundle')
734 write_bundle(cg, fname)
734 write_bundle(cg, fname)
735
735
736 def cat(ui, repo, file1, *pats, **opts):
736 def cat(ui, repo, file1, *pats, **opts):
737 """output the latest or given revisions of files
737 """output the latest or given revisions of files
738
738
739 Print the specified files as they were at the given revision.
739 Print the specified files as they were at the given revision.
740 If no revision is given then working dir parent is used, or tip
740 If no revision is given then working dir parent is used, or tip
741 if no revision is checked out.
741 if no revision is checked out.
742
742
743 Output may be to a file, in which case the name of the file is
743 Output may be to a file, in which case the name of the file is
744 given using a format string. The formatting rules are the same as
744 given using a format string. The formatting rules are the same as
745 for the export command, with the following additions:
745 for the export command, with the following additions:
746
746
747 %s basename of file being printed
747 %s basename of file being printed
748 %d dirname of file being printed, or '.' if in repo root
748 %d dirname of file being printed, or '.' if in repo root
749 %p root-relative path name of file being printed
749 %p root-relative path name of file being printed
750 """
750 """
751 ctx = repo.changectx(opts['rev'])
751 ctx = repo.changectx(opts['rev'])
752 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
752 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
753 ctx.node()):
753 ctx.node()):
754 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
754 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
755 fp.write(ctx.filectx(abs).data())
755 fp.write(ctx.filectx(abs).data())
756
756
757 def clone(ui, source, dest=None, **opts):
757 def clone(ui, source, dest=None, **opts):
758 """make a copy of an existing repository
758 """make a copy of an existing repository
759
759
760 Create a copy of an existing repository in a new directory.
760 Create a copy of an existing repository in a new directory.
761
761
762 If no destination directory name is specified, it defaults to the
762 If no destination directory name is specified, it defaults to the
763 basename of the source.
763 basename of the source.
764
764
765 The location of the source is added to the new repository's
765 The location of the source is added to the new repository's
766 .hg/hgrc file, as the default to be used for future pulls.
766 .hg/hgrc file, as the default to be used for future pulls.
767
767
768 For efficiency, hardlinks are used for cloning whenever the source
768 For efficiency, hardlinks are used for cloning whenever the source
769 and destination are on the same filesystem (note this applies only
769 and destination are on the same filesystem (note this applies only
770 to the repository data, not to the checked out files). Some
770 to the repository data, not to the checked out files). Some
771 filesystems, such as AFS, implement hardlinking incorrectly, but
771 filesystems, such as AFS, implement hardlinking incorrectly, but
772 do not report errors. In these cases, use the --pull option to
772 do not report errors. In these cases, use the --pull option to
773 avoid hardlinking.
773 avoid hardlinking.
774
774
775 You can safely clone repositories and checked out files using full
775 You can safely clone repositories and checked out files using full
776 hardlinks with
776 hardlinks with
777
777
778 $ cp -al REPO REPOCLONE
778 $ cp -al REPO REPOCLONE
779
779
780 which is the fastest way to clone. However, the operation is not
780 which is the fastest way to clone. However, the operation is not
781 atomic (making sure REPO is not modified during the operation is
781 atomic (making sure REPO is not modified during the operation is
782 up to you) and you have to make sure your editor breaks hardlinks
782 up to you) and you have to make sure your editor breaks hardlinks
783 (Emacs and most Linux Kernel tools do so).
783 (Emacs and most Linux Kernel tools do so).
784
784
785 If you use the -r option to clone up to a specific revision, no
785 If you use the -r option to clone up to a specific revision, no
786 subsequent revisions will be present in the cloned repository.
786 subsequent revisions will be present in the cloned repository.
787 This option implies --pull, even on local repositories.
787 This option implies --pull, even on local repositories.
788
788
789 See pull for valid source format details.
789 See pull for valid source format details.
790
790
791 It is possible to specify an ssh:// URL as the destination, but no
791 It is possible to specify an ssh:// URL as the destination, but no
792 .hg/hgrc and working directory will be created on the remote side.
792 .hg/hgrc and working directory will be created on the remote side.
793 Look at the help text for the pull command for important details
793 Look at the help text for the pull command for important details
794 about ssh:// URLs.
794 about ssh:// URLs.
795 """
795 """
796 setremoteconfig(ui, opts)
796 setremoteconfig(ui, opts)
797 hg.clone(ui, ui.expandpath(source), dest,
797 hg.clone(ui, ui.expandpath(source), dest,
798 pull=opts['pull'],
798 pull=opts['pull'],
799 stream=opts['uncompressed'],
799 stream=opts['uncompressed'],
800 rev=opts['rev'],
800 rev=opts['rev'],
801 update=not opts['noupdate'])
801 update=not opts['noupdate'])
802
802
803 def commit(ui, repo, *pats, **opts):
803 def commit(ui, repo, *pats, **opts):
804 """commit the specified files or all outstanding changes
804 """commit the specified files or all outstanding changes
805
805
806 Commit changes to the given files into the repository.
806 Commit changes to the given files into the repository.
807
807
808 If a list of files is omitted, all changes reported by "hg status"
808 If a list of files is omitted, all changes reported by "hg status"
809 will be committed.
809 will be committed.
810
810
811 If no commit message is specified, the editor configured in your hgrc
811 If no commit message is specified, the editor configured in your hgrc
812 or in the EDITOR environment variable is started to enter a message.
812 or in the EDITOR environment variable is started to enter a message.
813 """
813 """
814 message = logmessage(opts)
814 message = logmessage(opts)
815
815
816 if opts['addremove']:
816 if opts['addremove']:
817 cmdutil.addremove(repo, pats, opts)
817 cmdutil.addremove(repo, pats, opts)
818 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
818 fns, match, anypats = cmdutil.matchpats(repo, pats, opts)
819 if pats:
819 if pats:
820 modified, added, removed = repo.status(files=fns, match=match)[:3]
820 modified, added, removed = repo.status(files=fns, match=match)[:3]
821 files = modified + added + removed
821 files = modified + added + removed
822 else:
822 else:
823 files = []
823 files = []
824 try:
824 try:
825 repo.commit(files, message, opts['user'], opts['date'], match,
825 repo.commit(files, message, opts['user'], opts['date'], match,
826 force_editor=opts.get('force_editor'))
826 force_editor=opts.get('force_editor'))
827 except ValueError, inst:
827 except ValueError, inst:
828 raise util.Abort(str(inst))
828 raise util.Abort(str(inst))
829
829
830 def docopy(ui, repo, pats, opts, wlock):
830 def docopy(ui, repo, pats, opts, wlock):
831 # called with the repo lock held
831 # called with the repo lock held
832 cwd = repo.getcwd()
832 cwd = repo.getcwd()
833 errors = 0
833 errors = 0
834 copied = []
834 copied = []
835 targets = {}
835 targets = {}
836
836
837 def okaytocopy(abs, rel, exact):
837 def okaytocopy(abs, rel, exact):
838 reasons = {'?': _('is not managed'),
838 reasons = {'?': _('is not managed'),
839 'a': _('has been marked for add'),
839 'a': _('has been marked for add'),
840 'r': _('has been marked for remove')}
840 'r': _('has been marked for remove')}
841 state = repo.dirstate.state(abs)
841 state = repo.dirstate.state(abs)
842 reason = reasons.get(state)
842 reason = reasons.get(state)
843 if reason:
843 if reason:
844 if state == 'a':
844 if state == 'a':
845 origsrc = repo.dirstate.copied(abs)
845 origsrc = repo.dirstate.copied(abs)
846 if origsrc is not None:
846 if origsrc is not None:
847 return origsrc
847 return origsrc
848 if exact:
848 if exact:
849 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
849 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
850 else:
850 else:
851 return abs
851 return abs
852
852
853 def copy(origsrc, abssrc, relsrc, target, exact):
853 def copy(origsrc, abssrc, relsrc, target, exact):
854 abstarget = util.canonpath(repo.root, cwd, target)
854 abstarget = util.canonpath(repo.root, cwd, target)
855 reltarget = util.pathto(cwd, abstarget)
855 reltarget = util.pathto(cwd, abstarget)
856 prevsrc = targets.get(abstarget)
856 prevsrc = targets.get(abstarget)
857 if prevsrc is not None:
857 if prevsrc is not None:
858 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
858 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
859 (reltarget, abssrc, prevsrc))
859 (reltarget, abssrc, prevsrc))
860 return
860 return
861 if (not opts['after'] and os.path.exists(reltarget) or
861 if (not opts['after'] and os.path.exists(reltarget) or
862 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
862 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
863 if not opts['force']:
863 if not opts['force']:
864 ui.warn(_('%s: not overwriting - file exists\n') %
864 ui.warn(_('%s: not overwriting - file exists\n') %
865 reltarget)
865 reltarget)
866 return
866 return
867 if not opts['after'] and not opts.get('dry_run'):
867 if not opts['after'] and not opts.get('dry_run'):
868 os.unlink(reltarget)
868 os.unlink(reltarget)
869 if opts['after']:
869 if opts['after']:
870 if not os.path.exists(reltarget):
870 if not os.path.exists(reltarget):
871 return
871 return
872 else:
872 else:
873 targetdir = os.path.dirname(reltarget) or '.'
873 targetdir = os.path.dirname(reltarget) or '.'
874 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
874 if not os.path.isdir(targetdir) and not opts.get('dry_run'):
875 os.makedirs(targetdir)
875 os.makedirs(targetdir)
876 try:
876 try:
877 restore = repo.dirstate.state(abstarget) == 'r'
877 restore = repo.dirstate.state(abstarget) == 'r'
878 if restore and not opts.get('dry_run'):
878 if restore and not opts.get('dry_run'):
879 repo.undelete([abstarget], wlock)
879 repo.undelete([abstarget], wlock)
880 try:
880 try:
881 if not opts.get('dry_run'):
881 if not opts.get('dry_run'):
882 util.copyfile(relsrc, reltarget)
882 util.copyfile(relsrc, reltarget)
883 restore = False
883 restore = False
884 finally:
884 finally:
885 if restore:
885 if restore:
886 repo.remove([abstarget], wlock)
886 repo.remove([abstarget], wlock)
887 except IOError, inst:
887 except IOError, inst:
888 if inst.errno == errno.ENOENT:
888 if inst.errno == errno.ENOENT:
889 ui.warn(_('%s: deleted in working copy\n') % relsrc)
889 ui.warn(_('%s: deleted in working copy\n') % relsrc)
890 else:
890 else:
891 ui.warn(_('%s: cannot copy - %s\n') %
891 ui.warn(_('%s: cannot copy - %s\n') %
892 (relsrc, inst.strerror))
892 (relsrc, inst.strerror))
893 errors += 1
893 errors += 1
894 return
894 return
895 if ui.verbose or not exact:
895 if ui.verbose or not exact:
896 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
896 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
897 targets[abstarget] = abssrc
897 targets[abstarget] = abssrc
898 if abstarget != origsrc and not opts.get('dry_run'):
898 if abstarget != origsrc and not opts.get('dry_run'):
899 repo.copy(origsrc, abstarget, wlock)
899 repo.copy(origsrc, abstarget, wlock)
900 copied.append((abssrc, relsrc, exact))
900 copied.append((abssrc, relsrc, exact))
901
901
902 def targetpathfn(pat, dest, srcs):
902 def targetpathfn(pat, dest, srcs):
903 if os.path.isdir(pat):
903 if os.path.isdir(pat):
904 abspfx = util.canonpath(repo.root, cwd, pat)
904 abspfx = util.canonpath(repo.root, cwd, pat)
905 if destdirexists:
905 if destdirexists:
906 striplen = len(os.path.split(abspfx)[0])
906 striplen = len(os.path.split(abspfx)[0])
907 else:
907 else:
908 striplen = len(abspfx)
908 striplen = len(abspfx)
909 if striplen:
909 if striplen:
910 striplen += len(os.sep)
910 striplen += len(os.sep)
911 res = lambda p: os.path.join(dest, p[striplen:])
911 res = lambda p: os.path.join(dest, p[striplen:])
912 elif destdirexists:
912 elif destdirexists:
913 res = lambda p: os.path.join(dest, os.path.basename(p))
913 res = lambda p: os.path.join(dest, os.path.basename(p))
914 else:
914 else:
915 res = lambda p: dest
915 res = lambda p: dest
916 return res
916 return res
917
917
918 def targetpathafterfn(pat, dest, srcs):
918 def targetpathafterfn(pat, dest, srcs):
919 if util.patkind(pat, None)[0]:
919 if util.patkind(pat, None)[0]:
920 # a mercurial pattern
920 # a mercurial pattern
921 res = lambda p: os.path.join(dest, os.path.basename(p))
921 res = lambda p: os.path.join(dest, os.path.basename(p))
922 else:
922 else:
923 abspfx = util.canonpath(repo.root, cwd, pat)
923 abspfx = util.canonpath(repo.root, cwd, pat)
924 if len(abspfx) < len(srcs[0][0]):
924 if len(abspfx) < len(srcs[0][0]):
925 # A directory. Either the target path contains the last
925 # A directory. Either the target path contains the last
926 # component of the source path or it does not.
926 # component of the source path or it does not.
927 def evalpath(striplen):
927 def evalpath(striplen):
928 score = 0
928 score = 0
929 for s in srcs:
929 for s in srcs:
930 t = os.path.join(dest, s[0][striplen:])
930 t = os.path.join(dest, s[0][striplen:])
931 if os.path.exists(t):
931 if os.path.exists(t):
932 score += 1
932 score += 1
933 return score
933 return score
934
934
935 striplen = len(abspfx)
935 striplen = len(abspfx)
936 if striplen:
936 if striplen:
937 striplen += len(os.sep)
937 striplen += len(os.sep)
938 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
938 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
939 score = evalpath(striplen)
939 score = evalpath(striplen)
940 striplen1 = len(os.path.split(abspfx)[0])
940 striplen1 = len(os.path.split(abspfx)[0])
941 if striplen1:
941 if striplen1:
942 striplen1 += len(os.sep)
942 striplen1 += len(os.sep)
943 if evalpath(striplen1) > score:
943 if evalpath(striplen1) > score:
944 striplen = striplen1
944 striplen = striplen1
945 res = lambda p: os.path.join(dest, p[striplen:])
945 res = lambda p: os.path.join(dest, p[striplen:])
946 else:
946 else:
947 # a file
947 # a file
948 if destdirexists:
948 if destdirexists:
949 res = lambda p: os.path.join(dest, os.path.basename(p))
949 res = lambda p: os.path.join(dest, os.path.basename(p))
950 else:
950 else:
951 res = lambda p: dest
951 res = lambda p: dest
952 return res
952 return res
953
953
954
954
955 pats = list(pats)
955 pats = list(pats)
956 if not pats:
956 if not pats:
957 raise util.Abort(_('no source or destination specified'))
957 raise util.Abort(_('no source or destination specified'))
958 if len(pats) == 1:
958 if len(pats) == 1:
959 raise util.Abort(_('no destination specified'))
959 raise util.Abort(_('no destination specified'))
960 dest = pats.pop()
960 dest = pats.pop()
961 destdirexists = os.path.isdir(dest)
961 destdirexists = os.path.isdir(dest)
962 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
962 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
963 raise util.Abort(_('with multiple sources, destination must be an '
963 raise util.Abort(_('with multiple sources, destination must be an '
964 'existing directory'))
964 'existing directory'))
965 if opts['after']:
965 if opts['after']:
966 tfn = targetpathafterfn
966 tfn = targetpathafterfn
967 else:
967 else:
968 tfn = targetpathfn
968 tfn = targetpathfn
969 copylist = []
969 copylist = []
970 for pat in pats:
970 for pat in pats:
971 srcs = []
971 srcs = []
972 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
972 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts):
973 origsrc = okaytocopy(abssrc, relsrc, exact)
973 origsrc = okaytocopy(abssrc, relsrc, exact)
974 if origsrc:
974 if origsrc:
975 srcs.append((origsrc, abssrc, relsrc, exact))
975 srcs.append((origsrc, abssrc, relsrc, exact))
976 if not srcs:
976 if not srcs:
977 continue
977 continue
978 copylist.append((tfn(pat, dest, srcs), srcs))
978 copylist.append((tfn(pat, dest, srcs), srcs))
979 if not copylist:
979 if not copylist:
980 raise util.Abort(_('no files to copy'))
980 raise util.Abort(_('no files to copy'))
981
981
982 for targetpath, srcs in copylist:
982 for targetpath, srcs in copylist:
983 for origsrc, abssrc, relsrc, exact in srcs:
983 for origsrc, abssrc, relsrc, exact in srcs:
984 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
984 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
985
985
986 if errors:
986 if errors:
987 ui.warn(_('(consider using --after)\n'))
987 ui.warn(_('(consider using --after)\n'))
988 return errors, copied
988 return errors, copied
989
989
990 def copy(ui, repo, *pats, **opts):
990 def copy(ui, repo, *pats, **opts):
991 """mark files as copied for the next commit
991 """mark files as copied for the next commit
992
992
993 Mark dest as having copies of source files. If dest is a
993 Mark dest as having copies of source files. If dest is a
994 directory, copies are put in that directory. If dest is a file,
994 directory, copies are put in that directory. If dest is a file,
995 there can only be one source.
995 there can only be one source.
996
996
997 By default, this command copies the contents of files as they
997 By default, this command copies the contents of files as they
998 stand in the working directory. If invoked with --after, the
998 stand in the working directory. If invoked with --after, the
999 operation is recorded, but no copying is performed.
999 operation is recorded, but no copying is performed.
1000
1000
1001 This command takes effect in the next commit.
1001 This command takes effect in the next commit.
1002
1002
1003 NOTE: This command should be treated as experimental. While it
1003 NOTE: This command should be treated as experimental. While it
1004 should properly record copied files, this information is not yet
1004 should properly record copied files, this information is not yet
1005 fully used by merge, nor fully reported by log.
1005 fully used by merge, nor fully reported by log.
1006 """
1006 """
1007 wlock = repo.wlock(0)
1007 wlock = repo.wlock(0)
1008 errs, copied = docopy(ui, repo, pats, opts, wlock)
1008 errs, copied = docopy(ui, repo, pats, opts, wlock)
1009 return errs
1009 return errs
1010
1010
1011 def debugancestor(ui, index, rev1, rev2):
1011 def debugancestor(ui, index, rev1, rev2):
1012 """find the ancestor revision of two revisions in a given index"""
1012 """find the ancestor revision of two revisions in a given index"""
1013 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1013 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0)
1014 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1014 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1015 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1015 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1016
1016
1017 def debugcomplete(ui, cmd='', **opts):
1017 def debugcomplete(ui, cmd='', **opts):
1018 """returns the completion list associated with the given command"""
1018 """returns the completion list associated with the given command"""
1019
1019
1020 if opts['options']:
1020 if opts['options']:
1021 options = []
1021 options = []
1022 otables = [globalopts]
1022 otables = [globalopts]
1023 if cmd:
1023 if cmd:
1024 aliases, entry = findcmd(ui, cmd)
1024 aliases, entry = findcmd(ui, cmd)
1025 otables.append(entry[1])
1025 otables.append(entry[1])
1026 for t in otables:
1026 for t in otables:
1027 for o in t:
1027 for o in t:
1028 if o[0]:
1028 if o[0]:
1029 options.append('-%s' % o[0])
1029 options.append('-%s' % o[0])
1030 options.append('--%s' % o[1])
1030 options.append('--%s' % o[1])
1031 ui.write("%s\n" % "\n".join(options))
1031 ui.write("%s\n" % "\n".join(options))
1032 return
1032 return
1033
1033
1034 clist = findpossible(ui, cmd).keys()
1034 clist = findpossible(ui, cmd).keys()
1035 clist.sort()
1035 clist.sort()
1036 ui.write("%s\n" % "\n".join(clist))
1036 ui.write("%s\n" % "\n".join(clist))
1037
1037
1038 def debugrebuildstate(ui, repo, rev=None):
1038 def debugrebuildstate(ui, repo, rev=None):
1039 """rebuild the dirstate as it would look like for the given revision"""
1039 """rebuild the dirstate as it would look like for the given revision"""
1040 if not rev:
1040 if not rev:
1041 rev = repo.changelog.tip()
1041 rev = repo.changelog.tip()
1042 else:
1042 else:
1043 rev = repo.lookup(rev)
1043 rev = repo.lookup(rev)
1044 change = repo.changelog.read(rev)
1044 change = repo.changelog.read(rev)
1045 n = change[0]
1045 n = change[0]
1046 files = repo.manifest.read(n)
1046 files = repo.manifest.read(n)
1047 wlock = repo.wlock()
1047 wlock = repo.wlock()
1048 repo.dirstate.rebuild(rev, files)
1048 repo.dirstate.rebuild(rev, files)
1049
1049
1050 def debugcheckstate(ui, repo):
1050 def debugcheckstate(ui, repo):
1051 """validate the correctness of the current dirstate"""
1051 """validate the correctness of the current dirstate"""
1052 parent1, parent2 = repo.dirstate.parents()
1052 parent1, parent2 = repo.dirstate.parents()
1053 repo.dirstate.read()
1053 repo.dirstate.read()
1054 dc = repo.dirstate.map
1054 dc = repo.dirstate.map
1055 keys = dc.keys()
1055 keys = dc.keys()
1056 keys.sort()
1056 keys.sort()
1057 m1n = repo.changelog.read(parent1)[0]
1057 m1n = repo.changelog.read(parent1)[0]
1058 m2n = repo.changelog.read(parent2)[0]
1058 m2n = repo.changelog.read(parent2)[0]
1059 m1 = repo.manifest.read(m1n)
1059 m1 = repo.manifest.read(m1n)
1060 m2 = repo.manifest.read(m2n)
1060 m2 = repo.manifest.read(m2n)
1061 errors = 0
1061 errors = 0
1062 for f in dc:
1062 for f in dc:
1063 state = repo.dirstate.state(f)
1063 state = repo.dirstate.state(f)
1064 if state in "nr" and f not in m1:
1064 if state in "nr" and f not in m1:
1065 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1065 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1066 errors += 1
1066 errors += 1
1067 if state in "a" and f in m1:
1067 if state in "a" and f in m1:
1068 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1068 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1069 errors += 1
1069 errors += 1
1070 if state in "m" and f not in m1 and f not in m2:
1070 if state in "m" and f not in m1 and f not in m2:
1071 ui.warn(_("%s in state %s, but not in either manifest\n") %
1071 ui.warn(_("%s in state %s, but not in either manifest\n") %
1072 (f, state))
1072 (f, state))
1073 errors += 1
1073 errors += 1
1074 for f in m1:
1074 for f in m1:
1075 state = repo.dirstate.state(f)
1075 state = repo.dirstate.state(f)
1076 if state not in "nrm":
1076 if state not in "nrm":
1077 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1077 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1078 errors += 1
1078 errors += 1
1079 if errors:
1079 if errors:
1080 error = _(".hg/dirstate inconsistent with current parent's manifest")
1080 error = _(".hg/dirstate inconsistent with current parent's manifest")
1081 raise util.Abort(error)
1081 raise util.Abort(error)
1082
1082
1083 def showconfig(ui, repo, *values, **opts):
1083 def showconfig(ui, repo, *values, **opts):
1084 """show combined config settings from all hgrc files
1084 """show combined config settings from all hgrc files
1085
1085
1086 With no args, print names and values of all config items.
1086 With no args, print names and values of all config items.
1087
1087
1088 With one arg of the form section.name, print just the value of
1088 With one arg of the form section.name, print just the value of
1089 that config item.
1089 that config item.
1090
1090
1091 With multiple args, print names and values of all config items
1091 With multiple args, print names and values of all config items
1092 with matching section names."""
1092 with matching section names."""
1093
1093
1094 untrusted = bool(opts.get('untrusted'))
1094 untrusted = bool(opts.get('untrusted'))
1095 if values:
1095 if values:
1096 if len([v for v in values if '.' in v]) > 1:
1096 if len([v for v in values if '.' in v]) > 1:
1097 raise util.Abort(_('only one config item permitted'))
1097 raise util.Abort(_('only one config item permitted'))
1098 for section, name, value in ui.walkconfig(untrusted=untrusted):
1098 for section, name, value in ui.walkconfig(untrusted=untrusted):
1099 sectname = section + '.' + name
1099 sectname = section + '.' + name
1100 if values:
1100 if values:
1101 for v in values:
1101 for v in values:
1102 if v == section:
1102 if v == section:
1103 ui.write('%s=%s\n' % (sectname, value))
1103 ui.write('%s=%s\n' % (sectname, value))
1104 elif v == sectname:
1104 elif v == sectname:
1105 ui.write(value, '\n')
1105 ui.write(value, '\n')
1106 else:
1106 else:
1107 ui.write('%s=%s\n' % (sectname, value))
1107 ui.write('%s=%s\n' % (sectname, value))
1108
1108
1109 def debugsetparents(ui, repo, rev1, rev2=None):
1109 def debugsetparents(ui, repo, rev1, rev2=None):
1110 """manually set the parents of the current working directory
1110 """manually set the parents of the current working directory
1111
1111
1112 This is useful for writing repository conversion tools, but should
1112 This is useful for writing repository conversion tools, but should
1113 be used with care.
1113 be used with care.
1114 """
1114 """
1115
1115
1116 if not rev2:
1116 if not rev2:
1117 rev2 = hex(nullid)
1117 rev2 = hex(nullid)
1118
1118
1119 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1119 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1120
1120
1121 def debugstate(ui, repo):
1121 def debugstate(ui, repo):
1122 """show the contents of the current dirstate"""
1122 """show the contents of the current dirstate"""
1123 repo.dirstate.read()
1123 repo.dirstate.read()
1124 dc = repo.dirstate.map
1124 dc = repo.dirstate.map
1125 keys = dc.keys()
1125 keys = dc.keys()
1126 keys.sort()
1126 keys.sort()
1127 for file_ in keys:
1127 for file_ in keys:
1128 ui.write("%c %3o %10d %s %s\n"
1128 ui.write("%c %3o %10d %s %s\n"
1129 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1129 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1130 time.strftime("%x %X",
1130 time.strftime("%x %X",
1131 time.localtime(dc[file_][3])), file_))
1131 time.localtime(dc[file_][3])), file_))
1132 for f in repo.dirstate.copies():
1132 for f in repo.dirstate.copies():
1133 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1133 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1134
1134
1135 def debugdata(ui, file_, rev):
1135 def debugdata(ui, file_, rev):
1136 """dump the contents of an data file revision"""
1136 """dump the contents of an data file revision"""
1137 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1137 r = revlog.revlog(util.opener(os.getcwd(), audit=False),
1138 file_[:-2] + ".i", file_, 0)
1138 file_[:-2] + ".i", file_, 0)
1139 try:
1139 try:
1140 ui.write(r.revision(r.lookup(rev)))
1140 ui.write(r.revision(r.lookup(rev)))
1141 except KeyError:
1141 except KeyError:
1142 raise util.Abort(_('invalid revision identifier %s') % rev)
1142 raise util.Abort(_('invalid revision identifier %s') % rev)
1143
1143
1144 def debugindex(ui, file_):
1144 def debugindex(ui, file_):
1145 """dump the contents of an index file"""
1145 """dump the contents of an index file"""
1146 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1146 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1147 ui.write(" rev offset length base linkrev" +
1147 ui.write(" rev offset length base linkrev" +
1148 " nodeid p1 p2\n")
1148 " nodeid p1 p2\n")
1149 for i in xrange(r.count()):
1149 for i in xrange(r.count()):
1150 node = r.node(i)
1150 node = r.node(i)
1151 pp = r.parents(node)
1151 pp = r.parents(node)
1152 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1152 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1153 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1153 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
1154 short(node), short(pp[0]), short(pp[1])))
1154 short(node), short(pp[0]), short(pp[1])))
1155
1155
1156 def debugindexdot(ui, file_):
1156 def debugindexdot(ui, file_):
1157 """dump an index DAG as a .dot file"""
1157 """dump an index DAG as a .dot file"""
1158 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1158 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0)
1159 ui.write("digraph G {\n")
1159 ui.write("digraph G {\n")
1160 for i in xrange(r.count()):
1160 for i in xrange(r.count()):
1161 node = r.node(i)
1161 node = r.node(i)
1162 pp = r.parents(node)
1162 pp = r.parents(node)
1163 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1163 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1164 if pp[1] != nullid:
1164 if pp[1] != nullid:
1165 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1165 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1166 ui.write("}\n")
1166 ui.write("}\n")
1167
1167
1168 def debugrename(ui, repo, file, rev=None):
1168 def debugrename(ui, repo, file, rev=None):
1169 """dump rename information"""
1169 """dump rename information"""
1170 r = repo.file(relpath(repo, [file])[0])
1170 r = repo.file(relpath(repo, [file])[0])
1171 if rev:
1171 if rev:
1172 try:
1172 try:
1173 # assume all revision numbers are for changesets
1173 # assume all revision numbers are for changesets
1174 n = repo.lookup(rev)
1174 n = repo.lookup(rev)
1175 change = repo.changelog.read(n)
1175 change = repo.changelog.read(n)
1176 m = repo.manifest.read(change[0])
1176 m = repo.manifest.read(change[0])
1177 n = m[relpath(repo, [file])[0]]
1177 n = m[relpath(repo, [file])[0]]
1178 except (hg.RepoError, KeyError):
1178 except (hg.RepoError, KeyError):
1179 n = r.lookup(rev)
1179 n = r.lookup(rev)
1180 else:
1180 else:
1181 n = r.tip()
1181 n = r.tip()
1182 m = r.renamed(n)
1182 m = r.renamed(n)
1183 if m:
1183 if m:
1184 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1184 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1185 else:
1185 else:
1186 ui.write(_("not renamed\n"))
1186 ui.write(_("not renamed\n"))
1187
1187
1188 def debugwalk(ui, repo, *pats, **opts):
1188 def debugwalk(ui, repo, *pats, **opts):
1189 """show how files match on given patterns"""
1189 """show how files match on given patterns"""
1190 items = list(cmdutil.walk(repo, pats, opts))
1190 items = list(cmdutil.walk(repo, pats, opts))
1191 if not items:
1191 if not items:
1192 return
1192 return
1193 fmt = '%%s %%-%ds %%-%ds %%s' % (
1193 fmt = '%%s %%-%ds %%-%ds %%s' % (
1194 max([len(abs) for (src, abs, rel, exact) in items]),
1194 max([len(abs) for (src, abs, rel, exact) in items]),
1195 max([len(rel) for (src, abs, rel, exact) in items]))
1195 max([len(rel) for (src, abs, rel, exact) in items]))
1196 for src, abs, rel, exact in items:
1196 for src, abs, rel, exact in items:
1197 line = fmt % (src, abs, rel, exact and 'exact' or '')
1197 line = fmt % (src, abs, rel, exact and 'exact' or '')
1198 ui.write("%s\n" % line.rstrip())
1198 ui.write("%s\n" % line.rstrip())
1199
1199
1200 def diff(ui, repo, *pats, **opts):
1200 def diff(ui, repo, *pats, **opts):
1201 """diff repository (or selected files)
1201 """diff repository (or selected files)
1202
1202
1203 Show differences between revisions for the specified files.
1203 Show differences between revisions for the specified files.
1204
1204
1205 Differences between files are shown using the unified diff format.
1205 Differences between files are shown using the unified diff format.
1206
1206
1207 When two revision arguments are given, then changes are shown
1207 When two revision arguments are given, then changes are shown
1208 between those revisions. If only one revision is specified then
1208 between those revisions. If only one revision is specified then
1209 that revision is compared to the working directory, and, when no
1209 that revision is compared to the working directory, and, when no
1210 revisions are specified, the working directory files are compared
1210 revisions are specified, the working directory files are compared
1211 to its parent.
1211 to its parent.
1212
1212
1213 Without the -a option, diff will avoid generating diffs of files
1213 Without the -a option, diff will avoid generating diffs of files
1214 it detects as binary. With -a, diff will generate a diff anyway,
1214 it detects as binary. With -a, diff will generate a diff anyway,
1215 probably with undesirable results.
1215 probably with undesirable results.
1216 """
1216 """
1217 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
1217 node1, node2 = cmdutil.revpair(ui, repo, opts['rev'])
1218
1218
1219 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1219 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
1220
1220
1221 patch.diff(repo, node1, node2, fns, match=matchfn,
1221 patch.diff(repo, node1, node2, fns, match=matchfn,
1222 opts=patch.diffopts(ui, opts))
1222 opts=patch.diffopts(ui, opts))
1223
1223
1224 def export(ui, repo, *changesets, **opts):
1224 def export(ui, repo, *changesets, **opts):
1225 """dump the header and diffs for one or more changesets
1225 """dump the header and diffs for one or more changesets
1226
1226
1227 Print the changeset header and diffs for one or more revisions.
1227 Print the changeset header and diffs for one or more revisions.
1228
1228
1229 The information shown in the changeset header is: author,
1229 The information shown in the changeset header is: author,
1230 changeset hash, parent and commit comment.
1230 changeset hash, parent and commit comment.
1231
1231
1232 Output may be to a file, in which case the name of the file is
1232 Output may be to a file, in which case the name of the file is
1233 given using a format string. The formatting rules are as follows:
1233 given using a format string. The formatting rules are as follows:
1234
1234
1235 %% literal "%" character
1235 %% literal "%" character
1236 %H changeset hash (40 bytes of hexadecimal)
1236 %H changeset hash (40 bytes of hexadecimal)
1237 %N number of patches being generated
1237 %N number of patches being generated
1238 %R changeset revision number
1238 %R changeset revision number
1239 %b basename of the exporting repository
1239 %b basename of the exporting repository
1240 %h short-form changeset hash (12 bytes of hexadecimal)
1240 %h short-form changeset hash (12 bytes of hexadecimal)
1241 %n zero-padded sequence number, starting at 1
1241 %n zero-padded sequence number, starting at 1
1242 %r zero-padded changeset revision number
1242 %r zero-padded changeset revision number
1243
1243
1244 Without the -a option, export will avoid generating diffs of files
1244 Without the -a option, export will avoid generating diffs of files
1245 it detects as binary. With -a, export will generate a diff anyway,
1245 it detects as binary. With -a, export will generate a diff anyway,
1246 probably with undesirable results.
1246 probably with undesirable results.
1247
1247
1248 With the --switch-parent option, the diff will be against the second
1248 With the --switch-parent option, the diff will be against the second
1249 parent. It can be useful to review a merge.
1249 parent. It can be useful to review a merge.
1250 """
1250 """
1251 if not changesets:
1251 if not changesets:
1252 raise util.Abort(_("export requires at least one changeset"))
1252 raise util.Abort(_("export requires at least one changeset"))
1253 revs = cmdutil.revrange(ui, repo, changesets)
1253 revs = cmdutil.revrange(ui, repo, changesets)
1254 if len(revs) > 1:
1254 if len(revs) > 1:
1255 ui.note(_('exporting patches:\n'))
1255 ui.note(_('exporting patches:\n'))
1256 else:
1256 else:
1257 ui.note(_('exporting patch:\n'))
1257 ui.note(_('exporting patch:\n'))
1258 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1258 patch.export(repo, map(repo.lookup, revs), template=opts['output'],
1259 switch_parent=opts['switch_parent'],
1259 switch_parent=opts['switch_parent'],
1260 opts=patch.diffopts(ui, opts))
1260 opts=patch.diffopts(ui, opts))
1261
1261
1262 def grep(ui, repo, pattern, *pats, **opts):
1262 def grep(ui, repo, pattern, *pats, **opts):
1263 """search for a pattern in specified files and revisions
1263 """search for a pattern in specified files and revisions
1264
1264
1265 Search revisions of files for a regular expression.
1265 Search revisions of files for a regular expression.
1266
1266
1267 This command behaves differently than Unix grep. It only accepts
1267 This command behaves differently than Unix grep. It only accepts
1268 Python/Perl regexps. It searches repository history, not the
1268 Python/Perl regexps. It searches repository history, not the
1269 working directory. It always prints the revision number in which
1269 working directory. It always prints the revision number in which
1270 a match appears.
1270 a match appears.
1271
1271
1272 By default, grep only prints output for the first revision of a
1272 By default, grep only prints output for the first revision of a
1273 file in which it finds a match. To get it to print every revision
1273 file in which it finds a match. To get it to print every revision
1274 that contains a change in match status ("-" for a match that
1274 that contains a change in match status ("-" for a match that
1275 becomes a non-match, or "+" for a non-match that becomes a match),
1275 becomes a non-match, or "+" for a non-match that becomes a match),
1276 use the --all flag.
1276 use the --all flag.
1277 """
1277 """
1278 reflags = 0
1278 reflags = 0
1279 if opts['ignore_case']:
1279 if opts['ignore_case']:
1280 reflags |= re.I
1280 reflags |= re.I
1281 regexp = re.compile(pattern, reflags)
1281 regexp = re.compile(pattern, reflags)
1282 sep, eol = ':', '\n'
1282 sep, eol = ':', '\n'
1283 if opts['print0']:
1283 if opts['print0']:
1284 sep = eol = '\0'
1284 sep = eol = '\0'
1285
1285
1286 fcache = {}
1286 fcache = {}
1287 def getfile(fn):
1287 def getfile(fn):
1288 if fn not in fcache:
1288 if fn not in fcache:
1289 fcache[fn] = repo.file(fn)
1289 fcache[fn] = repo.file(fn)
1290 return fcache[fn]
1290 return fcache[fn]
1291
1291
1292 def matchlines(body):
1292 def matchlines(body):
1293 begin = 0
1293 begin = 0
1294 linenum = 0
1294 linenum = 0
1295 while True:
1295 while True:
1296 match = regexp.search(body, begin)
1296 match = regexp.search(body, begin)
1297 if not match:
1297 if not match:
1298 break
1298 break
1299 mstart, mend = match.span()
1299 mstart, mend = match.span()
1300 linenum += body.count('\n', begin, mstart) + 1
1300 linenum += body.count('\n', begin, mstart) + 1
1301 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1301 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1302 lend = body.find('\n', mend)
1302 lend = body.find('\n', mend)
1303 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1303 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1304 begin = lend + 1
1304 begin = lend + 1
1305
1305
1306 class linestate(object):
1306 class linestate(object):
1307 def __init__(self, line, linenum, colstart, colend):
1307 def __init__(self, line, linenum, colstart, colend):
1308 self.line = line
1308 self.line = line
1309 self.linenum = linenum
1309 self.linenum = linenum
1310 self.colstart = colstart
1310 self.colstart = colstart
1311 self.colend = colend
1311 self.colend = colend
1312
1312
1313 def __eq__(self, other):
1313 def __eq__(self, other):
1314 return self.line == other.line
1314 return self.line == other.line
1315
1315
1316 matches = {}
1316 matches = {}
1317 copies = {}
1317 copies = {}
1318 def grepbody(fn, rev, body):
1318 def grepbody(fn, rev, body):
1319 matches[rev].setdefault(fn, [])
1319 matches[rev].setdefault(fn, [])
1320 m = matches[rev][fn]
1320 m = matches[rev][fn]
1321 for lnum, cstart, cend, line in matchlines(body):
1321 for lnum, cstart, cend, line in matchlines(body):
1322 s = linestate(line, lnum, cstart, cend)
1322 s = linestate(line, lnum, cstart, cend)
1323 m.append(s)
1323 m.append(s)
1324
1324
1325 def difflinestates(a, b):
1325 def difflinestates(a, b):
1326 sm = difflib.SequenceMatcher(None, a, b)
1326 sm = difflib.SequenceMatcher(None, a, b)
1327 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1327 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1328 if tag == 'insert':
1328 if tag == 'insert':
1329 for i in xrange(blo, bhi):
1329 for i in xrange(blo, bhi):
1330 yield ('+', b[i])
1330 yield ('+', b[i])
1331 elif tag == 'delete':
1331 elif tag == 'delete':
1332 for i in xrange(alo, ahi):
1332 for i in xrange(alo, ahi):
1333 yield ('-', a[i])
1333 yield ('-', a[i])
1334 elif tag == 'replace':
1334 elif tag == 'replace':
1335 for i in xrange(alo, ahi):
1335 for i in xrange(alo, ahi):
1336 yield ('-', a[i])
1336 yield ('-', a[i])
1337 for i in xrange(blo, bhi):
1337 for i in xrange(blo, bhi):
1338 yield ('+', b[i])
1338 yield ('+', b[i])
1339
1339
1340 prev = {}
1340 prev = {}
1341 def display(fn, rev, states, prevstates):
1341 def display(fn, rev, states, prevstates):
1342 counts = {'-': 0, '+': 0}
1342 counts = {'-': 0, '+': 0}
1343 filerevmatches = {}
1343 filerevmatches = {}
1344 if incrementing or not opts['all']:
1344 if incrementing or not opts['all']:
1345 a, b, r = prevstates, states, rev
1345 a, b, r = prevstates, states, rev
1346 else:
1346 else:
1347 a, b, r = states, prevstates, prev.get(fn, -1)
1347 a, b, r = states, prevstates, prev.get(fn, -1)
1348 for change, l in difflinestates(a, b):
1348 for change, l in difflinestates(a, b):
1349 cols = [fn, str(r)]
1349 cols = [fn, str(r)]
1350 if opts['line_number']:
1350 if opts['line_number']:
1351 cols.append(str(l.linenum))
1351 cols.append(str(l.linenum))
1352 if opts['all']:
1352 if opts['all']:
1353 cols.append(change)
1353 cols.append(change)
1354 if opts['user']:
1354 if opts['user']:
1355 cols.append(ui.shortuser(getchange(r)[1]))
1355 cols.append(ui.shortuser(getchange(r)[1]))
1356 if opts['files_with_matches']:
1356 if opts['files_with_matches']:
1357 c = (fn, r)
1357 c = (fn, r)
1358 if c in filerevmatches:
1358 if c in filerevmatches:
1359 continue
1359 continue
1360 filerevmatches[c] = 1
1360 filerevmatches[c] = 1
1361 else:
1361 else:
1362 cols.append(l.line)
1362 cols.append(l.line)
1363 ui.write(sep.join(cols), eol)
1363 ui.write(sep.join(cols), eol)
1364 counts[change] += 1
1364 counts[change] += 1
1365 return counts['+'], counts['-']
1365 return counts['+'], counts['-']
1366
1366
1367 fstate = {}
1367 fstate = {}
1368 skip = {}
1368 skip = {}
1369 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1369 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1370 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1370 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1371 count = 0
1371 count = 0
1372 incrementing = False
1372 incrementing = False
1373 follow = opts.get('follow')
1373 follow = opts.get('follow')
1374 for st, rev, fns in changeiter:
1374 for st, rev, fns in changeiter:
1375 if st == 'window':
1375 if st == 'window':
1376 incrementing = rev
1376 incrementing = rev
1377 matches.clear()
1377 matches.clear()
1378 elif st == 'add':
1378 elif st == 'add':
1379 mf = repo.changectx(rev).manifest()
1379 mf = repo.changectx(rev).manifest()
1380 matches[rev] = {}
1380 matches[rev] = {}
1381 for fn in fns:
1381 for fn in fns:
1382 if fn in skip:
1382 if fn in skip:
1383 continue
1383 continue
1384 fstate.setdefault(fn, {})
1384 fstate.setdefault(fn, {})
1385 try:
1385 try:
1386 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1386 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1387 if follow:
1387 if follow:
1388 copied = getfile(fn).renamed(mf[fn])
1388 copied = getfile(fn).renamed(mf[fn])
1389 if copied:
1389 if copied:
1390 copies.setdefault(rev, {})[fn] = copied[0]
1390 copies.setdefault(rev, {})[fn] = copied[0]
1391 except KeyError:
1391 except KeyError:
1392 pass
1392 pass
1393 elif st == 'iter':
1393 elif st == 'iter':
1394 states = matches[rev].items()
1394 states = matches[rev].items()
1395 states.sort()
1395 states.sort()
1396 for fn, m in states:
1396 for fn, m in states:
1397 copy = copies.get(rev, {}).get(fn)
1397 copy = copies.get(rev, {}).get(fn)
1398 if fn in skip:
1398 if fn in skip:
1399 if copy:
1399 if copy:
1400 skip[copy] = True
1400 skip[copy] = True
1401 continue
1401 continue
1402 if incrementing or not opts['all'] or fstate[fn]:
1402 if incrementing or not opts['all'] or fstate[fn]:
1403 pos, neg = display(fn, rev, m, fstate[fn])
1403 pos, neg = display(fn, rev, m, fstate[fn])
1404 count += pos + neg
1404 count += pos + neg
1405 if pos and not opts['all']:
1405 if pos and not opts['all']:
1406 skip[fn] = True
1406 skip[fn] = True
1407 if copy:
1407 if copy:
1408 skip[copy] = True
1408 skip[copy] = True
1409 fstate[fn] = m
1409 fstate[fn] = m
1410 if copy:
1410 if copy:
1411 fstate[copy] = m
1411 fstate[copy] = m
1412 prev[fn] = rev
1412 prev[fn] = rev
1413
1413
1414 if not incrementing:
1414 if not incrementing:
1415 fstate = fstate.items()
1415 fstate = fstate.items()
1416 fstate.sort()
1416 fstate.sort()
1417 for fn, state in fstate:
1417 for fn, state in fstate:
1418 if fn in skip:
1418 if fn in skip:
1419 continue
1419 continue
1420 if fn not in copies.get(prev[fn], {}):
1420 if fn not in copies.get(prev[fn], {}):
1421 display(fn, rev, {}, state)
1421 display(fn, rev, {}, state)
1422 return (count == 0 and 1) or 0
1422 return (count == 0 and 1) or 0
1423
1423
1424 def heads(ui, repo, **opts):
1424 def heads(ui, repo, **opts):
1425 """show current repository heads
1425 """show current repository heads
1426
1426
1427 Show all repository head changesets.
1427 Show all repository head changesets.
1428
1428
1429 Repository "heads" are changesets that don't have children
1429 Repository "heads" are changesets that don't have children
1430 changesets. They are where development generally takes place and
1430 changesets. They are where development generally takes place and
1431 are the usual targets for update and merge operations.
1431 are the usual targets for update and merge operations.
1432 """
1432 """
1433 if opts['rev']:
1433 if opts['rev']:
1434 heads = repo.heads(repo.lookup(opts['rev']))
1434 heads = repo.heads(repo.lookup(opts['rev']))
1435 else:
1435 else:
1436 heads = repo.heads()
1436 heads = repo.heads()
1437 br = None
1437 br = None
1438 if opts['branches']:
1438 if opts['branches']:
1439 ui.warn(_("the --branches option is deprecated, "
1439 ui.warn(_("the --branches option is deprecated, "
1440 "please use 'hg branches' instead\n"))
1440 "please use 'hg branches' instead\n"))
1441 br = repo.branchlookup(heads)
1441 br = repo.branchlookup(heads)
1442 displayer = cmdutil.show_changeset(ui, repo, opts)
1442 displayer = cmdutil.show_changeset(ui, repo, opts)
1443 for n in heads:
1443 for n in heads:
1444 displayer.show(changenode=n, brinfo=br)
1444 displayer.show(changenode=n, brinfo=br)
1445
1445
1446 def identify(ui, repo):
1446 def identify(ui, repo):
1447 """print information about the working copy
1447 """print information about the working copy
1448
1448
1449 Print a short summary of the current state of the repo.
1449 Print a short summary of the current state of the repo.
1450
1450
1451 This summary identifies the repository state using one or two parent
1451 This summary identifies the repository state using one or two parent
1452 hash identifiers, followed by a "+" if there are uncommitted changes
1452 hash identifiers, followed by a "+" if there are uncommitted changes
1453 in the working directory, followed by a list of tags for this revision.
1453 in the working directory, followed by a list of tags for this revision.
1454 """
1454 """
1455 parents = [p for p in repo.dirstate.parents() if p != nullid]
1455 parents = [p for p in repo.dirstate.parents() if p != nullid]
1456 if not parents:
1456 if not parents:
1457 ui.write(_("unknown\n"))
1457 ui.write(_("unknown\n"))
1458 return
1458 return
1459
1459
1460 hexfunc = ui.debugflag and hex or short
1460 hexfunc = ui.debugflag and hex or short
1461 modified, added, removed, deleted = repo.status()[:4]
1461 modified, added, removed, deleted = repo.status()[:4]
1462 output = ["%s%s" %
1462 output = ["%s%s" %
1463 ('+'.join([hexfunc(parent) for parent in parents]),
1463 ('+'.join([hexfunc(parent) for parent in parents]),
1464 (modified or added or removed or deleted) and "+" or "")]
1464 (modified or added or removed or deleted) and "+" or "")]
1465
1465
1466 if not ui.quiet:
1466 if not ui.quiet:
1467
1467
1468 branch = repo.workingctx().branch()
1468 branch = repo.workingctx().branch()
1469 if branch:
1469 if branch:
1470 output.append("(%s)" % branch)
1470 output.append("(%s)" % branch)
1471
1471
1472 # multiple tags for a single parent separated by '/'
1472 # multiple tags for a single parent separated by '/'
1473 parenttags = ['/'.join(tags)
1473 parenttags = ['/'.join(tags)
1474 for tags in map(repo.nodetags, parents) if tags]
1474 for tags in map(repo.nodetags, parents) if tags]
1475 # tags for multiple parents separated by ' + '
1475 # tags for multiple parents separated by ' + '
1476 if parenttags:
1476 if parenttags:
1477 output.append(' + '.join(parenttags))
1477 output.append(' + '.join(parenttags))
1478
1478
1479 ui.write("%s\n" % ' '.join(output))
1479 ui.write("%s\n" % ' '.join(output))
1480
1480
1481 def import_(ui, repo, patch1, *patches, **opts):
1481 def import_(ui, repo, patch1, *patches, **opts):
1482 """import an ordered set of patches
1482 """import an ordered set of patches
1483
1483
1484 Import a list of patches and commit them individually.
1484 Import a list of patches and commit them individually.
1485
1485
1486 If there are outstanding changes in the working directory, import
1486 If there are outstanding changes in the working directory, import
1487 will abort unless given the -f flag.
1487 will abort unless given the -f flag.
1488
1488
1489 You can import a patch straight from a mail message. Even patches
1489 You can import a patch straight from a mail message. Even patches
1490 as attachments work (body part must be type text/plain or
1490 as attachments work (body part must be type text/plain or
1491 text/x-patch to be used). From and Subject headers of email
1491 text/x-patch to be used). From and Subject headers of email
1492 message are used as default committer and commit message. All
1492 message are used as default committer and commit message. All
1493 text/plain body parts before first diff are added to commit
1493 text/plain body parts before first diff are added to commit
1494 message.
1494 message.
1495
1495
1496 If imported patch was generated by hg export, user and description
1496 If imported patch was generated by hg export, user and description
1497 from patch override values from message headers and body. Values
1497 from patch override values from message headers and body. Values
1498 given on command line with -m and -u override these.
1498 given on command line with -m and -u override these.
1499
1499
1500 To read a patch from standard input, use patch name "-".
1500 To read a patch from standard input, use patch name "-".
1501 """
1501 """
1502 patches = (patch1,) + patches
1502 patches = (patch1,) + patches
1503
1503
1504 if not opts['force']:
1504 if not opts['force']:
1505 bail_if_changed(repo)
1505 bail_if_changed(repo)
1506
1506
1507 d = opts["base"]
1507 d = opts["base"]
1508 strip = opts["strip"]
1508 strip = opts["strip"]
1509
1509
1510 wlock = repo.wlock()
1510 wlock = repo.wlock()
1511 lock = repo.lock()
1511 lock = repo.lock()
1512
1512
1513 for p in patches:
1513 for p in patches:
1514 pf = os.path.join(d, p)
1514 pf = os.path.join(d, p)
1515
1515
1516 if pf == '-':
1516 if pf == '-':
1517 ui.status(_("applying patch from stdin\n"))
1517 ui.status(_("applying patch from stdin\n"))
1518 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1518 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1519 else:
1519 else:
1520 ui.status(_("applying %s\n") % p)
1520 ui.status(_("applying %s\n") % p)
1521 tmpname, message, user, date = patch.extract(ui, file(pf))
1521 tmpname, message, user, date = patch.extract(ui, file(pf))
1522
1522
1523 if tmpname is None:
1523 if tmpname is None:
1524 raise util.Abort(_('no diffs found'))
1524 raise util.Abort(_('no diffs found'))
1525
1525
1526 try:
1526 try:
1527 if opts['message']:
1527 if opts['message']:
1528 # pickup the cmdline msg
1528 # pickup the cmdline msg
1529 message = opts['message']
1529 message = opts['message']
1530 elif message:
1530 elif message:
1531 # pickup the patch msg
1531 # pickup the patch msg
1532 message = message.strip()
1532 message = message.strip()
1533 else:
1533 else:
1534 # launch the editor
1534 # launch the editor
1535 message = None
1535 message = None
1536 ui.debug(_('message:\n%s\n') % message)
1536 ui.debug(_('message:\n%s\n') % message)
1537
1537
1538 files = {}
1538 files = {}
1539 try:
1539 try:
1540 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1540 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1541 files=files)
1541 files=files)
1542 finally:
1542 finally:
1543 files = patch.updatedir(ui, repo, files, wlock=wlock)
1543 files = patch.updatedir(ui, repo, files, wlock=wlock)
1544 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1544 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1545 finally:
1545 finally:
1546 os.unlink(tmpname)
1546 os.unlink(tmpname)
1547
1547
1548 def incoming(ui, repo, source="default", **opts):
1548 def incoming(ui, repo, source="default", **opts):
1549 """show new changesets found in source
1549 """show new changesets found in source
1550
1550
1551 Show new changesets found in the specified path/URL or the default
1551 Show new changesets found in the specified path/URL or the default
1552 pull location. These are the changesets that would be pulled if a pull
1552 pull location. These are the changesets that would be pulled if a pull
1553 was requested.
1553 was requested.
1554
1554
1555 For remote repository, using --bundle avoids downloading the changesets
1555 For remote repository, using --bundle avoids downloading the changesets
1556 twice if the incoming is followed by a pull.
1556 twice if the incoming is followed by a pull.
1557
1557
1558 See pull for valid source format details.
1558 See pull for valid source format details.
1559 """
1559 """
1560 source = ui.expandpath(source)
1560 source = ui.expandpath(source)
1561 setremoteconfig(ui, opts)
1561 setremoteconfig(ui, opts)
1562
1562
1563 other = hg.repository(ui, source)
1563 other = hg.repository(ui, source)
1564 incoming = repo.findincoming(other, force=opts["force"])
1564 incoming = repo.findincoming(other, force=opts["force"])
1565 if not incoming:
1565 if not incoming:
1566 ui.status(_("no changes found\n"))
1566 ui.status(_("no changes found\n"))
1567 return
1567 return
1568
1568
1569 cleanup = None
1569 cleanup = None
1570 try:
1570 try:
1571 fname = opts["bundle"]
1571 fname = opts["bundle"]
1572 if fname or not other.local():
1572 if fname or not other.local():
1573 # create a bundle (uncompressed if other repo is not local)
1573 # create a bundle (uncompressed if other repo is not local)
1574 cg = other.changegroup(incoming, "incoming")
1574 cg = other.changegroup(incoming, "incoming")
1575 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1575 fname = cleanup = write_bundle(cg, fname, compress=other.local())
1576 # keep written bundle?
1576 # keep written bundle?
1577 if opts["bundle"]:
1577 if opts["bundle"]:
1578 cleanup = None
1578 cleanup = None
1579 if not other.local():
1579 if not other.local():
1580 # use the created uncompressed bundlerepo
1580 # use the created uncompressed bundlerepo
1581 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1581 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1582
1582
1583 revs = None
1583 revs = None
1584 if opts['rev']:
1584 if opts['rev']:
1585 revs = [other.lookup(rev) for rev in opts['rev']]
1585 revs = [other.lookup(rev) for rev in opts['rev']]
1586 o = other.changelog.nodesbetween(incoming, revs)[0]
1586 o = other.changelog.nodesbetween(incoming, revs)[0]
1587 if opts['newest_first']:
1587 if opts['newest_first']:
1588 o.reverse()
1588 o.reverse()
1589 displayer = cmdutil.show_changeset(ui, other, opts)
1589 displayer = cmdutil.show_changeset(ui, other, opts)
1590 for n in o:
1590 for n in o:
1591 parents = [p for p in other.changelog.parents(n) if p != nullid]
1591 parents = [p for p in other.changelog.parents(n) if p != nullid]
1592 if opts['no_merges'] and len(parents) == 2:
1592 if opts['no_merges'] and len(parents) == 2:
1593 continue
1593 continue
1594 displayer.show(changenode=n)
1594 displayer.show(changenode=n)
1595 if opts['patch']:
1596 prev = (parents and parents[0]) or nullid
1597 patch.diff(other, prev, n, fp=repo.ui)
1598 ui.write("\n")
1599 finally:
1595 finally:
1600 if hasattr(other, 'close'):
1596 if hasattr(other, 'close'):
1601 other.close()
1597 other.close()
1602 if cleanup:
1598 if cleanup:
1603 os.unlink(cleanup)
1599 os.unlink(cleanup)
1604
1600
1605 def init(ui, dest=".", **opts):
1601 def init(ui, dest=".", **opts):
1606 """create a new repository in the given directory
1602 """create a new repository in the given directory
1607
1603
1608 Initialize a new repository in the given directory. If the given
1604 Initialize a new repository in the given directory. If the given
1609 directory does not exist, it is created.
1605 directory does not exist, it is created.
1610
1606
1611 If no directory is given, the current directory is used.
1607 If no directory is given, the current directory is used.
1612
1608
1613 It is possible to specify an ssh:// URL as the destination.
1609 It is possible to specify an ssh:// URL as the destination.
1614 Look at the help text for the pull command for important details
1610 Look at the help text for the pull command for important details
1615 about ssh:// URLs.
1611 about ssh:// URLs.
1616 """
1612 """
1617 setremoteconfig(ui, opts)
1613 setremoteconfig(ui, opts)
1618 hg.repository(ui, dest, create=1)
1614 hg.repository(ui, dest, create=1)
1619
1615
1620 def locate(ui, repo, *pats, **opts):
1616 def locate(ui, repo, *pats, **opts):
1621 """locate files matching specific patterns
1617 """locate files matching specific patterns
1622
1618
1623 Print all files under Mercurial control whose names match the
1619 Print all files under Mercurial control whose names match the
1624 given patterns.
1620 given patterns.
1625
1621
1626 This command searches the current directory and its
1622 This command searches the current directory and its
1627 subdirectories. To search an entire repository, move to the root
1623 subdirectories. To search an entire repository, move to the root
1628 of the repository.
1624 of the repository.
1629
1625
1630 If no patterns are given to match, this command prints all file
1626 If no patterns are given to match, this command prints all file
1631 names.
1627 names.
1632
1628
1633 If you want to feed the output of this command into the "xargs"
1629 If you want to feed the output of this command into the "xargs"
1634 command, use the "-0" option to both this command and "xargs".
1630 command, use the "-0" option to both this command and "xargs".
1635 This will avoid the problem of "xargs" treating single filenames
1631 This will avoid the problem of "xargs" treating single filenames
1636 that contain white space as multiple filenames.
1632 that contain white space as multiple filenames.
1637 """
1633 """
1638 end = opts['print0'] and '\0' or '\n'
1634 end = opts['print0'] and '\0' or '\n'
1639 rev = opts['rev']
1635 rev = opts['rev']
1640 if rev:
1636 if rev:
1641 node = repo.lookup(rev)
1637 node = repo.lookup(rev)
1642 else:
1638 else:
1643 node = None
1639 node = None
1644
1640
1645 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1641 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
1646 head='(?:.*/|)'):
1642 head='(?:.*/|)'):
1647 if not node and repo.dirstate.state(abs) == '?':
1643 if not node and repo.dirstate.state(abs) == '?':
1648 continue
1644 continue
1649 if opts['fullpath']:
1645 if opts['fullpath']:
1650 ui.write(os.path.join(repo.root, abs), end)
1646 ui.write(os.path.join(repo.root, abs), end)
1651 else:
1647 else:
1652 ui.write(((pats and rel) or abs), end)
1648 ui.write(((pats and rel) or abs), end)
1653
1649
1654 def log(ui, repo, *pats, **opts):
1650 def log(ui, repo, *pats, **opts):
1655 """show revision history of entire repository or files
1651 """show revision history of entire repository or files
1656
1652
1657 Print the revision history of the specified files or the entire
1653 Print the revision history of the specified files or the entire
1658 project.
1654 project.
1659
1655
1660 File history is shown without following rename or copy history of
1656 File history is shown without following rename or copy history of
1661 files. Use -f/--follow with a file name to follow history across
1657 files. Use -f/--follow with a file name to follow history across
1662 renames and copies. --follow without a file name will only show
1658 renames and copies. --follow without a file name will only show
1663 ancestors or descendants of the starting revision. --follow-first
1659 ancestors or descendants of the starting revision. --follow-first
1664 only follows the first parent of merge revisions.
1660 only follows the first parent of merge revisions.
1665
1661
1666 If no revision range is specified, the default is tip:0 unless
1662 If no revision range is specified, the default is tip:0 unless
1667 --follow is set, in which case the working directory parent is
1663 --follow is set, in which case the working directory parent is
1668 used as the starting revision.
1664 used as the starting revision.
1669
1665
1670 By default this command outputs: changeset id and hash, tags,
1666 By default this command outputs: changeset id and hash, tags,
1671 non-trivial parents, user, date and time, and a summary for each
1667 non-trivial parents, user, date and time, and a summary for each
1672 commit. When the -v/--verbose switch is used, the list of changed
1668 commit. When the -v/--verbose switch is used, the list of changed
1673 files and full commit message is shown.
1669 files and full commit message is shown.
1674 """
1670 """
1675 class dui(object):
1676 # Implement and delegate some ui protocol. Save hunks of
1677 # output for later display in the desired order.
1678 def __init__(self, ui):
1679 self.ui = ui
1680 self.hunk = {}
1681 self.header = {}
1682 self.quiet = ui.quiet
1683 self.verbose = ui.verbose
1684 self.debugflag = ui.debugflag
1685 def bump(self, rev):
1686 self.rev = rev
1687 self.hunk[rev] = []
1688 self.header[rev] = []
1689 def note(self, *args):
1690 if self.verbose:
1691 self.write(*args)
1692 def status(self, *args):
1693 if not self.quiet:
1694 self.write(*args)
1695 def write(self, *args):
1696 self.hunk[self.rev].extend(args)
1697 def write_header(self, *args):
1698 self.header[self.rev].extend(args)
1699 def debug(self, *args):
1700 if self.debugflag:
1701 self.write(*args)
1702 def __getattr__(self, key):
1703 return getattr(self.ui, key)
1704
1671
1705 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1672 getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
1706 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1673 changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
1707
1674
1708 if opts['branches']:
1675 if opts['branches']:
1709 ui.warn(_("the --branches option is deprecated, "
1676 ui.warn(_("the --branches option is deprecated, "
1710 "please use 'hg branches' instead\n"))
1677 "please use 'hg branches' instead\n"))
1711
1678
1712 if opts['limit']:
1679 if opts['limit']:
1713 try:
1680 try:
1714 limit = int(opts['limit'])
1681 limit = int(opts['limit'])
1715 except ValueError:
1682 except ValueError:
1716 raise util.Abort(_('limit must be a positive integer'))
1683 raise util.Abort(_('limit must be a positive integer'))
1717 if limit <= 0: raise util.Abort(_('limit must be positive'))
1684 if limit <= 0: raise util.Abort(_('limit must be positive'))
1718 else:
1685 else:
1719 limit = sys.maxint
1686 limit = sys.maxint
1720 count = 0
1687 count = 0
1721
1688
1722 if opts['copies'] and opts['rev']:
1689 if opts['copies'] and opts['rev']:
1723 endrev = max(cmdutil.revrange(ui, repo, opts['rev'])) + 1
1690 endrev = max(cmdutil.revrange(ui, repo, opts['rev'])) + 1
1724 else:
1691 else:
1725 endrev = repo.changelog.count()
1692 endrev = repo.changelog.count()
1726 rcache = {}
1693 rcache = {}
1727 ncache = {}
1694 ncache = {}
1728 dcache = []
1695 dcache = []
1729 def getrenamed(fn, rev, man):
1696 def getrenamed(fn, rev, man):
1730 '''looks up all renames for a file (up to endrev) the first
1697 '''looks up all renames for a file (up to endrev) the first
1731 time the file is given. It indexes on the changerev and only
1698 time the file is given. It indexes on the changerev and only
1732 parses the manifest if linkrev != changerev.
1699 parses the manifest if linkrev != changerev.
1733 Returns rename info for fn at changerev rev.'''
1700 Returns rename info for fn at changerev rev.'''
1734 if fn not in rcache:
1701 if fn not in rcache:
1735 rcache[fn] = {}
1702 rcache[fn] = {}
1736 ncache[fn] = {}
1703 ncache[fn] = {}
1737 fl = repo.file(fn)
1704 fl = repo.file(fn)
1738 for i in xrange(fl.count()):
1705 for i in xrange(fl.count()):
1739 node = fl.node(i)
1706 node = fl.node(i)
1740 lr = fl.linkrev(node)
1707 lr = fl.linkrev(node)
1741 renamed = fl.renamed(node)
1708 renamed = fl.renamed(node)
1742 rcache[fn][lr] = renamed
1709 rcache[fn][lr] = renamed
1743 if renamed:
1710 if renamed:
1744 ncache[fn][node] = renamed
1711 ncache[fn][node] = renamed
1745 if lr >= endrev:
1712 if lr >= endrev:
1746 break
1713 break
1747 if rev in rcache[fn]:
1714 if rev in rcache[fn]:
1748 return rcache[fn][rev]
1715 return rcache[fn][rev]
1749 mr = repo.manifest.rev(man)
1716 mr = repo.manifest.rev(man)
1750 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1717 if repo.manifest.parentrevs(mr) != (mr - 1, nullrev):
1751 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1718 return ncache[fn].get(repo.manifest.find(man, fn)[0])
1752 if not dcache or dcache[0] != man:
1719 if not dcache or dcache[0] != man:
1753 dcache[:] = [man, repo.manifest.readdelta(man)]
1720 dcache[:] = [man, repo.manifest.readdelta(man)]
1754 if fn in dcache[1]:
1721 if fn in dcache[1]:
1755 return ncache[fn].get(dcache[1][fn])
1722 return ncache[fn].get(dcache[1][fn])
1756 return None
1723 return None
1757
1724
1758 displayer = cmdutil.show_changeset(ui, repo, opts)
1725 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
1759 for st, rev, fns in changeiter:
1726 for st, rev, fns in changeiter:
1760 if st == 'window':
1727 if st == 'add':
1761 du = dui(ui)
1762 displayer.ui = du
1763 elif st == 'add':
1764 du.bump(rev)
1765 changenode = repo.changelog.node(rev)
1728 changenode = repo.changelog.node(rev)
1766 parents = [p for p in repo.changelog.parentrevs(rev)
1729 parents = [p for p in repo.changelog.parentrevs(rev)
1767 if p != nullrev]
1730 if p != nullrev]
1768 if opts['no_merges'] and len(parents) == 2:
1731 if opts['no_merges'] and len(parents) == 2:
1769 continue
1732 continue
1770 if opts['only_merges'] and len(parents) != 2:
1733 if opts['only_merges'] and len(parents) != 2:
1771 continue
1734 continue
1772
1735
1773 if opts['keyword']:
1736 if opts['keyword']:
1774 changes = getchange(rev)
1737 changes = getchange(rev)
1775 miss = 0
1738 miss = 0
1776 for k in [kw.lower() for kw in opts['keyword']]:
1739 for k in [kw.lower() for kw in opts['keyword']]:
1777 if not (k in changes[1].lower() or
1740 if not (k in changes[1].lower() or
1778 k in changes[4].lower() or
1741 k in changes[4].lower() or
1779 k in " ".join(changes[3][:20]).lower()):
1742 k in " ".join(changes[3][:20]).lower()):
1780 miss = 1
1743 miss = 1
1781 break
1744 break
1782 if miss:
1745 if miss:
1783 continue
1746 continue
1784
1747
1785 br = None
1748 br = None
1786 if opts['branches']:
1749 if opts['branches']:
1787 br = repo.branchlookup([repo.changelog.node(rev)])
1750 br = repo.branchlookup([repo.changelog.node(rev)])
1788
1751
1789 copies = []
1752 copies = []
1790 if opts.get('copies') and rev:
1753 if opts.get('copies') and rev:
1791 mf = getchange(rev)[0]
1754 mf = getchange(rev)[0]
1792 for fn in getchange(rev)[3]:
1755 for fn in getchange(rev)[3]:
1793 rename = getrenamed(fn, rev, mf)
1756 rename = getrenamed(fn, rev, mf)
1794 if rename:
1757 if rename:
1795 copies.append((fn, rename[0]))
1758 copies.append((fn, rename[0]))
1796 displayer.show(rev, changenode, brinfo=br, copies=copies)
1759 displayer.show(rev, changenode, brinfo=br, copies=copies)
1797 if opts['patch']:
1798 if parents:
1799 prev = parents[0]
1800 else:
1801 prev = nullrev
1802 prev = repo.changelog.node(prev)
1803 patch.diff(repo, prev, changenode, match=matchfn, fp=du)
1804 du.write("\n\n")
1805 elif st == 'iter':
1760 elif st == 'iter':
1806 if count == limit: break
1761 if count == limit: break
1807 if du.header[rev]:
1762 if displayer.flush(rev):
1808 ui.write_header(*du.header[rev])
1809 if du.hunk[rev]:
1810 count += 1
1763 count += 1
1811 ui.write(*du.hunk[rev])
1812
1764
1813 def manifest(ui, repo, rev=None):
1765 def manifest(ui, repo, rev=None):
1814 """output the latest or given revision of the project manifest
1766 """output the latest or given revision of the project manifest
1815
1767
1816 Print a list of version controlled files for the given revision.
1768 Print a list of version controlled files for the given revision.
1817
1769
1818 The manifest is the list of files being version controlled. If no revision
1770 The manifest is the list of files being version controlled. If no revision
1819 is given then the tip is used.
1771 is given then the tip is used.
1820 """
1772 """
1821 if rev:
1773 if rev:
1822 try:
1774 try:
1823 # assume all revision numbers are for changesets
1775 # assume all revision numbers are for changesets
1824 n = repo.lookup(rev)
1776 n = repo.lookup(rev)
1825 change = repo.changelog.read(n)
1777 change = repo.changelog.read(n)
1826 n = change[0]
1778 n = change[0]
1827 except hg.RepoError:
1779 except hg.RepoError:
1828 n = repo.manifest.lookup(rev)
1780 n = repo.manifest.lookup(rev)
1829 else:
1781 else:
1830 n = repo.manifest.tip()
1782 n = repo.manifest.tip()
1831 m = repo.manifest.read(n)
1783 m = repo.manifest.read(n)
1832 files = m.keys()
1784 files = m.keys()
1833 files.sort()
1785 files.sort()
1834
1786
1835 for f in files:
1787 for f in files:
1836 ui.write("%40s %3s %s\n" % (hex(m[f]),
1788 ui.write("%40s %3s %s\n" % (hex(m[f]),
1837 m.execf(f) and "755" or "644", f))
1789 m.execf(f) and "755" or "644", f))
1838
1790
1839 def merge(ui, repo, node=None, force=None, branch=None):
1791 def merge(ui, repo, node=None, force=None, branch=None):
1840 """Merge working directory with another revision
1792 """Merge working directory with another revision
1841
1793
1842 Merge the contents of the current working directory and the
1794 Merge the contents of the current working directory and the
1843 requested revision. Files that changed between either parent are
1795 requested revision. Files that changed between either parent are
1844 marked as changed for the next commit and a commit must be
1796 marked as changed for the next commit and a commit must be
1845 performed before any further updates are allowed.
1797 performed before any further updates are allowed.
1846
1798
1847 If no revision is specified, the working directory's parent is a
1799 If no revision is specified, the working directory's parent is a
1848 head revision, and the repository contains exactly one other head,
1800 head revision, and the repository contains exactly one other head,
1849 the other head is merged with by default. Otherwise, an explicit
1801 the other head is merged with by default. Otherwise, an explicit
1850 revision to merge with must be provided.
1802 revision to merge with must be provided.
1851 """
1803 """
1852
1804
1853 if node or branch:
1805 if node or branch:
1854 node = _lookup(repo, node, branch)
1806 node = _lookup(repo, node, branch)
1855 else:
1807 else:
1856 heads = repo.heads()
1808 heads = repo.heads()
1857 if len(heads) > 2:
1809 if len(heads) > 2:
1858 raise util.Abort(_('repo has %d heads - '
1810 raise util.Abort(_('repo has %d heads - '
1859 'please merge with an explicit rev') %
1811 'please merge with an explicit rev') %
1860 len(heads))
1812 len(heads))
1861 if len(heads) == 1:
1813 if len(heads) == 1:
1862 raise util.Abort(_('there is nothing to merge - '
1814 raise util.Abort(_('there is nothing to merge - '
1863 'use "hg update" instead'))
1815 'use "hg update" instead'))
1864 parent = repo.dirstate.parents()[0]
1816 parent = repo.dirstate.parents()[0]
1865 if parent not in heads:
1817 if parent not in heads:
1866 raise util.Abort(_('working dir not at a head rev - '
1818 raise util.Abort(_('working dir not at a head rev - '
1867 'use "hg update" or merge with an explicit rev'))
1819 'use "hg update" or merge with an explicit rev'))
1868 node = parent == heads[0] and heads[-1] or heads[0]
1820 node = parent == heads[0] and heads[-1] or heads[0]
1869 return hg.merge(repo, node, force=force)
1821 return hg.merge(repo, node, force=force)
1870
1822
1871 def outgoing(ui, repo, dest=None, **opts):
1823 def outgoing(ui, repo, dest=None, **opts):
1872 """show changesets not found in destination
1824 """show changesets not found in destination
1873
1825
1874 Show changesets not found in the specified destination repository or
1826 Show changesets not found in the specified destination repository or
1875 the default push location. These are the changesets that would be pushed
1827 the default push location. These are the changesets that would be pushed
1876 if a push was requested.
1828 if a push was requested.
1877
1829
1878 See pull for valid destination format details.
1830 See pull for valid destination format details.
1879 """
1831 """
1880 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1832 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1881 setremoteconfig(ui, opts)
1833 setremoteconfig(ui, opts)
1882 revs = None
1834 revs = None
1883 if opts['rev']:
1835 if opts['rev']:
1884 revs = [repo.lookup(rev) for rev in opts['rev']]
1836 revs = [repo.lookup(rev) for rev in opts['rev']]
1885
1837
1886 other = hg.repository(ui, dest)
1838 other = hg.repository(ui, dest)
1887 o = repo.findoutgoing(other, force=opts['force'])
1839 o = repo.findoutgoing(other, force=opts['force'])
1888 if not o:
1840 if not o:
1889 ui.status(_("no changes found\n"))
1841 ui.status(_("no changes found\n"))
1890 return
1842 return
1891 o = repo.changelog.nodesbetween(o, revs)[0]
1843 o = repo.changelog.nodesbetween(o, revs)[0]
1892 if opts['newest_first']:
1844 if opts['newest_first']:
1893 o.reverse()
1845 o.reverse()
1894 displayer = cmdutil.show_changeset(ui, repo, opts)
1846 displayer = cmdutil.show_changeset(ui, repo, opts)
1895 for n in o:
1847 for n in o:
1896 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1848 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1897 if opts['no_merges'] and len(parents) == 2:
1849 if opts['no_merges'] and len(parents) == 2:
1898 continue
1850 continue
1899 displayer.show(changenode=n)
1851 displayer.show(changenode=n)
1900 if opts['patch']:
1901 prev = (parents and parents[0]) or nullid
1902 patch.diff(repo, prev, n)
1903 ui.write("\n")
1904
1852
1905 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1853 def parents(ui, repo, file_=None, rev=None, branches=None, **opts):
1906 """show the parents of the working dir or revision
1854 """show the parents of the working dir or revision
1907
1855
1908 Print the working directory's parent revisions.
1856 Print the working directory's parent revisions.
1909 """
1857 """
1910 # legacy
1858 # legacy
1911 if file_ and not rev:
1859 if file_ and not rev:
1912 try:
1860 try:
1913 rev = repo.lookup(file_)
1861 rev = repo.lookup(file_)
1914 file_ = None
1862 file_ = None
1915 except hg.RepoError:
1863 except hg.RepoError:
1916 pass
1864 pass
1917 else:
1865 else:
1918 ui.warn(_("'hg parent REV' is deprecated, "
1866 ui.warn(_("'hg parent REV' is deprecated, "
1919 "please use 'hg parents -r REV instead\n"))
1867 "please use 'hg parents -r REV instead\n"))
1920
1868
1921 if rev:
1869 if rev:
1922 if file_:
1870 if file_:
1923 ctx = repo.filectx(file_, changeid=rev)
1871 ctx = repo.filectx(file_, changeid=rev)
1924 else:
1872 else:
1925 ctx = repo.changectx(rev)
1873 ctx = repo.changectx(rev)
1926 p = [cp.node() for cp in ctx.parents()]
1874 p = [cp.node() for cp in ctx.parents()]
1927 else:
1875 else:
1928 p = repo.dirstate.parents()
1876 p = repo.dirstate.parents()
1929
1877
1930 br = None
1878 br = None
1931 if branches is not None:
1879 if branches is not None:
1932 ui.warn(_("the --branches option is deprecated, "
1880 ui.warn(_("the --branches option is deprecated, "
1933 "please use 'hg branches' instead\n"))
1881 "please use 'hg branches' instead\n"))
1934 br = repo.branchlookup(p)
1882 br = repo.branchlookup(p)
1935 displayer = cmdutil.show_changeset(ui, repo, opts)
1883 displayer = cmdutil.show_changeset(ui, repo, opts)
1936 for n in p:
1884 for n in p:
1937 if n != nullid:
1885 if n != nullid:
1938 displayer.show(changenode=n, brinfo=br)
1886 displayer.show(changenode=n, brinfo=br)
1939
1887
1940 def paths(ui, repo, search=None):
1888 def paths(ui, repo, search=None):
1941 """show definition of symbolic path names
1889 """show definition of symbolic path names
1942
1890
1943 Show definition of symbolic path name NAME. If no name is given, show
1891 Show definition of symbolic path name NAME. If no name is given, show
1944 definition of available names.
1892 definition of available names.
1945
1893
1946 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1894 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1947 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1895 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1948 """
1896 """
1949 if search:
1897 if search:
1950 for name, path in ui.configitems("paths"):
1898 for name, path in ui.configitems("paths"):
1951 if name == search:
1899 if name == search:
1952 ui.write("%s\n" % path)
1900 ui.write("%s\n" % path)
1953 return
1901 return
1954 ui.warn(_("not found!\n"))
1902 ui.warn(_("not found!\n"))
1955 return 1
1903 return 1
1956 else:
1904 else:
1957 for name, path in ui.configitems("paths"):
1905 for name, path in ui.configitems("paths"):
1958 ui.write("%s = %s\n" % (name, path))
1906 ui.write("%s = %s\n" % (name, path))
1959
1907
1960 def postincoming(ui, repo, modheads, optupdate):
1908 def postincoming(ui, repo, modheads, optupdate):
1961 if modheads == 0:
1909 if modheads == 0:
1962 return
1910 return
1963 if optupdate:
1911 if optupdate:
1964 if modheads == 1:
1912 if modheads == 1:
1965 return hg.update(repo, repo.changelog.tip()) # update
1913 return hg.update(repo, repo.changelog.tip()) # update
1966 else:
1914 else:
1967 ui.status(_("not updating, since new heads added\n"))
1915 ui.status(_("not updating, since new heads added\n"))
1968 if modheads > 1:
1916 if modheads > 1:
1969 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1917 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
1970 else:
1918 else:
1971 ui.status(_("(run 'hg update' to get a working copy)\n"))
1919 ui.status(_("(run 'hg update' to get a working copy)\n"))
1972
1920
1973 def pull(ui, repo, source="default", **opts):
1921 def pull(ui, repo, source="default", **opts):
1974 """pull changes from the specified source
1922 """pull changes from the specified source
1975
1923
1976 Pull changes from a remote repository to a local one.
1924 Pull changes from a remote repository to a local one.
1977
1925
1978 This finds all changes from the repository at the specified path
1926 This finds all changes from the repository at the specified path
1979 or URL and adds them to the local repository. By default, this
1927 or URL and adds them to the local repository. By default, this
1980 does not update the copy of the project in the working directory.
1928 does not update the copy of the project in the working directory.
1981
1929
1982 Valid URLs are of the form:
1930 Valid URLs are of the form:
1983
1931
1984 local/filesystem/path (or file://local/filesystem/path)
1932 local/filesystem/path (or file://local/filesystem/path)
1985 http://[user@]host[:port]/[path]
1933 http://[user@]host[:port]/[path]
1986 https://[user@]host[:port]/[path]
1934 https://[user@]host[:port]/[path]
1987 ssh://[user@]host[:port]/[path]
1935 ssh://[user@]host[:port]/[path]
1988 static-http://host[:port]/[path]
1936 static-http://host[:port]/[path]
1989
1937
1990 Paths in the local filesystem can either point to Mercurial
1938 Paths in the local filesystem can either point to Mercurial
1991 repositories or to bundle files (as created by 'hg bundle' or
1939 repositories or to bundle files (as created by 'hg bundle' or
1992 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1940 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
1993 allows access to a Mercurial repository where you simply use a web
1941 allows access to a Mercurial repository where you simply use a web
1994 server to publish the .hg directory as static content.
1942 server to publish the .hg directory as static content.
1995
1943
1996 Some notes about using SSH with Mercurial:
1944 Some notes about using SSH with Mercurial:
1997 - SSH requires an accessible shell account on the destination machine
1945 - SSH requires an accessible shell account on the destination machine
1998 and a copy of hg in the remote path or specified with as remotecmd.
1946 and a copy of hg in the remote path or specified with as remotecmd.
1999 - path is relative to the remote user's home directory by default.
1947 - path is relative to the remote user's home directory by default.
2000 Use an extra slash at the start of a path to specify an absolute path:
1948 Use an extra slash at the start of a path to specify an absolute path:
2001 ssh://example.com//tmp/repository
1949 ssh://example.com//tmp/repository
2002 - Mercurial doesn't use its own compression via SSH; the right thing
1950 - Mercurial doesn't use its own compression via SSH; the right thing
2003 to do is to configure it in your ~/.ssh/config, e.g.:
1951 to do is to configure it in your ~/.ssh/config, e.g.:
2004 Host *.mylocalnetwork.example.com
1952 Host *.mylocalnetwork.example.com
2005 Compression no
1953 Compression no
2006 Host *
1954 Host *
2007 Compression yes
1955 Compression yes
2008 Alternatively specify "ssh -C" as your ssh command in your hgrc or
1956 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2009 with the --ssh command line option.
1957 with the --ssh command line option.
2010 """
1958 """
2011 source = ui.expandpath(source)
1959 source = ui.expandpath(source)
2012 setremoteconfig(ui, opts)
1960 setremoteconfig(ui, opts)
2013
1961
2014 other = hg.repository(ui, source)
1962 other = hg.repository(ui, source)
2015 ui.status(_('pulling from %s\n') % (source))
1963 ui.status(_('pulling from %s\n') % (source))
2016 revs = None
1964 revs = None
2017 if opts['rev']:
1965 if opts['rev']:
2018 if 'lookup' in other.capabilities:
1966 if 'lookup' in other.capabilities:
2019 revs = [other.lookup(rev) for rev in opts['rev']]
1967 revs = [other.lookup(rev) for rev in opts['rev']]
2020 else:
1968 else:
2021 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
1969 error = _("Other repository doesn't support revision lookup, so a rev cannot be specified.")
2022 raise util.Abort(error)
1970 raise util.Abort(error)
2023 modheads = repo.pull(other, heads=revs, force=opts['force'])
1971 modheads = repo.pull(other, heads=revs, force=opts['force'])
2024 return postincoming(ui, repo, modheads, opts['update'])
1972 return postincoming(ui, repo, modheads, opts['update'])
2025
1973
2026 def push(ui, repo, dest=None, **opts):
1974 def push(ui, repo, dest=None, **opts):
2027 """push changes to the specified destination
1975 """push changes to the specified destination
2028
1976
2029 Push changes from the local repository to the given destination.
1977 Push changes from the local repository to the given destination.
2030
1978
2031 This is the symmetrical operation for pull. It helps to move
1979 This is the symmetrical operation for pull. It helps to move
2032 changes from the current repository to a different one. If the
1980 changes from the current repository to a different one. If the
2033 destination is local this is identical to a pull in that directory
1981 destination is local this is identical to a pull in that directory
2034 from the current one.
1982 from the current one.
2035
1983
2036 By default, push will refuse to run if it detects the result would
1984 By default, push will refuse to run if it detects the result would
2037 increase the number of remote heads. This generally indicates the
1985 increase the number of remote heads. This generally indicates the
2038 the client has forgotten to sync and merge before pushing.
1986 the client has forgotten to sync and merge before pushing.
2039
1987
2040 Valid URLs are of the form:
1988 Valid URLs are of the form:
2041
1989
2042 local/filesystem/path (or file://local/filesystem/path)
1990 local/filesystem/path (or file://local/filesystem/path)
2043 ssh://[user@]host[:port]/[path]
1991 ssh://[user@]host[:port]/[path]
2044 http://[user@]host[:port]/[path]
1992 http://[user@]host[:port]/[path]
2045 https://[user@]host[:port]/[path]
1993 https://[user@]host[:port]/[path]
2046
1994
2047 Look at the help text for the pull command for important details
1995 Look at the help text for the pull command for important details
2048 about ssh:// URLs.
1996 about ssh:// URLs.
2049
1997
2050 Pushing to http:// and https:// URLs is only possible, if this
1998 Pushing to http:// and https:// URLs is only possible, if this
2051 feature is explicitly enabled on the remote Mercurial server.
1999 feature is explicitly enabled on the remote Mercurial server.
2052 """
2000 """
2053 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2001 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2054 setremoteconfig(ui, opts)
2002 setremoteconfig(ui, opts)
2055
2003
2056 other = hg.repository(ui, dest)
2004 other = hg.repository(ui, dest)
2057 ui.status('pushing to %s\n' % (dest))
2005 ui.status('pushing to %s\n' % (dest))
2058 revs = None
2006 revs = None
2059 if opts['rev']:
2007 if opts['rev']:
2060 revs = [repo.lookup(rev) for rev in opts['rev']]
2008 revs = [repo.lookup(rev) for rev in opts['rev']]
2061 r = repo.push(other, opts['force'], revs=revs)
2009 r = repo.push(other, opts['force'], revs=revs)
2062 return r == 0
2010 return r == 0
2063
2011
2064 def rawcommit(ui, repo, *flist, **rc):
2012 def rawcommit(ui, repo, *flist, **rc):
2065 """raw commit interface (DEPRECATED)
2013 """raw commit interface (DEPRECATED)
2066
2014
2067 (DEPRECATED)
2015 (DEPRECATED)
2068 Lowlevel commit, for use in helper scripts.
2016 Lowlevel commit, for use in helper scripts.
2069
2017
2070 This command is not intended to be used by normal users, as it is
2018 This command is not intended to be used by normal users, as it is
2071 primarily useful for importing from other SCMs.
2019 primarily useful for importing from other SCMs.
2072
2020
2073 This command is now deprecated and will be removed in a future
2021 This command is now deprecated and will be removed in a future
2074 release, please use debugsetparents and commit instead.
2022 release, please use debugsetparents and commit instead.
2075 """
2023 """
2076
2024
2077 ui.warn(_("(the rawcommit command is deprecated)\n"))
2025 ui.warn(_("(the rawcommit command is deprecated)\n"))
2078
2026
2079 message = rc['message']
2027 message = rc['message']
2080 if not message and rc['logfile']:
2028 if not message and rc['logfile']:
2081 try:
2029 try:
2082 message = open(rc['logfile']).read()
2030 message = open(rc['logfile']).read()
2083 except IOError:
2031 except IOError:
2084 pass
2032 pass
2085 if not message and not rc['logfile']:
2033 if not message and not rc['logfile']:
2086 raise util.Abort(_("missing commit message"))
2034 raise util.Abort(_("missing commit message"))
2087
2035
2088 files = relpath(repo, list(flist))
2036 files = relpath(repo, list(flist))
2089 if rc['files']:
2037 if rc['files']:
2090 files += open(rc['files']).read().splitlines()
2038 files += open(rc['files']).read().splitlines()
2091
2039
2092 rc['parent'] = map(repo.lookup, rc['parent'])
2040 rc['parent'] = map(repo.lookup, rc['parent'])
2093
2041
2094 try:
2042 try:
2095 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2043 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
2096 except ValueError, inst:
2044 except ValueError, inst:
2097 raise util.Abort(str(inst))
2045 raise util.Abort(str(inst))
2098
2046
2099 def recover(ui, repo):
2047 def recover(ui, repo):
2100 """roll back an interrupted transaction
2048 """roll back an interrupted transaction
2101
2049
2102 Recover from an interrupted commit or pull.
2050 Recover from an interrupted commit or pull.
2103
2051
2104 This command tries to fix the repository status after an interrupted
2052 This command tries to fix the repository status after an interrupted
2105 operation. It should only be necessary when Mercurial suggests it.
2053 operation. It should only be necessary when Mercurial suggests it.
2106 """
2054 """
2107 if repo.recover():
2055 if repo.recover():
2108 return hg.verify(repo)
2056 return hg.verify(repo)
2109 return 1
2057 return 1
2110
2058
2111 def remove(ui, repo, *pats, **opts):
2059 def remove(ui, repo, *pats, **opts):
2112 """remove the specified files on the next commit
2060 """remove the specified files on the next commit
2113
2061
2114 Schedule the indicated files for removal from the repository.
2062 Schedule the indicated files for removal from the repository.
2115
2063
2116 This command schedules the files to be removed at the next commit.
2064 This command schedules the files to be removed at the next commit.
2117 This only removes files from the current branch, not from the
2065 This only removes files from the current branch, not from the
2118 entire project history. If the files still exist in the working
2066 entire project history. If the files still exist in the working
2119 directory, they will be deleted from it. If invoked with --after,
2067 directory, they will be deleted from it. If invoked with --after,
2120 files that have been manually deleted are marked as removed.
2068 files that have been manually deleted are marked as removed.
2121
2069
2122 Modified files and added files are not removed by default. To
2070 Modified files and added files are not removed by default. To
2123 remove them, use the -f/--force option.
2071 remove them, use the -f/--force option.
2124 """
2072 """
2125 names = []
2073 names = []
2126 if not opts['after'] and not pats:
2074 if not opts['after'] and not pats:
2127 raise util.Abort(_('no files specified'))
2075 raise util.Abort(_('no files specified'))
2128 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2076 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2129 exact = dict.fromkeys(files)
2077 exact = dict.fromkeys(files)
2130 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2078 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5]
2131 modified, added, removed, deleted, unknown = mardu
2079 modified, added, removed, deleted, unknown = mardu
2132 remove, forget = [], []
2080 remove, forget = [], []
2133 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2081 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts):
2134 reason = None
2082 reason = None
2135 if abs not in deleted and opts['after']:
2083 if abs not in deleted and opts['after']:
2136 reason = _('is still present')
2084 reason = _('is still present')
2137 elif abs in modified and not opts['force']:
2085 elif abs in modified and not opts['force']:
2138 reason = _('is modified (use -f to force removal)')
2086 reason = _('is modified (use -f to force removal)')
2139 elif abs in added:
2087 elif abs in added:
2140 if opts['force']:
2088 if opts['force']:
2141 forget.append(abs)
2089 forget.append(abs)
2142 continue
2090 continue
2143 reason = _('has been marked for add (use -f to force removal)')
2091 reason = _('has been marked for add (use -f to force removal)')
2144 elif abs in unknown:
2092 elif abs in unknown:
2145 reason = _('is not managed')
2093 reason = _('is not managed')
2146 elif abs in removed:
2094 elif abs in removed:
2147 continue
2095 continue
2148 if reason:
2096 if reason:
2149 if exact:
2097 if exact:
2150 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2098 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2151 else:
2099 else:
2152 if ui.verbose or not exact:
2100 if ui.verbose or not exact:
2153 ui.status(_('removing %s\n') % rel)
2101 ui.status(_('removing %s\n') % rel)
2154 remove.append(abs)
2102 remove.append(abs)
2155 repo.forget(forget)
2103 repo.forget(forget)
2156 repo.remove(remove, unlink=not opts['after'])
2104 repo.remove(remove, unlink=not opts['after'])
2157
2105
2158 def rename(ui, repo, *pats, **opts):
2106 def rename(ui, repo, *pats, **opts):
2159 """rename files; equivalent of copy + remove
2107 """rename files; equivalent of copy + remove
2160
2108
2161 Mark dest as copies of sources; mark sources for deletion. If
2109 Mark dest as copies of sources; mark sources for deletion. If
2162 dest is a directory, copies are put in that directory. If dest is
2110 dest is a directory, copies are put in that directory. If dest is
2163 a file, there can only be one source.
2111 a file, there can only be one source.
2164
2112
2165 By default, this command copies the contents of files as they
2113 By default, this command copies the contents of files as they
2166 stand in the working directory. If invoked with --after, the
2114 stand in the working directory. If invoked with --after, the
2167 operation is recorded, but no copying is performed.
2115 operation is recorded, but no copying is performed.
2168
2116
2169 This command takes effect in the next commit.
2117 This command takes effect in the next commit.
2170
2118
2171 NOTE: This command should be treated as experimental. While it
2119 NOTE: This command should be treated as experimental. While it
2172 should properly record rename files, this information is not yet
2120 should properly record rename files, this information is not yet
2173 fully used by merge, nor fully reported by log.
2121 fully used by merge, nor fully reported by log.
2174 """
2122 """
2175 wlock = repo.wlock(0)
2123 wlock = repo.wlock(0)
2176 errs, copied = docopy(ui, repo, pats, opts, wlock)
2124 errs, copied = docopy(ui, repo, pats, opts, wlock)
2177 names = []
2125 names = []
2178 for abs, rel, exact in copied:
2126 for abs, rel, exact in copied:
2179 if ui.verbose or not exact:
2127 if ui.verbose or not exact:
2180 ui.status(_('removing %s\n') % rel)
2128 ui.status(_('removing %s\n') % rel)
2181 names.append(abs)
2129 names.append(abs)
2182 if not opts.get('dry_run'):
2130 if not opts.get('dry_run'):
2183 repo.remove(names, True, wlock)
2131 repo.remove(names, True, wlock)
2184 return errs
2132 return errs
2185
2133
2186 def revert(ui, repo, *pats, **opts):
2134 def revert(ui, repo, *pats, **opts):
2187 """revert files or dirs to their states as of some revision
2135 """revert files or dirs to their states as of some revision
2188
2136
2189 With no revision specified, revert the named files or directories
2137 With no revision specified, revert the named files or directories
2190 to the contents they had in the parent of the working directory.
2138 to the contents they had in the parent of the working directory.
2191 This restores the contents of the affected files to an unmodified
2139 This restores the contents of the affected files to an unmodified
2192 state. If the working directory has two parents, you must
2140 state. If the working directory has two parents, you must
2193 explicitly specify the revision to revert to.
2141 explicitly specify the revision to revert to.
2194
2142
2195 Modified files are saved with a .orig suffix before reverting.
2143 Modified files are saved with a .orig suffix before reverting.
2196 To disable these backups, use --no-backup.
2144 To disable these backups, use --no-backup.
2197
2145
2198 Using the -r option, revert the given files or directories to their
2146 Using the -r option, revert the given files or directories to their
2199 contents as of a specific revision. This can be helpful to "roll
2147 contents as of a specific revision. This can be helpful to "roll
2200 back" some or all of a change that should not have been committed.
2148 back" some or all of a change that should not have been committed.
2201
2149
2202 Revert modifies the working directory. It does not commit any
2150 Revert modifies the working directory. It does not commit any
2203 changes, or change the parent of the working directory. If you
2151 changes, or change the parent of the working directory. If you
2204 revert to a revision other than the parent of the working
2152 revert to a revision other than the parent of the working
2205 directory, the reverted files will thus appear modified
2153 directory, the reverted files will thus appear modified
2206 afterwards.
2154 afterwards.
2207
2155
2208 If a file has been deleted, it is recreated. If the executable
2156 If a file has been deleted, it is recreated. If the executable
2209 mode of a file was changed, it is reset.
2157 mode of a file was changed, it is reset.
2210
2158
2211 If names are given, all files matching the names are reverted.
2159 If names are given, all files matching the names are reverted.
2212
2160
2213 If no arguments are given, no files are reverted.
2161 If no arguments are given, no files are reverted.
2214 """
2162 """
2215
2163
2216 if not pats and not opts['all']:
2164 if not pats and not opts['all']:
2217 raise util.Abort(_('no files or directories specified; '
2165 raise util.Abort(_('no files or directories specified; '
2218 'use --all to revert the whole repo'))
2166 'use --all to revert the whole repo'))
2219
2167
2220 parent, p2 = repo.dirstate.parents()
2168 parent, p2 = repo.dirstate.parents()
2221 if not opts['rev'] and p2 != nullid:
2169 if not opts['rev'] and p2 != nullid:
2222 raise util.Abort(_('uncommitted merge - please provide a '
2170 raise util.Abort(_('uncommitted merge - please provide a '
2223 'specific revision'))
2171 'specific revision'))
2224 node = repo.changectx(opts['rev']).node()
2172 node = repo.changectx(opts['rev']).node()
2225 mf = repo.manifest.read(repo.changelog.read(node)[0])
2173 mf = repo.manifest.read(repo.changelog.read(node)[0])
2226 if node == parent:
2174 if node == parent:
2227 pmf = mf
2175 pmf = mf
2228 else:
2176 else:
2229 pmf = None
2177 pmf = None
2230
2178
2231 wlock = repo.wlock()
2179 wlock = repo.wlock()
2232
2180
2233 # need all matching names in dirstate and manifest of target rev,
2181 # need all matching names in dirstate and manifest of target rev,
2234 # so have to walk both. do not print errors if files exist in one
2182 # so have to walk both. do not print errors if files exist in one
2235 # but not other.
2183 # but not other.
2236
2184
2237 names = {}
2185 names = {}
2238 target_only = {}
2186 target_only = {}
2239
2187
2240 # walk dirstate.
2188 # walk dirstate.
2241
2189
2242 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2190 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts,
2243 badmatch=mf.has_key):
2191 badmatch=mf.has_key):
2244 names[abs] = (rel, exact)
2192 names[abs] = (rel, exact)
2245 if src == 'b':
2193 if src == 'b':
2246 target_only[abs] = True
2194 target_only[abs] = True
2247
2195
2248 # walk target manifest.
2196 # walk target manifest.
2249
2197
2250 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2198 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node,
2251 badmatch=names.has_key):
2199 badmatch=names.has_key):
2252 if abs in names: continue
2200 if abs in names: continue
2253 names[abs] = (rel, exact)
2201 names[abs] = (rel, exact)
2254 target_only[abs] = True
2202 target_only[abs] = True
2255
2203
2256 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2204 changes = repo.status(match=names.has_key, wlock=wlock)[:5]
2257 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2205 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes)
2258
2206
2259 revert = ([], _('reverting %s\n'))
2207 revert = ([], _('reverting %s\n'))
2260 add = ([], _('adding %s\n'))
2208 add = ([], _('adding %s\n'))
2261 remove = ([], _('removing %s\n'))
2209 remove = ([], _('removing %s\n'))
2262 forget = ([], _('forgetting %s\n'))
2210 forget = ([], _('forgetting %s\n'))
2263 undelete = ([], _('undeleting %s\n'))
2211 undelete = ([], _('undeleting %s\n'))
2264 update = {}
2212 update = {}
2265
2213
2266 disptable = (
2214 disptable = (
2267 # dispatch table:
2215 # dispatch table:
2268 # file state
2216 # file state
2269 # action if in target manifest
2217 # action if in target manifest
2270 # action if not in target manifest
2218 # action if not in target manifest
2271 # make backup if in target manifest
2219 # make backup if in target manifest
2272 # make backup if not in target manifest
2220 # make backup if not in target manifest
2273 (modified, revert, remove, True, True),
2221 (modified, revert, remove, True, True),
2274 (added, revert, forget, True, False),
2222 (added, revert, forget, True, False),
2275 (removed, undelete, None, False, False),
2223 (removed, undelete, None, False, False),
2276 (deleted, revert, remove, False, False),
2224 (deleted, revert, remove, False, False),
2277 (unknown, add, None, True, False),
2225 (unknown, add, None, True, False),
2278 (target_only, add, None, False, False),
2226 (target_only, add, None, False, False),
2279 )
2227 )
2280
2228
2281 entries = names.items()
2229 entries = names.items()
2282 entries.sort()
2230 entries.sort()
2283
2231
2284 for abs, (rel, exact) in entries:
2232 for abs, (rel, exact) in entries:
2285 mfentry = mf.get(abs)
2233 mfentry = mf.get(abs)
2286 def handle(xlist, dobackup):
2234 def handle(xlist, dobackup):
2287 xlist[0].append(abs)
2235 xlist[0].append(abs)
2288 update[abs] = 1
2236 update[abs] = 1
2289 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2237 if dobackup and not opts['no_backup'] and os.path.exists(rel):
2290 bakname = "%s.orig" % rel
2238 bakname = "%s.orig" % rel
2291 ui.note(_('saving current version of %s as %s\n') %
2239 ui.note(_('saving current version of %s as %s\n') %
2292 (rel, bakname))
2240 (rel, bakname))
2293 if not opts.get('dry_run'):
2241 if not opts.get('dry_run'):
2294 util.copyfile(rel, bakname)
2242 util.copyfile(rel, bakname)
2295 if ui.verbose or not exact:
2243 if ui.verbose or not exact:
2296 ui.status(xlist[1] % rel)
2244 ui.status(xlist[1] % rel)
2297 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2245 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2298 if abs not in table: continue
2246 if abs not in table: continue
2299 # file has changed in dirstate
2247 # file has changed in dirstate
2300 if mfentry:
2248 if mfentry:
2301 handle(hitlist, backuphit)
2249 handle(hitlist, backuphit)
2302 elif misslist is not None:
2250 elif misslist is not None:
2303 handle(misslist, backupmiss)
2251 handle(misslist, backupmiss)
2304 else:
2252 else:
2305 if exact: ui.warn(_('file not managed: %s\n' % rel))
2253 if exact: ui.warn(_('file not managed: %s\n' % rel))
2306 break
2254 break
2307 else:
2255 else:
2308 # file has not changed in dirstate
2256 # file has not changed in dirstate
2309 if node == parent:
2257 if node == parent:
2310 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2258 if exact: ui.warn(_('no changes needed to %s\n' % rel))
2311 continue
2259 continue
2312 if pmf is None:
2260 if pmf is None:
2313 # only need parent manifest in this unlikely case,
2261 # only need parent manifest in this unlikely case,
2314 # so do not read by default
2262 # so do not read by default
2315 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2263 pmf = repo.manifest.read(repo.changelog.read(parent)[0])
2316 if abs in pmf:
2264 if abs in pmf:
2317 if mfentry:
2265 if mfentry:
2318 # if version of file is same in parent and target
2266 # if version of file is same in parent and target
2319 # manifests, do nothing
2267 # manifests, do nothing
2320 if pmf[abs] != mfentry:
2268 if pmf[abs] != mfentry:
2321 handle(revert, False)
2269 handle(revert, False)
2322 else:
2270 else:
2323 handle(remove, False)
2271 handle(remove, False)
2324
2272
2325 if not opts.get('dry_run'):
2273 if not opts.get('dry_run'):
2326 repo.dirstate.forget(forget[0])
2274 repo.dirstate.forget(forget[0])
2327 r = hg.revert(repo, node, update.has_key, wlock)
2275 r = hg.revert(repo, node, update.has_key, wlock)
2328 repo.dirstate.update(add[0], 'a')
2276 repo.dirstate.update(add[0], 'a')
2329 repo.dirstate.update(undelete[0], 'n')
2277 repo.dirstate.update(undelete[0], 'n')
2330 repo.dirstate.update(remove[0], 'r')
2278 repo.dirstate.update(remove[0], 'r')
2331 return r
2279 return r
2332
2280
2333 def rollback(ui, repo):
2281 def rollback(ui, repo):
2334 """roll back the last transaction in this repository
2282 """roll back the last transaction in this repository
2335
2283
2336 Roll back the last transaction in this repository, restoring the
2284 Roll back the last transaction in this repository, restoring the
2337 project to its state prior to the transaction.
2285 project to its state prior to the transaction.
2338
2286
2339 Transactions are used to encapsulate the effects of all commands
2287 Transactions are used to encapsulate the effects of all commands
2340 that create new changesets or propagate existing changesets into a
2288 that create new changesets or propagate existing changesets into a
2341 repository. For example, the following commands are transactional,
2289 repository. For example, the following commands are transactional,
2342 and their effects can be rolled back:
2290 and their effects can be rolled back:
2343
2291
2344 commit
2292 commit
2345 import
2293 import
2346 pull
2294 pull
2347 push (with this repository as destination)
2295 push (with this repository as destination)
2348 unbundle
2296 unbundle
2349
2297
2350 This command should be used with care. There is only one level of
2298 This command should be used with care. There is only one level of
2351 rollback, and there is no way to undo a rollback.
2299 rollback, and there is no way to undo a rollback.
2352
2300
2353 This command is not intended for use on public repositories. Once
2301 This command is not intended for use on public repositories. Once
2354 changes are visible for pull by other users, rolling a transaction
2302 changes are visible for pull by other users, rolling a transaction
2355 back locally is ineffective (someone else may already have pulled
2303 back locally is ineffective (someone else may already have pulled
2356 the changes). Furthermore, a race is possible with readers of the
2304 the changes). Furthermore, a race is possible with readers of the
2357 repository; for example an in-progress pull from the repository
2305 repository; for example an in-progress pull from the repository
2358 may fail if a rollback is performed.
2306 may fail if a rollback is performed.
2359 """
2307 """
2360 repo.rollback()
2308 repo.rollback()
2361
2309
2362 def root(ui, repo):
2310 def root(ui, repo):
2363 """print the root (top) of the current working dir
2311 """print the root (top) of the current working dir
2364
2312
2365 Print the root directory of the current repository.
2313 Print the root directory of the current repository.
2366 """
2314 """
2367 ui.write(repo.root + "\n")
2315 ui.write(repo.root + "\n")
2368
2316
2369 def serve(ui, repo, **opts):
2317 def serve(ui, repo, **opts):
2370 """export the repository via HTTP
2318 """export the repository via HTTP
2371
2319
2372 Start a local HTTP repository browser and pull server.
2320 Start a local HTTP repository browser and pull server.
2373
2321
2374 By default, the server logs accesses to stdout and errors to
2322 By default, the server logs accesses to stdout and errors to
2375 stderr. Use the "-A" and "-E" options to log to files.
2323 stderr. Use the "-A" and "-E" options to log to files.
2376 """
2324 """
2377
2325
2378 if opts["stdio"]:
2326 if opts["stdio"]:
2379 if repo is None:
2327 if repo is None:
2380 raise hg.RepoError(_("There is no Mercurial repository here"
2328 raise hg.RepoError(_("There is no Mercurial repository here"
2381 " (.hg not found)"))
2329 " (.hg not found)"))
2382 s = sshserver.sshserver(ui, repo)
2330 s = sshserver.sshserver(ui, repo)
2383 s.serve_forever()
2331 s.serve_forever()
2384
2332
2385 optlist = ("name templates style address port ipv6"
2333 optlist = ("name templates style address port ipv6"
2386 " accesslog errorlog webdir_conf")
2334 " accesslog errorlog webdir_conf")
2387 for o in optlist.split():
2335 for o in optlist.split():
2388 if opts[o]:
2336 if opts[o]:
2389 ui.setconfig("web", o, str(opts[o]))
2337 ui.setconfig("web", o, str(opts[o]))
2390
2338
2391 if repo is None and not ui.config("web", "webdir_conf"):
2339 if repo is None and not ui.config("web", "webdir_conf"):
2392 raise hg.RepoError(_("There is no Mercurial repository here"
2340 raise hg.RepoError(_("There is no Mercurial repository here"
2393 " (.hg not found)"))
2341 " (.hg not found)"))
2394
2342
2395 if opts['daemon'] and not opts['daemon_pipefds']:
2343 if opts['daemon'] and not opts['daemon_pipefds']:
2396 rfd, wfd = os.pipe()
2344 rfd, wfd = os.pipe()
2397 args = sys.argv[:]
2345 args = sys.argv[:]
2398 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2346 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2399 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2347 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2400 args[0], args)
2348 args[0], args)
2401 os.close(wfd)
2349 os.close(wfd)
2402 os.read(rfd, 1)
2350 os.read(rfd, 1)
2403 os._exit(0)
2351 os._exit(0)
2404
2352
2405 httpd = hgweb.server.create_server(ui, repo)
2353 httpd = hgweb.server.create_server(ui, repo)
2406
2354
2407 if ui.verbose:
2355 if ui.verbose:
2408 if httpd.port != 80:
2356 if httpd.port != 80:
2409 ui.status(_('listening at http://%s:%d/\n') %
2357 ui.status(_('listening at http://%s:%d/\n') %
2410 (httpd.addr, httpd.port))
2358 (httpd.addr, httpd.port))
2411 else:
2359 else:
2412 ui.status(_('listening at http://%s/\n') % httpd.addr)
2360 ui.status(_('listening at http://%s/\n') % httpd.addr)
2413
2361
2414 if opts['pid_file']:
2362 if opts['pid_file']:
2415 fp = open(opts['pid_file'], 'w')
2363 fp = open(opts['pid_file'], 'w')
2416 fp.write(str(os.getpid()) + '\n')
2364 fp.write(str(os.getpid()) + '\n')
2417 fp.close()
2365 fp.close()
2418
2366
2419 if opts['daemon_pipefds']:
2367 if opts['daemon_pipefds']:
2420 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2368 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2421 os.close(rfd)
2369 os.close(rfd)
2422 os.write(wfd, 'y')
2370 os.write(wfd, 'y')
2423 os.close(wfd)
2371 os.close(wfd)
2424 sys.stdout.flush()
2372 sys.stdout.flush()
2425 sys.stderr.flush()
2373 sys.stderr.flush()
2426 fd = os.open(util.nulldev, os.O_RDWR)
2374 fd = os.open(util.nulldev, os.O_RDWR)
2427 if fd != 0: os.dup2(fd, 0)
2375 if fd != 0: os.dup2(fd, 0)
2428 if fd != 1: os.dup2(fd, 1)
2376 if fd != 1: os.dup2(fd, 1)
2429 if fd != 2: os.dup2(fd, 2)
2377 if fd != 2: os.dup2(fd, 2)
2430 if fd not in (0, 1, 2): os.close(fd)
2378 if fd not in (0, 1, 2): os.close(fd)
2431
2379
2432 httpd.serve_forever()
2380 httpd.serve_forever()
2433
2381
2434 def status(ui, repo, *pats, **opts):
2382 def status(ui, repo, *pats, **opts):
2435 """show changed files in the working directory
2383 """show changed files in the working directory
2436
2384
2437 Show status of files in the repository. If names are given, only
2385 Show status of files in the repository. If names are given, only
2438 files that match are shown. Files that are clean or ignored, are
2386 files that match are shown. Files that are clean or ignored, are
2439 not listed unless -c (clean), -i (ignored) or -A is given.
2387 not listed unless -c (clean), -i (ignored) or -A is given.
2440
2388
2441 If one revision is given, it is used as the base revision.
2389 If one revision is given, it is used as the base revision.
2442 If two revisions are given, the difference between them is shown.
2390 If two revisions are given, the difference between them is shown.
2443
2391
2444 The codes used to show the status of files are:
2392 The codes used to show the status of files are:
2445 M = modified
2393 M = modified
2446 A = added
2394 A = added
2447 R = removed
2395 R = removed
2448 C = clean
2396 C = clean
2449 ! = deleted, but still tracked
2397 ! = deleted, but still tracked
2450 ? = not tracked
2398 ? = not tracked
2451 I = ignored (not shown by default)
2399 I = ignored (not shown by default)
2452 = the previous added file was copied from here
2400 = the previous added file was copied from here
2453 """
2401 """
2454
2402
2455 all = opts['all']
2403 all = opts['all']
2456 node1, node2 = cmdutil.revpair(ui, repo, opts.get('rev'))
2404 node1, node2 = cmdutil.revpair(ui, repo, opts.get('rev'))
2457
2405
2458 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2406 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
2459 cwd = (pats and repo.getcwd()) or ''
2407 cwd = (pats and repo.getcwd()) or ''
2460 modified, added, removed, deleted, unknown, ignored, clean = [
2408 modified, added, removed, deleted, unknown, ignored, clean = [
2461 [util.pathto(cwd, x) for x in n]
2409 [util.pathto(cwd, x) for x in n]
2462 for n in repo.status(node1=node1, node2=node2, files=files,
2410 for n in repo.status(node1=node1, node2=node2, files=files,
2463 match=matchfn,
2411 match=matchfn,
2464 list_ignored=all or opts['ignored'],
2412 list_ignored=all or opts['ignored'],
2465 list_clean=all or opts['clean'])]
2413 list_clean=all or opts['clean'])]
2466
2414
2467 changetypes = (('modified', 'M', modified),
2415 changetypes = (('modified', 'M', modified),
2468 ('added', 'A', added),
2416 ('added', 'A', added),
2469 ('removed', 'R', removed),
2417 ('removed', 'R', removed),
2470 ('deleted', '!', deleted),
2418 ('deleted', '!', deleted),
2471 ('unknown', '?', unknown),
2419 ('unknown', '?', unknown),
2472 ('ignored', 'I', ignored))
2420 ('ignored', 'I', ignored))
2473
2421
2474 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2422 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2475
2423
2476 end = opts['print0'] and '\0' or '\n'
2424 end = opts['print0'] and '\0' or '\n'
2477
2425
2478 for opt, char, changes in ([ct for ct in explicit_changetypes
2426 for opt, char, changes in ([ct for ct in explicit_changetypes
2479 if all or opts[ct[0]]]
2427 if all or opts[ct[0]]]
2480 or changetypes):
2428 or changetypes):
2481 if opts['no_status']:
2429 if opts['no_status']:
2482 format = "%%s%s" % end
2430 format = "%%s%s" % end
2483 else:
2431 else:
2484 format = "%s %%s%s" % (char, end)
2432 format = "%s %%s%s" % (char, end)
2485
2433
2486 for f in changes:
2434 for f in changes:
2487 ui.write(format % f)
2435 ui.write(format % f)
2488 if ((all or opts.get('copies')) and not opts.get('no_status')):
2436 if ((all or opts.get('copies')) and not opts.get('no_status')):
2489 copied = repo.dirstate.copied(f)
2437 copied = repo.dirstate.copied(f)
2490 if copied:
2438 if copied:
2491 ui.write(' %s%s' % (copied, end))
2439 ui.write(' %s%s' % (copied, end))
2492
2440
2493 def tag(ui, repo, name, rev_=None, **opts):
2441 def tag(ui, repo, name, rev_=None, **opts):
2494 """add a tag for the current tip or a given revision
2442 """add a tag for the current tip or a given revision
2495
2443
2496 Name a particular revision using <name>.
2444 Name a particular revision using <name>.
2497
2445
2498 Tags are used to name particular revisions of the repository and are
2446 Tags are used to name particular revisions of the repository and are
2499 very useful to compare different revision, to go back to significant
2447 very useful to compare different revision, to go back to significant
2500 earlier versions or to mark branch points as releases, etc.
2448 earlier versions or to mark branch points as releases, etc.
2501
2449
2502 If no revision is given, the parent of the working directory is used.
2450 If no revision is given, the parent of the working directory is used.
2503
2451
2504 To facilitate version control, distribution, and merging of tags,
2452 To facilitate version control, distribution, and merging of tags,
2505 they are stored as a file named ".hgtags" which is managed
2453 they are stored as a file named ".hgtags" which is managed
2506 similarly to other project files and can be hand-edited if
2454 similarly to other project files and can be hand-edited if
2507 necessary. The file '.hg/localtags' is used for local tags (not
2455 necessary. The file '.hg/localtags' is used for local tags (not
2508 shared among repositories).
2456 shared among repositories).
2509 """
2457 """
2510 if name in ['tip', '.']:
2458 if name in ['tip', '.']:
2511 raise util.Abort(_("the name '%s' is reserved") % name)
2459 raise util.Abort(_("the name '%s' is reserved") % name)
2512 if rev_ is not None:
2460 if rev_ is not None:
2513 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2461 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2514 "please use 'hg tag [-r REV] NAME' instead\n"))
2462 "please use 'hg tag [-r REV] NAME' instead\n"))
2515 if opts['rev']:
2463 if opts['rev']:
2516 raise util.Abort(_("use only one form to specify the revision"))
2464 raise util.Abort(_("use only one form to specify the revision"))
2517 if opts['rev']:
2465 if opts['rev']:
2518 rev_ = opts['rev']
2466 rev_ = opts['rev']
2519 if not rev_ and repo.dirstate.parents()[1] != nullid:
2467 if not rev_ and repo.dirstate.parents()[1] != nullid:
2520 raise util.Abort(_('uncommitted merge - please provide a '
2468 raise util.Abort(_('uncommitted merge - please provide a '
2521 'specific revision'))
2469 'specific revision'))
2522 r = repo.changectx(rev_).node()
2470 r = repo.changectx(rev_).node()
2523
2471
2524 message = opts['message']
2472 message = opts['message']
2525 if not message:
2473 if not message:
2526 message = _('Added tag %s for changeset %s') % (name, short(r))
2474 message = _('Added tag %s for changeset %s') % (name, short(r))
2527
2475
2528 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2476 repo.tag(name, r, message, opts['local'], opts['user'], opts['date'])
2529
2477
2530 def tags(ui, repo):
2478 def tags(ui, repo):
2531 """list repository tags
2479 """list repository tags
2532
2480
2533 List the repository tags.
2481 List the repository tags.
2534
2482
2535 This lists both regular and local tags.
2483 This lists both regular and local tags.
2536 """
2484 """
2537
2485
2538 l = repo.tagslist()
2486 l = repo.tagslist()
2539 l.reverse()
2487 l.reverse()
2540 hexfunc = ui.debugflag and hex or short
2488 hexfunc = ui.debugflag and hex or short
2541 for t, n in l:
2489 for t, n in l:
2542 try:
2490 try:
2543 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2491 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n))
2544 except KeyError:
2492 except KeyError:
2545 r = " ?:?"
2493 r = " ?:?"
2546 if ui.quiet:
2494 if ui.quiet:
2547 ui.write("%s\n" % t)
2495 ui.write("%s\n" % t)
2548 else:
2496 else:
2549 ui.write("%-30s %s\n" % (t, r))
2497 ui.write("%-30s %s\n" % (t, r))
2550
2498
2551 def tip(ui, repo, **opts):
2499 def tip(ui, repo, **opts):
2552 """show the tip revision
2500 """show the tip revision
2553
2501
2554 Show the tip revision.
2502 Show the tip revision.
2555 """
2503 """
2556 n = repo.changelog.tip()
2504 n = repo.changelog.tip()
2557 br = None
2505 br = None
2558 if opts['branches']:
2506 if opts['branches']:
2559 ui.warn(_("the --branches option is deprecated, "
2507 ui.warn(_("the --branches option is deprecated, "
2560 "please use 'hg branches' instead\n"))
2508 "please use 'hg branches' instead\n"))
2561 br = repo.branchlookup([n])
2509 br = repo.branchlookup([n])
2562 cmdutil.show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2510 cmdutil.show_changeset(ui, repo, opts).show(changenode=n, brinfo=br)
2563 if opts['patch']:
2564 patch.diff(repo, repo.changelog.parents(n)[0], n)
2565
2511
2566 def unbundle(ui, repo, fname, **opts):
2512 def unbundle(ui, repo, fname, **opts):
2567 """apply a changegroup file
2513 """apply a changegroup file
2568
2514
2569 Apply a compressed changegroup file generated by the bundle
2515 Apply a compressed changegroup file generated by the bundle
2570 command.
2516 command.
2571 """
2517 """
2572 f = urllib.urlopen(fname)
2518 f = urllib.urlopen(fname)
2573
2519
2574 header = f.read(6)
2520 header = f.read(6)
2575 if not header.startswith("HG"):
2521 if not header.startswith("HG"):
2576 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2522 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2577 elif not header.startswith("HG10"):
2523 elif not header.startswith("HG10"):
2578 raise util.Abort(_("%s: unknown bundle version") % fname)
2524 raise util.Abort(_("%s: unknown bundle version") % fname)
2579 elif header == "HG10BZ":
2525 elif header == "HG10BZ":
2580 def generator(f):
2526 def generator(f):
2581 zd = bz2.BZ2Decompressor()
2527 zd = bz2.BZ2Decompressor()
2582 zd.decompress("BZ")
2528 zd.decompress("BZ")
2583 for chunk in f:
2529 for chunk in f:
2584 yield zd.decompress(chunk)
2530 yield zd.decompress(chunk)
2585 elif header == "HG10UN":
2531 elif header == "HG10UN":
2586 def generator(f):
2532 def generator(f):
2587 for chunk in f:
2533 for chunk in f:
2588 yield chunk
2534 yield chunk
2589 else:
2535 else:
2590 raise util.Abort(_("%s: unknown bundle compression type")
2536 raise util.Abort(_("%s: unknown bundle compression type")
2591 % fname)
2537 % fname)
2592 gen = generator(util.filechunkiter(f, 4096))
2538 gen = generator(util.filechunkiter(f, 4096))
2593 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2539 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle',
2594 'bundle:' + fname)
2540 'bundle:' + fname)
2595 return postincoming(ui, repo, modheads, opts['update'])
2541 return postincoming(ui, repo, modheads, opts['update'])
2596
2542
2597 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2543 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2598 branch=None):
2544 branch=None):
2599 """update or merge working directory
2545 """update or merge working directory
2600
2546
2601 Update the working directory to the specified revision.
2547 Update the working directory to the specified revision.
2602
2548
2603 If there are no outstanding changes in the working directory and
2549 If there are no outstanding changes in the working directory and
2604 there is a linear relationship between the current version and the
2550 there is a linear relationship between the current version and the
2605 requested version, the result is the requested version.
2551 requested version, the result is the requested version.
2606
2552
2607 To merge the working directory with another revision, use the
2553 To merge the working directory with another revision, use the
2608 merge command.
2554 merge command.
2609
2555
2610 By default, update will refuse to run if doing so would require
2556 By default, update will refuse to run if doing so would require
2611 merging or discarding local changes.
2557 merging or discarding local changes.
2612 """
2558 """
2613 node = _lookup(repo, node, branch)
2559 node = _lookup(repo, node, branch)
2614 if clean:
2560 if clean:
2615 return hg.clean(repo, node)
2561 return hg.clean(repo, node)
2616 else:
2562 else:
2617 return hg.update(repo, node)
2563 return hg.update(repo, node)
2618
2564
2619 def _lookup(repo, node, branch=None):
2565 def _lookup(repo, node, branch=None):
2620 if branch:
2566 if branch:
2621 repo.ui.warn(_("the --branch option is deprecated, "
2567 repo.ui.warn(_("the --branch option is deprecated, "
2622 "please use 'hg branch' instead\n"))
2568 "please use 'hg branch' instead\n"))
2623 br = repo.branchlookup(branch=branch)
2569 br = repo.branchlookup(branch=branch)
2624 found = []
2570 found = []
2625 for x in br:
2571 for x in br:
2626 if branch in br[x]:
2572 if branch in br[x]:
2627 found.append(x)
2573 found.append(x)
2628 if len(found) > 1:
2574 if len(found) > 1:
2629 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2575 repo.ui.warn(_("Found multiple heads for %s\n") % branch)
2630 for x in found:
2576 for x in found:
2631 cmdutil.show_changeset(ui, repo, {}).show(
2577 cmdutil.show_changeset(ui, repo, {}).show(
2632 changenode=x, brinfo=br)
2578 changenode=x, brinfo=br)
2633 raise util.Abort("")
2579 raise util.Abort("")
2634 if len(found) == 1:
2580 if len(found) == 1:
2635 node = found[0]
2581 node = found[0]
2636 repo.ui.warn(_("Using head %s for branch %s\n")
2582 repo.ui.warn(_("Using head %s for branch %s\n")
2637 % (short(node), branch))
2583 % (short(node), branch))
2638 else:
2584 else:
2639 raise util.Abort(_("branch %s not found") % branch)
2585 raise util.Abort(_("branch %s not found") % branch)
2640 else:
2586 else:
2641 node = node and repo.lookup(node) or repo.changelog.tip()
2587 node = node and repo.lookup(node) or repo.changelog.tip()
2642 return node
2588 return node
2643
2589
2644 def verify(ui, repo):
2590 def verify(ui, repo):
2645 """verify the integrity of the repository
2591 """verify the integrity of the repository
2646
2592
2647 Verify the integrity of the current repository.
2593 Verify the integrity of the current repository.
2648
2594
2649 This will perform an extensive check of the repository's
2595 This will perform an extensive check of the repository's
2650 integrity, validating the hashes and checksums of each entry in
2596 integrity, validating the hashes and checksums of each entry in
2651 the changelog, manifest, and tracked files, as well as the
2597 the changelog, manifest, and tracked files, as well as the
2652 integrity of their crosslinks and indices.
2598 integrity of their crosslinks and indices.
2653 """
2599 """
2654 return hg.verify(repo)
2600 return hg.verify(repo)
2655
2601
2656 # Command options and aliases are listed here, alphabetically
2602 # Command options and aliases are listed here, alphabetically
2657
2603
2658 globalopts = [
2604 globalopts = [
2659 ('R', 'repository', '',
2605 ('R', 'repository', '',
2660 _('repository root directory or symbolic path name')),
2606 _('repository root directory or symbolic path name')),
2661 ('', 'cwd', '', _('change working directory')),
2607 ('', 'cwd', '', _('change working directory')),
2662 ('y', 'noninteractive', None,
2608 ('y', 'noninteractive', None,
2663 _('do not prompt, assume \'yes\' for any required answers')),
2609 _('do not prompt, assume \'yes\' for any required answers')),
2664 ('q', 'quiet', None, _('suppress output')),
2610 ('q', 'quiet', None, _('suppress output')),
2665 ('v', 'verbose', None, _('enable additional output')),
2611 ('v', 'verbose', None, _('enable additional output')),
2666 ('', 'config', [], _('set/override config option')),
2612 ('', 'config', [], _('set/override config option')),
2667 ('', 'debug', None, _('enable debugging output')),
2613 ('', 'debug', None, _('enable debugging output')),
2668 ('', 'debugger', None, _('start debugger')),
2614 ('', 'debugger', None, _('start debugger')),
2669 ('', 'lsprof', None, _('print improved command execution profile')),
2615 ('', 'lsprof', None, _('print improved command execution profile')),
2670 ('', 'traceback', None, _('print traceback on exception')),
2616 ('', 'traceback', None, _('print traceback on exception')),
2671 ('', 'time', None, _('time how long the command takes')),
2617 ('', 'time', None, _('time how long the command takes')),
2672 ('', 'profile', None, _('print command execution profile')),
2618 ('', 'profile', None, _('print command execution profile')),
2673 ('', 'version', None, _('output version information and exit')),
2619 ('', 'version', None, _('output version information and exit')),
2674 ('h', 'help', None, _('display help and exit')),
2620 ('h', 'help', None, _('display help and exit')),
2675 ]
2621 ]
2676
2622
2677 dryrunopts = [('n', 'dry-run', None,
2623 dryrunopts = [('n', 'dry-run', None,
2678 _('do not perform actions, just print output'))]
2624 _('do not perform actions, just print output'))]
2679
2625
2680 remoteopts = [
2626 remoteopts = [
2681 ('e', 'ssh', '', _('specify ssh command to use')),
2627 ('e', 'ssh', '', _('specify ssh command to use')),
2682 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2628 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2683 ]
2629 ]
2684
2630
2685 walkopts = [
2631 walkopts = [
2686 ('I', 'include', [], _('include names matching the given patterns')),
2632 ('I', 'include', [], _('include names matching the given patterns')),
2687 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2633 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2688 ]
2634 ]
2689
2635
2690 table = {
2636 table = {
2691 "^add":
2637 "^add":
2692 (add,
2638 (add,
2693 walkopts + dryrunopts,
2639 walkopts + dryrunopts,
2694 _('hg add [OPTION]... [FILE]...')),
2640 _('hg add [OPTION]... [FILE]...')),
2695 "addremove":
2641 "addremove":
2696 (addremove,
2642 (addremove,
2697 [('s', 'similarity', '',
2643 [('s', 'similarity', '',
2698 _('guess renamed files by similarity (0<=s<=100)')),
2644 _('guess renamed files by similarity (0<=s<=100)')),
2699 ] + walkopts + dryrunopts,
2645 ] + walkopts + dryrunopts,
2700 _('hg addremove [OPTION]... [FILE]...')),
2646 _('hg addremove [OPTION]... [FILE]...')),
2701 "^annotate":
2647 "^annotate":
2702 (annotate,
2648 (annotate,
2703 [('r', 'rev', '', _('annotate the specified revision')),
2649 [('r', 'rev', '', _('annotate the specified revision')),
2704 ('f', 'follow', None, _('follow file copies and renames')),
2650 ('f', 'follow', None, _('follow file copies and renames')),
2705 ('a', 'text', None, _('treat all files as text')),
2651 ('a', 'text', None, _('treat all files as text')),
2706 ('u', 'user', None, _('list the author')),
2652 ('u', 'user', None, _('list the author')),
2707 ('d', 'date', None, _('list the date')),
2653 ('d', 'date', None, _('list the date')),
2708 ('n', 'number', None, _('list the revision number (default)')),
2654 ('n', 'number', None, _('list the revision number (default)')),
2709 ('c', 'changeset', None, _('list the changeset')),
2655 ('c', 'changeset', None, _('list the changeset')),
2710 ] + walkopts,
2656 ] + walkopts,
2711 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2657 _('hg annotate [-r REV] [-a] [-u] [-d] [-n] [-c] FILE...')),
2712 "archive":
2658 "archive":
2713 (archive,
2659 (archive,
2714 [('', 'no-decode', None, _('do not pass files through decoders')),
2660 [('', 'no-decode', None, _('do not pass files through decoders')),
2715 ('p', 'prefix', '', _('directory prefix for files in archive')),
2661 ('p', 'prefix', '', _('directory prefix for files in archive')),
2716 ('r', 'rev', '', _('revision to distribute')),
2662 ('r', 'rev', '', _('revision to distribute')),
2717 ('t', 'type', '', _('type of distribution to create')),
2663 ('t', 'type', '', _('type of distribution to create')),
2718 ] + walkopts,
2664 ] + walkopts,
2719 _('hg archive [OPTION]... DEST')),
2665 _('hg archive [OPTION]... DEST')),
2720 "backout":
2666 "backout":
2721 (backout,
2667 (backout,
2722 [('', 'merge', None,
2668 [('', 'merge', None,
2723 _('merge with old dirstate parent after backout')),
2669 _('merge with old dirstate parent after backout')),
2724 ('m', 'message', '', _('use <text> as commit message')),
2670 ('m', 'message', '', _('use <text> as commit message')),
2725 ('l', 'logfile', '', _('read commit message from <file>')),
2671 ('l', 'logfile', '', _('read commit message from <file>')),
2726 ('d', 'date', '', _('record datecode as commit date')),
2672 ('d', 'date', '', _('record datecode as commit date')),
2727 ('', 'parent', '', _('parent to choose when backing out merge')),
2673 ('', 'parent', '', _('parent to choose when backing out merge')),
2728 ('u', 'user', '', _('record user as committer')),
2674 ('u', 'user', '', _('record user as committer')),
2729 ] + walkopts,
2675 ] + walkopts,
2730 _('hg backout [OPTION]... REV')),
2676 _('hg backout [OPTION]... REV')),
2731 "branch": (branch, [], _('hg branch [NAME]')),
2677 "branch": (branch, [], _('hg branch [NAME]')),
2732 "branches": (branches, [], _('hg branches')),
2678 "branches": (branches, [], _('hg branches')),
2733 "bundle":
2679 "bundle":
2734 (bundle,
2680 (bundle,
2735 [('f', 'force', None,
2681 [('f', 'force', None,
2736 _('run even when remote repository is unrelated')),
2682 _('run even when remote repository is unrelated')),
2737 ('r', 'rev', [],
2683 ('r', 'rev', [],
2738 _('a changeset you would like to bundle')),
2684 _('a changeset you would like to bundle')),
2739 ('', 'base', [],
2685 ('', 'base', [],
2740 _('a base changeset to specify instead of a destination')),
2686 _('a base changeset to specify instead of a destination')),
2741 ] + remoteopts,
2687 ] + remoteopts,
2742 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2688 _('hg bundle [--base REV]... [--rev REV]... FILE [DEST]')),
2743 "cat":
2689 "cat":
2744 (cat,
2690 (cat,
2745 [('o', 'output', '', _('print output to file with formatted name')),
2691 [('o', 'output', '', _('print output to file with formatted name')),
2746 ('r', 'rev', '', _('print the given revision')),
2692 ('r', 'rev', '', _('print the given revision')),
2747 ] + walkopts,
2693 ] + walkopts,
2748 _('hg cat [OPTION]... FILE...')),
2694 _('hg cat [OPTION]... FILE...')),
2749 "^clone":
2695 "^clone":
2750 (clone,
2696 (clone,
2751 [('U', 'noupdate', None, _('do not update the new working directory')),
2697 [('U', 'noupdate', None, _('do not update the new working directory')),
2752 ('r', 'rev', [],
2698 ('r', 'rev', [],
2753 _('a changeset you would like to have after cloning')),
2699 _('a changeset you would like to have after cloning')),
2754 ('', 'pull', None, _('use pull protocol to copy metadata')),
2700 ('', 'pull', None, _('use pull protocol to copy metadata')),
2755 ('', 'uncompressed', None,
2701 ('', 'uncompressed', None,
2756 _('use uncompressed transfer (fast over LAN)')),
2702 _('use uncompressed transfer (fast over LAN)')),
2757 ] + remoteopts,
2703 ] + remoteopts,
2758 _('hg clone [OPTION]... SOURCE [DEST]')),
2704 _('hg clone [OPTION]... SOURCE [DEST]')),
2759 "^commit|ci":
2705 "^commit|ci":
2760 (commit,
2706 (commit,
2761 [('A', 'addremove', None,
2707 [('A', 'addremove', None,
2762 _('mark new/missing files as added/removed before committing')),
2708 _('mark new/missing files as added/removed before committing')),
2763 ('m', 'message', '', _('use <text> as commit message')),
2709 ('m', 'message', '', _('use <text> as commit message')),
2764 ('l', 'logfile', '', _('read the commit message from <file>')),
2710 ('l', 'logfile', '', _('read the commit message from <file>')),
2765 ('d', 'date', '', _('record datecode as commit date')),
2711 ('d', 'date', '', _('record datecode as commit date')),
2766 ('u', 'user', '', _('record user as commiter')),
2712 ('u', 'user', '', _('record user as commiter')),
2767 ] + walkopts,
2713 ] + walkopts,
2768 _('hg commit [OPTION]... [FILE]...')),
2714 _('hg commit [OPTION]... [FILE]...')),
2769 "copy|cp":
2715 "copy|cp":
2770 (copy,
2716 (copy,
2771 [('A', 'after', None, _('record a copy that has already occurred')),
2717 [('A', 'after', None, _('record a copy that has already occurred')),
2772 ('f', 'force', None,
2718 ('f', 'force', None,
2773 _('forcibly copy over an existing managed file')),
2719 _('forcibly copy over an existing managed file')),
2774 ] + walkopts + dryrunopts,
2720 ] + walkopts + dryrunopts,
2775 _('hg copy [OPTION]... [SOURCE]... DEST')),
2721 _('hg copy [OPTION]... [SOURCE]... DEST')),
2776 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2722 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2777 "debugcomplete":
2723 "debugcomplete":
2778 (debugcomplete,
2724 (debugcomplete,
2779 [('o', 'options', None, _('show the command options'))],
2725 [('o', 'options', None, _('show the command options'))],
2780 _('debugcomplete [-o] CMD')),
2726 _('debugcomplete [-o] CMD')),
2781 "debugrebuildstate":
2727 "debugrebuildstate":
2782 (debugrebuildstate,
2728 (debugrebuildstate,
2783 [('r', 'rev', '', _('revision to rebuild to'))],
2729 [('r', 'rev', '', _('revision to rebuild to'))],
2784 _('debugrebuildstate [-r REV] [REV]')),
2730 _('debugrebuildstate [-r REV] [REV]')),
2785 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2731 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2786 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2732 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2787 "debugstate": (debugstate, [], _('debugstate')),
2733 "debugstate": (debugstate, [], _('debugstate')),
2788 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2734 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2789 "debugindex": (debugindex, [], _('debugindex FILE')),
2735 "debugindex": (debugindex, [], _('debugindex FILE')),
2790 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2736 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2791 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2737 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2792 "debugwalk":
2738 "debugwalk":
2793 (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2739 (debugwalk, walkopts, _('debugwalk [OPTION]... [FILE]...')),
2794 "^diff":
2740 "^diff":
2795 (diff,
2741 (diff,
2796 [('r', 'rev', [], _('revision')),
2742 [('r', 'rev', [], _('revision')),
2797 ('a', 'text', None, _('treat all files as text')),
2743 ('a', 'text', None, _('treat all files as text')),
2798 ('p', 'show-function', None,
2744 ('p', 'show-function', None,
2799 _('show which function each change is in')),
2745 _('show which function each change is in')),
2800 ('g', 'git', None, _('use git extended diff format')),
2746 ('g', 'git', None, _('use git extended diff format')),
2801 ('', 'nodates', None, _("don't include dates in diff headers")),
2747 ('', 'nodates', None, _("don't include dates in diff headers")),
2802 ('w', 'ignore-all-space', None,
2748 ('w', 'ignore-all-space', None,
2803 _('ignore white space when comparing lines')),
2749 _('ignore white space when comparing lines')),
2804 ('b', 'ignore-space-change', None,
2750 ('b', 'ignore-space-change', None,
2805 _('ignore changes in the amount of white space')),
2751 _('ignore changes in the amount of white space')),
2806 ('B', 'ignore-blank-lines', None,
2752 ('B', 'ignore-blank-lines', None,
2807 _('ignore changes whose lines are all blank')),
2753 _('ignore changes whose lines are all blank')),
2808 ] + walkopts,
2754 ] + walkopts,
2809 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2755 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2810 "^export":
2756 "^export":
2811 (export,
2757 (export,
2812 [('o', 'output', '', _('print output to file with formatted name')),
2758 [('o', 'output', '', _('print output to file with formatted name')),
2813 ('a', 'text', None, _('treat all files as text')),
2759 ('a', 'text', None, _('treat all files as text')),
2814 ('g', 'git', None, _('use git extended diff format')),
2760 ('g', 'git', None, _('use git extended diff format')),
2815 ('', 'nodates', None, _("don't include dates in diff headers")),
2761 ('', 'nodates', None, _("don't include dates in diff headers")),
2816 ('', 'switch-parent', None, _('diff against the second parent'))],
2762 ('', 'switch-parent', None, _('diff against the second parent'))],
2817 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2763 _('hg export [-a] [-o OUTFILESPEC] REV...')),
2818 "grep":
2764 "grep":
2819 (grep,
2765 (grep,
2820 [('0', 'print0', None, _('end fields with NUL')),
2766 [('0', 'print0', None, _('end fields with NUL')),
2821 ('', 'all', None, _('print all revisions that match')),
2767 ('', 'all', None, _('print all revisions that match')),
2822 ('f', 'follow', None,
2768 ('f', 'follow', None,
2823 _('follow changeset history, or file history across copies and renames')),
2769 _('follow changeset history, or file history across copies and renames')),
2824 ('i', 'ignore-case', None, _('ignore case when matching')),
2770 ('i', 'ignore-case', None, _('ignore case when matching')),
2825 ('l', 'files-with-matches', None,
2771 ('l', 'files-with-matches', None,
2826 _('print only filenames and revs that match')),
2772 _('print only filenames and revs that match')),
2827 ('n', 'line-number', None, _('print matching line numbers')),
2773 ('n', 'line-number', None, _('print matching line numbers')),
2828 ('r', 'rev', [], _('search in given revision range')),
2774 ('r', 'rev', [], _('search in given revision range')),
2829 ('u', 'user', None, _('print user who committed change')),
2775 ('u', 'user', None, _('print user who committed change')),
2830 ] + walkopts,
2776 ] + walkopts,
2831 _('hg grep [OPTION]... PATTERN [FILE]...')),
2777 _('hg grep [OPTION]... PATTERN [FILE]...')),
2832 "heads":
2778 "heads":
2833 (heads,
2779 (heads,
2834 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2780 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2835 ('', 'style', '', _('display using template map file')),
2781 ('', 'style', '', _('display using template map file')),
2836 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2782 ('r', 'rev', '', _('show only heads which are descendants of rev')),
2837 ('', 'template', '', _('display with template'))],
2783 ('', 'template', '', _('display with template'))],
2838 _('hg heads [-r REV]')),
2784 _('hg heads [-r REV]')),
2839 "help": (help_, [], _('hg help [COMMAND]')),
2785 "help": (help_, [], _('hg help [COMMAND]')),
2840 "identify|id": (identify, [], _('hg identify')),
2786 "identify|id": (identify, [], _('hg identify')),
2841 "import|patch":
2787 "import|patch":
2842 (import_,
2788 (import_,
2843 [('p', 'strip', 1,
2789 [('p', 'strip', 1,
2844 _('directory strip option for patch. This has the same\n'
2790 _('directory strip option for patch. This has the same\n'
2845 'meaning as the corresponding patch option')),
2791 'meaning as the corresponding patch option')),
2846 ('m', 'message', '', _('use <text> as commit message')),
2792 ('m', 'message', '', _('use <text> as commit message')),
2847 ('b', 'base', '', _('base path (DEPRECATED)')),
2793 ('b', 'base', '', _('base path (DEPRECATED)')),
2848 ('f', 'force', None,
2794 ('f', 'force', None,
2849 _('skip check for outstanding uncommitted changes'))],
2795 _('skip check for outstanding uncommitted changes'))],
2850 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2796 _('hg import [-p NUM] [-m MESSAGE] [-f] PATCH...')),
2851 "incoming|in": (incoming,
2797 "incoming|in": (incoming,
2852 [('M', 'no-merges', None, _('do not show merges')),
2798 [('M', 'no-merges', None, _('do not show merges')),
2853 ('f', 'force', None,
2799 ('f', 'force', None,
2854 _('run even when remote repository is unrelated')),
2800 _('run even when remote repository is unrelated')),
2855 ('', 'style', '', _('display using template map file')),
2801 ('', 'style', '', _('display using template map file')),
2856 ('n', 'newest-first', None, _('show newest record first')),
2802 ('n', 'newest-first', None, _('show newest record first')),
2857 ('', 'bundle', '', _('file to store the bundles into')),
2803 ('', 'bundle', '', _('file to store the bundles into')),
2858 ('p', 'patch', None, _('show patch')),
2804 ('p', 'patch', None, _('show patch')),
2859 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2805 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2860 ('', 'template', '', _('display with template')),
2806 ('', 'template', '', _('display with template')),
2861 ] + remoteopts,
2807 ] + remoteopts,
2862 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2808 _('hg incoming [-p] [-n] [-M] [-r REV]...'
2863 ' [--bundle FILENAME] [SOURCE]')),
2809 ' [--bundle FILENAME] [SOURCE]')),
2864 "^init":
2810 "^init":
2865 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2811 (init, remoteopts, _('hg init [-e FILE] [--remotecmd FILE] [DEST]')),
2866 "locate":
2812 "locate":
2867 (locate,
2813 (locate,
2868 [('r', 'rev', '', _('search the repository as it stood at rev')),
2814 [('r', 'rev', '', _('search the repository as it stood at rev')),
2869 ('0', 'print0', None,
2815 ('0', 'print0', None,
2870 _('end filenames with NUL, for use with xargs')),
2816 _('end filenames with NUL, for use with xargs')),
2871 ('f', 'fullpath', None,
2817 ('f', 'fullpath', None,
2872 _('print complete paths from the filesystem root')),
2818 _('print complete paths from the filesystem root')),
2873 ] + walkopts,
2819 ] + walkopts,
2874 _('hg locate [OPTION]... [PATTERN]...')),
2820 _('hg locate [OPTION]... [PATTERN]...')),
2875 "^log|history":
2821 "^log|history":
2876 (log,
2822 (log,
2877 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2823 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2878 ('f', 'follow', None,
2824 ('f', 'follow', None,
2879 _('follow changeset history, or file history across copies and renames')),
2825 _('follow changeset history, or file history across copies and renames')),
2880 ('', 'follow-first', None,
2826 ('', 'follow-first', None,
2881 _('only follow the first parent of merge changesets')),
2827 _('only follow the first parent of merge changesets')),
2882 ('C', 'copies', None, _('show copied files')),
2828 ('C', 'copies', None, _('show copied files')),
2883 ('k', 'keyword', [], _('search for a keyword')),
2829 ('k', 'keyword', [], _('search for a keyword')),
2884 ('l', 'limit', '', _('limit number of changes displayed')),
2830 ('l', 'limit', '', _('limit number of changes displayed')),
2885 ('r', 'rev', [], _('show the specified revision or range')),
2831 ('r', 'rev', [], _('show the specified revision or range')),
2886 ('M', 'no-merges', None, _('do not show merges')),
2832 ('M', 'no-merges', None, _('do not show merges')),
2887 ('', 'style', '', _('display using template map file')),
2833 ('', 'style', '', _('display using template map file')),
2888 ('m', 'only-merges', None, _('show only merges')),
2834 ('m', 'only-merges', None, _('show only merges')),
2889 ('p', 'patch', None, _('show patch')),
2835 ('p', 'patch', None, _('show patch')),
2890 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2836 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
2891 ('', 'template', '', _('display with template')),
2837 ('', 'template', '', _('display with template')),
2892 ] + walkopts,
2838 ] + walkopts,
2893 _('hg log [OPTION]... [FILE]')),
2839 _('hg log [OPTION]... [FILE]')),
2894 "manifest": (manifest, [], _('hg manifest [REV]')),
2840 "manifest": (manifest, [], _('hg manifest [REV]')),
2895 "merge":
2841 "merge":
2896 (merge,
2842 (merge,
2897 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2843 [('b', 'branch', '', _('merge with head of a specific branch (DEPRECATED)')),
2898 ('f', 'force', None, _('force a merge with outstanding changes'))],
2844 ('f', 'force', None, _('force a merge with outstanding changes'))],
2899 _('hg merge [-f] [REV]')),
2845 _('hg merge [-f] [REV]')),
2900 "outgoing|out": (outgoing,
2846 "outgoing|out": (outgoing,
2901 [('M', 'no-merges', None, _('do not show merges')),
2847 [('M', 'no-merges', None, _('do not show merges')),
2902 ('f', 'force', None,
2848 ('f', 'force', None,
2903 _('run even when remote repository is unrelated')),
2849 _('run even when remote repository is unrelated')),
2904 ('p', 'patch', None, _('show patch')),
2850 ('p', 'patch', None, _('show patch')),
2905 ('', 'style', '', _('display using template map file')),
2851 ('', 'style', '', _('display using template map file')),
2906 ('r', 'rev', [], _('a specific revision you would like to push')),
2852 ('r', 'rev', [], _('a specific revision you would like to push')),
2907 ('n', 'newest-first', None, _('show newest record first')),
2853 ('n', 'newest-first', None, _('show newest record first')),
2908 ('', 'template', '', _('display with template')),
2854 ('', 'template', '', _('display with template')),
2909 ] + remoteopts,
2855 ] + remoteopts,
2910 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2856 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')),
2911 "^parents":
2857 "^parents":
2912 (parents,
2858 (parents,
2913 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2859 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2914 ('r', 'rev', '', _('show parents from the specified rev')),
2860 ('r', 'rev', '', _('show parents from the specified rev')),
2915 ('', 'style', '', _('display using template map file')),
2861 ('', 'style', '', _('display using template map file')),
2916 ('', 'template', '', _('display with template'))],
2862 ('', 'template', '', _('display with template'))],
2917 _('hg parents [-r REV] [FILE]')),
2863 _('hg parents [-r REV] [FILE]')),
2918 "paths": (paths, [], _('hg paths [NAME]')),
2864 "paths": (paths, [], _('hg paths [NAME]')),
2919 "^pull":
2865 "^pull":
2920 (pull,
2866 (pull,
2921 [('u', 'update', None,
2867 [('u', 'update', None,
2922 _('update to new tip if changesets were pulled')),
2868 _('update to new tip if changesets were pulled')),
2923 ('f', 'force', None,
2869 ('f', 'force', None,
2924 _('run even when remote repository is unrelated')),
2870 _('run even when remote repository is unrelated')),
2925 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2871 ('r', 'rev', [], _('a specific revision up to which you would like to pull')),
2926 ] + remoteopts,
2872 ] + remoteopts,
2927 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2873 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')),
2928 "^push":
2874 "^push":
2929 (push,
2875 (push,
2930 [('f', 'force', None, _('force push')),
2876 [('f', 'force', None, _('force push')),
2931 ('r', 'rev', [], _('a specific revision you would like to push')),
2877 ('r', 'rev', [], _('a specific revision you would like to push')),
2932 ] + remoteopts,
2878 ] + remoteopts,
2933 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2879 _('hg push [-f] [-r REV]... [-e FILE] [--remotecmd FILE] [DEST]')),
2934 "debugrawcommit|rawcommit":
2880 "debugrawcommit|rawcommit":
2935 (rawcommit,
2881 (rawcommit,
2936 [('p', 'parent', [], _('parent')),
2882 [('p', 'parent', [], _('parent')),
2937 ('d', 'date', '', _('date code')),
2883 ('d', 'date', '', _('date code')),
2938 ('u', 'user', '', _('user')),
2884 ('u', 'user', '', _('user')),
2939 ('F', 'files', '', _('file list')),
2885 ('F', 'files', '', _('file list')),
2940 ('m', 'message', '', _('commit message')),
2886 ('m', 'message', '', _('commit message')),
2941 ('l', 'logfile', '', _('commit message file'))],
2887 ('l', 'logfile', '', _('commit message file'))],
2942 _('hg debugrawcommit [OPTION]... [FILE]...')),
2888 _('hg debugrawcommit [OPTION]... [FILE]...')),
2943 "recover": (recover, [], _('hg recover')),
2889 "recover": (recover, [], _('hg recover')),
2944 "^remove|rm":
2890 "^remove|rm":
2945 (remove,
2891 (remove,
2946 [('A', 'after', None, _('record remove that has already occurred')),
2892 [('A', 'after', None, _('record remove that has already occurred')),
2947 ('f', 'force', None, _('remove file even if modified')),
2893 ('f', 'force', None, _('remove file even if modified')),
2948 ] + walkopts,
2894 ] + walkopts,
2949 _('hg remove [OPTION]... FILE...')),
2895 _('hg remove [OPTION]... FILE...')),
2950 "rename|mv":
2896 "rename|mv":
2951 (rename,
2897 (rename,
2952 [('A', 'after', None, _('record a rename that has already occurred')),
2898 [('A', 'after', None, _('record a rename that has already occurred')),
2953 ('f', 'force', None,
2899 ('f', 'force', None,
2954 _('forcibly copy over an existing managed file')),
2900 _('forcibly copy over an existing managed file')),
2955 ] + walkopts + dryrunopts,
2901 ] + walkopts + dryrunopts,
2956 _('hg rename [OPTION]... SOURCE... DEST')),
2902 _('hg rename [OPTION]... SOURCE... DEST')),
2957 "^revert":
2903 "^revert":
2958 (revert,
2904 (revert,
2959 [('a', 'all', None, _('revert all changes when no arguments given')),
2905 [('a', 'all', None, _('revert all changes when no arguments given')),
2960 ('r', 'rev', '', _('revision to revert to')),
2906 ('r', 'rev', '', _('revision to revert to')),
2961 ('', 'no-backup', None, _('do not save backup copies of files')),
2907 ('', 'no-backup', None, _('do not save backup copies of files')),
2962 ] + walkopts + dryrunopts,
2908 ] + walkopts + dryrunopts,
2963 _('hg revert [-r REV] [NAME]...')),
2909 _('hg revert [-r REV] [NAME]...')),
2964 "rollback": (rollback, [], _('hg rollback')),
2910 "rollback": (rollback, [], _('hg rollback')),
2965 "root": (root, [], _('hg root')),
2911 "root": (root, [], _('hg root')),
2966 "showconfig|debugconfig":
2912 "showconfig|debugconfig":
2967 (showconfig,
2913 (showconfig,
2968 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2914 [('u', 'untrusted', None, _('show untrusted configuration options'))],
2969 _('showconfig [-u] [NAME]...')),
2915 _('showconfig [-u] [NAME]...')),
2970 "^serve":
2916 "^serve":
2971 (serve,
2917 (serve,
2972 [('A', 'accesslog', '', _('name of access log file to write to')),
2918 [('A', 'accesslog', '', _('name of access log file to write to')),
2973 ('d', 'daemon', None, _('run server in background')),
2919 ('d', 'daemon', None, _('run server in background')),
2974 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2920 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2975 ('E', 'errorlog', '', _('name of error log file to write to')),
2921 ('E', 'errorlog', '', _('name of error log file to write to')),
2976 ('p', 'port', 0, _('port to use (default: 8000)')),
2922 ('p', 'port', 0, _('port to use (default: 8000)')),
2977 ('a', 'address', '', _('address to use')),
2923 ('a', 'address', '', _('address to use')),
2978 ('n', 'name', '',
2924 ('n', 'name', '',
2979 _('name to show in web pages (default: working dir)')),
2925 _('name to show in web pages (default: working dir)')),
2980 ('', 'webdir-conf', '', _('name of the webdir config file'
2926 ('', 'webdir-conf', '', _('name of the webdir config file'
2981 ' (serve more than one repo)')),
2927 ' (serve more than one repo)')),
2982 ('', 'pid-file', '', _('name of file to write process ID to')),
2928 ('', 'pid-file', '', _('name of file to write process ID to')),
2983 ('', 'stdio', None, _('for remote clients')),
2929 ('', 'stdio', None, _('for remote clients')),
2984 ('t', 'templates', '', _('web templates to use')),
2930 ('t', 'templates', '', _('web templates to use')),
2985 ('', 'style', '', _('template style to use')),
2931 ('', 'style', '', _('template style to use')),
2986 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2932 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2987 _('hg serve [OPTION]...')),
2933 _('hg serve [OPTION]...')),
2988 "^status|st":
2934 "^status|st":
2989 (status,
2935 (status,
2990 [('A', 'all', None, _('show status of all files')),
2936 [('A', 'all', None, _('show status of all files')),
2991 ('m', 'modified', None, _('show only modified files')),
2937 ('m', 'modified', None, _('show only modified files')),
2992 ('a', 'added', None, _('show only added files')),
2938 ('a', 'added', None, _('show only added files')),
2993 ('r', 'removed', None, _('show only removed files')),
2939 ('r', 'removed', None, _('show only removed files')),
2994 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2940 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2995 ('c', 'clean', None, _('show only files without changes')),
2941 ('c', 'clean', None, _('show only files without changes')),
2996 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2942 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2997 ('i', 'ignored', None, _('show ignored files')),
2943 ('i', 'ignored', None, _('show ignored files')),
2998 ('n', 'no-status', None, _('hide status prefix')),
2944 ('n', 'no-status', None, _('hide status prefix')),
2999 ('C', 'copies', None, _('show source of copied files')),
2945 ('C', 'copies', None, _('show source of copied files')),
3000 ('0', 'print0', None,
2946 ('0', 'print0', None,
3001 _('end filenames with NUL, for use with xargs')),
2947 _('end filenames with NUL, for use with xargs')),
3002 ('', 'rev', [], _('show difference from revision')),
2948 ('', 'rev', [], _('show difference from revision')),
3003 ] + walkopts,
2949 ] + walkopts,
3004 _('hg status [OPTION]... [FILE]...')),
2950 _('hg status [OPTION]... [FILE]...')),
3005 "tag":
2951 "tag":
3006 (tag,
2952 (tag,
3007 [('l', 'local', None, _('make the tag local')),
2953 [('l', 'local', None, _('make the tag local')),
3008 ('m', 'message', '', _('message for tag commit log entry')),
2954 ('m', 'message', '', _('message for tag commit log entry')),
3009 ('d', 'date', '', _('record datecode as commit date')),
2955 ('d', 'date', '', _('record datecode as commit date')),
3010 ('u', 'user', '', _('record user as commiter')),
2956 ('u', 'user', '', _('record user as commiter')),
3011 ('r', 'rev', '', _('revision to tag'))],
2957 ('r', 'rev', '', _('revision to tag'))],
3012 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
2958 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME')),
3013 "tags": (tags, [], _('hg tags')),
2959 "tags": (tags, [], _('hg tags')),
3014 "tip":
2960 "tip":
3015 (tip,
2961 (tip,
3016 [('b', 'branches', None, _('show branches (DEPRECATED)')),
2962 [('b', 'branches', None, _('show branches (DEPRECATED)')),
3017 ('', 'style', '', _('display using template map file')),
2963 ('', 'style', '', _('display using template map file')),
3018 ('p', 'patch', None, _('show patch')),
2964 ('p', 'patch', None, _('show patch')),
3019 ('', 'template', '', _('display with template'))],
2965 ('', 'template', '', _('display with template'))],
3020 _('hg tip [-p]')),
2966 _('hg tip [-p]')),
3021 "unbundle":
2967 "unbundle":
3022 (unbundle,
2968 (unbundle,
3023 [('u', 'update', None,
2969 [('u', 'update', None,
3024 _('update to new tip if changesets were unbundled'))],
2970 _('update to new tip if changesets were unbundled'))],
3025 _('hg unbundle [-u] FILE')),
2971 _('hg unbundle [-u] FILE')),
3026 "^update|up|checkout|co":
2972 "^update|up|checkout|co":
3027 (update,
2973 (update,
3028 [('b', 'branch', '',
2974 [('b', 'branch', '',
3029 _('checkout the head of a specific branch (DEPRECATED)')),
2975 _('checkout the head of a specific branch (DEPRECATED)')),
3030 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
2976 ('m', 'merge', None, _('allow merging of branches (DEPRECATED)')),
3031 ('C', 'clean', None, _('overwrite locally modified files')),
2977 ('C', 'clean', None, _('overwrite locally modified files')),
3032 ('f', 'force', None, _('force a merge with outstanding changes'))],
2978 ('f', 'force', None, _('force a merge with outstanding changes'))],
3033 _('hg update [-C] [-f] [REV]')),
2979 _('hg update [-C] [-f] [REV]')),
3034 "verify": (verify, [], _('hg verify')),
2980 "verify": (verify, [], _('hg verify')),
3035 "version": (show_version, [], _('hg version')),
2981 "version": (show_version, [], _('hg version')),
3036 }
2982 }
3037
2983
3038 norepo = ("clone init version help debugancestor debugcomplete debugdata"
2984 norepo = ("clone init version help debugancestor debugcomplete debugdata"
3039 " debugindex debugindexdot")
2985 " debugindex debugindexdot")
3040 optionalrepo = ("paths serve showconfig")
2986 optionalrepo = ("paths serve showconfig")
3041
2987
3042 def findpossible(ui, cmd):
2988 def findpossible(ui, cmd):
3043 """
2989 """
3044 Return cmd -> (aliases, command table entry)
2990 Return cmd -> (aliases, command table entry)
3045 for each matching command.
2991 for each matching command.
3046 Return debug commands (or their aliases) only if no normal command matches.
2992 Return debug commands (or their aliases) only if no normal command matches.
3047 """
2993 """
3048 choice = {}
2994 choice = {}
3049 debugchoice = {}
2995 debugchoice = {}
3050 for e in table.keys():
2996 for e in table.keys():
3051 aliases = e.lstrip("^").split("|")
2997 aliases = e.lstrip("^").split("|")
3052 found = None
2998 found = None
3053 if cmd in aliases:
2999 if cmd in aliases:
3054 found = cmd
3000 found = cmd
3055 elif not ui.config("ui", "strict"):
3001 elif not ui.config("ui", "strict"):
3056 for a in aliases:
3002 for a in aliases:
3057 if a.startswith(cmd):
3003 if a.startswith(cmd):
3058 found = a
3004 found = a
3059 break
3005 break
3060 if found is not None:
3006 if found is not None:
3061 if aliases[0].startswith("debug") or found.startswith("debug"):
3007 if aliases[0].startswith("debug") or found.startswith("debug"):
3062 debugchoice[found] = (aliases, table[e])
3008 debugchoice[found] = (aliases, table[e])
3063 else:
3009 else:
3064 choice[found] = (aliases, table[e])
3010 choice[found] = (aliases, table[e])
3065
3011
3066 if not choice and debugchoice:
3012 if not choice and debugchoice:
3067 choice = debugchoice
3013 choice = debugchoice
3068
3014
3069 return choice
3015 return choice
3070
3016
3071 def findcmd(ui, cmd):
3017 def findcmd(ui, cmd):
3072 """Return (aliases, command table entry) for command string."""
3018 """Return (aliases, command table entry) for command string."""
3073 choice = findpossible(ui, cmd)
3019 choice = findpossible(ui, cmd)
3074
3020
3075 if choice.has_key(cmd):
3021 if choice.has_key(cmd):
3076 return choice[cmd]
3022 return choice[cmd]
3077
3023
3078 if len(choice) > 1:
3024 if len(choice) > 1:
3079 clist = choice.keys()
3025 clist = choice.keys()
3080 clist.sort()
3026 clist.sort()
3081 raise AmbiguousCommand(cmd, clist)
3027 raise AmbiguousCommand(cmd, clist)
3082
3028
3083 if choice:
3029 if choice:
3084 return choice.values()[0]
3030 return choice.values()[0]
3085
3031
3086 raise UnknownCommand(cmd)
3032 raise UnknownCommand(cmd)
3087
3033
3088 def catchterm(*args):
3034 def catchterm(*args):
3089 raise util.SignalInterrupt
3035 raise util.SignalInterrupt
3090
3036
3091 def run():
3037 def run():
3092 sys.exit(dispatch(sys.argv[1:]))
3038 sys.exit(dispatch(sys.argv[1:]))
3093
3039
3094 class ParseError(Exception):
3040 class ParseError(Exception):
3095 """Exception raised on errors in parsing the command line."""
3041 """Exception raised on errors in parsing the command line."""
3096
3042
3097 def parse(ui, args):
3043 def parse(ui, args):
3098 options = {}
3044 options = {}
3099 cmdoptions = {}
3045 cmdoptions = {}
3100
3046
3101 try:
3047 try:
3102 args = fancyopts.fancyopts(args, globalopts, options)
3048 args = fancyopts.fancyopts(args, globalopts, options)
3103 except fancyopts.getopt.GetoptError, inst:
3049 except fancyopts.getopt.GetoptError, inst:
3104 raise ParseError(None, inst)
3050 raise ParseError(None, inst)
3105
3051
3106 if args:
3052 if args:
3107 cmd, args = args[0], args[1:]
3053 cmd, args = args[0], args[1:]
3108 aliases, i = findcmd(ui, cmd)
3054 aliases, i = findcmd(ui, cmd)
3109 cmd = aliases[0]
3055 cmd = aliases[0]
3110 defaults = ui.config("defaults", cmd)
3056 defaults = ui.config("defaults", cmd)
3111 if defaults:
3057 if defaults:
3112 args = shlex.split(defaults) + args
3058 args = shlex.split(defaults) + args
3113 c = list(i[1])
3059 c = list(i[1])
3114 else:
3060 else:
3115 cmd = None
3061 cmd = None
3116 c = []
3062 c = []
3117
3063
3118 # combine global options into local
3064 # combine global options into local
3119 for o in globalopts:
3065 for o in globalopts:
3120 c.append((o[0], o[1], options[o[1]], o[3]))
3066 c.append((o[0], o[1], options[o[1]], o[3]))
3121
3067
3122 try:
3068 try:
3123 args = fancyopts.fancyopts(args, c, cmdoptions)
3069 args = fancyopts.fancyopts(args, c, cmdoptions)
3124 except fancyopts.getopt.GetoptError, inst:
3070 except fancyopts.getopt.GetoptError, inst:
3125 raise ParseError(cmd, inst)
3071 raise ParseError(cmd, inst)
3126
3072
3127 # separate global options back out
3073 # separate global options back out
3128 for o in globalopts:
3074 for o in globalopts:
3129 n = o[1]
3075 n = o[1]
3130 options[n] = cmdoptions[n]
3076 options[n] = cmdoptions[n]
3131 del cmdoptions[n]
3077 del cmdoptions[n]
3132
3078
3133 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3079 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
3134
3080
3135 external = {}
3081 external = {}
3136
3082
3137 def findext(name):
3083 def findext(name):
3138 '''return module with given extension name'''
3084 '''return module with given extension name'''
3139 try:
3085 try:
3140 return sys.modules[external[name]]
3086 return sys.modules[external[name]]
3141 except KeyError:
3087 except KeyError:
3142 for k, v in external.iteritems():
3088 for k, v in external.iteritems():
3143 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3089 if k.endswith('.' + name) or k.endswith('/' + name) or v == name:
3144 return sys.modules[v]
3090 return sys.modules[v]
3145 raise KeyError(name)
3091 raise KeyError(name)
3146
3092
3147 def load_extensions(ui):
3093 def load_extensions(ui):
3148 added = []
3094 added = []
3149 for ext_name, load_from_name in ui.extensions():
3095 for ext_name, load_from_name in ui.extensions():
3150 if ext_name in external:
3096 if ext_name in external:
3151 continue
3097 continue
3152 try:
3098 try:
3153 if load_from_name:
3099 if load_from_name:
3154 # the module will be loaded in sys.modules
3100 # the module will be loaded in sys.modules
3155 # choose an unique name so that it doesn't
3101 # choose an unique name so that it doesn't
3156 # conflicts with other modules
3102 # conflicts with other modules
3157 module_name = "hgext_%s" % ext_name.replace('.', '_')
3103 module_name = "hgext_%s" % ext_name.replace('.', '_')
3158 mod = imp.load_source(module_name, load_from_name)
3104 mod = imp.load_source(module_name, load_from_name)
3159 else:
3105 else:
3160 def importh(name):
3106 def importh(name):
3161 mod = __import__(name)
3107 mod = __import__(name)
3162 components = name.split('.')
3108 components = name.split('.')
3163 for comp in components[1:]:
3109 for comp in components[1:]:
3164 mod = getattr(mod, comp)
3110 mod = getattr(mod, comp)
3165 return mod
3111 return mod
3166 try:
3112 try:
3167 mod = importh("hgext.%s" % ext_name)
3113 mod = importh("hgext.%s" % ext_name)
3168 except ImportError:
3114 except ImportError:
3169 mod = importh(ext_name)
3115 mod = importh(ext_name)
3170 external[ext_name] = mod.__name__
3116 external[ext_name] = mod.__name__
3171 added.append((mod, ext_name))
3117 added.append((mod, ext_name))
3172 except (util.SignalInterrupt, KeyboardInterrupt):
3118 except (util.SignalInterrupt, KeyboardInterrupt):
3173 raise
3119 raise
3174 except Exception, inst:
3120 except Exception, inst:
3175 ui.warn(_("*** failed to import extension %s: %s\n") %
3121 ui.warn(_("*** failed to import extension %s: %s\n") %
3176 (ext_name, inst))
3122 (ext_name, inst))
3177 if ui.print_exc():
3123 if ui.print_exc():
3178 return 1
3124 return 1
3179
3125
3180 for mod, name in added:
3126 for mod, name in added:
3181 uisetup = getattr(mod, 'uisetup', None)
3127 uisetup = getattr(mod, 'uisetup', None)
3182 if uisetup:
3128 if uisetup:
3183 uisetup(ui)
3129 uisetup(ui)
3184 cmdtable = getattr(mod, 'cmdtable', {})
3130 cmdtable = getattr(mod, 'cmdtable', {})
3185 for t in cmdtable:
3131 for t in cmdtable:
3186 if t in table:
3132 if t in table:
3187 ui.warn(_("module %s overrides %s\n") % (name, t))
3133 ui.warn(_("module %s overrides %s\n") % (name, t))
3188 table.update(cmdtable)
3134 table.update(cmdtable)
3189
3135
3190 def parseconfig(config):
3136 def parseconfig(config):
3191 """parse the --config options from the command line"""
3137 """parse the --config options from the command line"""
3192 parsed = []
3138 parsed = []
3193 for cfg in config:
3139 for cfg in config:
3194 try:
3140 try:
3195 name, value = cfg.split('=', 1)
3141 name, value = cfg.split('=', 1)
3196 section, name = name.split('.', 1)
3142 section, name = name.split('.', 1)
3197 if not section or not name:
3143 if not section or not name:
3198 raise IndexError
3144 raise IndexError
3199 parsed.append((section, name, value))
3145 parsed.append((section, name, value))
3200 except (IndexError, ValueError):
3146 except (IndexError, ValueError):
3201 raise util.Abort(_('malformed --config option: %s') % cfg)
3147 raise util.Abort(_('malformed --config option: %s') % cfg)
3202 return parsed
3148 return parsed
3203
3149
3204 def dispatch(args):
3150 def dispatch(args):
3205 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3151 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
3206 num = getattr(signal, name, None)
3152 num = getattr(signal, name, None)
3207 if num: signal.signal(num, catchterm)
3153 if num: signal.signal(num, catchterm)
3208
3154
3209 try:
3155 try:
3210 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3156 u = ui.ui(traceback='--traceback' in sys.argv[1:])
3211 except util.Abort, inst:
3157 except util.Abort, inst:
3212 sys.stderr.write(_("abort: %s\n") % inst)
3158 sys.stderr.write(_("abort: %s\n") % inst)
3213 return -1
3159 return -1
3214
3160
3215 load_extensions(u)
3161 load_extensions(u)
3216 u.addreadhook(load_extensions)
3162 u.addreadhook(load_extensions)
3217
3163
3218 try:
3164 try:
3219 cmd, func, args, options, cmdoptions = parse(u, args)
3165 cmd, func, args, options, cmdoptions = parse(u, args)
3220 if options["time"]:
3166 if options["time"]:
3221 def get_times():
3167 def get_times():
3222 t = os.times()
3168 t = os.times()
3223 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3169 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
3224 t = (t[0], t[1], t[2], t[3], time.clock())
3170 t = (t[0], t[1], t[2], t[3], time.clock())
3225 return t
3171 return t
3226 s = get_times()
3172 s = get_times()
3227 def print_time():
3173 def print_time():
3228 t = get_times()
3174 t = get_times()
3229 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3175 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
3230 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3176 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
3231 atexit.register(print_time)
3177 atexit.register(print_time)
3232
3178
3233 # enter the debugger before command execution
3179 # enter the debugger before command execution
3234 if options['debugger']:
3180 if options['debugger']:
3235 pdb.set_trace()
3181 pdb.set_trace()
3236
3182
3237 try:
3183 try:
3238 if options['cwd']:
3184 if options['cwd']:
3239 try:
3185 try:
3240 os.chdir(options['cwd'])
3186 os.chdir(options['cwd'])
3241 except OSError, inst:
3187 except OSError, inst:
3242 raise util.Abort('%s: %s' %
3188 raise util.Abort('%s: %s' %
3243 (options['cwd'], inst.strerror))
3189 (options['cwd'], inst.strerror))
3244
3190
3245 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3191 u.updateopts(options["verbose"], options["debug"], options["quiet"],
3246 not options["noninteractive"], options["traceback"],
3192 not options["noninteractive"], options["traceback"],
3247 parseconfig(options["config"]))
3193 parseconfig(options["config"]))
3248
3194
3249 path = u.expandpath(options["repository"]) or ""
3195 path = u.expandpath(options["repository"]) or ""
3250 repo = path and hg.repository(u, path=path) or None
3196 repo = path and hg.repository(u, path=path) or None
3251 if repo and not repo.local():
3197 if repo and not repo.local():
3252 raise util.Abort(_("repository '%s' is not local") % path)
3198 raise util.Abort(_("repository '%s' is not local") % path)
3253
3199
3254 if options['help']:
3200 if options['help']:
3255 return help_(u, cmd, options['version'])
3201 return help_(u, cmd, options['version'])
3256 elif options['version']:
3202 elif options['version']:
3257 return show_version(u)
3203 return show_version(u)
3258 elif not cmd:
3204 elif not cmd:
3259 return help_(u, 'shortlist')
3205 return help_(u, 'shortlist')
3260
3206
3261 if cmd not in norepo.split():
3207 if cmd not in norepo.split():
3262 try:
3208 try:
3263 if not repo:
3209 if not repo:
3264 repo = hg.repository(u, path=path)
3210 repo = hg.repository(u, path=path)
3265 u = repo.ui
3211 u = repo.ui
3266 for name in external.itervalues():
3212 for name in external.itervalues():
3267 mod = sys.modules[name]
3213 mod = sys.modules[name]
3268 if hasattr(mod, 'reposetup'):
3214 if hasattr(mod, 'reposetup'):
3269 mod.reposetup(u, repo)
3215 mod.reposetup(u, repo)
3270 hg.repo_setup_hooks.append(mod.reposetup)
3216 hg.repo_setup_hooks.append(mod.reposetup)
3271 except hg.RepoError:
3217 except hg.RepoError:
3272 if cmd not in optionalrepo.split():
3218 if cmd not in optionalrepo.split():
3273 raise
3219 raise
3274 d = lambda: func(u, repo, *args, **cmdoptions)
3220 d = lambda: func(u, repo, *args, **cmdoptions)
3275 else:
3221 else:
3276 d = lambda: func(u, *args, **cmdoptions)
3222 d = lambda: func(u, *args, **cmdoptions)
3277
3223
3278 try:
3224 try:
3279 if options['profile']:
3225 if options['profile']:
3280 import hotshot, hotshot.stats
3226 import hotshot, hotshot.stats
3281 prof = hotshot.Profile("hg.prof")
3227 prof = hotshot.Profile("hg.prof")
3282 try:
3228 try:
3283 try:
3229 try:
3284 return prof.runcall(d)
3230 return prof.runcall(d)
3285 except:
3231 except:
3286 try:
3232 try:
3287 u.warn(_('exception raised - generating '
3233 u.warn(_('exception raised - generating '
3288 'profile anyway\n'))
3234 'profile anyway\n'))
3289 except:
3235 except:
3290 pass
3236 pass
3291 raise
3237 raise
3292 finally:
3238 finally:
3293 prof.close()
3239 prof.close()
3294 stats = hotshot.stats.load("hg.prof")
3240 stats = hotshot.stats.load("hg.prof")
3295 stats.strip_dirs()
3241 stats.strip_dirs()
3296 stats.sort_stats('time', 'calls')
3242 stats.sort_stats('time', 'calls')
3297 stats.print_stats(40)
3243 stats.print_stats(40)
3298 elif options['lsprof']:
3244 elif options['lsprof']:
3299 try:
3245 try:
3300 from mercurial import lsprof
3246 from mercurial import lsprof
3301 except ImportError:
3247 except ImportError:
3302 raise util.Abort(_(
3248 raise util.Abort(_(
3303 'lsprof not available - install from '
3249 'lsprof not available - install from '
3304 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3250 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
3305 p = lsprof.Profiler()
3251 p = lsprof.Profiler()
3306 p.enable(subcalls=True)
3252 p.enable(subcalls=True)
3307 try:
3253 try:
3308 return d()
3254 return d()
3309 finally:
3255 finally:
3310 p.disable()
3256 p.disable()
3311 stats = lsprof.Stats(p.getstats())
3257 stats = lsprof.Stats(p.getstats())
3312 stats.sort()
3258 stats.sort()
3313 stats.pprint(top=10, file=sys.stderr, climit=5)
3259 stats.pprint(top=10, file=sys.stderr, climit=5)
3314 else:
3260 else:
3315 return d()
3261 return d()
3316 finally:
3262 finally:
3317 u.flush()
3263 u.flush()
3318 except:
3264 except:
3319 # enter the debugger when we hit an exception
3265 # enter the debugger when we hit an exception
3320 if options['debugger']:
3266 if options['debugger']:
3321 pdb.post_mortem(sys.exc_info()[2])
3267 pdb.post_mortem(sys.exc_info()[2])
3322 u.print_exc()
3268 u.print_exc()
3323 raise
3269 raise
3324 except ParseError, inst:
3270 except ParseError, inst:
3325 if inst.args[0]:
3271 if inst.args[0]:
3326 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3272 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
3327 help_(u, inst.args[0])
3273 help_(u, inst.args[0])
3328 else:
3274 else:
3329 u.warn(_("hg: %s\n") % inst.args[1])
3275 u.warn(_("hg: %s\n") % inst.args[1])
3330 help_(u, 'shortlist')
3276 help_(u, 'shortlist')
3331 except AmbiguousCommand, inst:
3277 except AmbiguousCommand, inst:
3332 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3278 u.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
3333 (inst.args[0], " ".join(inst.args[1])))
3279 (inst.args[0], " ".join(inst.args[1])))
3334 except UnknownCommand, inst:
3280 except UnknownCommand, inst:
3335 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3281 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
3336 help_(u, 'shortlist')
3282 help_(u, 'shortlist')
3337 except hg.RepoError, inst:
3283 except hg.RepoError, inst:
3338 u.warn(_("abort: %s!\n") % inst)
3284 u.warn(_("abort: %s!\n") % inst)
3339 except lock.LockHeld, inst:
3285 except lock.LockHeld, inst:
3340 if inst.errno == errno.ETIMEDOUT:
3286 if inst.errno == errno.ETIMEDOUT:
3341 reason = _('timed out waiting for lock held by %s') % inst.locker
3287 reason = _('timed out waiting for lock held by %s') % inst.locker
3342 else:
3288 else:
3343 reason = _('lock held by %s') % inst.locker
3289 reason = _('lock held by %s') % inst.locker
3344 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3290 u.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
3345 except lock.LockUnavailable, inst:
3291 except lock.LockUnavailable, inst:
3346 u.warn(_("abort: could not lock %s: %s\n") %
3292 u.warn(_("abort: could not lock %s: %s\n") %
3347 (inst.desc or inst.filename, inst.strerror))
3293 (inst.desc or inst.filename, inst.strerror))
3348 except revlog.RevlogError, inst:
3294 except revlog.RevlogError, inst:
3349 u.warn(_("abort: %s!\n") % inst)
3295 u.warn(_("abort: %s!\n") % inst)
3350 except util.SignalInterrupt:
3296 except util.SignalInterrupt:
3351 u.warn(_("killed!\n"))
3297 u.warn(_("killed!\n"))
3352 except KeyboardInterrupt:
3298 except KeyboardInterrupt:
3353 try:
3299 try:
3354 u.warn(_("interrupted!\n"))
3300 u.warn(_("interrupted!\n"))
3355 except IOError, inst:
3301 except IOError, inst:
3356 if inst.errno == errno.EPIPE:
3302 if inst.errno == errno.EPIPE:
3357 if u.debugflag:
3303 if u.debugflag:
3358 u.warn(_("\nbroken pipe\n"))
3304 u.warn(_("\nbroken pipe\n"))
3359 else:
3305 else:
3360 raise
3306 raise
3361 except IOError, inst:
3307 except IOError, inst:
3362 if hasattr(inst, "code"):
3308 if hasattr(inst, "code"):
3363 u.warn(_("abort: %s\n") % inst)
3309 u.warn(_("abort: %s\n") % inst)
3364 elif hasattr(inst, "reason"):
3310 elif hasattr(inst, "reason"):
3365 u.warn(_("abort: error: %s\n") % inst.reason[1])
3311 u.warn(_("abort: error: %s\n") % inst.reason[1])
3366 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3312 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
3367 if u.debugflag:
3313 if u.debugflag:
3368 u.warn(_("broken pipe\n"))
3314 u.warn(_("broken pipe\n"))
3369 elif getattr(inst, "strerror", None):
3315 elif getattr(inst, "strerror", None):
3370 if getattr(inst, "filename", None):
3316 if getattr(inst, "filename", None):
3371 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3317 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3372 else:
3318 else:
3373 u.warn(_("abort: %s\n") % inst.strerror)
3319 u.warn(_("abort: %s\n") % inst.strerror)
3374 else:
3320 else:
3375 raise
3321 raise
3376 except OSError, inst:
3322 except OSError, inst:
3377 if getattr(inst, "filename", None):
3323 if getattr(inst, "filename", None):
3378 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3324 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
3379 else:
3325 else:
3380 u.warn(_("abort: %s\n") % inst.strerror)
3326 u.warn(_("abort: %s\n") % inst.strerror)
3381 except util.UnexpectedOutput, inst:
3327 except util.UnexpectedOutput, inst:
3382 u.warn(_("abort: %s") % inst[0])
3328 u.warn(_("abort: %s") % inst[0])
3383 if not isinstance(inst[1], basestring):
3329 if not isinstance(inst[1], basestring):
3384 u.warn(" %r\n" % (inst[1],))
3330 u.warn(" %r\n" % (inst[1],))
3385 elif not inst[1]:
3331 elif not inst[1]:
3386 u.warn(_(" empty string\n"))
3332 u.warn(_(" empty string\n"))
3387 else:
3333 else:
3388 u.warn("\n%r%s\n" %
3334 u.warn("\n%r%s\n" %
3389 (inst[1][:400], len(inst[1]) > 400 and '...' or ''))
3335 (inst[1][:400], len(inst[1]) > 400 and '...' or ''))
3390 except util.Abort, inst:
3336 except util.Abort, inst:
3391 u.warn(_("abort: %s\n") % inst)
3337 u.warn(_("abort: %s\n") % inst)
3392 except TypeError, inst:
3338 except TypeError, inst:
3393 # was this an argument error?
3339 # was this an argument error?
3394 tb = traceback.extract_tb(sys.exc_info()[2])
3340 tb = traceback.extract_tb(sys.exc_info()[2])
3395 if len(tb) > 2: # no
3341 if len(tb) > 2: # no
3396 raise
3342 raise
3397 u.debug(inst, "\n")
3343 u.debug(inst, "\n")
3398 u.warn(_("%s: invalid arguments\n") % cmd)
3344 u.warn(_("%s: invalid arguments\n") % cmd)
3399 help_(u, cmd)
3345 help_(u, cmd)
3400 except SystemExit, inst:
3346 except SystemExit, inst:
3401 # Commands shouldn't sys.exit directly, but give a return code.
3347 # Commands shouldn't sys.exit directly, but give a return code.
3402 # Just in case catch this and and pass exit code to caller.
3348 # Just in case catch this and and pass exit code to caller.
3403 return inst.code
3349 return inst.code
3404 except:
3350 except:
3405 u.warn(_("** unknown exception encountered, details follow\n"))
3351 u.warn(_("** unknown exception encountered, details follow\n"))
3406 u.warn(_("** report bug details to "
3352 u.warn(_("** report bug details to "
3407 "http://www.selenic.com/mercurial/bts\n"))
3353 "http://www.selenic.com/mercurial/bts\n"))
3408 u.warn(_("** or mercurial@selenic.com\n"))
3354 u.warn(_("** or mercurial@selenic.com\n"))
3409 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3355 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
3410 % version.get_version())
3356 % version.get_version())
3411 raise
3357 raise
3412
3358
3413 return -1
3359 return -1
@@ -1,58 +1,56 b''
1 not removing foo: file is not managed
1 not removing foo: file is not managed
2 abort: no files specified
2 abort: no files specified
3 undeleting foo
3 undeleting foo
4 removing foo
4 removing foo
5 # HG changeset patch
5 # HG changeset patch
6 # User test
6 # User test
7 # Date 1000000 0
7 # Date 1000000 0
8 # Node ID 8ba83d44753d6259db5ce6524974dd1174e90f47
8 # Node ID 8ba83d44753d6259db5ce6524974dd1174e90f47
9 # Parent 0000000000000000000000000000000000000000
9 # Parent 0000000000000000000000000000000000000000
10 1
10 1
11
11
12 diff -r 000000000000 -r 8ba83d44753d foo
12 diff -r 000000000000 -r 8ba83d44753d foo
13 --- /dev/null
13 --- /dev/null
14 +++ b/foo
14 +++ b/foo
15 @@ -0,0 +1,1 @@
15 @@ -0,0 +1,1 @@
16 +a
16 +a
17 # HG changeset patch
17 # HG changeset patch
18 # User test
18 # User test
19 # Date 1000000 0
19 # Date 1000000 0
20 # Node ID a1fce69c50d97881c5c014ab23f580f720c78678
20 # Node ID a1fce69c50d97881c5c014ab23f580f720c78678
21 # Parent 8ba83d44753d6259db5ce6524974dd1174e90f47
21 # Parent 8ba83d44753d6259db5ce6524974dd1174e90f47
22 2
22 2
23
23
24 diff -r 8ba83d44753d -r a1fce69c50d9 foo
24 diff -r 8ba83d44753d -r a1fce69c50d9 foo
25 --- a/foo
25 --- a/foo
26 +++ /dev/null
26 +++ /dev/null
27 @@ -1,1 +0,0 @@
27 @@ -1,1 +0,0 @@
28 -a
28 -a
29 changeset: 0:8ba83d44753d
29 changeset: 0:8ba83d44753d
30 user: test
30 user: test
31 date: Mon Jan 12 13:46:40 1970 +0000
31 date: Mon Jan 12 13:46:40 1970 +0000
32 summary: 1
32 summary: 1
33
33
34 diff -r 000000000000 -r 8ba83d44753d foo
34 diff -r 000000000000 -r 8ba83d44753d foo
35 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36 +++ b/foo Mon Jan 12 13:46:40 1970 +0000
36 +++ b/foo Mon Jan 12 13:46:40 1970 +0000
37 @@ -0,0 +1,1 @@
37 @@ -0,0 +1,1 @@
38 +a
38 +a
39
39
40
41 changeset: 1:a1fce69c50d9
40 changeset: 1:a1fce69c50d9
42 tag: tip
41 tag: tip
43 user: test
42 user: test
44 date: Mon Jan 12 13:46:40 1970 +0000
43 date: Mon Jan 12 13:46:40 1970 +0000
45 summary: 2
44 summary: 2
46
45
47 diff -r 8ba83d44753d -r a1fce69c50d9 foo
46 diff -r 8ba83d44753d -r a1fce69c50d9 foo
48 --- a/foo Mon Jan 12 13:46:40 1970 +0000
47 --- a/foo Mon Jan 12 13:46:40 1970 +0000
49 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
48 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
50 @@ -1,1 +0,0 @@
49 @@ -1,1 +0,0 @@
51 -a
50 -a
52
51
53
54 not removing a: file has been marked for add (use -f to force removal)
52 not removing a: file has been marked for add (use -f to force removal)
55 adding a
53 adding a
56 adding b
54 adding b
57 not removing b: file is modified (use -f to force removal)
55 not removing b: file is modified (use -f to force removal)
58 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
General Comments 0
You need to be logged in to leave comments. Login now