Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/commands.py @ 3044:fcadf7a32425
Merge with mpm
author | Josef "Jeff" Sipek <jeffpc@josefsipek.net> |
---|---|
date | Sun, 03 Sep 2006 06:06:02 -0400 |
parents | eef469259745 |
children | f63667f694de |
comparison
equal
deleted
inserted
replaced
3043:2a4d4aecb2b4 | 3044:fcadf7a32425 |
---|---|
1 # commands.py - command processing for mercurial | 1 # commands.py - command processing for mercurial |
2 # | 2 # |
3 # Copyright 2005 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 shutil imp urllib pdb") | 11 demandload(globals(), "os re sys signal shutil imp urllib pdb") |
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") | 12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo") |
13 demandload(globals(), "fnmatch mdiff random signal tempfile time") | 13 demandload(globals(), "fnmatch difflib patch random signal tempfile time") |
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2") | 14 demandload(globals(), "traceback errno socket version struct atexit sets bz2") |
15 demandload(globals(), "archival cStringIO changegroup email.Parser") | 15 demandload(globals(), "archival cStringIO changegroup") |
16 demandload(globals(), "hgweb.server sshserver") | 16 demandload(globals(), "cmdutil hgweb.server sshserver") |
17 | 17 |
18 class UnknownCommand(Exception): | 18 class UnknownCommand(Exception): |
19 """Exception raised if command is not in the command table.""" | 19 """Exception raised if command is not in the command table.""" |
20 class AmbiguousCommand(Exception): | 20 class AmbiguousCommand(Exception): |
21 """Exception raised if command shortcut matches more than one command.""" | 21 """Exception raised if command shortcut matches more than one command.""" |
22 | 22 |
23 def bail_if_changed(repo): | 23 def bail_if_changed(repo): |
24 modified, added, removed, deleted, unknown = repo.changes() | 24 modified, added, removed, deleted = repo.status()[:4] |
25 if modified or added or removed or deleted: | 25 if modified or added or removed or deleted: |
26 raise util.Abort(_("outstanding uncommitted changes")) | 26 raise util.Abort(_("outstanding uncommitted changes")) |
27 | |
28 def filterfiles(filters, files): | |
29 l = [x for x in files if x in filters] | |
30 | |
31 for t in filters: | |
32 if t and t[-1] != "/": | |
33 t += "/" | |
34 l += [x for x in files if x.startswith(t)] | |
35 return l | |
36 | 27 |
37 def relpath(repo, args): | 28 def relpath(repo, args): |
38 cwd = repo.getcwd() | 29 cwd = repo.getcwd() |
39 if cwd: | 30 if cwd: |
40 return [util.normpath(os.path.join(cwd, x)) for x in args] | 31 return [util.normpath(os.path.join(cwd, x)) for x in args] |
41 return args | 32 return args |
42 | 33 |
43 def matchpats(repo, pats=[], opts={}, head=''): | 34 def logmessage(opts): |
44 cwd = repo.getcwd() | 35 """ get the log message according to -m and -l option """ |
45 if not pats and cwd: | 36 message = opts['message'] |
46 opts['include'] = [os.path.join(cwd, i) for i in opts['include']] | 37 logfile = opts['logfile'] |
47 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']] | 38 |
48 cwd = '' | 39 if message and logfile: |
49 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'), | 40 raise util.Abort(_('options --message and --logfile are mutually ' |
50 opts.get('exclude'), head) | 41 'exclusive')) |
51 | 42 if not message and logfile: |
52 def makewalk(repo, pats, opts, node=None, head='', badmatch=None): | 43 try: |
53 files, matchfn, anypats = matchpats(repo, pats, opts, head) | 44 if logfile == '-': |
54 exact = dict(zip(files, files)) | 45 message = sys.stdin.read() |
55 def walk(): | 46 else: |
56 for src, fn in repo.walk(node=node, files=files, match=matchfn, | 47 message = open(logfile).read() |
57 badmatch=badmatch): | 48 except IOError, inst: |
58 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact | 49 raise util.Abort(_("can't read commit message '%s': %s") % |
59 return files, matchfn, walk() | 50 (logfile, inst.strerror)) |
60 | 51 return message |
61 def walk(repo, pats, opts, node=None, head='', badmatch=None): | |
62 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch) | |
63 for r in results: | |
64 yield r | |
65 | 52 |
66 def walkchangerevs(ui, repo, pats, opts): | 53 def walkchangerevs(ui, repo, pats, opts): |
67 '''Iterate over files and the revs they changed in. | 54 '''Iterate over files and the revs they changed in. |
68 | 55 |
69 Callers most commonly need to iterate backwards over the history | 56 Callers most commonly need to iterate backwards over the history |
103 start -= windowsize | 90 start -= windowsize |
104 if windowsize < sizelimit: | 91 if windowsize < sizelimit: |
105 windowsize *= 2 | 92 windowsize *= 2 |
106 | 93 |
107 | 94 |
108 files, matchfn, anypats = matchpats(repo, pats, opts) | 95 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
96 follow = opts.get('follow') or opts.get('follow_first') | |
109 | 97 |
110 if repo.changelog.count() == 0: | 98 if repo.changelog.count() == 0: |
111 return [], False, matchfn | 99 return [], False, matchfn |
112 | 100 |
113 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0'])) | 101 if follow: |
102 p = repo.dirstate.parents()[0] | |
103 if p == nullid: | |
104 ui.warn(_('No working directory revision; defaulting to tip\n')) | |
105 start = 'tip' | |
106 else: | |
107 start = repo.changelog.rev(p) | |
108 defrange = '%s:0' % start | |
109 else: | |
110 defrange = 'tip:0' | |
111 revs = map(int, revrange(ui, repo, opts['rev'] or [defrange])) | |
114 wanted = {} | 112 wanted = {} |
115 slowpath = anypats | 113 slowpath = anypats |
116 fncache = {} | 114 fncache = {} |
117 | 115 |
118 chcache = {} | 116 chcache = {} |
123 return ch | 121 return ch |
124 | 122 |
125 if not slowpath and not files: | 123 if not slowpath and not files: |
126 # No files, no patterns. Display all revs. | 124 # No files, no patterns. Display all revs. |
127 wanted = dict(zip(revs, revs)) | 125 wanted = dict(zip(revs, revs)) |
126 copies = [] | |
128 if not slowpath: | 127 if not slowpath: |
129 # Only files, no patterns. Check the history of each file. | 128 # Only files, no patterns. Check the history of each file. |
130 def filerevgen(filelog): | 129 def filerevgen(filelog, node): |
131 cl_count = repo.changelog.count() | 130 cl_count = repo.changelog.count() |
132 for i, window in increasing_windows(filelog.count()-1, -1): | 131 if node is None: |
132 last = filelog.count() - 1 | |
133 else: | |
134 last = filelog.rev(node) | |
135 for i, window in increasing_windows(last, -1): | |
133 revs = [] | 136 revs = [] |
134 for j in xrange(i - window, i + 1): | 137 for j in xrange(i - window, i + 1): |
135 revs.append(filelog.linkrev(filelog.node(j))) | 138 n = filelog.node(j) |
139 revs.append((filelog.linkrev(n), | |
140 follow and filelog.renamed(n))) | |
136 revs.reverse() | 141 revs.reverse() |
137 for rev in revs: | 142 for rev in revs: |
138 # only yield rev for which we have the changelog, it can | 143 # only yield rev for which we have the changelog, it can |
139 # happen while doing "hg log" during a pull or commit | 144 # happen while doing "hg log" during a pull or commit |
140 if rev < cl_count: | 145 if rev[0] < cl_count: |
141 yield rev | 146 yield rev |
142 | 147 def iterfiles(): |
148 for filename in files: | |
149 yield filename, None | |
150 for filename_node in copies: | |
151 yield filename_node | |
143 minrev, maxrev = min(revs), max(revs) | 152 minrev, maxrev = min(revs), max(revs) |
144 for file_ in files: | 153 for file_, node in iterfiles(): |
145 filelog = repo.file(file_) | 154 filelog = repo.file(file_) |
146 # A zero count may be a directory or deleted file, so | 155 # A zero count may be a directory or deleted file, so |
147 # try to find matching entries on the slow path. | 156 # try to find matching entries on the slow path. |
148 if filelog.count() == 0: | 157 if filelog.count() == 0: |
149 slowpath = True | 158 slowpath = True |
150 break | 159 break |
151 for rev in filerevgen(filelog): | 160 for rev, copied in filerevgen(filelog, node): |
152 if rev <= maxrev: | 161 if rev <= maxrev: |
153 if rev < minrev: | 162 if rev < minrev: |
154 break | 163 break |
155 fncache.setdefault(rev, []) | 164 fncache.setdefault(rev, []) |
156 fncache[rev].append(file_) | 165 fncache[rev].append(file_) |
157 wanted[rev] = 1 | 166 wanted[rev] = 1 |
167 if follow and copied: | |
168 copies.append(copied) | |
158 if slowpath: | 169 if slowpath: |
170 if follow: | |
171 raise util.Abort(_('can only follow copies/renames for explicit ' | |
172 'file names')) | |
173 | |
159 # The slow path checks files modified in every changeset. | 174 # The slow path checks files modified in every changeset. |
160 def changerevgen(): | 175 def changerevgen(): |
161 for i, window in increasing_windows(repo.changelog.count()-1, -1): | 176 for i, window in increasing_windows(repo.changelog.count()-1, -1): |
162 for j in xrange(i - window, i + 1): | 177 for j in xrange(i - window, i + 1): |
163 yield j, getchange(j)[3] | 178 yield j, getchange(j)[3] |
166 matches = filter(matchfn, changefiles) | 181 matches = filter(matchfn, changefiles) |
167 if matches: | 182 if matches: |
168 fncache[rev] = matches | 183 fncache[rev] = matches |
169 wanted[rev] = 1 | 184 wanted[rev] = 1 |
170 | 185 |
186 class followfilter: | |
187 def __init__(self, onlyfirst=False): | |
188 self.startrev = -1 | |
189 self.roots = [] | |
190 self.onlyfirst = onlyfirst | |
191 | |
192 def match(self, rev): | |
193 def realparents(rev): | |
194 if self.onlyfirst: | |
195 return repo.changelog.parentrevs(rev)[0:1] | |
196 else: | |
197 return filter(lambda x: x != -1, repo.changelog.parentrevs(rev)) | |
198 | |
199 if self.startrev == -1: | |
200 self.startrev = rev | |
201 return True | |
202 | |
203 if rev > self.startrev: | |
204 # forward: all descendants | |
205 if not self.roots: | |
206 self.roots.append(self.startrev) | |
207 for parent in realparents(rev): | |
208 if parent in self.roots: | |
209 self.roots.append(rev) | |
210 return True | |
211 else: | |
212 # backwards: all parents | |
213 if not self.roots: | |
214 self.roots.extend(realparents(self.startrev)) | |
215 if rev in self.roots: | |
216 self.roots.remove(rev) | |
217 self.roots.extend(realparents(rev)) | |
218 return True | |
219 | |
220 return False | |
221 | |
222 # it might be worthwhile to do this in the iterator if the rev range | |
223 # is descending and the prune args are all within that range | |
224 for rev in opts.get('prune', ()): | |
225 rev = repo.changelog.rev(repo.lookup(rev)) | |
226 ff = followfilter() | |
227 stop = min(revs[0], revs[-1]) | |
228 for x in range(rev, stop-1, -1): | |
229 if ff.match(x) and wanted.has_key(x): | |
230 del wanted[x] | |
231 | |
171 def iterate(): | 232 def iterate(): |
233 if follow and not files: | |
234 ff = followfilter(onlyfirst=opts.get('follow_first')) | |
235 def want(rev): | |
236 if ff.match(rev) and rev in wanted: | |
237 return True | |
238 return False | |
239 else: | |
240 def want(rev): | |
241 return rev in wanted | |
242 | |
172 for i, window in increasing_windows(0, len(revs)): | 243 for i, window in increasing_windows(0, len(revs)): |
173 yield 'window', revs[0] < revs[-1], revs[-1] | 244 yield 'window', revs[0] < revs[-1], revs[-1] |
174 nrevs = [rev for rev in revs[i:i+window] | 245 nrevs = [rev for rev in revs[i:i+window] if want(rev)] |
175 if rev in wanted] | |
176 srevs = list(nrevs) | 246 srevs = list(nrevs) |
177 srevs.sort() | 247 srevs.sort() |
178 for rev in srevs: | 248 for rev in srevs: |
179 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3]) | 249 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3]) |
180 yield 'add', rev, fns | 250 yield 'add', rev, fns |
250 if rev in seen: | 320 if rev in seen: |
251 continue | 321 continue |
252 seen[rev] = 1 | 322 seen[rev] = 1 |
253 yield str(rev) | 323 yield str(rev) |
254 | 324 |
255 def make_filename(repo, pat, node, | |
256 total=None, seqno=None, revwidth=None, pathname=None): | |
257 node_expander = { | |
258 'H': lambda: hex(node), | |
259 'R': lambda: str(repo.changelog.rev(node)), | |
260 'h': lambda: short(node), | |
261 } | |
262 expander = { | |
263 '%': lambda: '%', | |
264 'b': lambda: os.path.basename(repo.root), | |
265 } | |
266 | |
267 try: | |
268 if node: | |
269 expander.update(node_expander) | |
270 if node and revwidth is not None: | |
271 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth) | |
272 if total is not None: | |
273 expander['N'] = lambda: str(total) | |
274 if seqno is not None: | |
275 expander['n'] = lambda: str(seqno) | |
276 if total is not None and seqno is not None: | |
277 expander['n'] = lambda:str(seqno).zfill(len(str(total))) | |
278 if pathname is not None: | |
279 expander['s'] = lambda: os.path.basename(pathname) | |
280 expander['d'] = lambda: os.path.dirname(pathname) or '.' | |
281 expander['p'] = lambda: pathname | |
282 | |
283 newname = [] | |
284 patlen = len(pat) | |
285 i = 0 | |
286 while i < patlen: | |
287 c = pat[i] | |
288 if c == '%': | |
289 i += 1 | |
290 c = pat[i] | |
291 c = expander[c]() | |
292 newname.append(c) | |
293 i += 1 | |
294 return ''.join(newname) | |
295 except KeyError, inst: | |
296 raise util.Abort(_("invalid format spec '%%%s' in output file name"), | |
297 inst.args[0]) | |
298 | |
299 def make_file(repo, pat, node=None, | |
300 total=None, seqno=None, revwidth=None, mode='wb', pathname=None): | |
301 if not pat or pat == '-': | |
302 return 'w' in mode and sys.stdout or sys.stdin | |
303 if hasattr(pat, 'write') and 'w' in mode: | |
304 return pat | |
305 if hasattr(pat, 'read') and 'r' in mode: | |
306 return pat | |
307 return open(make_filename(repo, pat, node, total, seqno, revwidth, | |
308 pathname), | |
309 mode) | |
310 | |
311 def write_bundle(cg, filename=None, compress=True): | 325 def write_bundle(cg, filename=None, compress=True): |
312 """Write a bundle file and return its filename. | 326 """Write a bundle file and return its filename. |
313 | 327 |
314 Existing files will not be overwritten. | 328 Existing files will not be overwritten. |
315 If no filename is specified, a temporary file is created. | 329 If no filename is specified, a temporary file is created. |
358 if fh is not None: | 372 if fh is not None: |
359 fh.close() | 373 fh.close() |
360 if cleanup is not None: | 374 if cleanup is not None: |
361 os.unlink(cleanup) | 375 os.unlink(cleanup) |
362 | 376 |
363 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always, | |
364 changes=None, text=False, opts={}): | |
365 if not node1: | |
366 node1 = repo.dirstate.parents()[0] | |
367 # reading the data for node1 early allows it to play nicely | |
368 # with repo.changes and the revlog cache. | |
369 change = repo.changelog.read(node1) | |
370 mmap = repo.manifest.read(change[0]) | |
371 date1 = util.datestr(change[2]) | |
372 | |
373 if not changes: | |
374 changes = repo.changes(node1, node2, files, match=match) | |
375 modified, added, removed, deleted, unknown = changes | |
376 if files: | |
377 modified, added, removed = map(lambda x: filterfiles(files, x), | |
378 (modified, added, removed)) | |
379 | |
380 if not modified and not added and not removed: | |
381 return | |
382 | |
383 if node2: | |
384 change = repo.changelog.read(node2) | |
385 mmap2 = repo.manifest.read(change[0]) | |
386 _date2 = util.datestr(change[2]) | |
387 def date2(f): | |
388 return _date2 | |
389 def read(f): | |
390 return repo.file(f).read(mmap2[f]) | |
391 else: | |
392 tz = util.makedate()[1] | |
393 _date2 = util.datestr() | |
394 def date2(f): | |
395 try: | |
396 return util.datestr((os.lstat(repo.wjoin(f)).st_mtime, tz)) | |
397 except OSError, err: | |
398 if err.errno != errno.ENOENT: raise | |
399 return _date2 | |
400 def read(f): | |
401 return repo.wread(f) | |
402 | |
403 if ui.quiet: | |
404 r = None | |
405 else: | |
406 hexfunc = ui.verbose and hex or short | |
407 r = [hexfunc(node) for node in [node1, node2] if node] | |
408 | |
409 diffopts = ui.diffopts() | |
410 showfunc = opts.get('show_function') or diffopts['showfunc'] | |
411 ignorews = opts.get('ignore_all_space') or diffopts['ignorews'] | |
412 ignorewsamount = opts.get('ignore_space_change') or \ | |
413 diffopts['ignorewsamount'] | |
414 ignoreblanklines = opts.get('ignore_blank_lines') or \ | |
415 diffopts['ignoreblanklines'] | |
416 for f in modified: | |
417 to = None | |
418 if f in mmap: | |
419 to = repo.file(f).read(mmap[f]) | |
420 tn = read(f) | |
421 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
422 showfunc=showfunc, ignorews=ignorews, | |
423 ignorewsamount=ignorewsamount, | |
424 ignoreblanklines=ignoreblanklines)) | |
425 for f in added: | |
426 to = None | |
427 tn = read(f) | |
428 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
429 showfunc=showfunc, ignorews=ignorews, | |
430 ignorewsamount=ignorewsamount, | |
431 ignoreblanklines=ignoreblanklines)) | |
432 for f in removed: | |
433 to = repo.file(f).read(mmap[f]) | |
434 tn = None | |
435 fp.write(mdiff.unidiff(to, date1, tn, date2(f), f, r, text=text, | |
436 showfunc=showfunc, ignorews=ignorews, | |
437 ignorewsamount=ignorewsamount, | |
438 ignoreblanklines=ignoreblanklines)) | |
439 | |
440 def trimuser(ui, name, rev, revcache): | 377 def trimuser(ui, name, rev, revcache): |
441 """trim the name of the user who committed a change""" | 378 """trim the name of the user who committed a change""" |
442 user = revcache.get(rev) | 379 user = revcache.get(rev) |
443 if user is None: | 380 if user is None: |
444 user = revcache[rev] = ui.shortuser(name) | 381 user = revcache[rev] = ui.shortuser(name) |
464 return | 401 return |
465 | 402 |
466 changes = log.read(changenode) | 403 changes = log.read(changenode) |
467 date = util.datestr(changes[2]) | 404 date = util.datestr(changes[2]) |
468 | 405 |
469 parents = [(log.rev(p), self.ui.verbose and hex(p) or short(p)) | 406 hexfunc = self.ui.debugflag and hex or short |
470 for p in log.parents(changenode) | 407 |
408 parents = [(log.rev(p), hexfunc(p)) for p in log.parents(changenode) | |
471 if self.ui.debugflag or p != nullid] | 409 if self.ui.debugflag or p != nullid] |
472 if (not self.ui.debugflag and len(parents) == 1 and | 410 if (not self.ui.debugflag and len(parents) == 1 and |
473 parents[0][0] == rev-1): | 411 parents[0][0] == rev-1): |
474 parents = [] | 412 parents = [] |
475 | 413 |
476 if self.ui.verbose: | 414 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode))) |
477 self.ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode))) | |
478 else: | |
479 self.ui.write(_("changeset: %d:%s\n") % (rev, short(changenode))) | |
480 | 415 |
481 for tag in self.repo.nodetags(changenode): | 416 for tag in self.repo.nodetags(changenode): |
482 self.ui.status(_("tag: %s\n") % tag) | 417 self.ui.status(_("tag: %s\n") % tag) |
483 for parent in parents: | 418 for parent in parents: |
484 self.ui.write(_("parent: %d:%s\n") % parent) | 419 self.ui.write(_("parent: %d:%s\n") % parent) |
491 (self.repo.manifest.rev(changes[0]), hex(changes[0]))) | 426 (self.repo.manifest.rev(changes[0]), hex(changes[0]))) |
492 self.ui.status(_("user: %s\n") % changes[1]) | 427 self.ui.status(_("user: %s\n") % changes[1]) |
493 self.ui.status(_("date: %s\n") % date) | 428 self.ui.status(_("date: %s\n") % date) |
494 | 429 |
495 if self.ui.debugflag: | 430 if self.ui.debugflag: |
496 files = self.repo.changes(log.parents(changenode)[0], changenode) | 431 files = self.repo.status(log.parents(changenode)[0], changenode)[:3] |
497 for key, value in zip([_("files:"), _("files+:"), _("files-:")], | 432 for key, value in zip([_("files:"), _("files+:"), _("files-:")], |
498 files): | 433 files): |
499 if value: | 434 if value: |
500 self.ui.note("%-12s %s\n" % (key, " ".join(value))) | 435 self.ui.note("%-12s %s\n" % (key, " ".join(value))) |
501 else: | 436 else: |
535 raise util.Abort(inst.args[0]) | 470 raise util.Abort(inst.args[0]) |
536 if tmpl: t.use_template(tmpl) | 471 if tmpl: t.use_template(tmpl) |
537 return t | 472 return t |
538 return changeset_printer(ui, repo) | 473 return changeset_printer(ui, repo) |
539 | 474 |
475 def setremoteconfig(ui, opts): | |
476 "copy remote options to ui tree" | |
477 if opts.get('ssh'): | |
478 ui.setconfig("ui", "ssh", opts['ssh']) | |
479 if opts.get('remotecmd'): | |
480 ui.setconfig("ui", "remotecmd", opts['remotecmd']) | |
481 | |
540 def show_version(ui): | 482 def show_version(ui): |
541 """output version and copyright information""" | 483 """output version and copyright information""" |
542 ui.write(_("Mercurial Distributed SCM (version %s)\n") | 484 ui.write(_("Mercurial Distributed SCM (version %s)\n") |
543 % version.get_version()) | 485 % version.get_version()) |
544 ui.status(_( | 486 ui.status(_( |
545 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n" | 487 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n" |
546 "This is free software; see the source for copying conditions. " | 488 "This is free software; see the source for copying conditions. " |
547 "There is NO\nwarranty; " | 489 "There is NO\nwarranty; " |
548 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" | 490 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" |
549 )) | 491 )) |
550 | 492 |
694 | 636 |
695 If no names are given, add all files in the repository. | 637 If no names are given, add all files in the repository. |
696 """ | 638 """ |
697 | 639 |
698 names = [] | 640 names = [] |
699 for src, abs, rel, exact in walk(repo, pats, opts): | 641 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
700 if exact: | 642 if exact: |
701 if ui.verbose: | 643 if ui.verbose: |
702 ui.status(_('adding %s\n') % rel) | 644 ui.status(_('adding %s\n') % rel) |
703 names.append(abs) | 645 names.append(abs) |
704 elif repo.dirstate.state(abs) == '?': | 646 elif repo.dirstate.state(abs) == '?': |
708 repo.add(names) | 650 repo.add(names) |
709 | 651 |
710 def addremove(ui, repo, *pats, **opts): | 652 def addremove(ui, repo, *pats, **opts): |
711 """add all new files, delete all missing files (DEPRECATED) | 653 """add all new files, delete all missing files (DEPRECATED) |
712 | 654 |
713 (DEPRECATED) | |
714 Add all new files and remove all missing files from the repository. | 655 Add all new files and remove all missing files from the repository. |
715 | 656 |
716 New files are ignored if they match any of the patterns in .hgignore. As | 657 New files are ignored if they match any of the patterns in .hgignore. As |
717 with add, these changes take effect at the next commit. | 658 with add, these changes take effect at the next commit. |
718 | 659 |
719 This command is now deprecated and will be removed in a future | 660 Use the -s option to detect renamed files. With a parameter > 0, |
720 release. Please use add and remove --after instead. | 661 this compares every removed file with every added file and records |
721 """ | 662 those similar enough as renames. This option takes a percentage |
722 ui.warn(_('(the addremove command is deprecated; use add and remove ' | 663 between 0 (disabled) and 100 (files must be identical) as its |
723 '--after instead)\n')) | 664 parameter. Detecting renamed files this way can be expensive. |
724 return addremove_lock(ui, repo, pats, opts) | 665 """ |
725 | 666 sim = float(opts.get('similarity') or 0) |
726 def addremove_lock(ui, repo, pats, opts, wlock=None): | 667 if sim < 0 or sim > 100: |
727 add, remove = [], [] | 668 raise util.Abort(_('similarity must be between 0 and 100')) |
728 for src, abs, rel, exact in walk(repo, pats, opts): | 669 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.) |
729 if src == 'f' and repo.dirstate.state(abs) == '?': | |
730 add.append(abs) | |
731 if ui.verbose or not exact: | |
732 ui.status(_('adding %s\n') % ((pats and rel) or abs)) | |
733 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): | |
734 remove.append(abs) | |
735 if ui.verbose or not exact: | |
736 ui.status(_('removing %s\n') % ((pats and rel) or abs)) | |
737 if not opts.get('dry_run'): | |
738 repo.add(add, wlock=wlock) | |
739 repo.remove(remove, wlock=wlock) | |
740 | 670 |
741 def annotate(ui, repo, *pats, **opts): | 671 def annotate(ui, repo, *pats, **opts): |
742 """show changeset information per file line | 672 """show changeset information per file line |
743 | 673 |
744 List changes in files, showing the revision id responsible for each line | 674 List changes in files, showing the revision id responsible for each line |
777 if not opts['user'] and not opts['changeset'] and not opts['date']: | 707 if not opts['user'] and not opts['changeset'] and not opts['date']: |
778 opts['number'] = 1 | 708 opts['number'] = 1 |
779 | 709 |
780 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) | 710 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) |
781 | 711 |
782 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()): | 712 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, |
713 node=ctx.node()): | |
783 fctx = ctx.filectx(abs) | 714 fctx = ctx.filectx(abs) |
784 if not opts['text'] and util.binary(fctx.data()): | 715 if not opts['text'] and util.binary(fctx.data()): |
785 ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) | 716 ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) |
786 continue | 717 continue |
787 | 718 |
829 node, p2 = repo.dirstate.parents() | 760 node, p2 = repo.dirstate.parents() |
830 if p2 != nullid: | 761 if p2 != nullid: |
831 raise util.Abort(_('uncommitted merge - please provide a ' | 762 raise util.Abort(_('uncommitted merge - please provide a ' |
832 'specific revision')) | 763 'specific revision')) |
833 | 764 |
834 dest = make_filename(repo, dest, node) | 765 dest = cmdutil.make_filename(repo, dest, node) |
835 if os.path.realpath(dest) == repo.root: | 766 if os.path.realpath(dest) == repo.root: |
836 raise util.Abort(_('repository root cannot be destination')) | 767 raise util.Abort(_('repository root cannot be destination')) |
837 dummy, matchfn, dummy = matchpats(repo, [], opts) | 768 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts) |
838 kind = opts.get('type') or 'files' | 769 kind = opts.get('type') or 'files' |
839 prefix = opts['prefix'] | 770 prefix = opts['prefix'] |
840 if dest == '-': | 771 if dest == '-': |
841 if kind == 'files': | 772 if kind == 'files': |
842 raise util.Abort(_('cannot archive plain files to stdout')) | 773 raise util.Abort(_('cannot archive plain files to stdout')) |
843 dest = sys.stdout | 774 dest = sys.stdout |
844 if not prefix: prefix = os.path.basename(repo.root) + '-%h' | 775 if not prefix: prefix = os.path.basename(repo.root) + '-%h' |
845 prefix = make_filename(repo, prefix, node) | 776 prefix = cmdutil.make_filename(repo, prefix, node) |
846 archival.archive(repo, dest, node, kind, not opts['no_decode'], | 777 archival.archive(repo, dest, node, kind, not opts['no_decode'], |
847 matchfn, prefix) | 778 matchfn, prefix) |
848 | 779 |
849 def backout(ui, repo, rev, **opts): | 780 def backout(ui, repo, rev, **opts): |
850 '''reverse effect of earlier changeset | 781 '''reverse effect of earlier changeset |
883 parent = p | 814 parent = p |
884 else: | 815 else: |
885 if opts['parent']: | 816 if opts['parent']: |
886 raise util.Abort(_('cannot use --parent on non-merge changeset')) | 817 raise util.Abort(_('cannot use --parent on non-merge changeset')) |
887 parent = p1 | 818 parent = p1 |
888 repo.update(node, force=True, show_stats=False) | 819 hg.clean(repo, node, show_stats=False) |
889 revert_opts = opts.copy() | 820 revert_opts = opts.copy() |
890 revert_opts['rev'] = hex(parent) | 821 revert_opts['rev'] = hex(parent) |
891 revert(ui, repo, **revert_opts) | 822 revert(ui, repo, **revert_opts) |
892 commit_opts = opts.copy() | 823 commit_opts = opts.copy() |
893 commit_opts['addremove'] = False | 824 commit_opts['addremove'] = False |
900 ui.status(_('changeset %s backs out changeset %s\n') % | 831 ui.status(_('changeset %s backs out changeset %s\n') % |
901 (nice(repo.changelog.tip()), nice(node))) | 832 (nice(repo.changelog.tip()), nice(node))) |
902 if op1 != node: | 833 if op1 != node: |
903 if opts['merge']: | 834 if opts['merge']: |
904 ui.status(_('merging with changeset %s\n') % nice(op1)) | 835 ui.status(_('merging with changeset %s\n') % nice(op1)) |
905 doupdate(ui, repo, hex(op1), **opts) | 836 n = _lookup(repo, hex(op1)) |
837 hg.merge(repo, n) | |
906 else: | 838 else: |
907 ui.status(_('the backout changeset is a new head - ' | 839 ui.status(_('the backout changeset is a new head - ' |
908 'do not forget to merge\n')) | 840 'do not forget to merge\n')) |
909 ui.status(_('(use "backout -m" if you want to auto-merge)\n')) | 841 ui.status(_('(use "backout --merge" ' |
842 'if you want to auto-merge)\n')) | |
910 | 843 |
911 def bundle(ui, repo, fname, dest=None, **opts): | 844 def bundle(ui, repo, fname, dest=None, **opts): |
912 """create a changegroup file | 845 """create a changegroup file |
913 | 846 |
914 Generate a compressed changegroup file collecting all changesets | 847 Generate a compressed changegroup file collecting all changesets |
942 %s basename of file being printed | 875 %s basename of file being printed |
943 %d dirname of file being printed, or '.' if in repo root | 876 %d dirname of file being printed, or '.' if in repo root |
944 %p root-relative path name of file being printed | 877 %p root-relative path name of file being printed |
945 """ | 878 """ |
946 ctx = repo.changectx(opts['rev'] or "-1") | 879 ctx = repo.changectx(opts['rev'] or "-1") |
947 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()): | 880 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, |
948 fp = make_file(repo, opts['output'], ctx.node(), pathname=abs) | 881 ctx.node()): |
882 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) | |
949 fp.write(ctx.filectx(abs).data()) | 883 fp.write(ctx.filectx(abs).data()) |
950 | 884 |
951 def clone(ui, source, dest=None, **opts): | 885 def clone(ui, source, dest=None, **opts): |
952 """make a copy of an existing repository | 886 """make a copy of an existing repository |
953 | 887 |
958 | 892 |
959 The location of the source is added to the new repository's | 893 The location of the source is added to the new repository's |
960 .hg/hgrc file, as the default to be used for future pulls. | 894 .hg/hgrc file, as the default to be used for future pulls. |
961 | 895 |
962 For efficiency, hardlinks are used for cloning whenever the source | 896 For efficiency, hardlinks are used for cloning whenever the source |
963 and destination are on the same filesystem. Some filesystems, | 897 and destination are on the same filesystem (note this applies only |
964 such as AFS, implement hardlinking incorrectly, but do not report | 898 to the repository data, not to the checked out files). Some |
965 errors. In these cases, use the --pull option to avoid | 899 filesystems, such as AFS, implement hardlinking incorrectly, but |
966 hardlinking. | 900 do not report errors. In these cases, use the --pull option to |
901 avoid hardlinking. | |
902 | |
903 You can safely clone repositories and checked out files using full | |
904 hardlinks with | |
905 | |
906 $ cp -al REPO REPOCLONE | |
907 | |
908 which is the fastest way to clone. However, the operation is not | |
909 atomic (making sure REPO is not modified during the operation is | |
910 up to you) and you have to make sure your editor breaks hardlinks | |
911 (Emacs and most Linux Kernel tools do so). | |
912 | |
913 If you use the -r option to clone up to a specific revision, no | |
914 subsequent revisions will be present in the cloned repository. | |
915 This option implies --pull, even on local repositories. | |
967 | 916 |
968 See pull for valid source format details. | 917 See pull for valid source format details. |
969 | 918 |
970 It is possible to specify an ssh:// URL as the destination, but no | 919 It is possible to specify an ssh:// URL as the destination, but no |
971 .hg/hgrc will be created on the remote side. Look at the help text | 920 .hg/hgrc will be created on the remote side. Look at the help text |
972 for the pull command for important details about ssh:// URLs. | 921 for the pull command for important details about ssh:// URLs. |
973 """ | 922 """ |
974 ui.setconfig_remoteopts(**opts) | 923 setremoteconfig(ui, opts) |
975 hg.clone(ui, ui.expandpath(source), dest, | 924 hg.clone(ui, ui.expandpath(source), dest, |
976 pull=opts['pull'], | 925 pull=opts['pull'], |
977 stream=opts['uncompressed'], | 926 stream=opts['uncompressed'], |
978 rev=opts['rev'], | 927 rev=opts['rev'], |
979 update=not opts['noupdate']) | 928 update=not opts['noupdate']) |
987 will be committed. | 936 will be committed. |
988 | 937 |
989 If no commit message is specified, the editor configured in your hgrc | 938 If no commit message is specified, the editor configured in your hgrc |
990 or in the EDITOR environment variable is started to enter a message. | 939 or in the EDITOR environment variable is started to enter a message. |
991 """ | 940 """ |
992 message = opts['message'] | 941 message = logmessage(opts) |
993 logfile = opts['logfile'] | |
994 | |
995 if message and logfile: | |
996 raise util.Abort(_('options --message and --logfile are mutually ' | |
997 'exclusive')) | |
998 if not message and logfile: | |
999 try: | |
1000 if logfile == '-': | |
1001 message = sys.stdin.read() | |
1002 else: | |
1003 message = open(logfile).read() | |
1004 except IOError, inst: | |
1005 raise util.Abort(_("can't read commit message '%s': %s") % | |
1006 (logfile, inst.strerror)) | |
1007 | 942 |
1008 if opts['addremove']: | 943 if opts['addremove']: |
1009 addremove_lock(ui, repo, pats, opts) | 944 cmdutil.addremove(repo, pats, opts) |
1010 fns, match, anypats = matchpats(repo, pats, opts) | 945 fns, match, anypats = cmdutil.matchpats(repo, pats, opts) |
1011 if pats: | 946 if pats: |
1012 modified, added, removed, deleted, unknown = ( | 947 modified, added, removed = repo.status(files=fns, match=match)[:3] |
1013 repo.changes(files=fns, match=match)) | |
1014 files = modified + added + removed | 948 files = modified + added + removed |
1015 else: | 949 else: |
1016 files = [] | 950 files = [] |
1017 try: | 951 try: |
1018 repo.commit(files, message, opts['user'], opts['date'], match, | 952 repo.commit(files, message, opts['user'], opts['date'], match, |
1163 else: | 1097 else: |
1164 tfn = targetpathfn | 1098 tfn = targetpathfn |
1165 copylist = [] | 1099 copylist = [] |
1166 for pat in pats: | 1100 for pat in pats: |
1167 srcs = [] | 1101 srcs = [] |
1168 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): | 1102 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts): |
1169 origsrc = okaytocopy(abssrc, relsrc, exact) | 1103 origsrc = okaytocopy(abssrc, relsrc, exact) |
1170 if origsrc: | 1104 if origsrc: |
1171 srcs.append((origsrc, abssrc, relsrc, exact)) | 1105 srcs.append((origsrc, abssrc, relsrc, exact)) |
1172 if not srcs: | 1106 if not srcs: |
1173 continue | 1107 continue |
1237 rev = repo.changelog.tip() | 1171 rev = repo.changelog.tip() |
1238 else: | 1172 else: |
1239 rev = repo.lookup(rev) | 1173 rev = repo.lookup(rev) |
1240 change = repo.changelog.read(rev) | 1174 change = repo.changelog.read(rev) |
1241 n = change[0] | 1175 n = change[0] |
1242 files = repo.manifest.readflags(n) | 1176 files = repo.manifest.read(n) |
1243 wlock = repo.wlock() | 1177 wlock = repo.wlock() |
1244 repo.dirstate.rebuild(rev, files.iteritems()) | 1178 repo.dirstate.rebuild(rev, files) |
1245 | 1179 |
1246 def debugcheckstate(ui, repo): | 1180 def debugcheckstate(ui, repo): |
1247 """validate the correctness of the current dirstate""" | 1181 """validate the correctness of the current dirstate""" |
1248 parent1, parent2 = repo.dirstate.parents() | 1182 parent1, parent2 = repo.dirstate.parents() |
1249 repo.dirstate.read() | 1183 repo.dirstate.read() |
1380 else: | 1314 else: |
1381 ui.write(_("not renamed\n")) | 1315 ui.write(_("not renamed\n")) |
1382 | 1316 |
1383 def debugwalk(ui, repo, *pats, **opts): | 1317 def debugwalk(ui, repo, *pats, **opts): |
1384 """show how files match on given patterns""" | 1318 """show how files match on given patterns""" |
1385 items = list(walk(repo, pats, opts)) | 1319 items = list(cmdutil.walk(repo, pats, opts)) |
1386 if not items: | 1320 if not items: |
1387 return | 1321 return |
1388 fmt = '%%s %%-%ds %%-%ds %%s' % ( | 1322 fmt = '%%s %%-%ds %%-%ds %%s' % ( |
1389 max([len(abs) for (src, abs, rel, exact) in items]), | 1323 max([len(abs) for (src, abs, rel, exact) in items]), |
1390 max([len(rel) for (src, abs, rel, exact) in items])) | 1324 max([len(rel) for (src, abs, rel, exact) in items])) |
1409 it detects as binary. With -a, diff will generate a diff anyway, | 1343 it detects as binary. With -a, diff will generate a diff anyway, |
1410 probably with undesirable results. | 1344 probably with undesirable results. |
1411 """ | 1345 """ |
1412 node1, node2 = revpair(ui, repo, opts['rev']) | 1346 node1, node2 = revpair(ui, repo, opts['rev']) |
1413 | 1347 |
1414 fns, matchfn, anypats = matchpats(repo, pats, opts) | 1348 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
1415 | 1349 |
1416 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, | 1350 patch.diff(repo, node1, node2, fns, match=matchfn, |
1417 text=opts['text'], opts=opts) | 1351 opts=patch.diffopts(ui, opts)) |
1418 | |
1419 def doexport(ui, repo, changeset, seqno, total, revwidth, opts): | |
1420 node = repo.lookup(changeset) | |
1421 parents = [p for p in repo.changelog.parents(node) if p != nullid] | |
1422 if opts['switch_parent']: | |
1423 parents.reverse() | |
1424 prev = (parents and parents[0]) or nullid | |
1425 change = repo.changelog.read(node) | |
1426 | |
1427 fp = make_file(repo, opts['output'], node, total=total, seqno=seqno, | |
1428 revwidth=revwidth) | |
1429 if fp != sys.stdout: | |
1430 ui.note("%s\n" % fp.name) | |
1431 | |
1432 fp.write("# HG changeset patch\n") | |
1433 fp.write("# User %s\n" % change[1]) | |
1434 fp.write("# Date %d %d\n" % change[2]) | |
1435 fp.write("# Node ID %s\n" % hex(node)) | |
1436 fp.write("# Parent %s\n" % hex(prev)) | |
1437 if len(parents) > 1: | |
1438 fp.write("# Parent %s\n" % hex(parents[1])) | |
1439 fp.write(change[4].rstrip()) | |
1440 fp.write("\n\n") | |
1441 | |
1442 dodiff(fp, ui, repo, prev, node, text=opts['text']) | |
1443 if fp != sys.stdout: | |
1444 fp.close() | |
1445 | 1352 |
1446 def export(ui, repo, *changesets, **opts): | 1353 def export(ui, repo, *changesets, **opts): |
1447 """dump the header and diffs for one or more changesets | 1354 """dump the header and diffs for one or more changesets |
1448 | 1355 |
1449 Print the changeset header and diffs for one or more revisions. | 1356 Print the changeset header and diffs for one or more revisions. |
1470 With the --switch-parent option, the diff will be against the second | 1377 With the --switch-parent option, the diff will be against the second |
1471 parent. It can be useful to review a merge. | 1378 parent. It can be useful to review a merge. |
1472 """ | 1379 """ |
1473 if not changesets: | 1380 if not changesets: |
1474 raise util.Abort(_("export requires at least one changeset")) | 1381 raise util.Abort(_("export requires at least one changeset")) |
1475 seqno = 0 | |
1476 revs = list(revrange(ui, repo, changesets)) | 1382 revs = list(revrange(ui, repo, changesets)) |
1477 total = len(revs) | 1383 if len(revs) > 1: |
1478 revwidth = max(map(len, revs)) | 1384 ui.note(_('exporting patches:\n')) |
1479 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n") | 1385 else: |
1480 ui.note(msg) | 1386 ui.note(_('exporting patch:\n')) |
1481 for cset in revs: | 1387 patch.export(repo, map(repo.lookup, revs), template=opts['output'], |
1482 seqno += 1 | 1388 switch_parent=opts['switch_parent'], |
1483 doexport(ui, repo, cset, seqno, total, revwidth, opts) | 1389 opts=patch.diffopts(ui, opts)) |
1484 | 1390 |
1485 def forget(ui, repo, *pats, **opts): | 1391 def forget(ui, repo, *pats, **opts): |
1486 """don't add the specified files on the next commit (DEPRECATED) | 1392 """don't add the specified files on the next commit (DEPRECATED) |
1487 | 1393 |
1488 (DEPRECATED) | 1394 (DEPRECATED) |
1491 This command is now deprecated and will be removed in a future | 1397 This command is now deprecated and will be removed in a future |
1492 release. Please use revert instead. | 1398 release. Please use revert instead. |
1493 """ | 1399 """ |
1494 ui.warn(_("(the forget command is deprecated; use revert instead)\n")) | 1400 ui.warn(_("(the forget command is deprecated; use revert instead)\n")) |
1495 forget = [] | 1401 forget = [] |
1496 for src, abs, rel, exact in walk(repo, pats, opts): | 1402 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
1497 if repo.dirstate.state(abs) == 'a': | 1403 if repo.dirstate.state(abs) == 'a': |
1498 forget.append(abs) | 1404 forget.append(abs) |
1499 if ui.verbose or not exact: | 1405 if ui.verbose or not exact: |
1500 ui.status(_('forgetting %s\n') % ((pats and rel) or abs)) | 1406 ui.status(_('forgetting %s\n') % ((pats and rel) or abs)) |
1501 repo.forget(forget) | 1407 repo.forget(forget) |
1548 def __init__(self, line, linenum, colstart, colend): | 1454 def __init__(self, line, linenum, colstart, colend): |
1549 self.line = line | 1455 self.line = line |
1550 self.linenum = linenum | 1456 self.linenum = linenum |
1551 self.colstart = colstart | 1457 self.colstart = colstart |
1552 self.colend = colend | 1458 self.colend = colend |
1459 | |
1553 def __eq__(self, other): | 1460 def __eq__(self, other): |
1554 return self.line == other.line | 1461 return self.line == other.line |
1555 def __hash__(self): | |
1556 return hash(self.line) | |
1557 | 1462 |
1558 matches = {} | 1463 matches = {} |
1464 copies = {} | |
1559 def grepbody(fn, rev, body): | 1465 def grepbody(fn, rev, body): |
1560 matches[rev].setdefault(fn, {}) | 1466 matches[rev].setdefault(fn, []) |
1561 m = matches[rev][fn] | 1467 m = matches[rev][fn] |
1562 for lnum, cstart, cend, line in matchlines(body): | 1468 for lnum, cstart, cend, line in matchlines(body): |
1563 s = linestate(line, lnum, cstart, cend) | 1469 s = linestate(line, lnum, cstart, cend) |
1564 m[s] = s | 1470 m.append(s) |
1565 | 1471 |
1566 # FIXME: prev isn't used, why ? | 1472 def difflinestates(a, b): |
1473 sm = difflib.SequenceMatcher(None, a, b) | |
1474 for tag, alo, ahi, blo, bhi in sm.get_opcodes(): | |
1475 if tag == 'insert': | |
1476 for i in range(blo, bhi): | |
1477 yield ('+', b[i]) | |
1478 elif tag == 'delete': | |
1479 for i in range(alo, ahi): | |
1480 yield ('-', a[i]) | |
1481 elif tag == 'replace': | |
1482 for i in range(alo, ahi): | |
1483 yield ('-', a[i]) | |
1484 for i in range(blo, bhi): | |
1485 yield ('+', b[i]) | |
1486 | |
1567 prev = {} | 1487 prev = {} |
1568 ucache = {} | 1488 ucache = {} |
1569 def display(fn, rev, states, prevstates): | 1489 def display(fn, rev, states, prevstates): |
1570 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates))) | |
1571 diff.sort(lambda x, y: cmp(x.linenum, y.linenum)) | |
1572 counts = {'-': 0, '+': 0} | 1490 counts = {'-': 0, '+': 0} |
1573 filerevmatches = {} | 1491 filerevmatches = {} |
1574 for l in diff: | 1492 if incrementing or not opts['all']: |
1493 a, b = prevstates, states | |
1494 else: | |
1495 a, b = states, prevstates | |
1496 for change, l in difflinestates(a, b): | |
1575 if incrementing or not opts['all']: | 1497 if incrementing or not opts['all']: |
1576 change = ((l in prevstates) and '-') or '+' | |
1577 r = rev | 1498 r = rev |
1578 else: | 1499 else: |
1579 change = ((l in states) and '-') or '+' | |
1580 r = prev[fn] | 1500 r = prev[fn] |
1581 cols = [fn, str(rev)] | 1501 cols = [fn, str(r)] |
1582 if opts['line_number']: | 1502 if opts['line_number']: |
1583 cols.append(str(l.linenum)) | 1503 cols.append(str(l.linenum)) |
1584 if opts['all']: | 1504 if opts['all']: |
1585 cols.append(change) | 1505 cols.append(change) |
1586 if opts['user']: | 1506 if opts['user']: |
1587 cols.append(trimuser(ui, getchange(rev)[1], rev, | 1507 cols.append(trimuser(ui, getchange(r)[1], rev, |
1588 ucache)) | 1508 ucache)) |
1589 if opts['files_with_matches']: | 1509 if opts['files_with_matches']: |
1590 c = (fn, rev) | 1510 c = (fn, rev) |
1591 if c in filerevmatches: | 1511 if c in filerevmatches: |
1592 continue | 1512 continue |
1593 filerevmatches[c] = 1 | 1513 filerevmatches[c] = 1 |
1600 fstate = {} | 1520 fstate = {} |
1601 skip = {} | 1521 skip = {} |
1602 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) | 1522 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) |
1603 count = 0 | 1523 count = 0 |
1604 incrementing = False | 1524 incrementing = False |
1525 follow = opts.get('follow') | |
1605 for st, rev, fns in changeiter: | 1526 for st, rev, fns in changeiter: |
1606 if st == 'window': | 1527 if st == 'window': |
1607 incrementing = rev | 1528 incrementing = rev |
1608 matches.clear() | 1529 matches.clear() |
1609 elif st == 'add': | 1530 elif st == 'add': |
1614 if fn in skip: | 1535 if fn in skip: |
1615 continue | 1536 continue |
1616 fstate.setdefault(fn, {}) | 1537 fstate.setdefault(fn, {}) |
1617 try: | 1538 try: |
1618 grepbody(fn, rev, getfile(fn).read(mf[fn])) | 1539 grepbody(fn, rev, getfile(fn).read(mf[fn])) |
1540 if follow: | |
1541 copied = getfile(fn).renamed(mf[fn]) | |
1542 if copied: | |
1543 copies.setdefault(rev, {})[fn] = copied[0] | |
1619 except KeyError: | 1544 except KeyError: |
1620 pass | 1545 pass |
1621 elif st == 'iter': | 1546 elif st == 'iter': |
1622 states = matches[rev].items() | 1547 states = matches[rev].items() |
1623 states.sort() | 1548 states.sort() |
1624 for fn, m in states: | 1549 for fn, m in states: |
1550 copy = copies.get(rev, {}).get(fn) | |
1625 if fn in skip: | 1551 if fn in skip: |
1552 if copy: | |
1553 skip[copy] = True | |
1626 continue | 1554 continue |
1627 if incrementing or not opts['all'] or fstate[fn]: | 1555 if incrementing or not opts['all'] or fstate[fn]: |
1628 pos, neg = display(fn, rev, m, fstate[fn]) | 1556 pos, neg = display(fn, rev, m, fstate[fn]) |
1629 count += pos + neg | 1557 count += pos + neg |
1630 if pos and not opts['all']: | 1558 if pos and not opts['all']: |
1631 skip[fn] = True | 1559 skip[fn] = True |
1560 if copy: | |
1561 skip[copy] = True | |
1632 fstate[fn] = m | 1562 fstate[fn] = m |
1563 if copy: | |
1564 fstate[copy] = m | |
1633 prev[fn] = rev | 1565 prev[fn] = rev |
1634 | 1566 |
1635 if not incrementing: | 1567 if not incrementing: |
1636 fstate = fstate.items() | 1568 fstate = fstate.items() |
1637 fstate.sort() | 1569 fstate.sort() |
1638 for fn, state in fstate: | 1570 for fn, state in fstate: |
1639 if fn in skip: | 1571 if fn in skip: |
1640 continue | 1572 continue |
1641 display(fn, rev, {}, state) | 1573 if fn not in copies.get(prev[fn], {}): |
1574 display(fn, rev, {}, state) | |
1642 return (count == 0 and 1) or 0 | 1575 return (count == 0 and 1) or 0 |
1643 | 1576 |
1644 def heads(ui, repo, **opts): | 1577 def heads(ui, repo, **opts): |
1645 """show current repository heads | 1578 """show current repository heads |
1646 | 1579 |
1673 parents = [p for p in repo.dirstate.parents() if p != nullid] | 1606 parents = [p for p in repo.dirstate.parents() if p != nullid] |
1674 if not parents: | 1607 if not parents: |
1675 ui.write(_("unknown\n")) | 1608 ui.write(_("unknown\n")) |
1676 return | 1609 return |
1677 | 1610 |
1678 hexfunc = ui.verbose and hex or short | 1611 hexfunc = ui.debugflag and hex or short |
1679 modified, added, removed, deleted, unknown = repo.changes() | 1612 modified, added, removed, deleted = repo.status()[:4] |
1680 output = ["%s%s" % | 1613 output = ["%s%s" % |
1681 ('+'.join([hexfunc(parent) for parent in parents]), | 1614 ('+'.join([hexfunc(parent) for parent in parents]), |
1682 (modified or added or removed or deleted) and "+" or "")] | 1615 (modified or added or removed or deleted) and "+" or "")] |
1683 | 1616 |
1684 if not ui.quiet: | 1617 if not ui.quiet: |
1718 bail_if_changed(repo) | 1651 bail_if_changed(repo) |
1719 | 1652 |
1720 d = opts["base"] | 1653 d = opts["base"] |
1721 strip = opts["strip"] | 1654 strip = opts["strip"] |
1722 | 1655 |
1723 mailre = re.compile(r'(?:From |[\w-]+:)') | 1656 wlock = repo.wlock() |
1724 | 1657 lock = repo.lock() |
1725 # attempt to detect the start of a patch | 1658 |
1726 # (this heuristic is borrowed from quilt) | 1659 for p in patches: |
1727 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + | 1660 pf = os.path.join(d, p) |
1728 'retrieving revision [0-9]+(\.[0-9]+)*$|' + | 1661 |
1729 '(---|\*\*\*)[ \t])', re.MULTILINE) | |
1730 | |
1731 for patch in patches: | |
1732 pf = os.path.join(d, patch) | |
1733 | |
1734 message = None | |
1735 user = None | |
1736 date = None | |
1737 hgpatch = False | |
1738 | |
1739 p = email.Parser.Parser() | |
1740 if pf == '-': | 1662 if pf == '-': |
1741 msg = p.parse(sys.stdin) | |
1742 ui.status(_("applying patch from stdin\n")) | 1663 ui.status(_("applying patch from stdin\n")) |
1664 tmpname, message, user, date = patch.extract(ui, sys.stdin) | |
1743 else: | 1665 else: |
1744 msg = p.parse(file(pf)) | 1666 ui.status(_("applying %s\n") % p) |
1745 ui.status(_("applying %s\n") % patch) | 1667 tmpname, message, user, date = patch.extract(ui, file(pf)) |
1746 | 1668 |
1747 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') | 1669 if tmpname is None: |
1748 tmpfp = os.fdopen(fd, 'w') | 1670 raise util.Abort(_('no diffs found')) |
1671 | |
1749 try: | 1672 try: |
1750 message = msg['Subject'] | |
1751 if message: | |
1752 message = message.replace('\n\t', ' ') | |
1753 ui.debug('Subject: %s\n' % message) | |
1754 user = msg['From'] | |
1755 if user: | |
1756 ui.debug('From: %s\n' % user) | |
1757 diffs_seen = 0 | |
1758 ok_types = ('text/plain', 'text/x-patch') | |
1759 for part in msg.walk(): | |
1760 content_type = part.get_content_type() | |
1761 ui.debug('Content-Type: %s\n' % content_type) | |
1762 if content_type not in ok_types: | |
1763 continue | |
1764 payload = part.get_payload(decode=True) | |
1765 m = diffre.search(payload) | |
1766 if m: | |
1767 ui.debug(_('found patch at byte %d\n') % m.start(0)) | |
1768 diffs_seen += 1 | |
1769 hgpatch = False | |
1770 fp = cStringIO.StringIO() | |
1771 if message: | |
1772 fp.write(message) | |
1773 fp.write('\n') | |
1774 for line in payload[:m.start(0)].splitlines(): | |
1775 if line.startswith('# HG changeset patch'): | |
1776 ui.debug(_('patch generated by hg export\n')) | |
1777 hgpatch = True | |
1778 # drop earlier commit message content | |
1779 fp.seek(0) | |
1780 fp.truncate() | |
1781 elif hgpatch: | |
1782 if line.startswith('# User '): | |
1783 user = line[7:] | |
1784 ui.debug('From: %s\n' % user) | |
1785 elif line.startswith("# Date "): | |
1786 date = line[7:] | |
1787 if not line.startswith('# '): | |
1788 fp.write(line) | |
1789 fp.write('\n') | |
1790 message = fp.getvalue() | |
1791 if tmpfp: | |
1792 tmpfp.write(payload) | |
1793 if not payload.endswith('\n'): | |
1794 tmpfp.write('\n') | |
1795 elif not diffs_seen and message and content_type == 'text/plain': | |
1796 message += '\n' + payload | |
1797 | |
1798 if opts['message']: | 1673 if opts['message']: |
1799 # pickup the cmdline msg | 1674 # pickup the cmdline msg |
1800 message = opts['message'] | 1675 message = opts['message'] |
1801 elif message: | 1676 elif message: |
1802 # pickup the patch msg | 1677 # pickup the patch msg |
1804 else: | 1679 else: |
1805 # launch the editor | 1680 # launch the editor |
1806 message = None | 1681 message = None |
1807 ui.debug(_('message:\n%s\n') % message) | 1682 ui.debug(_('message:\n%s\n') % message) |
1808 | 1683 |
1809 tmpfp.close() | 1684 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) |
1810 if not diffs_seen: | 1685 files = patch.updatedir(ui, repo, files, wlock=wlock) |
1811 raise util.Abort(_('no diffs found')) | 1686 repo.commit(files, message, user, date, wlock=wlock, lock=lock) |
1812 | |
1813 files = util.patch(strip, tmpname, ui) | |
1814 if len(files) > 0: | |
1815 addremove_lock(ui, repo, files, {}) | |
1816 repo.commit(files, message, user, date) | |
1817 finally: | 1687 finally: |
1818 os.unlink(tmpname) | 1688 os.unlink(tmpname) |
1819 | 1689 |
1820 def incoming(ui, repo, source="default", **opts): | 1690 def incoming(ui, repo, source="default", **opts): |
1821 """show new changesets found in source | 1691 """show new changesets found in source |
1828 twice if the incoming is followed by a pull. | 1698 twice if the incoming is followed by a pull. |
1829 | 1699 |
1830 See pull for valid source format details. | 1700 See pull for valid source format details. |
1831 """ | 1701 """ |
1832 source = ui.expandpath(source) | 1702 source = ui.expandpath(source) |
1833 ui.setconfig_remoteopts(**opts) | 1703 setremoteconfig(ui, opts) |
1834 | 1704 |
1835 other = hg.repository(ui, source) | 1705 other = hg.repository(ui, source) |
1836 incoming = repo.findincoming(other, force=opts["force"]) | 1706 incoming = repo.findincoming(other, force=opts["force"]) |
1837 if not incoming: | 1707 if not incoming: |
1838 ui.status(_("no changes found\n")) | 1708 ui.status(_("no changes found\n")) |
1864 if opts['no_merges'] and len(parents) == 2: | 1734 if opts['no_merges'] and len(parents) == 2: |
1865 continue | 1735 continue |
1866 displayer.show(changenode=n) | 1736 displayer.show(changenode=n) |
1867 if opts['patch']: | 1737 if opts['patch']: |
1868 prev = (parents and parents[0]) or nullid | 1738 prev = (parents and parents[0]) or nullid |
1869 dodiff(ui, ui, other, prev, n) | 1739 patch.diff(other, prev, n, fp=repo.ui) |
1870 ui.write("\n") | 1740 ui.write("\n") |
1871 finally: | 1741 finally: |
1872 if hasattr(other, 'close'): | 1742 if hasattr(other, 'close'): |
1873 other.close() | 1743 other.close() |
1874 if cleanup: | 1744 if cleanup: |
1884 | 1754 |
1885 It is possible to specify an ssh:// URL as the destination. | 1755 It is possible to specify an ssh:// URL as the destination. |
1886 Look at the help text for the pull command for important details | 1756 Look at the help text for the pull command for important details |
1887 about ssh:// URLs. | 1757 about ssh:// URLs. |
1888 """ | 1758 """ |
1889 ui.setconfig_remoteopts(**opts) | 1759 setremoteconfig(ui, opts) |
1890 hg.repository(ui, dest, create=1) | 1760 hg.repository(ui, dest, create=1) |
1891 | 1761 |
1892 def locate(ui, repo, *pats, **opts): | 1762 def locate(ui, repo, *pats, **opts): |
1893 """locate files matching specific patterns | 1763 """locate files matching specific patterns |
1894 | 1764 |
1912 if rev: | 1782 if rev: |
1913 node = repo.lookup(rev) | 1783 node = repo.lookup(rev) |
1914 else: | 1784 else: |
1915 node = None | 1785 node = None |
1916 | 1786 |
1917 for src, abs, rel, exact in walk(repo, pats, opts, node=node, | 1787 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, |
1918 head='(?:.*/|)'): | 1788 head='(?:.*/|)'): |
1919 if not node and repo.dirstate.state(abs) == '?': | 1789 if not node and repo.dirstate.state(abs) == '?': |
1920 continue | 1790 continue |
1921 if opts['fullpath']: | 1791 if opts['fullpath']: |
1922 ui.write(os.path.join(repo.root, abs), end) | 1792 ui.write(os.path.join(repo.root, abs), end) |
1923 else: | 1793 else: |
1924 ui.write(((pats and rel) or abs), end) | 1794 ui.write(((pats and rel) or abs), end) |
1925 | 1795 |
1926 def log(ui, repo, *pats, **opts): | 1796 def log(ui, repo, *pats, **opts): |
1927 """show revision history of entire repository or files | 1797 """show revision history of entire repository or files |
1928 | 1798 |
1929 Print the revision history of the specified files or the entire project. | 1799 Print the revision history of the specified files or the entire |
1800 project. | |
1801 | |
1802 File history is shown without following rename or copy history of | |
1803 files. Use -f/--follow with a file name to follow history across | |
1804 renames and copies. --follow without a file name will only show | |
1805 ancestors or descendants of the starting revision. --follow-first | |
1806 only follows the first parent of merge revisions. | |
1807 | |
1808 If no revision range is specified, the default is tip:0 unless | |
1809 --follow is set, in which case the working directory parent is | |
1810 used as the starting revision. | |
1930 | 1811 |
1931 By default this command outputs: changeset id and hash, tags, | 1812 By default this command outputs: changeset id and hash, tags, |
1932 non-trivial parents, user, date and time, and a summary for each | 1813 non-trivial parents, user, date and time, and a summary for each |
1933 commit. When the -v/--verbose switch is used, the list of changed | 1814 commit. When the -v/--verbose switch is used, the list of changed |
1934 files and full commit message is shown. | 1815 files and full commit message is shown. |
2004 br = repo.branchlookup([repo.changelog.node(rev)]) | 1885 br = repo.branchlookup([repo.changelog.node(rev)]) |
2005 | 1886 |
2006 displayer.show(rev, brinfo=br) | 1887 displayer.show(rev, brinfo=br) |
2007 if opts['patch']: | 1888 if opts['patch']: |
2008 prev = (parents and parents[0]) or nullid | 1889 prev = (parents and parents[0]) or nullid |
2009 dodiff(du, du, repo, prev, changenode, match=matchfn) | 1890 patch.diff(repo, prev, changenode, match=matchfn, fp=du) |
2010 du.write("\n\n") | 1891 du.write("\n\n") |
2011 elif st == 'iter': | 1892 elif st == 'iter': |
2012 if count == limit: break | 1893 if count == limit: break |
2013 if du.header[rev]: | 1894 if du.header[rev]: |
2014 for args in du.header[rev]: | 1895 for args in du.header[rev]: |
2035 except hg.RepoError: | 1916 except hg.RepoError: |
2036 n = repo.manifest.lookup(rev) | 1917 n = repo.manifest.lookup(rev) |
2037 else: | 1918 else: |
2038 n = repo.manifest.tip() | 1919 n = repo.manifest.tip() |
2039 m = repo.manifest.read(n) | 1920 m = repo.manifest.read(n) |
2040 mf = repo.manifest.readflags(n) | |
2041 files = m.keys() | 1921 files = m.keys() |
2042 files.sort() | 1922 files.sort() |
2043 | 1923 |
2044 for f in files: | 1924 for f in files: |
2045 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f)) | 1925 ui.write("%40s %3s %s\n" % (hex(m[f]), |
2046 | 1926 m.execf(f) and "755" or "644", f)) |
2047 def merge(ui, repo, node=None, **opts): | 1927 |
1928 def merge(ui, repo, node=None, force=None, branch=None): | |
2048 """Merge working directory with another revision | 1929 """Merge working directory with another revision |
2049 | 1930 |
2050 Merge the contents of the current working directory and the | 1931 Merge the contents of the current working directory and the |
2051 requested revision. Files that changed between either parent are | 1932 requested revision. Files that changed between either parent are |
2052 marked as changed for the next commit and a commit must be | 1933 marked as changed for the next commit and a commit must be |
2053 performed before any further updates are allowed. | 1934 performed before any further updates are allowed. |
2054 """ | 1935 |
2055 return doupdate(ui, repo, node=node, merge=True, **opts) | 1936 If no revision is specified, the working directory's parent is a |
1937 head revision, and the repository contains exactly one other head, | |
1938 the other head is merged with by default. Otherwise, an explicit | |
1939 revision to merge with must be provided. | |
1940 """ | |
1941 | |
1942 if node: | |
1943 node = _lookup(repo, node, branch) | |
1944 else: | |
1945 heads = repo.heads() | |
1946 if len(heads) > 2: | |
1947 raise util.Abort(_('repo has %d heads - ' | |
1948 'please merge with an explicit rev') % | |
1949 len(heads)) | |
1950 if len(heads) == 1: | |
1951 raise util.Abort(_('there is nothing to merge - ' | |
1952 'use "hg update" instead')) | |
1953 parent = repo.dirstate.parents()[0] | |
1954 if parent not in heads: | |
1955 raise util.Abort(_('working dir not at a head rev - ' | |
1956 'use "hg update" or merge with an explicit rev')) | |
1957 node = parent == heads[0] and heads[-1] or heads[0] | |
1958 return hg.merge(repo, node, force=force) | |
2056 | 1959 |
2057 def outgoing(ui, repo, dest=None, **opts): | 1960 def outgoing(ui, repo, dest=None, **opts): |
2058 """show changesets not found in destination | 1961 """show changesets not found in destination |
2059 | 1962 |
2060 Show changesets not found in the specified destination repository or | 1963 Show changesets not found in the specified destination repository or |
2062 if a push was requested. | 1965 if a push was requested. |
2063 | 1966 |
2064 See pull for valid destination format details. | 1967 See pull for valid destination format details. |
2065 """ | 1968 """ |
2066 dest = ui.expandpath(dest or 'default-push', dest or 'default') | 1969 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2067 ui.setconfig_remoteopts(**opts) | 1970 setremoteconfig(ui, opts) |
2068 revs = None | 1971 revs = None |
2069 if opts['rev']: | 1972 if opts['rev']: |
2070 revs = [repo.lookup(rev) for rev in opts['rev']] | 1973 revs = [repo.lookup(rev) for rev in opts['rev']] |
2071 | 1974 |
2072 other = hg.repository(ui, dest) | 1975 other = hg.repository(ui, dest) |
2083 if opts['no_merges'] and len(parents) == 2: | 1986 if opts['no_merges'] and len(parents) == 2: |
2084 continue | 1987 continue |
2085 displayer.show(changenode=n) | 1988 displayer.show(changenode=n) |
2086 if opts['patch']: | 1989 if opts['patch']: |
2087 prev = (parents and parents[0]) or nullid | 1990 prev = (parents and parents[0]) or nullid |
2088 dodiff(ui, ui, repo, prev, n) | 1991 patch.diff(repo, prev, n) |
2089 ui.write("\n") | 1992 ui.write("\n") |
2090 | 1993 |
2091 def parents(ui, repo, file_=None, rev=None, branches=None, **opts): | 1994 def parents(ui, repo, file_=None, rev=None, branches=None, **opts): |
2092 """show the parents of the working dir or revision | 1995 """show the parents of the working dir or revision |
2093 | 1996 |
2144 def postincoming(ui, repo, modheads, optupdate): | 2047 def postincoming(ui, repo, modheads, optupdate): |
2145 if modheads == 0: | 2048 if modheads == 0: |
2146 return | 2049 return |
2147 if optupdate: | 2050 if optupdate: |
2148 if modheads == 1: | 2051 if modheads == 1: |
2149 return doupdate(ui, repo) | 2052 return hg.update(repo, repo.changelog.tip()) # update |
2150 else: | 2053 else: |
2151 ui.status(_("not updating, since new heads added\n")) | 2054 ui.status(_("not updating, since new heads added\n")) |
2152 if modheads > 1: | 2055 if modheads > 1: |
2153 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) | 2056 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) |
2154 else: | 2057 else: |
2184 Compression on | 2087 Compression on |
2185 Alternatively specify "ssh -C" as your ssh command in your hgrc or | 2088 Alternatively specify "ssh -C" as your ssh command in your hgrc or |
2186 with the --ssh command line option. | 2089 with the --ssh command line option. |
2187 """ | 2090 """ |
2188 source = ui.expandpath(source) | 2091 source = ui.expandpath(source) |
2189 ui.setconfig_remoteopts(**opts) | 2092 setremoteconfig(ui, opts) |
2190 | 2093 |
2191 other = hg.repository(ui, source) | 2094 other = hg.repository(ui, source) |
2192 ui.status(_('pulling from %s\n') % (source)) | 2095 ui.status(_('pulling from %s\n') % (source)) |
2193 revs = None | 2096 revs = None |
2194 if opts['rev'] and not other.local(): | 2097 if opts['rev'] and not other.local(): |
2222 | 2125 |
2223 Pushing to http:// and https:// URLs is possible, too, if this | 2126 Pushing to http:// and https:// URLs is possible, too, if this |
2224 feature is enabled on the remote Mercurial server. | 2127 feature is enabled on the remote Mercurial server. |
2225 """ | 2128 """ |
2226 dest = ui.expandpath(dest or 'default-push', dest or 'default') | 2129 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2227 ui.setconfig_remoteopts(**opts) | 2130 setremoteconfig(ui, opts) |
2228 | 2131 |
2229 other = hg.repository(ui, dest) | 2132 other = hg.repository(ui, dest) |
2230 ui.status('pushing to %s\n' % (dest)) | 2133 ui.status('pushing to %s\n' % (dest)) |
2231 revs = None | 2134 revs = None |
2232 if opts['rev']: | 2135 if opts['rev']: |
2276 | 2179 |
2277 This command tries to fix the repository status after an interrupted | 2180 This command tries to fix the repository status after an interrupted |
2278 operation. It should only be necessary when Mercurial suggests it. | 2181 operation. It should only be necessary when Mercurial suggests it. |
2279 """ | 2182 """ |
2280 if repo.recover(): | 2183 if repo.recover(): |
2281 return repo.verify() | 2184 return hg.verify(repo) |
2282 return 1 | 2185 return 1 |
2283 | 2186 |
2284 def remove(ui, repo, *pats, **opts): | 2187 def remove(ui, repo, *pats, **opts): |
2285 """remove the specified files on the next commit | 2188 """remove the specified files on the next commit |
2286 | 2189 |
2296 remove them, use the -f/--force option. | 2199 remove them, use the -f/--force option. |
2297 """ | 2200 """ |
2298 names = [] | 2201 names = [] |
2299 if not opts['after'] and not pats: | 2202 if not opts['after'] and not pats: |
2300 raise util.Abort(_('no files specified')) | 2203 raise util.Abort(_('no files specified')) |
2301 files, matchfn, anypats = matchpats(repo, pats, opts) | 2204 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
2302 exact = dict.fromkeys(files) | 2205 exact = dict.fromkeys(files) |
2303 mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn)) | 2206 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] |
2304 modified, added, removed, deleted, unknown = mardu | 2207 modified, added, removed, deleted, unknown = mardu |
2305 remove, forget = [], [] | 2208 remove, forget = [], [] |
2306 for src, abs, rel, exact in walk(repo, pats, opts): | 2209 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
2307 reason = None | 2210 reason = None |
2308 if abs not in deleted and opts['after']: | 2211 if abs not in deleted and opts['after']: |
2309 reason = _('is still present') | 2212 reason = _('is still present') |
2310 elif abs in modified and not opts['force']: | 2213 elif abs in modified and not opts['force']: |
2311 reason = _('is modified (use -f to force removal)') | 2214 reason = _('is modified (use -f to force removal)') |
2408 names = {} | 2311 names = {} |
2409 target_only = {} | 2312 target_only = {} |
2410 | 2313 |
2411 # walk dirstate. | 2314 # walk dirstate. |
2412 | 2315 |
2413 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key): | 2316 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, |
2317 badmatch=mf.has_key): | |
2414 names[abs] = (rel, exact) | 2318 names[abs] = (rel, exact) |
2415 if src == 'b': | 2319 if src == 'b': |
2416 target_only[abs] = True | 2320 target_only[abs] = True |
2417 | 2321 |
2418 # walk target manifest. | 2322 # walk target manifest. |
2419 | 2323 |
2420 for src, abs, rel, exact in walk(repo, pats, opts, node=node, | 2324 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, |
2421 badmatch=names.has_key): | 2325 badmatch=names.has_key): |
2422 if abs in names: continue | 2326 if abs in names: continue |
2423 names[abs] = (rel, exact) | 2327 names[abs] = (rel, exact) |
2424 target_only[abs] = True | 2328 target_only[abs] = True |
2425 | 2329 |
2426 changes = repo.changes(match=names.has_key, wlock=wlock) | 2330 changes = repo.status(match=names.has_key, wlock=wlock)[:5] |
2427 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) | 2331 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) |
2428 | 2332 |
2429 revert = ([], _('reverting %s\n')) | 2333 revert = ([], _('reverting %s\n')) |
2430 add = ([], _('adding %s\n')) | 2334 add = ([], _('adding %s\n')) |
2431 remove = ([], _('removing %s\n')) | 2335 remove = ([], _('removing %s\n')) |
2493 else: | 2397 else: |
2494 handle(remove, False) | 2398 handle(remove, False) |
2495 | 2399 |
2496 if not opts.get('dry_run'): | 2400 if not opts.get('dry_run'): |
2497 repo.dirstate.forget(forget[0]) | 2401 repo.dirstate.forget(forget[0]) |
2498 r = repo.update(node, False, True, update.has_key, False, wlock=wlock, | 2402 r = hg.revert(repo, node, update.has_key, wlock) |
2499 show_stats=False) | |
2500 repo.dirstate.update(add[0], 'a') | 2403 repo.dirstate.update(add[0], 'a') |
2501 repo.dirstate.update(undelete[0], 'n') | 2404 repo.dirstate.update(undelete[0], 'n') |
2502 repo.dirstate.update(remove[0], 'r') | 2405 repo.dirstate.update(remove[0], 'r') |
2503 return r | 2406 return r |
2504 | 2407 |
2629 = the previous added file was copied from here | 2532 = the previous added file was copied from here |
2630 """ | 2533 """ |
2631 | 2534 |
2632 all = opts['all'] | 2535 all = opts['all'] |
2633 | 2536 |
2634 files, matchfn, anypats = matchpats(repo, pats, opts) | 2537 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
2635 cwd = (pats and repo.getcwd()) or '' | 2538 cwd = (pats and repo.getcwd()) or '' |
2636 modified, added, removed, deleted, unknown, ignored, clean = [ | 2539 modified, added, removed, deleted, unknown, ignored, clean = [ |
2637 [util.pathto(cwd, x) for x in n] | 2540 [util.pathto(cwd, x) for x in n] |
2638 for n in repo.status(files=files, match=matchfn, | 2541 for n in repo.status(files=files, match=matchfn, |
2639 list_ignored=all or opts['ignored'], | 2542 list_ignored=all or opts['ignored'], |
2679 they are stored as a file named ".hgtags" which is managed | 2582 they are stored as a file named ".hgtags" which is managed |
2680 similarly to other project files and can be hand-edited if | 2583 similarly to other project files and can be hand-edited if |
2681 necessary. The file '.hg/localtags' is used for local tags (not | 2584 necessary. The file '.hg/localtags' is used for local tags (not |
2682 shared among repositories). | 2585 shared among repositories). |
2683 """ | 2586 """ |
2684 if name == "tip": | 2587 if name in ['tip', '.']: |
2685 raise util.Abort(_("the name 'tip' is reserved")) | 2588 raise util.Abort(_("the name '%s' is reserved") % name) |
2686 if rev_ is not None: | 2589 if rev_ is not None: |
2687 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " | 2590 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " |
2688 "please use 'hg tag [-r REV] NAME' instead\n")) | 2591 "please use 'hg tag [-r REV] NAME' instead\n")) |
2689 if opts['rev']: | 2592 if opts['rev']: |
2690 raise util.Abort(_("use only one form to specify the revision")) | 2593 raise util.Abort(_("use only one form to specify the revision")) |
2691 if opts['rev']: | 2594 if opts['rev']: |
2692 rev_ = opts['rev'] | 2595 rev_ = opts['rev'] |
2693 if rev_: | 2596 if rev_: |
2694 r = hex(repo.lookup(rev_)) | 2597 r = repo.lookup(rev_) |
2695 else: | 2598 else: |
2696 p1, p2 = repo.dirstate.parents() | 2599 p1, p2 = repo.dirstate.parents() |
2697 if p1 == nullid: | 2600 if p1 == nullid: |
2698 raise util.Abort(_('no revision to tag')) | 2601 raise util.Abort(_('no revision to tag')) |
2699 if p2 != nullid: | 2602 if p2 != nullid: |
2700 raise util.Abort(_('outstanding uncommitted merges')) | 2603 raise util.Abort(_('outstanding uncommitted merges')) |
2701 r = hex(p1) | 2604 r = p1 |
2702 | 2605 |
2703 repo.tag(name, r, opts['local'], opts['message'], opts['user'], | 2606 message = opts['message'] |
2704 opts['date']) | 2607 if not message: |
2608 message = _('Added tag %s for changeset %s') % (name, short(r)) | |
2609 | |
2610 repo.tag(name, r, message, opts['local'], opts['user'], opts['date']) | |
2705 | 2611 |
2706 def tags(ui, repo): | 2612 def tags(ui, repo): |
2707 """list repository tags | 2613 """list repository tags |
2708 | 2614 |
2709 List the repository tags. | 2615 List the repository tags. |
2711 This lists both regular and local tags. | 2617 This lists both regular and local tags. |
2712 """ | 2618 """ |
2713 | 2619 |
2714 l = repo.tagslist() | 2620 l = repo.tagslist() |
2715 l.reverse() | 2621 l.reverse() |
2622 hexfunc = ui.debugflag and hex or short | |
2716 for t, n in l: | 2623 for t, n in l: |
2717 try: | 2624 try: |
2718 r = "%5d:%s" % (repo.changelog.rev(n), hex(n)) | 2625 r = "%5d:%s" % (repo.changelog.rev(n), hexfunc(n)) |
2719 except KeyError: | 2626 except KeyError: |
2720 r = " ?:?" | 2627 r = " ?:?" |
2721 if ui.quiet: | 2628 if ui.quiet: |
2722 ui.write("%s\n" % t) | 2629 ui.write("%s\n" % t) |
2723 else: | 2630 else: |
2732 br = None | 2639 br = None |
2733 if opts['branches']: | 2640 if opts['branches']: |
2734 br = repo.branchlookup([n]) | 2641 br = repo.branchlookup([n]) |
2735 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) | 2642 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) |
2736 if opts['patch']: | 2643 if opts['patch']: |
2737 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n) | 2644 patch.diff(repo, repo.changelog.parents(n)[0], n) |
2738 | 2645 |
2739 def unbundle(ui, repo, fname, **opts): | 2646 def unbundle(ui, repo, fname, **opts): |
2740 """apply a changegroup file | 2647 """apply a changegroup file |
2741 | 2648 |
2742 Apply a compressed changegroup file generated by the bundle | 2649 Apply a compressed changegroup file generated by the bundle |
2777 """ | 2684 """ |
2778 ui.warn(_('(the undo command is deprecated; use rollback instead)\n')) | 2685 ui.warn(_('(the undo command is deprecated; use rollback instead)\n')) |
2779 repo.rollback() | 2686 repo.rollback() |
2780 | 2687 |
2781 def update(ui, repo, node=None, merge=False, clean=False, force=None, | 2688 def update(ui, repo, node=None, merge=False, clean=False, force=None, |
2782 branch=None, **opts): | 2689 branch=None): |
2783 """update or merge working directory | 2690 """update or merge working directory |
2784 | 2691 |
2785 Update the working directory to the specified revision. | 2692 Update the working directory to the specified revision. |
2786 | 2693 |
2787 If there are no outstanding changes in the working directory and | 2694 If there are no outstanding changes in the working directory and |
2792 merge command. | 2699 merge command. |
2793 | 2700 |
2794 By default, update will refuse to run if doing so would require | 2701 By default, update will refuse to run if doing so would require |
2795 merging or discarding local changes. | 2702 merging or discarding local changes. |
2796 """ | 2703 """ |
2704 node = _lookup(repo, node, branch) | |
2797 if merge: | 2705 if merge: |
2798 ui.warn(_('(the -m/--merge option is deprecated; ' | 2706 ui.warn(_('(the -m/--merge option is deprecated; ' |
2799 'use the merge command instead)\n')) | 2707 'use the merge command instead)\n')) |
2800 return doupdate(ui, repo, node, merge, clean, force, branch, **opts) | 2708 return hg.merge(repo, node, force=force) |
2801 | 2709 elif clean: |
2802 def doupdate(ui, repo, node=None, merge=False, clean=False, force=None, | 2710 return hg.clean(repo, node) |
2803 branch=None, **opts): | 2711 else: |
2712 return hg.update(repo, node) | |
2713 | |
2714 def _lookup(repo, node, branch=None): | |
2804 if branch: | 2715 if branch: |
2805 br = repo.branchlookup(branch=branch) | 2716 br = repo.branchlookup(branch=branch) |
2806 found = [] | 2717 found = [] |
2807 for x in br: | 2718 for x in br: |
2808 if branch in br[x]: | 2719 if branch in br[x]: |
2809 found.append(x) | 2720 found.append(x) |
2810 if len(found) > 1: | 2721 if len(found) > 1: |
2811 ui.warn(_("Found multiple heads for %s\n") % branch) | 2722 repo.ui.warn(_("Found multiple heads for %s\n") % branch) |
2812 for x in found: | 2723 for x in found: |
2813 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br) | 2724 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br) |
2814 return 1 | 2725 raise util.Abort("") |
2815 if len(found) == 1: | 2726 if len(found) == 1: |
2816 node = found[0] | 2727 node = found[0] |
2817 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch)) | 2728 repo.ui.warn(_("Using head %s for branch %s\n") |
2729 % (short(node), branch)) | |
2818 else: | 2730 else: |
2819 ui.warn(_("branch %s not found\n") % (branch)) | 2731 raise util.Abort(_("branch %s not found\n") % (branch)) |
2820 return 1 | |
2821 else: | 2732 else: |
2822 node = node and repo.lookup(node) or repo.changelog.tip() | 2733 node = node and repo.lookup(node) or repo.changelog.tip() |
2823 return repo.update(node, allow=merge, force=clean, forcemerge=force) | 2734 return node |
2824 | 2735 |
2825 def verify(ui, repo): | 2736 def verify(ui, repo): |
2826 """verify the integrity of the repository | 2737 """verify the integrity of the repository |
2827 | 2738 |
2828 Verify the integrity of the current repository. | 2739 Verify the integrity of the current repository. |
2830 This will perform an extensive check of the repository's | 2741 This will perform an extensive check of the repository's |
2831 integrity, validating the hashes and checksums of each entry in | 2742 integrity, validating the hashes and checksums of each entry in |
2832 the changelog, manifest, and tracked files, as well as the | 2743 the changelog, manifest, and tracked files, as well as the |
2833 integrity of their crosslinks and indices. | 2744 integrity of their crosslinks and indices. |
2834 """ | 2745 """ |
2835 return repo.verify() | 2746 return hg.verify(repo) |
2836 | 2747 |
2837 # Command options and aliases are listed here, alphabetically | 2748 # Command options and aliases are listed here, alphabetically |
2838 | 2749 |
2839 table = { | 2750 table = { |
2840 "^add": | 2751 "^add": |
2841 (add, | 2752 (add, |
2842 [('I', 'include', [], _('include names matching the given patterns')), | 2753 [('I', 'include', [], _('include names matching the given patterns')), |
2843 ('X', 'exclude', [], _('exclude names matching the given patterns')), | 2754 ('X', 'exclude', [], _('exclude names matching the given patterns')), |
2844 ('n', 'dry-run', None, _('do not perform actions, just print output'))], | 2755 ('n', 'dry-run', None, _('do not perform actions, just print output'))], |
2845 _('hg add [OPTION]... [FILE]...')), | 2756 _('hg add [OPTION]... [FILE]...')), |
2846 "debugaddremove|addremove": | 2757 "addremove": |
2847 (addremove, | 2758 (addremove, |
2848 [('I', 'include', [], _('include names matching the given patterns')), | 2759 [('I', 'include', [], _('include names matching the given patterns')), |
2849 ('X', 'exclude', [], _('exclude names matching the given patterns')), | 2760 ('X', 'exclude', [], _('exclude names matching the given patterns')), |
2850 ('n', 'dry-run', None, _('do not perform actions, just print output'))], | 2761 ('n', 'dry-run', None, |
2762 _('do not perform actions, just print output')), | |
2763 ('s', 'similarity', '', | |
2764 _('guess renamed files by similarity (0<=s<=1)'))], | |
2851 _('hg addremove [OPTION]... [FILE]...')), | 2765 _('hg addremove [OPTION]... [FILE]...')), |
2852 "^annotate": | 2766 "^annotate": |
2853 (annotate, | 2767 (annotate, |
2854 [('r', 'rev', '', _('annotate the specified revision')), | 2768 [('r', 'rev', '', _('annotate the specified revision')), |
2855 ('a', 'text', None, _('treat all files as text')), | 2769 ('a', 'text', None, _('treat all files as text')), |
2951 (diff, | 2865 (diff, |
2952 [('r', 'rev', [], _('revision')), | 2866 [('r', 'rev', [], _('revision')), |
2953 ('a', 'text', None, _('treat all files as text')), | 2867 ('a', 'text', None, _('treat all files as text')), |
2954 ('p', 'show-function', None, | 2868 ('p', 'show-function', None, |
2955 _('show which function each change is in')), | 2869 _('show which function each change is in')), |
2870 ('g', 'git', None, _('use git extended diff format')), | |
2956 ('w', 'ignore-all-space', None, | 2871 ('w', 'ignore-all-space', None, |
2957 _('ignore white space when comparing lines')), | 2872 _('ignore white space when comparing lines')), |
2958 ('b', 'ignore-space-change', None, | 2873 ('b', 'ignore-space-change', None, |
2959 _('ignore changes in the amount of white space')), | 2874 _('ignore changes in the amount of white space')), |
2960 ('B', 'ignore-blank-lines', None, | 2875 ('B', 'ignore-blank-lines', None, |
2975 _('hg forget [OPTION]... FILE...')), | 2890 _('hg forget [OPTION]... FILE...')), |
2976 "grep": | 2891 "grep": |
2977 (grep, | 2892 (grep, |
2978 [('0', 'print0', None, _('end fields with NUL')), | 2893 [('0', 'print0', None, _('end fields with NUL')), |
2979 ('', 'all', None, _('print all revisions that match')), | 2894 ('', 'all', None, _('print all revisions that match')), |
2895 ('f', 'follow', None, | |
2896 _('follow changeset history, or file history across copies and renames')), | |
2980 ('i', 'ignore-case', None, _('ignore case when matching')), | 2897 ('i', 'ignore-case', None, _('ignore case when matching')), |
2981 ('l', 'files-with-matches', None, | 2898 ('l', 'files-with-matches', None, |
2982 _('print only filenames and revs that match')), | 2899 _('print only filenames and revs that match')), |
2983 ('n', 'line-number', None, _('print matching line numbers')), | 2900 ('n', 'line-number', None, _('print matching line numbers')), |
2984 ('r', 'rev', [], _('search in given revision range')), | 2901 ('r', 'rev', [], _('search in given revision range')), |
3011 _('run even when remote repository is unrelated')), | 2928 _('run even when remote repository is unrelated')), |
3012 ('', 'style', '', _('display using template map file')), | 2929 ('', 'style', '', _('display using template map file')), |
3013 ('n', 'newest-first', None, _('show newest record first')), | 2930 ('n', 'newest-first', None, _('show newest record first')), |
3014 ('', 'bundle', '', _('file to store the bundles into')), | 2931 ('', 'bundle', '', _('file to store the bundles into')), |
3015 ('p', 'patch', None, _('show patch')), | 2932 ('p', 'patch', None, _('show patch')), |
3016 ('r', 'rev', [], _('a specific revision you would like to pull')), | 2933 ('r', 'rev', [], _('a specific revision up to which you would like to pull')), |
3017 ('', 'template', '', _('display with template')), | 2934 ('', 'template', '', _('display with template')), |
3018 ('e', 'ssh', '', _('specify ssh command to use')), | 2935 ('e', 'ssh', '', _('specify ssh command to use')), |
3019 ('', 'remotecmd', '', | 2936 ('', 'remotecmd', '', |
3020 _('specify hg command to run on the remote side'))], | 2937 _('specify hg command to run on the remote side'))], |
3021 _('hg incoming [-p] [-n] [-M] [-r REV]...' | 2938 _('hg incoming [-p] [-n] [-M] [-r REV]...' |
3037 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 2954 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
3038 _('hg locate [OPTION]... [PATTERN]...')), | 2955 _('hg locate [OPTION]... [PATTERN]...')), |
3039 "^log|history": | 2956 "^log|history": |
3040 (log, | 2957 (log, |
3041 [('b', 'branches', None, _('show branches')), | 2958 [('b', 'branches', None, _('show branches')), |
2959 ('f', 'follow', None, | |
2960 _('follow changeset history, or file history across copies and renames')), | |
2961 ('', 'follow-first', None, | |
2962 _('only follow the first parent of merge changesets')), | |
3042 ('k', 'keyword', [], _('search for a keyword')), | 2963 ('k', 'keyword', [], _('search for a keyword')), |
3043 ('l', 'limit', '', _('limit number of changes displayed')), | 2964 ('l', 'limit', '', _('limit number of changes displayed')), |
3044 ('r', 'rev', [], _('show the specified revision or range')), | 2965 ('r', 'rev', [], _('show the specified revision or range')), |
3045 ('M', 'no-merges', None, _('do not show merges')), | 2966 ('M', 'no-merges', None, _('do not show merges')), |
3046 ('', 'style', '', _('display using template map file')), | 2967 ('', 'style', '', _('display using template map file')), |
3047 ('m', 'only-merges', None, _('show only merges')), | 2968 ('m', 'only-merges', None, _('show only merges')), |
3048 ('p', 'patch', None, _('show patch')), | 2969 ('p', 'patch', None, _('show patch')), |
2970 ('P', 'prune', [], _('do not display revision or any of its ancestors')), | |
3049 ('', 'template', '', _('display with template')), | 2971 ('', 'template', '', _('display with template')), |
3050 ('I', 'include', [], _('include names matching the given patterns')), | 2972 ('I', 'include', [], _('include names matching the given patterns')), |
3051 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 2973 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
3052 _('hg log [OPTION]... [FILE]')), | 2974 _('hg log [OPTION]... [FILE]')), |
3053 "manifest": (manifest, [], _('hg manifest [REV]')), | 2975 "manifest": (manifest, [], _('hg manifest [REV]')), |
3082 [('u', 'update', None, | 3004 [('u', 'update', None, |
3083 _('update the working directory to tip after pull')), | 3005 _('update the working directory to tip after pull')), |
3084 ('e', 'ssh', '', _('specify ssh command to use')), | 3006 ('e', 'ssh', '', _('specify ssh command to use')), |
3085 ('f', 'force', None, | 3007 ('f', 'force', None, |
3086 _('run even when remote repository is unrelated')), | 3008 _('run even when remote repository is unrelated')), |
3087 ('r', 'rev', [], _('a specific revision you would like to pull')), | 3009 ('r', 'rev', [], _('a specific revision up to which you would like to pull')), |
3088 ('', 'remotecmd', '', | 3010 ('', 'remotecmd', '', |
3089 _('specify hg command to run on the remote side'))], | 3011 _('specify hg command to run on the remote side'))], |
3090 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), | 3012 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), |
3091 "^push": | 3013 "^push": |
3092 (push, | 3014 (push, |
3321 def findext(name): | 3243 def findext(name): |
3322 '''return module with given extension name''' | 3244 '''return module with given extension name''' |
3323 try: | 3245 try: |
3324 return sys.modules[external[name]] | 3246 return sys.modules[external[name]] |
3325 except KeyError: | 3247 except KeyError: |
3326 dotname = '.' + name | |
3327 for k, v in external.iteritems(): | 3248 for k, v in external.iteritems(): |
3328 if k.endswith('.' + name) or v == name: | 3249 if k.endswith('.' + name) or k.endswith('/' + name) or v == name: |
3329 return sys.modules[v] | 3250 return sys.modules[v] |
3330 raise KeyError(name) | 3251 raise KeyError(name) |
3331 | 3252 |
3332 def dispatch(args): | 3253 def load_extensions(ui): |
3333 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | 3254 added = [] |
3334 num = getattr(signal, name, None) | 3255 for ext_name, load_from_name in ui.extensions(): |
3335 if num: signal.signal(num, catchterm) | 3256 if ext_name in external: |
3336 | 3257 continue |
3337 try: | |
3338 u = ui.ui(traceback='--traceback' in sys.argv[1:]) | |
3339 except util.Abort, inst: | |
3340 sys.stderr.write(_("abort: %s\n") % inst) | |
3341 return -1 | |
3342 | |
3343 for ext_name, load_from_name in u.extensions(): | |
3344 try: | 3258 try: |
3345 if load_from_name: | 3259 if load_from_name: |
3346 # the module will be loaded in sys.modules | 3260 # the module will be loaded in sys.modules |
3347 # choose an unique name so that it doesn't | 3261 # choose an unique name so that it doesn't |
3348 # conflicts with other modules | 3262 # conflicts with other modules |
3358 try: | 3272 try: |
3359 mod = importh("hgext.%s" % ext_name) | 3273 mod = importh("hgext.%s" % ext_name) |
3360 except ImportError: | 3274 except ImportError: |
3361 mod = importh(ext_name) | 3275 mod = importh(ext_name) |
3362 external[ext_name] = mod.__name__ | 3276 external[ext_name] = mod.__name__ |
3277 added.append((mod, ext_name)) | |
3363 except (util.SignalInterrupt, KeyboardInterrupt): | 3278 except (util.SignalInterrupt, KeyboardInterrupt): |
3364 raise | 3279 raise |
3365 except Exception, inst: | 3280 except Exception, inst: |
3366 u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst)) | 3281 ui.warn(_("*** failed to import extension %s: %s\n") % |
3367 if u.print_exc(): | 3282 (ext_name, inst)) |
3283 if ui.print_exc(): | |
3368 return 1 | 3284 return 1 |
3369 | 3285 |
3370 for name in external.itervalues(): | 3286 for mod, name in added: |
3371 mod = sys.modules[name] | |
3372 uisetup = getattr(mod, 'uisetup', None) | 3287 uisetup = getattr(mod, 'uisetup', None) |
3373 if uisetup: | 3288 if uisetup: |
3374 uisetup(u) | 3289 uisetup(ui) |
3375 cmdtable = getattr(mod, 'cmdtable', {}) | 3290 cmdtable = getattr(mod, 'cmdtable', {}) |
3376 for t in cmdtable: | 3291 for t in cmdtable: |
3377 if t in table: | 3292 if t in table: |
3378 u.warn(_("module %s overrides %s\n") % (name, t)) | 3293 ui.warn(_("module %s overrides %s\n") % (name, t)) |
3379 table.update(cmdtable) | 3294 table.update(cmdtable) |
3295 | |
3296 def dispatch(args): | |
3297 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |
3298 num = getattr(signal, name, None) | |
3299 if num: signal.signal(num, catchterm) | |
3300 | |
3301 try: | |
3302 u = ui.ui(traceback='--traceback' in sys.argv[1:], | |
3303 readhooks=[load_extensions]) | |
3304 except util.Abort, inst: | |
3305 sys.stderr.write(_("abort: %s\n") % inst) | |
3306 return -1 | |
3380 | 3307 |
3381 try: | 3308 try: |
3382 cmd, func, args, options, cmdoptions = parse(u, args) | 3309 cmd, func, args, options, cmdoptions = parse(u, args) |
3383 if options["time"]: | 3310 if options["time"]: |
3384 def get_times(): | 3311 def get_times(): |
3426 u = repo.ui | 3353 u = repo.ui |
3427 for name in external.itervalues(): | 3354 for name in external.itervalues(): |
3428 mod = sys.modules[name] | 3355 mod = sys.modules[name] |
3429 if hasattr(mod, 'reposetup'): | 3356 if hasattr(mod, 'reposetup'): |
3430 mod.reposetup(u, repo) | 3357 mod.reposetup(u, repo) |
3358 hg.repo_setup_hooks.append(mod.reposetup) | |
3431 except hg.RepoError: | 3359 except hg.RepoError: |
3432 if cmd not in optionalrepo.split(): | 3360 if cmd not in optionalrepo.split(): |
3433 raise | 3361 raise |
3434 d = lambda: func(u, repo, *args, **cmdoptions) | 3362 d = lambda: func(u, repo, *args, **cmdoptions) |
3435 else: | 3363 else: |
3436 d = lambda: func(u, *args, **cmdoptions) | 3364 d = lambda: func(u, *args, **cmdoptions) |
3365 | |
3366 # reupdate the options, repo/.hg/hgrc may have changed them | |
3367 u.updateopts(options["verbose"], options["debug"], options["quiet"], | |
3368 not options["noninteractive"], options["traceback"], | |
3369 options["config"]) | |
3437 | 3370 |
3438 try: | 3371 try: |
3439 if options['profile']: | 3372 if options['profile']: |
3440 import hotshot, hotshot.stats | 3373 import hotshot, hotshot.stats |
3441 prof = hotshot.Profile("hg.prof") | 3374 prof = hotshot.Profile("hg.prof") |