Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/commands.py @ 2956:6dddcba7596a
merge.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 18 Aug 2006 21:17:28 -0700 |
parents | 9d1c3529ebbc 731f6b3d27c2 |
children | ff3ea21a981a |
comparison
equal
deleted
inserted
replaced
2955:9d1c3529ebbc | 2956:6dddcba7596a |
---|---|
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) |
491 (self.repo.manifest.rev(changes[0]), hex(changes[0]))) | 428 (self.repo.manifest.rev(changes[0]), hex(changes[0]))) |
492 self.ui.status(_("user: %s\n") % changes[1]) | 429 self.ui.status(_("user: %s\n") % changes[1]) |
493 self.ui.status(_("date: %s\n") % date) | 430 self.ui.status(_("date: %s\n") % date) |
494 | 431 |
495 if self.ui.debugflag: | 432 if self.ui.debugflag: |
496 files = self.repo.changes(log.parents(changenode)[0], changenode) | 433 files = self.repo.status(log.parents(changenode)[0], changenode)[:3] |
497 for key, value in zip([_("files:"), _("files+:"), _("files-:")], | 434 for key, value in zip([_("files:"), _("files+:"), _("files-:")], |
498 files): | 435 files): |
499 if value: | 436 if value: |
500 self.ui.note("%-12s %s\n" % (key, " ".join(value))) | 437 self.ui.note("%-12s %s\n" % (key, " ".join(value))) |
501 else: | 438 else: |
535 raise util.Abort(inst.args[0]) | 472 raise util.Abort(inst.args[0]) |
536 if tmpl: t.use_template(tmpl) | 473 if tmpl: t.use_template(tmpl) |
537 return t | 474 return t |
538 return changeset_printer(ui, repo) | 475 return changeset_printer(ui, repo) |
539 | 476 |
477 def setremoteconfig(ui, opts): | |
478 "copy remote options to ui tree" | |
479 if opts.get('ssh'): | |
480 ui.setconfig("ui", "ssh", opts['ssh']) | |
481 if opts.get('remotecmd'): | |
482 ui.setconfig("ui", "remotecmd", opts['remotecmd']) | |
483 | |
540 def show_version(ui): | 484 def show_version(ui): |
541 """output version and copyright information""" | 485 """output version and copyright information""" |
542 ui.write(_("Mercurial Distributed SCM (version %s)\n") | 486 ui.write(_("Mercurial Distributed SCM (version %s)\n") |
543 % version.get_version()) | 487 % version.get_version()) |
544 ui.status(_( | 488 ui.status(_( |
545 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n" | 489 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n" |
546 "This is free software; see the source for copying conditions. " | 490 "This is free software; see the source for copying conditions. " |
547 "There is NO\nwarranty; " | 491 "There is NO\nwarranty; " |
548 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" | 492 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" |
549 )) | 493 )) |
550 | 494 |
694 | 638 |
695 If no names are given, add all files in the repository. | 639 If no names are given, add all files in the repository. |
696 """ | 640 """ |
697 | 641 |
698 names = [] | 642 names = [] |
699 for src, abs, rel, exact in walk(repo, pats, opts): | 643 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
700 if exact: | 644 if exact: |
701 if ui.verbose: | 645 if ui.verbose: |
702 ui.status(_('adding %s\n') % rel) | 646 ui.status(_('adding %s\n') % rel) |
703 names.append(abs) | 647 names.append(abs) |
704 elif repo.dirstate.state(abs) == '?': | 648 elif repo.dirstate.state(abs) == '?': |
713 Add all new files and remove all missing files from the repository. | 657 Add all new files and remove all missing files from the repository. |
714 | 658 |
715 New files are ignored if they match any of the patterns in .hgignore. As | 659 New files are ignored if they match any of the patterns in .hgignore. As |
716 with add, these changes take effect at the next commit. | 660 with add, these changes take effect at the next commit. |
717 """ | 661 """ |
718 return addremove_lock(ui, repo, pats, opts) | 662 return cmdutil.addremove(repo, pats, opts) |
719 | |
720 def addremove_lock(ui, repo, pats, opts, wlock=None): | |
721 add, remove = [], [] | |
722 for src, abs, rel, exact in walk(repo, pats, opts): | |
723 if src == 'f' and repo.dirstate.state(abs) == '?': | |
724 add.append(abs) | |
725 if ui.verbose or not exact: | |
726 ui.status(_('adding %s\n') % ((pats and rel) or abs)) | |
727 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): | |
728 remove.append(abs) | |
729 if ui.verbose or not exact: | |
730 ui.status(_('removing %s\n') % ((pats and rel) or abs)) | |
731 if not opts.get('dry_run'): | |
732 repo.add(add, wlock=wlock) | |
733 repo.remove(remove, wlock=wlock) | |
734 | 663 |
735 def annotate(ui, repo, *pats, **opts): | 664 def annotate(ui, repo, *pats, **opts): |
736 """show changeset information per file line | 665 """show changeset information per file line |
737 | 666 |
738 List changes in files, showing the revision id responsible for each line | 667 List changes in files, showing the revision id responsible for each line |
771 if not opts['user'] and not opts['changeset'] and not opts['date']: | 700 if not opts['user'] and not opts['changeset'] and not opts['date']: |
772 opts['number'] = 1 | 701 opts['number'] = 1 |
773 | 702 |
774 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) | 703 ctx = repo.changectx(opts['rev'] or repo.dirstate.parents()[0]) |
775 | 704 |
776 for src, abs, rel, exact in walk(repo, pats, opts, node=ctx.node()): | 705 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, |
706 node=ctx.node()): | |
777 fctx = ctx.filectx(abs) | 707 fctx = ctx.filectx(abs) |
778 if not opts['text'] and util.binary(fctx.data()): | 708 if not opts['text'] and util.binary(fctx.data()): |
779 ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) | 709 ui.write(_("%s: binary file\n") % ((pats and rel) or abs)) |
780 continue | 710 continue |
781 | 711 |
823 node, p2 = repo.dirstate.parents() | 753 node, p2 = repo.dirstate.parents() |
824 if p2 != nullid: | 754 if p2 != nullid: |
825 raise util.Abort(_('uncommitted merge - please provide a ' | 755 raise util.Abort(_('uncommitted merge - please provide a ' |
826 'specific revision')) | 756 'specific revision')) |
827 | 757 |
828 dest = make_filename(repo, dest, node) | 758 dest = cmdutil.make_filename(repo, dest, node) |
829 if os.path.realpath(dest) == repo.root: | 759 if os.path.realpath(dest) == repo.root: |
830 raise util.Abort(_('repository root cannot be destination')) | 760 raise util.Abort(_('repository root cannot be destination')) |
831 dummy, matchfn, dummy = matchpats(repo, [], opts) | 761 dummy, matchfn, dummy = cmdutil.matchpats(repo, [], opts) |
832 kind = opts.get('type') or 'files' | 762 kind = opts.get('type') or 'files' |
833 prefix = opts['prefix'] | 763 prefix = opts['prefix'] |
834 if dest == '-': | 764 if dest == '-': |
835 if kind == 'files': | 765 if kind == 'files': |
836 raise util.Abort(_('cannot archive plain files to stdout')) | 766 raise util.Abort(_('cannot archive plain files to stdout')) |
837 dest = sys.stdout | 767 dest = sys.stdout |
838 if not prefix: prefix = os.path.basename(repo.root) + '-%h' | 768 if not prefix: prefix = os.path.basename(repo.root) + '-%h' |
839 prefix = make_filename(repo, prefix, node) | 769 prefix = cmdutil.make_filename(repo, prefix, node) |
840 archival.archive(repo, dest, node, kind, not opts['no_decode'], | 770 archival.archive(repo, dest, node, kind, not opts['no_decode'], |
841 matchfn, prefix) | 771 matchfn, prefix) |
842 | 772 |
843 def backout(ui, repo, rev, **opts): | 773 def backout(ui, repo, rev, **opts): |
844 '''reverse effect of earlier changeset | 774 '''reverse effect of earlier changeset |
877 parent = p | 807 parent = p |
878 else: | 808 else: |
879 if opts['parent']: | 809 if opts['parent']: |
880 raise util.Abort(_('cannot use --parent on non-merge changeset')) | 810 raise util.Abort(_('cannot use --parent on non-merge changeset')) |
881 parent = p1 | 811 parent = p1 |
882 repo.update(node, force=True, show_stats=False) | 812 hg.clean(repo, node, show_stats=False) |
883 revert_opts = opts.copy() | 813 revert_opts = opts.copy() |
884 revert_opts['rev'] = hex(parent) | 814 revert_opts['rev'] = hex(parent) |
885 revert(ui, repo, **revert_opts) | 815 revert(ui, repo, **revert_opts) |
886 commit_opts = opts.copy() | 816 commit_opts = opts.copy() |
887 commit_opts['addremove'] = False | 817 commit_opts['addremove'] = False |
894 ui.status(_('changeset %s backs out changeset %s\n') % | 824 ui.status(_('changeset %s backs out changeset %s\n') % |
895 (nice(repo.changelog.tip()), nice(node))) | 825 (nice(repo.changelog.tip()), nice(node))) |
896 if op1 != node: | 826 if op1 != node: |
897 if opts['merge']: | 827 if opts['merge']: |
898 ui.status(_('merging with changeset %s\n') % nice(op1)) | 828 ui.status(_('merging with changeset %s\n') % nice(op1)) |
899 doupdate(ui, repo, hex(op1), **opts) | 829 n = _lookup(repo, hex(op1)) |
830 hg.merge(repo, n) | |
900 else: | 831 else: |
901 ui.status(_('the backout changeset is a new head - ' | 832 ui.status(_('the backout changeset is a new head - ' |
902 'do not forget to merge\n')) | 833 'do not forget to merge\n')) |
903 ui.status(_('(use "backout -m" if you want to auto-merge)\n')) | 834 ui.status(_('(use "backout --merge" ' |
835 'if you want to auto-merge)\n')) | |
904 | 836 |
905 def bundle(ui, repo, fname, dest=None, **opts): | 837 def bundle(ui, repo, fname, dest=None, **opts): |
906 """create a changegroup file | 838 """create a changegroup file |
907 | 839 |
908 Generate a compressed changegroup file collecting all changesets | 840 Generate a compressed changegroup file collecting all changesets |
935 | 867 |
936 %s basename of file being printed | 868 %s basename of file being printed |
937 %d dirname of file being printed, or '.' if in repo root | 869 %d dirname of file being printed, or '.' if in repo root |
938 %p root-relative path name of file being printed | 870 %p root-relative path name of file being printed |
939 """ | 871 """ |
940 ctx = repo.changectx(opts['rev'] or -1) | 872 ctx = repo.changectx(opts['rev'] or "-1") |
941 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, ctx.node()): | 873 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, |
942 fp = make_file(repo, opts['output'], ctx.node(), pathname=abs) | 874 ctx.node()): |
875 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) | |
943 fp.write(ctx.filectx(abs).data()) | 876 fp.write(ctx.filectx(abs).data()) |
944 | 877 |
945 def clone(ui, source, dest=None, **opts): | 878 def clone(ui, source, dest=None, **opts): |
946 """make a copy of an existing repository | 879 """make a copy of an existing repository |
947 | 880 |
952 | 885 |
953 The location of the source is added to the new repository's | 886 The location of the source is added to the new repository's |
954 .hg/hgrc file, as the default to be used for future pulls. | 887 .hg/hgrc file, as the default to be used for future pulls. |
955 | 888 |
956 For efficiency, hardlinks are used for cloning whenever the source | 889 For efficiency, hardlinks are used for cloning whenever the source |
957 and destination are on the same filesystem. Some filesystems, | 890 and destination are on the same filesystem (note this applies only |
958 such as AFS, implement hardlinking incorrectly, but do not report | 891 to the repository data, not to the checked out files). Some |
959 errors. In these cases, use the --pull option to avoid | 892 filesystems, such as AFS, implement hardlinking incorrectly, but |
960 hardlinking. | 893 do not report errors. In these cases, use the --pull option to |
894 avoid hardlinking. | |
895 | |
896 You can safely clone repositories and checked out files using full | |
897 hardlinks with | |
898 | |
899 $ cp -al REPO REPOCLONE | |
900 | |
901 which is the fastest way to clone. However, the operation is not | |
902 atomic (making sure REPO is not modified during the operation is | |
903 up to you) and you have to make sure your editor breaks hardlinks | |
904 (Emacs and most Linux Kernel tools do so). | |
905 | |
906 If you use the -r option to clone up to a specific revision, no | |
907 subsequent revisions will be present in the cloned repository. | |
908 This option implies --pull, even on local repositories. | |
961 | 909 |
962 See pull for valid source format details. | 910 See pull for valid source format details. |
963 | 911 |
964 It is possible to specify an ssh:// URL as the destination, but no | 912 It is possible to specify an ssh:// URL as the destination, but no |
965 .hg/hgrc will be created on the remote side. Look at the help text | 913 .hg/hgrc will be created on the remote side. Look at the help text |
966 for the pull command for important details about ssh:// URLs. | 914 for the pull command for important details about ssh:// URLs. |
967 """ | 915 """ |
968 ui.setconfig_remoteopts(**opts) | 916 setremoteconfig(ui, opts) |
969 hg.clone(ui, ui.expandpath(source), dest, | 917 hg.clone(ui, ui.expandpath(source), dest, |
970 pull=opts['pull'], | 918 pull=opts['pull'], |
971 stream=opts['uncompressed'], | 919 stream=opts['uncompressed'], |
972 rev=opts['rev'], | 920 rev=opts['rev'], |
973 update=not opts['noupdate']) | 921 update=not opts['noupdate']) |
981 will be committed. | 929 will be committed. |
982 | 930 |
983 If no commit message is specified, the editor configured in your hgrc | 931 If no commit message is specified, the editor configured in your hgrc |
984 or in the EDITOR environment variable is started to enter a message. | 932 or in the EDITOR environment variable is started to enter a message. |
985 """ | 933 """ |
986 message = opts['message'] | 934 message = logmessage(opts) |
987 logfile = opts['logfile'] | |
988 | |
989 if message and logfile: | |
990 raise util.Abort(_('options --message and --logfile are mutually ' | |
991 'exclusive')) | |
992 if not message and logfile: | |
993 try: | |
994 if logfile == '-': | |
995 message = sys.stdin.read() | |
996 else: | |
997 message = open(logfile).read() | |
998 except IOError, inst: | |
999 raise util.Abort(_("can't read commit message '%s': %s") % | |
1000 (logfile, inst.strerror)) | |
1001 | 935 |
1002 if opts['addremove']: | 936 if opts['addremove']: |
1003 addremove_lock(ui, repo, pats, opts) | 937 cmdutil.addremove(repo, pats, opts) |
1004 fns, match, anypats = matchpats(repo, pats, opts) | 938 fns, match, anypats = cmdutil.matchpats(repo, pats, opts) |
1005 if pats: | 939 if pats: |
1006 modified, added, removed, deleted, unknown = ( | 940 modified, added, removed = repo.status(files=fns, match=match)[:3] |
1007 repo.changes(files=fns, match=match)) | |
1008 files = modified + added + removed | 941 files = modified + added + removed |
1009 else: | 942 else: |
1010 files = [] | 943 files = [] |
1011 try: | 944 try: |
1012 repo.commit(files, message, opts['user'], opts['date'], match, | 945 repo.commit(files, message, opts['user'], opts['date'], match, |
1157 else: | 1090 else: |
1158 tfn = targetpathfn | 1091 tfn = targetpathfn |
1159 copylist = [] | 1092 copylist = [] |
1160 for pat in pats: | 1093 for pat in pats: |
1161 srcs = [] | 1094 srcs = [] |
1162 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts): | 1095 for tag, abssrc, relsrc, exact in cmdutil.walk(repo, [pat], opts): |
1163 origsrc = okaytocopy(abssrc, relsrc, exact) | 1096 origsrc = okaytocopy(abssrc, relsrc, exact) |
1164 if origsrc: | 1097 if origsrc: |
1165 srcs.append((origsrc, abssrc, relsrc, exact)) | 1098 srcs.append((origsrc, abssrc, relsrc, exact)) |
1166 if not srcs: | 1099 if not srcs: |
1167 continue | 1100 continue |
1231 rev = repo.changelog.tip() | 1164 rev = repo.changelog.tip() |
1232 else: | 1165 else: |
1233 rev = repo.lookup(rev) | 1166 rev = repo.lookup(rev) |
1234 change = repo.changelog.read(rev) | 1167 change = repo.changelog.read(rev) |
1235 n = change[0] | 1168 n = change[0] |
1236 files = repo.manifest.readflags(n) | 1169 files = repo.manifest.read(n) |
1237 wlock = repo.wlock() | 1170 wlock = repo.wlock() |
1238 repo.dirstate.rebuild(rev, files.iteritems()) | 1171 repo.dirstate.rebuild(rev, files) |
1239 | 1172 |
1240 def debugcheckstate(ui, repo): | 1173 def debugcheckstate(ui, repo): |
1241 """validate the correctness of the current dirstate""" | 1174 """validate the correctness of the current dirstate""" |
1242 parent1, parent2 = repo.dirstate.parents() | 1175 parent1, parent2 = repo.dirstate.parents() |
1243 repo.dirstate.read() | 1176 repo.dirstate.read() |
1374 else: | 1307 else: |
1375 ui.write(_("not renamed\n")) | 1308 ui.write(_("not renamed\n")) |
1376 | 1309 |
1377 def debugwalk(ui, repo, *pats, **opts): | 1310 def debugwalk(ui, repo, *pats, **opts): |
1378 """show how files match on given patterns""" | 1311 """show how files match on given patterns""" |
1379 items = list(walk(repo, pats, opts)) | 1312 items = list(cmdutil.walk(repo, pats, opts)) |
1380 if not items: | 1313 if not items: |
1381 return | 1314 return |
1382 fmt = '%%s %%-%ds %%-%ds %%s' % ( | 1315 fmt = '%%s %%-%ds %%-%ds %%s' % ( |
1383 max([len(abs) for (src, abs, rel, exact) in items]), | 1316 max([len(abs) for (src, abs, rel, exact) in items]), |
1384 max([len(rel) for (src, abs, rel, exact) in items])) | 1317 max([len(rel) for (src, abs, rel, exact) in items])) |
1403 it detects as binary. With -a, diff will generate a diff anyway, | 1336 it detects as binary. With -a, diff will generate a diff anyway, |
1404 probably with undesirable results. | 1337 probably with undesirable results. |
1405 """ | 1338 """ |
1406 node1, node2 = revpair(ui, repo, opts['rev']) | 1339 node1, node2 = revpair(ui, repo, opts['rev']) |
1407 | 1340 |
1408 fns, matchfn, anypats = matchpats(repo, pats, opts) | 1341 fns, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
1409 | 1342 |
1410 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn, | 1343 patch.diff(repo, node1, node2, fns, match=matchfn, |
1411 text=opts['text'], opts=opts) | 1344 opts=patch.diffopts(ui, opts)) |
1412 | |
1413 def doexport(ui, repo, changeset, seqno, total, revwidth, opts): | |
1414 node = repo.lookup(changeset) | |
1415 parents = [p for p in repo.changelog.parents(node) if p != nullid] | |
1416 if opts['switch_parent']: | |
1417 parents.reverse() | |
1418 prev = (parents and parents[0]) or nullid | |
1419 change = repo.changelog.read(node) | |
1420 | |
1421 fp = make_file(repo, opts['output'], node, total=total, seqno=seqno, | |
1422 revwidth=revwidth) | |
1423 if fp != sys.stdout: | |
1424 ui.note("%s\n" % fp.name) | |
1425 | |
1426 fp.write("# HG changeset patch\n") | |
1427 fp.write("# User %s\n" % change[1]) | |
1428 fp.write("# Date %d %d\n" % change[2]) | |
1429 fp.write("# Node ID %s\n" % hex(node)) | |
1430 fp.write("# Parent %s\n" % hex(prev)) | |
1431 if len(parents) > 1: | |
1432 fp.write("# Parent %s\n" % hex(parents[1])) | |
1433 fp.write(change[4].rstrip()) | |
1434 fp.write("\n\n") | |
1435 | |
1436 dodiff(fp, ui, repo, prev, node, text=opts['text']) | |
1437 if fp != sys.stdout: | |
1438 fp.close() | |
1439 | 1345 |
1440 def export(ui, repo, *changesets, **opts): | 1346 def export(ui, repo, *changesets, **opts): |
1441 """dump the header and diffs for one or more changesets | 1347 """dump the header and diffs for one or more changesets |
1442 | 1348 |
1443 Print the changeset header and diffs for one or more revisions. | 1349 Print the changeset header and diffs for one or more revisions. |
1464 With the --switch-parent option, the diff will be against the second | 1370 With the --switch-parent option, the diff will be against the second |
1465 parent. It can be useful to review a merge. | 1371 parent. It can be useful to review a merge. |
1466 """ | 1372 """ |
1467 if not changesets: | 1373 if not changesets: |
1468 raise util.Abort(_("export requires at least one changeset")) | 1374 raise util.Abort(_("export requires at least one changeset")) |
1469 seqno = 0 | |
1470 revs = list(revrange(ui, repo, changesets)) | 1375 revs = list(revrange(ui, repo, changesets)) |
1471 total = len(revs) | 1376 if len(revs) > 1: |
1472 revwidth = max(map(len, revs)) | 1377 ui.note(_('exporting patches:\n')) |
1473 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n") | 1378 else: |
1474 ui.note(msg) | 1379 ui.note(_('exporting patch:\n')) |
1475 for cset in revs: | 1380 patch.export(repo, map(repo.lookup, revs), template=opts['output'], |
1476 seqno += 1 | 1381 switch_parent=opts['switch_parent'], |
1477 doexport(ui, repo, cset, seqno, total, revwidth, opts) | 1382 opts=patch.diffopts(ui, opts)) |
1478 | 1383 |
1479 def forget(ui, repo, *pats, **opts): | 1384 def forget(ui, repo, *pats, **opts): |
1480 """don't add the specified files on the next commit (DEPRECATED) | 1385 """don't add the specified files on the next commit (DEPRECATED) |
1481 | 1386 |
1482 (DEPRECATED) | 1387 (DEPRECATED) |
1485 This command is now deprecated and will be removed in a future | 1390 This command is now deprecated and will be removed in a future |
1486 release. Please use revert instead. | 1391 release. Please use revert instead. |
1487 """ | 1392 """ |
1488 ui.warn(_("(the forget command is deprecated; use revert instead)\n")) | 1393 ui.warn(_("(the forget command is deprecated; use revert instead)\n")) |
1489 forget = [] | 1394 forget = [] |
1490 for src, abs, rel, exact in walk(repo, pats, opts): | 1395 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
1491 if repo.dirstate.state(abs) == 'a': | 1396 if repo.dirstate.state(abs) == 'a': |
1492 forget.append(abs) | 1397 forget.append(abs) |
1493 if ui.verbose or not exact: | 1398 if ui.verbose or not exact: |
1494 ui.status(_('forgetting %s\n') % ((pats and rel) or abs)) | 1399 ui.status(_('forgetting %s\n') % ((pats and rel) or abs)) |
1495 repo.forget(forget) | 1400 repo.forget(forget) |
1542 def __init__(self, line, linenum, colstart, colend): | 1447 def __init__(self, line, linenum, colstart, colend): |
1543 self.line = line | 1448 self.line = line |
1544 self.linenum = linenum | 1449 self.linenum = linenum |
1545 self.colstart = colstart | 1450 self.colstart = colstart |
1546 self.colend = colend | 1451 self.colend = colend |
1452 | |
1547 def __eq__(self, other): | 1453 def __eq__(self, other): |
1548 return self.line == other.line | 1454 return self.line == other.line |
1549 def __hash__(self): | |
1550 return hash(self.line) | |
1551 | 1455 |
1552 matches = {} | 1456 matches = {} |
1457 copies = {} | |
1553 def grepbody(fn, rev, body): | 1458 def grepbody(fn, rev, body): |
1554 matches[rev].setdefault(fn, {}) | 1459 matches[rev].setdefault(fn, []) |
1555 m = matches[rev][fn] | 1460 m = matches[rev][fn] |
1556 for lnum, cstart, cend, line in matchlines(body): | 1461 for lnum, cstart, cend, line in matchlines(body): |
1557 s = linestate(line, lnum, cstart, cend) | 1462 s = linestate(line, lnum, cstart, cend) |
1558 m[s] = s | 1463 m.append(s) |
1559 | 1464 |
1560 # FIXME: prev isn't used, why ? | 1465 def difflinestates(a, b): |
1466 sm = difflib.SequenceMatcher(None, a, b) | |
1467 for tag, alo, ahi, blo, bhi in sm.get_opcodes(): | |
1468 if tag == 'insert': | |
1469 for i in range(blo, bhi): | |
1470 yield ('+', b[i]) | |
1471 elif tag == 'delete': | |
1472 for i in range(alo, ahi): | |
1473 yield ('-', a[i]) | |
1474 elif tag == 'replace': | |
1475 for i in range(alo, ahi): | |
1476 yield ('-', a[i]) | |
1477 for i in range(blo, bhi): | |
1478 yield ('+', b[i]) | |
1479 | |
1561 prev = {} | 1480 prev = {} |
1562 ucache = {} | 1481 ucache = {} |
1563 def display(fn, rev, states, prevstates): | 1482 def display(fn, rev, states, prevstates): |
1564 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates))) | |
1565 diff.sort(lambda x, y: cmp(x.linenum, y.linenum)) | |
1566 counts = {'-': 0, '+': 0} | 1483 counts = {'-': 0, '+': 0} |
1567 filerevmatches = {} | 1484 filerevmatches = {} |
1568 for l in diff: | 1485 if incrementing or not opts['all']: |
1486 a, b = prevstates, states | |
1487 else: | |
1488 a, b = states, prevstates | |
1489 for change, l in difflinestates(a, b): | |
1569 if incrementing or not opts['all']: | 1490 if incrementing or not opts['all']: |
1570 change = ((l in prevstates) and '-') or '+' | |
1571 r = rev | 1491 r = rev |
1572 else: | 1492 else: |
1573 change = ((l in states) and '-') or '+' | |
1574 r = prev[fn] | 1493 r = prev[fn] |
1575 cols = [fn, str(rev)] | 1494 cols = [fn, str(r)] |
1576 if opts['line_number']: | 1495 if opts['line_number']: |
1577 cols.append(str(l.linenum)) | 1496 cols.append(str(l.linenum)) |
1578 if opts['all']: | 1497 if opts['all']: |
1579 cols.append(change) | 1498 cols.append(change) |
1580 if opts['user']: | 1499 if opts['user']: |
1581 cols.append(trimuser(ui, getchange(rev)[1], rev, | 1500 cols.append(trimuser(ui, getchange(r)[1], rev, |
1582 ucache)) | 1501 ucache)) |
1583 if opts['files_with_matches']: | 1502 if opts['files_with_matches']: |
1584 c = (fn, rev) | 1503 c = (fn, rev) |
1585 if c in filerevmatches: | 1504 if c in filerevmatches: |
1586 continue | 1505 continue |
1587 filerevmatches[c] = 1 | 1506 filerevmatches[c] = 1 |
1594 fstate = {} | 1513 fstate = {} |
1595 skip = {} | 1514 skip = {} |
1596 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) | 1515 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts) |
1597 count = 0 | 1516 count = 0 |
1598 incrementing = False | 1517 incrementing = False |
1518 follow = opts.get('follow') | |
1599 for st, rev, fns in changeiter: | 1519 for st, rev, fns in changeiter: |
1600 if st == 'window': | 1520 if st == 'window': |
1601 incrementing = rev | 1521 incrementing = rev |
1602 matches.clear() | 1522 matches.clear() |
1603 elif st == 'add': | 1523 elif st == 'add': |
1608 if fn in skip: | 1528 if fn in skip: |
1609 continue | 1529 continue |
1610 fstate.setdefault(fn, {}) | 1530 fstate.setdefault(fn, {}) |
1611 try: | 1531 try: |
1612 grepbody(fn, rev, getfile(fn).read(mf[fn])) | 1532 grepbody(fn, rev, getfile(fn).read(mf[fn])) |
1533 if follow: | |
1534 copied = getfile(fn).renamed(mf[fn]) | |
1535 if copied: | |
1536 copies.setdefault(rev, {})[fn] = copied[0] | |
1613 except KeyError: | 1537 except KeyError: |
1614 pass | 1538 pass |
1615 elif st == 'iter': | 1539 elif st == 'iter': |
1616 states = matches[rev].items() | 1540 states = matches[rev].items() |
1617 states.sort() | 1541 states.sort() |
1618 for fn, m in states: | 1542 for fn, m in states: |
1543 copy = copies.get(rev, {}).get(fn) | |
1619 if fn in skip: | 1544 if fn in skip: |
1545 if copy: | |
1546 skip[copy] = True | |
1620 continue | 1547 continue |
1621 if incrementing or not opts['all'] or fstate[fn]: | 1548 if incrementing or not opts['all'] or fstate[fn]: |
1622 pos, neg = display(fn, rev, m, fstate[fn]) | 1549 pos, neg = display(fn, rev, m, fstate[fn]) |
1623 count += pos + neg | 1550 count += pos + neg |
1624 if pos and not opts['all']: | 1551 if pos and not opts['all']: |
1625 skip[fn] = True | 1552 skip[fn] = True |
1553 if copy: | |
1554 skip[copy] = True | |
1626 fstate[fn] = m | 1555 fstate[fn] = m |
1556 if copy: | |
1557 fstate[copy] = m | |
1627 prev[fn] = rev | 1558 prev[fn] = rev |
1628 | 1559 |
1629 if not incrementing: | 1560 if not incrementing: |
1630 fstate = fstate.items() | 1561 fstate = fstate.items() |
1631 fstate.sort() | 1562 fstate.sort() |
1632 for fn, state in fstate: | 1563 for fn, state in fstate: |
1633 if fn in skip: | 1564 if fn in skip: |
1634 continue | 1565 continue |
1635 display(fn, rev, {}, state) | 1566 if fn not in copies.get(prev[fn], {}): |
1567 display(fn, rev, {}, state) | |
1636 return (count == 0 and 1) or 0 | 1568 return (count == 0 and 1) or 0 |
1637 | 1569 |
1638 def heads(ui, repo, **opts): | 1570 def heads(ui, repo, **opts): |
1639 """show current repository heads | 1571 """show current repository heads |
1640 | 1572 |
1668 if not parents: | 1600 if not parents: |
1669 ui.write(_("unknown\n")) | 1601 ui.write(_("unknown\n")) |
1670 return | 1602 return |
1671 | 1603 |
1672 hexfunc = ui.verbose and hex or short | 1604 hexfunc = ui.verbose and hex or short |
1673 modified, added, removed, deleted, unknown = repo.changes() | 1605 modified, added, removed, deleted = repo.status()[:4] |
1674 output = ["%s%s" % | 1606 output = ["%s%s" % |
1675 ('+'.join([hexfunc(parent) for parent in parents]), | 1607 ('+'.join([hexfunc(parent) for parent in parents]), |
1676 (modified or added or removed or deleted) and "+" or "")] | 1608 (modified or added or removed or deleted) and "+" or "")] |
1677 | 1609 |
1678 if not ui.quiet: | 1610 if not ui.quiet: |
1712 bail_if_changed(repo) | 1644 bail_if_changed(repo) |
1713 | 1645 |
1714 d = opts["base"] | 1646 d = opts["base"] |
1715 strip = opts["strip"] | 1647 strip = opts["strip"] |
1716 | 1648 |
1717 mailre = re.compile(r'(?:From |[\w-]+:)') | 1649 wlock = repo.wlock() |
1718 | 1650 lock = repo.lock() |
1719 # attempt to detect the start of a patch | 1651 |
1720 # (this heuristic is borrowed from quilt) | 1652 for p in patches: |
1721 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' + | 1653 pf = os.path.join(d, p) |
1722 'retrieving revision [0-9]+(\.[0-9]+)*$|' + | 1654 |
1723 '(---|\*\*\*)[ \t])', re.MULTILINE) | |
1724 | |
1725 for patch in patches: | |
1726 pf = os.path.join(d, patch) | |
1727 | |
1728 message = None | |
1729 user = None | |
1730 date = None | |
1731 hgpatch = False | |
1732 | |
1733 p = email.Parser.Parser() | |
1734 if pf == '-': | 1655 if pf == '-': |
1735 msg = p.parse(sys.stdin) | |
1736 ui.status(_("applying patch from stdin\n")) | 1656 ui.status(_("applying patch from stdin\n")) |
1737 else: | 1657 tmpname, message, user, date = patch.extract(ui, sys.stdin) |
1738 msg = p.parse(file(pf)) | 1658 else: |
1739 ui.status(_("applying %s\n") % patch) | 1659 ui.status(_("applying %s\n") % p) |
1740 | 1660 tmpname, message, user, date = patch.extract(ui, file(pf)) |
1741 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-') | 1661 |
1742 tmpfp = os.fdopen(fd, 'w') | 1662 if tmpname is None: |
1663 raise util.Abort(_('no diffs found')) | |
1664 | |
1743 try: | 1665 try: |
1744 message = msg['Subject'] | |
1745 if message: | |
1746 message = message.replace('\n\t', ' ') | |
1747 ui.debug('Subject: %s\n' % message) | |
1748 user = msg['From'] | |
1749 if user: | |
1750 ui.debug('From: %s\n' % user) | |
1751 diffs_seen = 0 | |
1752 ok_types = ('text/plain', 'text/x-patch') | |
1753 for part in msg.walk(): | |
1754 content_type = part.get_content_type() | |
1755 ui.debug('Content-Type: %s\n' % content_type) | |
1756 if content_type not in ok_types: | |
1757 continue | |
1758 payload = part.get_payload(decode=True) | |
1759 m = diffre.search(payload) | |
1760 if m: | |
1761 ui.debug(_('found patch at byte %d\n') % m.start(0)) | |
1762 diffs_seen += 1 | |
1763 hgpatch = False | |
1764 fp = cStringIO.StringIO() | |
1765 if message: | |
1766 fp.write(message) | |
1767 fp.write('\n') | |
1768 for line in payload[:m.start(0)].splitlines(): | |
1769 if line.startswith('# HG changeset patch'): | |
1770 ui.debug(_('patch generated by hg export\n')) | |
1771 hgpatch = True | |
1772 # drop earlier commit message content | |
1773 fp.seek(0) | |
1774 fp.truncate() | |
1775 elif hgpatch: | |
1776 if line.startswith('# User '): | |
1777 user = line[7:] | |
1778 ui.debug('From: %s\n' % user) | |
1779 elif line.startswith("# Date "): | |
1780 date = line[7:] | |
1781 if not line.startswith('# '): | |
1782 fp.write(line) | |
1783 fp.write('\n') | |
1784 message = fp.getvalue() | |
1785 if tmpfp: | |
1786 tmpfp.write(payload) | |
1787 if not payload.endswith('\n'): | |
1788 tmpfp.write('\n') | |
1789 elif not diffs_seen and message and content_type == 'text/plain': | |
1790 message += '\n' + payload | |
1791 | |
1792 if opts['message']: | 1666 if opts['message']: |
1793 # pickup the cmdline msg | 1667 # pickup the cmdline msg |
1794 message = opts['message'] | 1668 message = opts['message'] |
1795 elif message: | 1669 elif message: |
1796 # pickup the patch msg | 1670 # pickup the patch msg |
1798 else: | 1672 else: |
1799 # launch the editor | 1673 # launch the editor |
1800 message = None | 1674 message = None |
1801 ui.debug(_('message:\n%s\n') % message) | 1675 ui.debug(_('message:\n%s\n') % message) |
1802 | 1676 |
1803 tmpfp.close() | 1677 files, fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root) |
1804 if not diffs_seen: | 1678 files = patch.updatedir(ui, repo, files, wlock=wlock) |
1805 raise util.Abort(_('no diffs found')) | 1679 repo.commit(files, message, user, date, wlock=wlock, lock=lock) |
1806 | |
1807 files = util.patch(strip, tmpname, ui) | |
1808 if len(files) > 0: | |
1809 addremove_lock(ui, repo, files, {}) | |
1810 repo.commit(files, message, user, date) | |
1811 finally: | 1680 finally: |
1812 os.unlink(tmpname) | 1681 os.unlink(tmpname) |
1813 | 1682 |
1814 def incoming(ui, repo, source="default", **opts): | 1683 def incoming(ui, repo, source="default", **opts): |
1815 """show new changesets found in source | 1684 """show new changesets found in source |
1822 twice if the incoming is followed by a pull. | 1691 twice if the incoming is followed by a pull. |
1823 | 1692 |
1824 See pull for valid source format details. | 1693 See pull for valid source format details. |
1825 """ | 1694 """ |
1826 source = ui.expandpath(source) | 1695 source = ui.expandpath(source) |
1827 ui.setconfig_remoteopts(**opts) | 1696 setremoteconfig(ui, opts) |
1828 | 1697 |
1829 other = hg.repository(ui, source) | 1698 other = hg.repository(ui, source) |
1830 incoming = repo.findincoming(other, force=opts["force"]) | 1699 incoming = repo.findincoming(other, force=opts["force"]) |
1831 if not incoming: | 1700 if not incoming: |
1832 ui.status(_("no changes found\n")) | 1701 ui.status(_("no changes found\n")) |
1858 if opts['no_merges'] and len(parents) == 2: | 1727 if opts['no_merges'] and len(parents) == 2: |
1859 continue | 1728 continue |
1860 displayer.show(changenode=n) | 1729 displayer.show(changenode=n) |
1861 if opts['patch']: | 1730 if opts['patch']: |
1862 prev = (parents and parents[0]) or nullid | 1731 prev = (parents and parents[0]) or nullid |
1863 dodiff(ui, ui, other, prev, n) | 1732 patch.diff(repo, other, prev, n) |
1864 ui.write("\n") | 1733 ui.write("\n") |
1865 finally: | 1734 finally: |
1866 if hasattr(other, 'close'): | 1735 if hasattr(other, 'close'): |
1867 other.close() | 1736 other.close() |
1868 if cleanup: | 1737 if cleanup: |
1878 | 1747 |
1879 It is possible to specify an ssh:// URL as the destination. | 1748 It is possible to specify an ssh:// URL as the destination. |
1880 Look at the help text for the pull command for important details | 1749 Look at the help text for the pull command for important details |
1881 about ssh:// URLs. | 1750 about ssh:// URLs. |
1882 """ | 1751 """ |
1883 ui.setconfig_remoteopts(**opts) | 1752 setremoteconfig(ui, opts) |
1884 hg.repository(ui, dest, create=1) | 1753 hg.repository(ui, dest, create=1) |
1885 | 1754 |
1886 def locate(ui, repo, *pats, **opts): | 1755 def locate(ui, repo, *pats, **opts): |
1887 """locate files matching specific patterns | 1756 """locate files matching specific patterns |
1888 | 1757 |
1906 if rev: | 1775 if rev: |
1907 node = repo.lookup(rev) | 1776 node = repo.lookup(rev) |
1908 else: | 1777 else: |
1909 node = None | 1778 node = None |
1910 | 1779 |
1911 for src, abs, rel, exact in walk(repo, pats, opts, node=node, | 1780 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, |
1912 head='(?:.*/|)'): | 1781 head='(?:.*/|)'): |
1913 if not node and repo.dirstate.state(abs) == '?': | 1782 if not node and repo.dirstate.state(abs) == '?': |
1914 continue | 1783 continue |
1915 if opts['fullpath']: | 1784 if opts['fullpath']: |
1916 ui.write(os.path.join(repo.root, abs), end) | 1785 ui.write(os.path.join(repo.root, abs), end) |
1917 else: | 1786 else: |
1918 ui.write(((pats and rel) or abs), end) | 1787 ui.write(((pats and rel) or abs), end) |
1919 | 1788 |
1920 def log(ui, repo, *pats, **opts): | 1789 def log(ui, repo, *pats, **opts): |
1921 """show revision history of entire repository or files | 1790 """show revision history of entire repository or files |
1922 | 1791 |
1923 Print the revision history of the specified files or the entire project. | 1792 Print the revision history of the specified files or the entire |
1793 project. | |
1794 | |
1795 File history is shown without following rename or copy history of | |
1796 files. Use -f/--follow with a file name to follow history across | |
1797 renames and copies. --follow without a file name will only show | |
1798 ancestors or descendants of the starting revision. --follow-first | |
1799 only follows the first parent of merge revisions. | |
1800 | |
1801 If no revision range is specified, the default is tip:0 unless | |
1802 --follow is set, in which case the working directory parent is | |
1803 used as the starting revision. | |
1924 | 1804 |
1925 By default this command outputs: changeset id and hash, tags, | 1805 By default this command outputs: changeset id and hash, tags, |
1926 non-trivial parents, user, date and time, and a summary for each | 1806 non-trivial parents, user, date and time, and a summary for each |
1927 commit. When the -v/--verbose switch is used, the list of changed | 1807 commit. When the -v/--verbose switch is used, the list of changed |
1928 files and full commit message is shown. | 1808 files and full commit message is shown. |
1998 br = repo.branchlookup([repo.changelog.node(rev)]) | 1878 br = repo.branchlookup([repo.changelog.node(rev)]) |
1999 | 1879 |
2000 displayer.show(rev, brinfo=br) | 1880 displayer.show(rev, brinfo=br) |
2001 if opts['patch']: | 1881 if opts['patch']: |
2002 prev = (parents and parents[0]) or nullid | 1882 prev = (parents and parents[0]) or nullid |
2003 dodiff(du, du, repo, prev, changenode, match=matchfn) | 1883 patch.diff(repo, prev, changenode, match=matchfn, fp=du) |
2004 du.write("\n\n") | 1884 du.write("\n\n") |
2005 elif st == 'iter': | 1885 elif st == 'iter': |
2006 if count == limit: break | 1886 if count == limit: break |
2007 if du.header[rev]: | 1887 if du.header[rev]: |
2008 for args in du.header[rev]: | 1888 for args in du.header[rev]: |
2029 except hg.RepoError: | 1909 except hg.RepoError: |
2030 n = repo.manifest.lookup(rev) | 1910 n = repo.manifest.lookup(rev) |
2031 else: | 1911 else: |
2032 n = repo.manifest.tip() | 1912 n = repo.manifest.tip() |
2033 m = repo.manifest.read(n) | 1913 m = repo.manifest.read(n) |
2034 mf = repo.manifest.readflags(n) | |
2035 files = m.keys() | 1914 files = m.keys() |
2036 files.sort() | 1915 files.sort() |
2037 | 1916 |
2038 for f in files: | 1917 for f in files: |
2039 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f)) | 1918 ui.write("%40s %3s %s\n" % (hex(m[f]), |
2040 | 1919 m.execf(f) and "755" or "644", f)) |
2041 def merge(ui, repo, node=None, **opts): | 1920 |
1921 def merge(ui, repo, node=None, force=None, branch=None): | |
2042 """Merge working directory with another revision | 1922 """Merge working directory with another revision |
2043 | 1923 |
2044 Merge the contents of the current working directory and the | 1924 Merge the contents of the current working directory and the |
2045 requested revision. Files that changed between either parent are | 1925 requested revision. Files that changed between either parent are |
2046 marked as changed for the next commit and a commit must be | 1926 marked as changed for the next commit and a commit must be |
2047 performed before any further updates are allowed. | 1927 performed before any further updates are allowed. |
2048 """ | 1928 |
2049 return doupdate(ui, repo, node=node, merge=True, **opts) | 1929 If no revision is specified, the working directory's parent is a |
1930 head revision, and the repository contains exactly one other head, | |
1931 the other head is merged with by default. Otherwise, an explicit | |
1932 revision to merge with must be provided. | |
1933 """ | |
1934 | |
1935 if node: | |
1936 node = _lookup(repo, node, branch) | |
1937 else: | |
1938 heads = repo.heads() | |
1939 if len(heads) > 2: | |
1940 raise util.Abort(_('repo has %d heads - ' | |
1941 'please merge with an explicit rev') % | |
1942 len(heads)) | |
1943 if len(heads) == 1: | |
1944 raise util.Abort(_('there is nothing to merge - ' | |
1945 'use "hg update" instead')) | |
1946 parent = repo.dirstate.parents()[0] | |
1947 if parent not in heads: | |
1948 raise util.Abort(_('working dir not at a head rev - ' | |
1949 'use "hg update" or merge with an explicit rev')) | |
1950 node = parent == heads[0] and heads[-1] or heads[0] | |
1951 return hg.merge(repo, node, force=force) | |
2050 | 1952 |
2051 def outgoing(ui, repo, dest=None, **opts): | 1953 def outgoing(ui, repo, dest=None, **opts): |
2052 """show changesets not found in destination | 1954 """show changesets not found in destination |
2053 | 1955 |
2054 Show changesets not found in the specified destination repository or | 1956 Show changesets not found in the specified destination repository or |
2056 if a push was requested. | 1958 if a push was requested. |
2057 | 1959 |
2058 See pull for valid destination format details. | 1960 See pull for valid destination format details. |
2059 """ | 1961 """ |
2060 dest = ui.expandpath(dest or 'default-push', dest or 'default') | 1962 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2061 ui.setconfig_remoteopts(**opts) | 1963 setremoteconfig(ui, opts) |
2062 revs = None | 1964 revs = None |
2063 if opts['rev']: | 1965 if opts['rev']: |
2064 revs = [repo.lookup(rev) for rev in opts['rev']] | 1966 revs = [repo.lookup(rev) for rev in opts['rev']] |
2065 | 1967 |
2066 other = hg.repository(ui, dest) | 1968 other = hg.repository(ui, dest) |
2077 if opts['no_merges'] and len(parents) == 2: | 1979 if opts['no_merges'] and len(parents) == 2: |
2078 continue | 1980 continue |
2079 displayer.show(changenode=n) | 1981 displayer.show(changenode=n) |
2080 if opts['patch']: | 1982 if opts['patch']: |
2081 prev = (parents and parents[0]) or nullid | 1983 prev = (parents and parents[0]) or nullid |
2082 dodiff(ui, ui, repo, prev, n) | 1984 patch.diff(repo, prev, n) |
2083 ui.write("\n") | 1985 ui.write("\n") |
2084 | 1986 |
2085 def parents(ui, repo, rev=None, branches=None, **opts): | 1987 def parents(ui, repo, file_=None, rev=None, branches=None, **opts): |
2086 """show the parents of the working dir or revision | 1988 """show the parents of the working dir or revision |
2087 | 1989 |
2088 Print the working directory's parent revisions. | 1990 Print the working directory's parent revisions. |
2089 """ | 1991 """ |
1992 # legacy | |
1993 if file_ and not rev: | |
1994 try: | |
1995 rev = repo.lookup(file_) | |
1996 file_ = None | |
1997 except hg.RepoError: | |
1998 pass | |
1999 else: | |
2000 ui.warn(_("'hg parent REV' is deprecated, " | |
2001 "please use 'hg parents -r REV instead\n")) | |
2002 | |
2090 if rev: | 2003 if rev: |
2091 p = repo.changelog.parents(repo.lookup(rev)) | 2004 if file_: |
2005 ctx = repo.filectx(file_, changeid=rev) | |
2006 else: | |
2007 ctx = repo.changectx(rev) | |
2008 p = [cp.node() for cp in ctx.parents()] | |
2092 else: | 2009 else: |
2093 p = repo.dirstate.parents() | 2010 p = repo.dirstate.parents() |
2094 | 2011 |
2095 br = None | 2012 br = None |
2096 if branches is not None: | 2013 if branches is not None: |
2123 def postincoming(ui, repo, modheads, optupdate): | 2040 def postincoming(ui, repo, modheads, optupdate): |
2124 if modheads == 0: | 2041 if modheads == 0: |
2125 return | 2042 return |
2126 if optupdate: | 2043 if optupdate: |
2127 if modheads == 1: | 2044 if modheads == 1: |
2128 return doupdate(ui, repo) | 2045 return hg.update(repo, repo.changelog.tip()) # update |
2129 else: | 2046 else: |
2130 ui.status(_("not updating, since new heads added\n")) | 2047 ui.status(_("not updating, since new heads added\n")) |
2131 if modheads > 1: | 2048 if modheads > 1: |
2132 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) | 2049 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n")) |
2133 else: | 2050 else: |
2163 Compression on | 2080 Compression on |
2164 Alternatively specify "ssh -C" as your ssh command in your hgrc or | 2081 Alternatively specify "ssh -C" as your ssh command in your hgrc or |
2165 with the --ssh command line option. | 2082 with the --ssh command line option. |
2166 """ | 2083 """ |
2167 source = ui.expandpath(source) | 2084 source = ui.expandpath(source) |
2168 ui.setconfig_remoteopts(**opts) | 2085 setremoteconfig(ui, opts) |
2169 | 2086 |
2170 other = hg.repository(ui, source) | 2087 other = hg.repository(ui, source) |
2171 ui.status(_('pulling from %s\n') % (source)) | 2088 ui.status(_('pulling from %s\n') % (source)) |
2172 revs = None | 2089 revs = None |
2173 if opts['rev'] and not other.local(): | 2090 if opts['rev'] and not other.local(): |
2201 | 2118 |
2202 Pushing to http:// and https:// URLs is possible, too, if this | 2119 Pushing to http:// and https:// URLs is possible, too, if this |
2203 feature is enabled on the remote Mercurial server. | 2120 feature is enabled on the remote Mercurial server. |
2204 """ | 2121 """ |
2205 dest = ui.expandpath(dest or 'default-push', dest or 'default') | 2122 dest = ui.expandpath(dest or 'default-push', dest or 'default') |
2206 ui.setconfig_remoteopts(**opts) | 2123 setremoteconfig(ui, opts) |
2207 | 2124 |
2208 other = hg.repository(ui, dest) | 2125 other = hg.repository(ui, dest) |
2209 ui.status('pushing to %s\n' % (dest)) | 2126 ui.status('pushing to %s\n' % (dest)) |
2210 revs = None | 2127 revs = None |
2211 if opts['rev']: | 2128 if opts['rev']: |
2255 | 2172 |
2256 This command tries to fix the repository status after an interrupted | 2173 This command tries to fix the repository status after an interrupted |
2257 operation. It should only be necessary when Mercurial suggests it. | 2174 operation. It should only be necessary when Mercurial suggests it. |
2258 """ | 2175 """ |
2259 if repo.recover(): | 2176 if repo.recover(): |
2260 return repo.verify() | 2177 return hg.verify(repo) |
2261 return 1 | 2178 return 1 |
2262 | 2179 |
2263 def remove(ui, repo, *pats, **opts): | 2180 def remove(ui, repo, *pats, **opts): |
2264 """remove the specified files on the next commit | 2181 """remove the specified files on the next commit |
2265 | 2182 |
2275 remove them, use the -f/--force option. | 2192 remove them, use the -f/--force option. |
2276 """ | 2193 """ |
2277 names = [] | 2194 names = [] |
2278 if not opts['after'] and not pats: | 2195 if not opts['after'] and not pats: |
2279 raise util.Abort(_('no files specified')) | 2196 raise util.Abort(_('no files specified')) |
2280 files, matchfn, anypats = matchpats(repo, pats, opts) | 2197 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) |
2281 exact = dict.fromkeys(files) | 2198 exact = dict.fromkeys(files) |
2282 mardu = map(dict.fromkeys, repo.changes(files=files, match=matchfn)) | 2199 mardu = map(dict.fromkeys, repo.status(files=files, match=matchfn))[:5] |
2283 modified, added, removed, deleted, unknown = mardu | 2200 modified, added, removed, deleted, unknown = mardu |
2284 remove, forget = [], [] | 2201 remove, forget = [], [] |
2285 for src, abs, rel, exact in walk(repo, pats, opts): | 2202 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts): |
2286 reason = None | 2203 reason = None |
2287 if abs not in deleted and opts['after']: | 2204 if abs not in deleted and opts['after']: |
2288 reason = _('is still present') | 2205 reason = _('is still present') |
2289 elif abs in modified and not opts['force']: | 2206 elif abs in modified and not opts['force']: |
2290 reason = _('is modified (use -f to force removal)') | 2207 reason = _('is modified (use -f to force removal)') |
2387 names = {} | 2304 names = {} |
2388 target_only = {} | 2305 target_only = {} |
2389 | 2306 |
2390 # walk dirstate. | 2307 # walk dirstate. |
2391 | 2308 |
2392 for src, abs, rel, exact in walk(repo, pats, opts, badmatch=mf.has_key): | 2309 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, |
2310 badmatch=mf.has_key): | |
2393 names[abs] = (rel, exact) | 2311 names[abs] = (rel, exact) |
2394 if src == 'b': | 2312 if src == 'b': |
2395 target_only[abs] = True | 2313 target_only[abs] = True |
2396 | 2314 |
2397 # walk target manifest. | 2315 # walk target manifest. |
2398 | 2316 |
2399 for src, abs, rel, exact in walk(repo, pats, opts, node=node, | 2317 for src, abs, rel, exact in cmdutil.walk(repo, pats, opts, node=node, |
2400 badmatch=names.has_key): | 2318 badmatch=names.has_key): |
2401 if abs in names: continue | 2319 if abs in names: continue |
2402 names[abs] = (rel, exact) | 2320 names[abs] = (rel, exact) |
2403 target_only[abs] = True | 2321 target_only[abs] = True |
2404 | 2322 |
2405 changes = repo.changes(match=names.has_key, wlock=wlock) | 2323 changes = repo.status(match=names.has_key, wlock=wlock)[:5] |
2406 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) | 2324 modified, added, removed, deleted, unknown = map(dict.fromkeys, changes) |
2407 | 2325 |
2408 revert = ([], _('reverting %s\n')) | 2326 revert = ([], _('reverting %s\n')) |
2409 add = ([], _('adding %s\n')) | 2327 add = ([], _('adding %s\n')) |
2410 remove = ([], _('removing %s\n')) | 2328 remove = ([], _('removing %s\n')) |
2472 else: | 2390 else: |
2473 handle(remove, False) | 2391 handle(remove, False) |
2474 | 2392 |
2475 if not opts.get('dry_run'): | 2393 if not opts.get('dry_run'): |
2476 repo.dirstate.forget(forget[0]) | 2394 repo.dirstate.forget(forget[0]) |
2477 r = repo.update(node, False, True, update.has_key, False, wlock=wlock, | 2395 r = hg.revert(repo, node, update.has_key, wlock) |
2478 show_stats=False) | |
2479 repo.dirstate.update(add[0], 'a') | 2396 repo.dirstate.update(add[0], 'a') |
2480 repo.dirstate.update(undelete[0], 'n') | 2397 repo.dirstate.update(undelete[0], 'n') |
2481 repo.dirstate.update(remove[0], 'r') | 2398 repo.dirstate.update(remove[0], 'r') |
2482 return r | 2399 return r |
2483 | 2400 |
2591 httpd.serve_forever() | 2508 httpd.serve_forever() |
2592 | 2509 |
2593 def status(ui, repo, *pats, **opts): | 2510 def status(ui, repo, *pats, **opts): |
2594 """show changed files in the working directory | 2511 """show changed files in the working directory |
2595 | 2512 |
2596 Show changed files in the repository. If names are | 2513 Show status of files in the repository. If names are given, only |
2597 given, only files that match are shown. | 2514 files that match are shown. Files that are clean or ignored, are |
2515 not listed unless -c (clean), -i (ignored) or -A is given. | |
2598 | 2516 |
2599 The codes used to show the status of files are: | 2517 The codes used to show the status of files are: |
2600 M = modified | 2518 M = modified |
2601 A = added | 2519 A = added |
2602 R = removed | 2520 R = removed |
2521 C = clean | |
2603 ! = deleted, but still tracked | 2522 ! = deleted, but still tracked |
2604 ? = not tracked | 2523 ? = not tracked |
2605 I = ignored (not shown by default) | 2524 I = ignored (not shown by default) |
2606 = the previous added file was copied from here | 2525 = the previous added file was copied from here |
2607 """ | 2526 """ |
2608 | 2527 |
2609 show_ignored = opts['ignored'] and True or False | 2528 all = opts['all'] |
2610 files, matchfn, anypats = matchpats(repo, pats, opts) | 2529 |
2530 files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts) | |
2611 cwd = (pats and repo.getcwd()) or '' | 2531 cwd = (pats and repo.getcwd()) or '' |
2612 modified, added, removed, deleted, unknown, ignored = [ | 2532 modified, added, removed, deleted, unknown, ignored, clean = [ |
2613 [util.pathto(cwd, x) for x in n] | 2533 [util.pathto(cwd, x) for x in n] |
2614 for n in repo.changes(files=files, match=matchfn, | 2534 for n in repo.status(files=files, match=matchfn, |
2615 show_ignored=show_ignored)] | 2535 list_ignored=all or opts['ignored'], |
2616 | 2536 list_clean=all or opts['clean'])] |
2617 changetypes = [('modified', 'M', modified), | 2537 |
2538 changetypes = (('modified', 'M', modified), | |
2618 ('added', 'A', added), | 2539 ('added', 'A', added), |
2619 ('removed', 'R', removed), | 2540 ('removed', 'R', removed), |
2620 ('deleted', '!', deleted), | 2541 ('deleted', '!', deleted), |
2621 ('unknown', '?', unknown), | 2542 ('unknown', '?', unknown), |
2622 ('ignored', 'I', ignored)] | 2543 ('ignored', 'I', ignored)) |
2544 | |
2545 explicit_changetypes = changetypes + (('clean', 'C', clean),) | |
2623 | 2546 |
2624 end = opts['print0'] and '\0' or '\n' | 2547 end = opts['print0'] and '\0' or '\n' |
2625 | 2548 |
2626 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]] | 2549 for opt, char, changes in ([ct for ct in explicit_changetypes |
2550 if all or opts[ct[0]]] | |
2627 or changetypes): | 2551 or changetypes): |
2628 if opts['no_status']: | 2552 if opts['no_status']: |
2629 format = "%%s%s" % end | 2553 format = "%%s%s" % end |
2630 else: | 2554 else: |
2631 format = "%s %%s%s" % (char, end) | 2555 format = "%s %%s%s" % (char, end) |
2632 | 2556 |
2633 for f in changes: | 2557 for f in changes: |
2634 ui.write(format % f) | 2558 ui.write(format % f) |
2635 if (opts.get('copies') and not opts.get('no_status') | 2559 if ((all or opts.get('copies')) and not opts.get('no_status') |
2636 and opt == 'added' and repo.dirstate.copies.has_key(f)): | 2560 and opt == 'added' and repo.dirstate.copies.has_key(f)): |
2637 ui.write(' %s%s' % (repo.dirstate.copies[f], end)) | 2561 ui.write(' %s%s' % (repo.dirstate.copies[f], end)) |
2638 | 2562 |
2639 def tag(ui, repo, name, rev_=None, **opts): | 2563 def tag(ui, repo, name, rev_=None, **opts): |
2640 """add a tag for the current tip or a given revision | 2564 """add a tag for the current tip or a given revision |
2643 | 2567 |
2644 Tags are used to name particular revisions of the repository and are | 2568 Tags are used to name particular revisions of the repository and are |
2645 very useful to compare different revision, to go back to significant | 2569 very useful to compare different revision, to go back to significant |
2646 earlier versions or to mark branch points as releases, etc. | 2570 earlier versions or to mark branch points as releases, etc. |
2647 | 2571 |
2648 If no revision is given, the tip is used. | 2572 If no revision is given, the parent of the working directory is used. |
2649 | 2573 |
2650 To facilitate version control, distribution, and merging of tags, | 2574 To facilitate version control, distribution, and merging of tags, |
2651 they are stored as a file named ".hgtags" which is managed | 2575 they are stored as a file named ".hgtags" which is managed |
2652 similarly to other project files and can be hand-edited if | 2576 similarly to other project files and can be hand-edited if |
2653 necessary. The file '.hg/localtags' is used for local tags (not | 2577 necessary. The file '.hg/localtags' is used for local tags (not |
2654 shared among repositories). | 2578 shared among repositories). |
2655 """ | 2579 """ |
2656 if name == "tip": | 2580 if name in ['tip', '.']: |
2657 raise util.Abort(_("the name 'tip' is reserved")) | 2581 raise util.Abort(_("the name '%s' is reserved") % name) |
2658 if rev_ is not None: | 2582 if rev_ is not None: |
2659 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " | 2583 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, " |
2660 "please use 'hg tag [-r REV] NAME' instead\n")) | 2584 "please use 'hg tag [-r REV] NAME' instead\n")) |
2661 if opts['rev']: | 2585 if opts['rev']: |
2662 raise util.Abort(_("use only one form to specify the revision")) | 2586 raise util.Abort(_("use only one form to specify the revision")) |
2663 if opts['rev']: | 2587 if opts['rev']: |
2664 rev_ = opts['rev'] | 2588 rev_ = opts['rev'] |
2665 if rev_: | 2589 if rev_: |
2666 r = hex(repo.lookup(rev_)) | 2590 r = hex(repo.lookup(rev_)) |
2667 else: | 2591 else: |
2668 r = hex(repo.changelog.tip()) | 2592 p1, p2 = repo.dirstate.parents() |
2593 if p1 == nullid: | |
2594 raise util.Abort(_('no revision to tag')) | |
2595 if p2 != nullid: | |
2596 raise util.Abort(_('outstanding uncommitted merges')) | |
2597 r = hex(p1) | |
2669 | 2598 |
2670 repo.tag(name, r, opts['local'], opts['message'], opts['user'], | 2599 repo.tag(name, r, opts['local'], opts['message'], opts['user'], |
2671 opts['date']) | 2600 opts['date']) |
2672 | 2601 |
2673 def tags(ui, repo): | 2602 def tags(ui, repo): |
2699 br = None | 2628 br = None |
2700 if opts['branches']: | 2629 if opts['branches']: |
2701 br = repo.branchlookup([n]) | 2630 br = repo.branchlookup([n]) |
2702 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) | 2631 show_changeset(ui, repo, opts).show(changenode=n, brinfo=br) |
2703 if opts['patch']: | 2632 if opts['patch']: |
2704 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n) | 2633 patch.diff(repo, repo.changelog.parents(n)[0], n) |
2705 | 2634 |
2706 def unbundle(ui, repo, fname, **opts): | 2635 def unbundle(ui, repo, fname, **opts): |
2707 """apply a changegroup file | 2636 """apply a changegroup file |
2708 | 2637 |
2709 Apply a compressed changegroup file generated by the bundle | 2638 Apply a compressed changegroup file generated by the bundle |
2728 yield chunk | 2657 yield chunk |
2729 else: | 2658 else: |
2730 raise util.Abort(_("%s: unknown bundle compression type") | 2659 raise util.Abort(_("%s: unknown bundle compression type") |
2731 % fname) | 2660 % fname) |
2732 gen = generator(util.filechunkiter(f, 4096)) | 2661 gen = generator(util.filechunkiter(f, 4096)) |
2733 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle') | 2662 modheads = repo.addchangegroup(util.chunkbuffer(gen), 'unbundle', |
2663 'bundle:' + fname) | |
2734 return postincoming(ui, repo, modheads, opts['update']) | 2664 return postincoming(ui, repo, modheads, opts['update']) |
2735 | 2665 |
2736 def undo(ui, repo): | 2666 def undo(ui, repo): |
2737 """undo the last commit or pull (DEPRECATED) | 2667 """undo the last commit or pull (DEPRECATED) |
2738 | 2668 |
2743 """ | 2673 """ |
2744 ui.warn(_('(the undo command is deprecated; use rollback instead)\n')) | 2674 ui.warn(_('(the undo command is deprecated; use rollback instead)\n')) |
2745 repo.rollback() | 2675 repo.rollback() |
2746 | 2676 |
2747 def update(ui, repo, node=None, merge=False, clean=False, force=None, | 2677 def update(ui, repo, node=None, merge=False, clean=False, force=None, |
2748 branch=None, **opts): | 2678 branch=None): |
2749 """update or merge working directory | 2679 """update or merge working directory |
2750 | 2680 |
2751 Update the working directory to the specified revision. | 2681 Update the working directory to the specified revision. |
2752 | 2682 |
2753 If there are no outstanding changes in the working directory and | 2683 If there are no outstanding changes in the working directory and |
2758 merge command. | 2688 merge command. |
2759 | 2689 |
2760 By default, update will refuse to run if doing so would require | 2690 By default, update will refuse to run if doing so would require |
2761 merging or discarding local changes. | 2691 merging or discarding local changes. |
2762 """ | 2692 """ |
2693 node = _lookup(repo, node, branch) | |
2763 if merge: | 2694 if merge: |
2764 ui.warn(_('(the -m/--merge option is deprecated; ' | 2695 ui.warn(_('(the -m/--merge option is deprecated; ' |
2765 'use the merge command instead)\n')) | 2696 'use the merge command instead)\n')) |
2766 return doupdate(ui, repo, node, merge, clean, force, branch, **opts) | 2697 return hg.merge(repo, node, force=force) |
2767 | 2698 elif clean: |
2768 def doupdate(ui, repo, node=None, merge=False, clean=False, force=None, | 2699 return hg.clean(repo, node) |
2769 branch=None, **opts): | 2700 else: |
2701 return hg.update(repo, node) | |
2702 | |
2703 def _lookup(repo, node, branch=None): | |
2770 if branch: | 2704 if branch: |
2771 br = repo.branchlookup(branch=branch) | 2705 br = repo.branchlookup(branch=branch) |
2772 found = [] | 2706 found = [] |
2773 for x in br: | 2707 for x in br: |
2774 if branch in br[x]: | 2708 if branch in br[x]: |
2775 found.append(x) | 2709 found.append(x) |
2776 if len(found) > 1: | 2710 if len(found) > 1: |
2777 ui.warn(_("Found multiple heads for %s\n") % branch) | 2711 repo.ui.warn(_("Found multiple heads for %s\n") % branch) |
2778 for x in found: | 2712 for x in found: |
2779 show_changeset(ui, repo, opts).show(changenode=x, brinfo=br) | 2713 show_changeset(ui, repo, {}).show(changenode=x, brinfo=br) |
2780 return 1 | 2714 raise util.Abort("") |
2781 if len(found) == 1: | 2715 if len(found) == 1: |
2782 node = found[0] | 2716 node = found[0] |
2783 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch)) | 2717 repo.ui.warn(_("Using head %s for branch %s\n") |
2784 else: | 2718 % (short(node), branch)) |
2785 ui.warn(_("branch %s not found\n") % (branch)) | 2719 else: |
2786 return 1 | 2720 raise util.Abort(_("branch %s not found\n") % (branch)) |
2787 else: | 2721 else: |
2788 node = node and repo.lookup(node) or repo.changelog.tip() | 2722 node = node and repo.lookup(node) or repo.changelog.tip() |
2789 return repo.update(node, allow=merge, force=clean, forcemerge=force) | 2723 return node |
2790 | 2724 |
2791 def verify(ui, repo): | 2725 def verify(ui, repo): |
2792 """verify the integrity of the repository | 2726 """verify the integrity of the repository |
2793 | 2727 |
2794 Verify the integrity of the current repository. | 2728 Verify the integrity of the current repository. |
2796 This will perform an extensive check of the repository's | 2730 This will perform an extensive check of the repository's |
2797 integrity, validating the hashes and checksums of each entry in | 2731 integrity, validating the hashes and checksums of each entry in |
2798 the changelog, manifest, and tracked files, as well as the | 2732 the changelog, manifest, and tracked files, as well as the |
2799 integrity of their crosslinks and indices. | 2733 integrity of their crosslinks and indices. |
2800 """ | 2734 """ |
2801 return repo.verify() | 2735 return hg.verify(repo) |
2802 | 2736 |
2803 # Command options and aliases are listed here, alphabetically | 2737 # Command options and aliases are listed here, alphabetically |
2804 | 2738 |
2805 table = { | 2739 table = { |
2806 "^add": | 2740 "^add": |
2917 (diff, | 2851 (diff, |
2918 [('r', 'rev', [], _('revision')), | 2852 [('r', 'rev', [], _('revision')), |
2919 ('a', 'text', None, _('treat all files as text')), | 2853 ('a', 'text', None, _('treat all files as text')), |
2920 ('p', 'show-function', None, | 2854 ('p', 'show-function', None, |
2921 _('show which function each change is in')), | 2855 _('show which function each change is in')), |
2856 ('g', 'git', None, _('use git extended diff format')), | |
2922 ('w', 'ignore-all-space', None, | 2857 ('w', 'ignore-all-space', None, |
2923 _('ignore white space when comparing lines')), | 2858 _('ignore white space when comparing lines')), |
2924 ('b', 'ignore-space-change', None, | 2859 ('b', 'ignore-space-change', None, |
2925 _('ignore changes in the amount of white space')), | 2860 _('ignore changes in the amount of white space')), |
2926 ('B', 'ignore-blank-lines', None, | 2861 ('B', 'ignore-blank-lines', None, |
2941 _('hg forget [OPTION]... FILE...')), | 2876 _('hg forget [OPTION]... FILE...')), |
2942 "grep": | 2877 "grep": |
2943 (grep, | 2878 (grep, |
2944 [('0', 'print0', None, _('end fields with NUL')), | 2879 [('0', 'print0', None, _('end fields with NUL')), |
2945 ('', 'all', None, _('print all revisions that match')), | 2880 ('', 'all', None, _('print all revisions that match')), |
2881 ('f', 'follow', None, | |
2882 _('follow changeset history, or file history across copies and renames')), | |
2946 ('i', 'ignore-case', None, _('ignore case when matching')), | 2883 ('i', 'ignore-case', None, _('ignore case when matching')), |
2947 ('l', 'files-with-matches', None, | 2884 ('l', 'files-with-matches', None, |
2948 _('print only filenames and revs that match')), | 2885 _('print only filenames and revs that match')), |
2949 ('n', 'line-number', None, _('print matching line numbers')), | 2886 ('n', 'line-number', None, _('print matching line numbers')), |
2950 ('r', 'rev', [], _('search in given revision range')), | 2887 ('r', 'rev', [], _('search in given revision range')), |
2977 _('run even when remote repository is unrelated')), | 2914 _('run even when remote repository is unrelated')), |
2978 ('', 'style', '', _('display using template map file')), | 2915 ('', 'style', '', _('display using template map file')), |
2979 ('n', 'newest-first', None, _('show newest record first')), | 2916 ('n', 'newest-first', None, _('show newest record first')), |
2980 ('', 'bundle', '', _('file to store the bundles into')), | 2917 ('', 'bundle', '', _('file to store the bundles into')), |
2981 ('p', 'patch', None, _('show patch')), | 2918 ('p', 'patch', None, _('show patch')), |
2982 ('r', 'rev', [], _('a specific revision you would like to pull')), | 2919 ('r', 'rev', [], _('a specific revision up to which you would like to pull')), |
2983 ('', 'template', '', _('display with template')), | 2920 ('', 'template', '', _('display with template')), |
2984 ('e', 'ssh', '', _('specify ssh command to use')), | 2921 ('e', 'ssh', '', _('specify ssh command to use')), |
2985 ('', 'remotecmd', '', | 2922 ('', 'remotecmd', '', |
2986 _('specify hg command to run on the remote side'))], | 2923 _('specify hg command to run on the remote side'))], |
2987 _('hg incoming [-p] [-n] [-M] [-r REV]...' | 2924 _('hg incoming [-p] [-n] [-M] [-r REV]...' |
3003 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 2940 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
3004 _('hg locate [OPTION]... [PATTERN]...')), | 2941 _('hg locate [OPTION]... [PATTERN]...')), |
3005 "^log|history": | 2942 "^log|history": |
3006 (log, | 2943 (log, |
3007 [('b', 'branches', None, _('show branches')), | 2944 [('b', 'branches', None, _('show branches')), |
2945 ('f', 'follow', None, | |
2946 _('follow changeset history, or file history across copies and renames')), | |
2947 ('', 'follow-first', None, | |
2948 _('only follow the first parent of merge changesets')), | |
3008 ('k', 'keyword', [], _('search for a keyword')), | 2949 ('k', 'keyword', [], _('search for a keyword')), |
3009 ('l', 'limit', '', _('limit number of changes displayed')), | 2950 ('l', 'limit', '', _('limit number of changes displayed')), |
3010 ('r', 'rev', [], _('show the specified revision or range')), | 2951 ('r', 'rev', [], _('show the specified revision or range')), |
3011 ('M', 'no-merges', None, _('do not show merges')), | 2952 ('M', 'no-merges', None, _('do not show merges')), |
3012 ('', 'style', '', _('display using template map file')), | 2953 ('', 'style', '', _('display using template map file')), |
3013 ('m', 'only-merges', None, _('show only merges')), | 2954 ('m', 'only-merges', None, _('show only merges')), |
3014 ('p', 'patch', None, _('show patch')), | 2955 ('p', 'patch', None, _('show patch')), |
2956 ('P', 'prune', [], _('do not display revision or any of its ancestors')), | |
3015 ('', 'template', '', _('display with template')), | 2957 ('', 'template', '', _('display with template')), |
3016 ('I', 'include', [], _('include names matching the given patterns')), | 2958 ('I', 'include', [], _('include names matching the given patterns')), |
3017 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | 2959 ('X', 'exclude', [], _('exclude names matching the given patterns'))], |
3018 _('hg log [OPTION]... [FILE]')), | 2960 _('hg log [OPTION]... [FILE]')), |
3019 "manifest": (manifest, [], _('hg manifest [REV]')), | 2961 "manifest": (manifest, [], _('hg manifest [REV]')), |
3036 _('specify hg command to run on the remote side'))], | 2978 _('specify hg command to run on the remote side'))], |
3037 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')), | 2979 _('hg outgoing [-M] [-p] [-n] [-r REV]... [DEST]')), |
3038 "^parents": | 2980 "^parents": |
3039 (parents, | 2981 (parents, |
3040 [('b', 'branches', None, _('show branches')), | 2982 [('b', 'branches', None, _('show branches')), |
2983 ('r', 'rev', '', _('show parents from the specified rev')), | |
3041 ('', 'style', '', _('display using template map file')), | 2984 ('', 'style', '', _('display using template map file')), |
3042 ('', 'template', '', _('display with template'))], | 2985 ('', 'template', '', _('display with template'))], |
3043 _('hg parents [-b] [REV]')), | 2986 _('hg parents [-b] [-r REV] [FILE]')), |
3044 "paths": (paths, [], _('hg paths [NAME]')), | 2987 "paths": (paths, [], _('hg paths [NAME]')), |
3045 "^pull": | 2988 "^pull": |
3046 (pull, | 2989 (pull, |
3047 [('u', 'update', None, | 2990 [('u', 'update', None, |
3048 _('update the working directory to tip after pull')), | 2991 _('update the working directory to tip after pull')), |
3049 ('e', 'ssh', '', _('specify ssh command to use')), | 2992 ('e', 'ssh', '', _('specify ssh command to use')), |
3050 ('f', 'force', None, | 2993 ('f', 'force', None, |
3051 _('run even when remote repository is unrelated')), | 2994 _('run even when remote repository is unrelated')), |
3052 ('r', 'rev', [], _('a specific revision you would like to pull')), | 2995 ('r', 'rev', [], _('a specific revision up to which you would like to pull')), |
3053 ('', 'remotecmd', '', | 2996 ('', 'remotecmd', '', |
3054 _('specify hg command to run on the remote side'))], | 2997 _('specify hg command to run on the remote side'))], |
3055 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), | 2998 _('hg pull [-u] [-r REV]... [-e FILE] [--remotecmd FILE] [SOURCE]')), |
3056 "^push": | 2999 "^push": |
3057 (push, | 3000 (push, |
3115 ('', 'style', '', _('template style to use')), | 3058 ('', 'style', '', _('template style to use')), |
3116 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))], | 3059 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))], |
3117 _('hg serve [OPTION]...')), | 3060 _('hg serve [OPTION]...')), |
3118 "^status|st": | 3061 "^status|st": |
3119 (status, | 3062 (status, |
3120 [('m', 'modified', None, _('show only modified files')), | 3063 [('A', 'all', None, _('show status of all files')), |
3064 ('m', 'modified', None, _('show only modified files')), | |
3121 ('a', 'added', None, _('show only added files')), | 3065 ('a', 'added', None, _('show only added files')), |
3122 ('r', 'removed', None, _('show only removed files')), | 3066 ('r', 'removed', None, _('show only removed files')), |
3123 ('d', 'deleted', None, _('show only deleted (but tracked) files')), | 3067 ('d', 'deleted', None, _('show only deleted (but tracked) files')), |
3068 ('c', 'clean', None, _('show only files without changes')), | |
3124 ('u', 'unknown', None, _('show only unknown (not tracked) files')), | 3069 ('u', 'unknown', None, _('show only unknown (not tracked) files')), |
3125 ('i', 'ignored', None, _('show ignored files')), | 3070 ('i', 'ignored', None, _('show ignored files')), |
3126 ('n', 'no-status', None, _('hide status prefix')), | 3071 ('n', 'no-status', None, _('hide status prefix')), |
3127 ('C', 'copies', None, _('show source of copied files')), | 3072 ('C', 'copies', None, _('show source of copied files')), |
3128 ('0', 'print0', None, | 3073 ('0', 'print0', None, |
3284 def findext(name): | 3229 def findext(name): |
3285 '''return module with given extension name''' | 3230 '''return module with given extension name''' |
3286 try: | 3231 try: |
3287 return sys.modules[external[name]] | 3232 return sys.modules[external[name]] |
3288 except KeyError: | 3233 except KeyError: |
3289 dotname = '.' + name | |
3290 for k, v in external.iteritems(): | 3234 for k, v in external.iteritems(): |
3291 if k.endswith('.' + name) or v == name: | 3235 if k.endswith('.' + name) or k.endswith('/' + name) or v == name: |
3292 return sys.modules[v] | 3236 return sys.modules[v] |
3293 raise KeyError(name) | 3237 raise KeyError(name) |
3294 | 3238 |
3295 def dispatch(args): | 3239 def load_extensions(ui): |
3296 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | 3240 added = [] |
3297 num = getattr(signal, name, None) | 3241 for ext_name, load_from_name in ui.extensions(): |
3298 if num: signal.signal(num, catchterm) | 3242 if ext_name in external: |
3299 | 3243 continue |
3300 try: | |
3301 u = ui.ui(traceback='--traceback' in sys.argv[1:]) | |
3302 except util.Abort, inst: | |
3303 sys.stderr.write(_("abort: %s\n") % inst) | |
3304 return -1 | |
3305 | |
3306 for ext_name, load_from_name in u.extensions(): | |
3307 try: | 3244 try: |
3308 if load_from_name: | 3245 if load_from_name: |
3309 # the module will be loaded in sys.modules | 3246 # the module will be loaded in sys.modules |
3310 # choose an unique name so that it doesn't | 3247 # choose an unique name so that it doesn't |
3311 # conflicts with other modules | 3248 # conflicts with other modules |
3321 try: | 3258 try: |
3322 mod = importh("hgext.%s" % ext_name) | 3259 mod = importh("hgext.%s" % ext_name) |
3323 except ImportError: | 3260 except ImportError: |
3324 mod = importh(ext_name) | 3261 mod = importh(ext_name) |
3325 external[ext_name] = mod.__name__ | 3262 external[ext_name] = mod.__name__ |
3263 added.append((mod, ext_name)) | |
3326 except (util.SignalInterrupt, KeyboardInterrupt): | 3264 except (util.SignalInterrupt, KeyboardInterrupt): |
3327 raise | 3265 raise |
3328 except Exception, inst: | 3266 except Exception, inst: |
3329 u.warn(_("*** failed to import extension %s: %s\n") % (ext_name, inst)) | 3267 ui.warn(_("*** failed to import extension %s: %s\n") % |
3330 if u.print_exc(): | 3268 (ext_name, inst)) |
3269 if ui.print_exc(): | |
3331 return 1 | 3270 return 1 |
3332 | 3271 |
3333 for name in external.itervalues(): | 3272 for mod, name in added: |
3334 mod = sys.modules[name] | |
3335 uisetup = getattr(mod, 'uisetup', None) | 3273 uisetup = getattr(mod, 'uisetup', None) |
3336 if uisetup: | 3274 if uisetup: |
3337 uisetup(u) | 3275 uisetup(ui) |
3338 cmdtable = getattr(mod, 'cmdtable', {}) | 3276 cmdtable = getattr(mod, 'cmdtable', {}) |
3339 for t in cmdtable: | 3277 for t in cmdtable: |
3340 if t in table: | 3278 if t in table: |
3341 u.warn(_("module %s overrides %s\n") % (name, t)) | 3279 ui.warn(_("module %s overrides %s\n") % (name, t)) |
3342 table.update(cmdtable) | 3280 table.update(cmdtable) |
3281 | |
3282 def dispatch(args): | |
3283 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | |
3284 num = getattr(signal, name, None) | |
3285 if num: signal.signal(num, catchterm) | |
3286 | |
3287 try: | |
3288 u = ui.ui(traceback='--traceback' in sys.argv[1:], | |
3289 readhooks=[load_extensions]) | |
3290 except util.Abort, inst: | |
3291 sys.stderr.write(_("abort: %s\n") % inst) | |
3292 return -1 | |
3343 | 3293 |
3344 try: | 3294 try: |
3345 cmd, func, args, options, cmdoptions = parse(u, args) | 3295 cmd, func, args, options, cmdoptions = parse(u, args) |
3346 if options["time"]: | 3296 if options["time"]: |
3347 def get_times(): | 3297 def get_times(): |
3389 u = repo.ui | 3339 u = repo.ui |
3390 for name in external.itervalues(): | 3340 for name in external.itervalues(): |
3391 mod = sys.modules[name] | 3341 mod = sys.modules[name] |
3392 if hasattr(mod, 'reposetup'): | 3342 if hasattr(mod, 'reposetup'): |
3393 mod.reposetup(u, repo) | 3343 mod.reposetup(u, repo) |
3344 hg.repo_setup_hooks.append(mod.reposetup) | |
3394 except hg.RepoError: | 3345 except hg.RepoError: |
3395 if cmd not in optionalrepo.split(): | 3346 if cmd not in optionalrepo.split(): |
3396 raise | 3347 raise |
3397 d = lambda: func(u, repo, *args, **cmdoptions) | 3348 d = lambda: func(u, repo, *args, **cmdoptions) |
3398 else: | 3349 else: |
3399 d = lambda: func(u, *args, **cmdoptions) | 3350 d = lambda: func(u, *args, **cmdoptions) |
3351 | |
3352 # reupdate the options, repo/.hg/hgrc may have changed them | |
3353 u.updateopts(options["verbose"], options["debug"], options["quiet"], | |
3354 not options["noninteractive"], options["traceback"], | |
3355 options["config"]) | |
3400 | 3356 |
3401 try: | 3357 try: |
3402 if options['profile']: | 3358 if options['profile']: |
3403 import hotshot, hotshot.stats | 3359 import hotshot, hotshot.stats |
3404 prof = hotshot.Profile("hg.prof") | 3360 prof = hotshot.Profile("hg.prof") |