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