##// END OF EJS Templates
allow 'hg out' / 'hg in' to show newest commit first
Michal Kvasnica -
r1439:65cbe22b default
parent child Browse files
Show More
@@ -1,2626 +1,2632 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 from node import *
9 from node import *
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18
18
19 def filterfiles(filters, files):
19 def filterfiles(filters, files):
20 l = [x for x in files if x in filters]
20 l = [x for x in files if x in filters]
21
21
22 for t in filters:
22 for t in filters:
23 if t and t[-1] != "/":
23 if t and t[-1] != "/":
24 t += "/"
24 t += "/"
25 l += [x for x in files if x.startswith(t)]
25 l += [x for x in files if x.startswith(t)]
26 return l
26 return l
27
27
28 def relpath(repo, args):
28 def relpath(repo, args):
29 cwd = repo.getcwd()
29 cwd = repo.getcwd()
30 if cwd:
30 if cwd:
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
31 return [util.normpath(os.path.join(cwd, x)) for x in args]
32 return args
32 return args
33
33
34 def matchpats(repo, cwd, pats=[], opts={}, head=''):
34 def matchpats(repo, cwd, pats=[], opts={}, head=''):
35 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
35 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
36 opts.get('exclude'), head)
36 opts.get('exclude'), head)
37
37
38 def makewalk(repo, pats, opts, head=''):
38 def makewalk(repo, pats, opts, head=''):
39 cwd = repo.getcwd()
39 cwd = repo.getcwd()
40 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
40 files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
41 exact = dict(zip(files, files))
41 exact = dict(zip(files, files))
42 def walk():
42 def walk():
43 for src, fn in repo.walk(files=files, match=matchfn):
43 for src, fn in repo.walk(files=files, match=matchfn):
44 yield src, fn, util.pathto(cwd, fn), fn in exact
44 yield src, fn, util.pathto(cwd, fn), fn in exact
45 return files, matchfn, walk()
45 return files, matchfn, walk()
46
46
47 def walk(repo, pats, opts, head=''):
47 def walk(repo, pats, opts, head=''):
48 files, matchfn, results = makewalk(repo, pats, opts, head)
48 files, matchfn, results = makewalk(repo, pats, opts, head)
49 for r in results:
49 for r in results:
50 yield r
50 yield r
51
51
52 def walkchangerevs(ui, repo, cwd, pats, opts):
52 def walkchangerevs(ui, repo, cwd, pats, opts):
53 '''Iterate over files and the revs they changed in.
53 '''Iterate over files and the revs they changed in.
54
54
55 Callers most commonly need to iterate backwards over the history
55 Callers most commonly need to iterate backwards over the history
56 it is interested in. Doing so has awful (quadratic-looking)
56 it is interested in. Doing so has awful (quadratic-looking)
57 performance, so we use iterators in a "windowed" way.
57 performance, so we use iterators in a "windowed" way.
58
58
59 We walk a window of revisions in the desired order. Within the
59 We walk a window of revisions in the desired order. Within the
60 window, we first walk forwards to gather data, then in the desired
60 window, we first walk forwards to gather data, then in the desired
61 order (usually backwards) to display it.
61 order (usually backwards) to display it.
62
62
63 This function returns an (iterator, getchange) pair. The
63 This function returns an (iterator, getchange) pair. The
64 getchange function returns the changelog entry for a numeric
64 getchange function returns the changelog entry for a numeric
65 revision. The iterator yields 3-tuples. They will be of one of
65 revision. The iterator yields 3-tuples. They will be of one of
66 the following forms:
66 the following forms:
67
67
68 "window", incrementing, lastrev: stepping through a window,
68 "window", incrementing, lastrev: stepping through a window,
69 positive if walking forwards through revs, last rev in the
69 positive if walking forwards through revs, last rev in the
70 sequence iterated over - use to reset state for the current window
70 sequence iterated over - use to reset state for the current window
71
71
72 "add", rev, fns: out-of-order traversal of the given file names
72 "add", rev, fns: out-of-order traversal of the given file names
73 fns, which changed during revision rev - use to gather data for
73 fns, which changed during revision rev - use to gather data for
74 possible display
74 possible display
75
75
76 "iter", rev, None: in-order traversal of the revs earlier iterated
76 "iter", rev, None: in-order traversal of the revs earlier iterated
77 over with "add" - use to display data'''
77 over with "add" - use to display data'''
78
78
79 if repo.changelog.count() == 0:
79 if repo.changelog.count() == 0:
80 return [], False
80 return [], False
81
81
82 cwd = repo.getcwd()
82 cwd = repo.getcwd()
83 if not pats and cwd:
83 if not pats and cwd:
84 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
84 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
85 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
85 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
86 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
86 files, matchfn, anypats = matchpats(repo, (pats and cwd) or '',
87 pats, opts)
87 pats, opts)
88 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
88 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
89 wanted = {}
89 wanted = {}
90 slowpath = anypats
90 slowpath = anypats
91 window = 300
91 window = 300
92 fncache = {}
92 fncache = {}
93
93
94 chcache = {}
94 chcache = {}
95 def getchange(rev):
95 def getchange(rev):
96 ch = chcache.get(rev)
96 ch = chcache.get(rev)
97 if ch is None:
97 if ch is None:
98 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
98 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
99 return ch
99 return ch
100
100
101 if not slowpath and not files:
101 if not slowpath and not files:
102 # No files, no patterns. Display all revs.
102 # No files, no patterns. Display all revs.
103 wanted = dict(zip(revs, revs))
103 wanted = dict(zip(revs, revs))
104 if not slowpath:
104 if not slowpath:
105 # Only files, no patterns. Check the history of each file.
105 # Only files, no patterns. Check the history of each file.
106 def filerevgen(filelog):
106 def filerevgen(filelog):
107 for i in xrange(filelog.count() - 1, -1, -window):
107 for i in xrange(filelog.count() - 1, -1, -window):
108 revs = []
108 revs = []
109 for j in xrange(max(0, i - window), i + 1):
109 for j in xrange(max(0, i - window), i + 1):
110 revs.append(filelog.linkrev(filelog.node(j)))
110 revs.append(filelog.linkrev(filelog.node(j)))
111 revs.reverse()
111 revs.reverse()
112 for rev in revs:
112 for rev in revs:
113 yield rev
113 yield rev
114
114
115 minrev, maxrev = min(revs), max(revs)
115 minrev, maxrev = min(revs), max(revs)
116 for file in files:
116 for file in files:
117 filelog = repo.file(file)
117 filelog = repo.file(file)
118 # A zero count may be a directory or deleted file, so
118 # A zero count may be a directory or deleted file, so
119 # try to find matching entries on the slow path.
119 # try to find matching entries on the slow path.
120 if filelog.count() == 0:
120 if filelog.count() == 0:
121 slowpath = True
121 slowpath = True
122 break
122 break
123 for rev in filerevgen(filelog):
123 for rev in filerevgen(filelog):
124 if rev <= maxrev:
124 if rev <= maxrev:
125 if rev < minrev:
125 if rev < minrev:
126 break
126 break
127 fncache.setdefault(rev, [])
127 fncache.setdefault(rev, [])
128 fncache[rev].append(file)
128 fncache[rev].append(file)
129 wanted[rev] = 1
129 wanted[rev] = 1
130 if slowpath:
130 if slowpath:
131 # The slow path checks files modified in every changeset.
131 # The slow path checks files modified in every changeset.
132 def changerevgen():
132 def changerevgen():
133 for i in xrange(repo.changelog.count() - 1, -1, -window):
133 for i in xrange(repo.changelog.count() - 1, -1, -window):
134 for j in xrange(max(0, i - window), i + 1):
134 for j in xrange(max(0, i - window), i + 1):
135 yield j, getchange(j)[3]
135 yield j, getchange(j)[3]
136
136
137 for rev, changefiles in changerevgen():
137 for rev, changefiles in changerevgen():
138 matches = filter(matchfn, changefiles)
138 matches = filter(matchfn, changefiles)
139 if matches:
139 if matches:
140 fncache[rev] = matches
140 fncache[rev] = matches
141 wanted[rev] = 1
141 wanted[rev] = 1
142
142
143 def iterate():
143 def iterate():
144 for i in xrange(0, len(revs), window):
144 for i in xrange(0, len(revs), window):
145 yield 'window', revs[0] < revs[-1], revs[-1]
145 yield 'window', revs[0] < revs[-1], revs[-1]
146 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
146 nrevs = [rev for rev in revs[i:min(i+window, len(revs))]
147 if rev in wanted]
147 if rev in wanted]
148 srevs = list(nrevs)
148 srevs = list(nrevs)
149 srevs.sort()
149 srevs.sort()
150 for rev in srevs:
150 for rev in srevs:
151 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
151 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
152 yield 'add', rev, fns
152 yield 'add', rev, fns
153 for rev in nrevs:
153 for rev in nrevs:
154 yield 'iter', rev, None
154 yield 'iter', rev, None
155 return iterate(), getchange
155 return iterate(), getchange
156
156
157 revrangesep = ':'
157 revrangesep = ':'
158
158
159 def revrange(ui, repo, revs, revlog=None):
159 def revrange(ui, repo, revs, revlog=None):
160 """Yield revision as strings from a list of revision specifications."""
160 """Yield revision as strings from a list of revision specifications."""
161 if revlog is None:
161 if revlog is None:
162 revlog = repo.changelog
162 revlog = repo.changelog
163 revcount = revlog.count()
163 revcount = revlog.count()
164 def fix(val, defval):
164 def fix(val, defval):
165 if not val:
165 if not val:
166 return defval
166 return defval
167 try:
167 try:
168 num = int(val)
168 num = int(val)
169 if str(num) != val:
169 if str(num) != val:
170 raise ValueError
170 raise ValueError
171 if num < 0: num += revcount
171 if num < 0: num += revcount
172 if num < 0: num = 0
172 if num < 0: num = 0
173 elif num >= revcount:
173 elif num >= revcount:
174 raise ValueError
174 raise ValueError
175 except ValueError:
175 except ValueError:
176 try:
176 try:
177 num = repo.changelog.rev(repo.lookup(val))
177 num = repo.changelog.rev(repo.lookup(val))
178 except KeyError:
178 except KeyError:
179 try:
179 try:
180 num = revlog.rev(revlog.lookup(val))
180 num = revlog.rev(revlog.lookup(val))
181 except KeyError:
181 except KeyError:
182 raise util.Abort(_('invalid revision identifier %s'), val)
182 raise util.Abort(_('invalid revision identifier %s'), val)
183 return num
183 return num
184 seen = {}
184 seen = {}
185 for spec in revs:
185 for spec in revs:
186 if spec.find(revrangesep) >= 0:
186 if spec.find(revrangesep) >= 0:
187 start, end = spec.split(revrangesep, 1)
187 start, end = spec.split(revrangesep, 1)
188 start = fix(start, 0)
188 start = fix(start, 0)
189 end = fix(end, revcount - 1)
189 end = fix(end, revcount - 1)
190 step = start > end and -1 or 1
190 step = start > end and -1 or 1
191 for rev in xrange(start, end+step, step):
191 for rev in xrange(start, end+step, step):
192 if rev in seen: continue
192 if rev in seen: continue
193 seen[rev] = 1
193 seen[rev] = 1
194 yield str(rev)
194 yield str(rev)
195 else:
195 else:
196 rev = fix(spec, None)
196 rev = fix(spec, None)
197 if rev in seen: continue
197 if rev in seen: continue
198 seen[rev] = 1
198 seen[rev] = 1
199 yield str(rev)
199 yield str(rev)
200
200
201 def make_filename(repo, r, pat, node=None,
201 def make_filename(repo, r, pat, node=None,
202 total=None, seqno=None, revwidth=None, pathname=None):
202 total=None, seqno=None, revwidth=None, pathname=None):
203 node_expander = {
203 node_expander = {
204 'H': lambda: hex(node),
204 'H': lambda: hex(node),
205 'R': lambda: str(r.rev(node)),
205 'R': lambda: str(r.rev(node)),
206 'h': lambda: short(node),
206 'h': lambda: short(node),
207 }
207 }
208 expander = {
208 expander = {
209 '%': lambda: '%',
209 '%': lambda: '%',
210 'b': lambda: os.path.basename(repo.root),
210 'b': lambda: os.path.basename(repo.root),
211 }
211 }
212
212
213 try:
213 try:
214 if node:
214 if node:
215 expander.update(node_expander)
215 expander.update(node_expander)
216 if node and revwidth is not None:
216 if node and revwidth is not None:
217 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
217 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
218 if total is not None:
218 if total is not None:
219 expander['N'] = lambda: str(total)
219 expander['N'] = lambda: str(total)
220 if seqno is not None:
220 if seqno is not None:
221 expander['n'] = lambda: str(seqno)
221 expander['n'] = lambda: str(seqno)
222 if total is not None and seqno is not None:
222 if total is not None and seqno is not None:
223 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
223 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
224 if pathname is not None:
224 if pathname is not None:
225 expander['s'] = lambda: os.path.basename(pathname)
225 expander['s'] = lambda: os.path.basename(pathname)
226 expander['d'] = lambda: os.path.dirname(pathname) or '.'
226 expander['d'] = lambda: os.path.dirname(pathname) or '.'
227 expander['p'] = lambda: pathname
227 expander['p'] = lambda: pathname
228
228
229 newname = []
229 newname = []
230 patlen = len(pat)
230 patlen = len(pat)
231 i = 0
231 i = 0
232 while i < patlen:
232 while i < patlen:
233 c = pat[i]
233 c = pat[i]
234 if c == '%':
234 if c == '%':
235 i += 1
235 i += 1
236 c = pat[i]
236 c = pat[i]
237 c = expander[c]()
237 c = expander[c]()
238 newname.append(c)
238 newname.append(c)
239 i += 1
239 i += 1
240 return ''.join(newname)
240 return ''.join(newname)
241 except KeyError, inst:
241 except KeyError, inst:
242 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
242 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
243 inst.args[0])
243 inst.args[0])
244
244
245 def make_file(repo, r, pat, node=None,
245 def make_file(repo, r, pat, node=None,
246 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
246 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
247 if not pat or pat == '-':
247 if not pat or pat == '-':
248 return 'w' in mode and sys.stdout or sys.stdin
248 return 'w' in mode and sys.stdout or sys.stdin
249 if hasattr(pat, 'write') and 'w' in mode:
249 if hasattr(pat, 'write') and 'w' in mode:
250 return pat
250 return pat
251 if hasattr(pat, 'read') and 'r' in mode:
251 if hasattr(pat, 'read') and 'r' in mode:
252 return pat
252 return pat
253 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
253 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
254 pathname),
254 pathname),
255 mode)
255 mode)
256
256
257 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
257 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
258 changes=None, text=False):
258 changes=None, text=False):
259 if not changes:
259 if not changes:
260 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
260 (c, a, d, u) = repo.changes(node1, node2, files, match=match)
261 else:
261 else:
262 (c, a, d, u) = changes
262 (c, a, d, u) = changes
263 if files:
263 if files:
264 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
264 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
265
265
266 if not c and not a and not d:
266 if not c and not a and not d:
267 return
267 return
268
268
269 if node2:
269 if node2:
270 change = repo.changelog.read(node2)
270 change = repo.changelog.read(node2)
271 mmap2 = repo.manifest.read(change[0])
271 mmap2 = repo.manifest.read(change[0])
272 date2 = util.datestr(change[2])
272 date2 = util.datestr(change[2])
273 def read(f):
273 def read(f):
274 return repo.file(f).read(mmap2[f])
274 return repo.file(f).read(mmap2[f])
275 else:
275 else:
276 date2 = util.datestr()
276 date2 = util.datestr()
277 if not node1:
277 if not node1:
278 node1 = repo.dirstate.parents()[0]
278 node1 = repo.dirstate.parents()[0]
279 def read(f):
279 def read(f):
280 return repo.wfile(f).read()
280 return repo.wfile(f).read()
281
281
282 if ui.quiet:
282 if ui.quiet:
283 r = None
283 r = None
284 else:
284 else:
285 hexfunc = ui.verbose and hex or short
285 hexfunc = ui.verbose and hex or short
286 r = [hexfunc(node) for node in [node1, node2] if node]
286 r = [hexfunc(node) for node in [node1, node2] if node]
287
287
288 change = repo.changelog.read(node1)
288 change = repo.changelog.read(node1)
289 mmap = repo.manifest.read(change[0])
289 mmap = repo.manifest.read(change[0])
290 date1 = util.datestr(change[2])
290 date1 = util.datestr(change[2])
291
291
292 for f in c:
292 for f in c:
293 to = None
293 to = None
294 if f in mmap:
294 if f in mmap:
295 to = repo.file(f).read(mmap[f])
295 to = repo.file(f).read(mmap[f])
296 tn = read(f)
296 tn = read(f)
297 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
297 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
298 for f in a:
298 for f in a:
299 to = None
299 to = None
300 tn = read(f)
300 tn = read(f)
301 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
301 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
302 for f in d:
302 for f in d:
303 to = repo.file(f).read(mmap[f])
303 to = repo.file(f).read(mmap[f])
304 tn = None
304 tn = None
305 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
305 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
306
306
307 def trimuser(ui, name, rev, revcache):
307 def trimuser(ui, name, rev, revcache):
308 """trim the name of the user who committed a change"""
308 """trim the name of the user who committed a change"""
309 user = revcache.get(rev)
309 user = revcache.get(rev)
310 if user is None:
310 if user is None:
311 user = revcache[rev] = ui.shortuser(name)
311 user = revcache[rev] = ui.shortuser(name)
312 return user
312 return user
313
313
314 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
314 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
315 """show a single changeset or file revision"""
315 """show a single changeset or file revision"""
316 log = repo.changelog
316 log = repo.changelog
317 if changenode is None:
317 if changenode is None:
318 changenode = log.node(rev)
318 changenode = log.node(rev)
319 elif not rev:
319 elif not rev:
320 rev = log.rev(changenode)
320 rev = log.rev(changenode)
321
321
322 if ui.quiet:
322 if ui.quiet:
323 ui.write("%d:%s\n" % (rev, short(changenode)))
323 ui.write("%d:%s\n" % (rev, short(changenode)))
324 return
324 return
325
325
326 changes = log.read(changenode)
326 changes = log.read(changenode)
327 date = util.datestr(changes[2])
327 date = util.datestr(changes[2])
328
328
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
329 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
330 for p in log.parents(changenode)
330 for p in log.parents(changenode)
331 if ui.debugflag or p != nullid]
331 if ui.debugflag or p != nullid]
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
332 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
333 parents = []
333 parents = []
334
334
335 if ui.verbose:
335 if ui.verbose:
336 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
336 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
337 else:
337 else:
338 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
338 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
339
339
340 for tag in repo.nodetags(changenode):
340 for tag in repo.nodetags(changenode):
341 ui.status(_("tag: %s\n") % tag)
341 ui.status(_("tag: %s\n") % tag)
342 for parent in parents:
342 for parent in parents:
343 ui.write(_("parent: %d:%s\n") % parent)
343 ui.write(_("parent: %d:%s\n") % parent)
344
344
345 if brinfo and changenode in brinfo:
345 if brinfo and changenode in brinfo:
346 br = brinfo[changenode]
346 br = brinfo[changenode]
347 ui.write(_("branch: %s\n") % " ".join(br))
347 ui.write(_("branch: %s\n") % " ".join(br))
348
348
349 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
349 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
350 hex(changes[0])))
350 hex(changes[0])))
351 ui.status(_("user: %s\n") % changes[1])
351 ui.status(_("user: %s\n") % changes[1])
352 ui.status(_("date: %s\n") % date)
352 ui.status(_("date: %s\n") % date)
353
353
354 if ui.debugflag:
354 if ui.debugflag:
355 files = repo.changes(log.parents(changenode)[0], changenode)
355 files = repo.changes(log.parents(changenode)[0], changenode)
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
356 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
357 if value:
357 if value:
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
358 ui.note("%-12s %s\n" % (key, " ".join(value)))
359 else:
359 else:
360 ui.note(_("files: %s\n") % " ".join(changes[3]))
360 ui.note(_("files: %s\n") % " ".join(changes[3]))
361
361
362 description = changes[4].strip()
362 description = changes[4].strip()
363 if description:
363 if description:
364 if ui.verbose:
364 if ui.verbose:
365 ui.status(_("description:\n"))
365 ui.status(_("description:\n"))
366 ui.status(description)
366 ui.status(description)
367 ui.status("\n\n")
367 ui.status("\n\n")
368 else:
368 else:
369 ui.status(_("summary: %s\n") % description.splitlines()[0])
369 ui.status(_("summary: %s\n") % description.splitlines()[0])
370 ui.status("\n")
370 ui.status("\n")
371
371
372 def show_version(ui):
372 def show_version(ui):
373 """output version and copyright information"""
373 """output version and copyright information"""
374 ui.write(_("Mercurial Distributed SCM (version %s)\n")
374 ui.write(_("Mercurial Distributed SCM (version %s)\n")
375 % version.get_version())
375 % version.get_version())
376 ui.status(_(
376 ui.status(_(
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
377 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
378 "This is free software; see the source for copying conditions. "
378 "This is free software; see the source for copying conditions. "
379 "There is NO\nwarranty; "
379 "There is NO\nwarranty; "
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
380 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
381 ))
381 ))
382
382
383 def help_(ui, cmd=None, with_version=False):
383 def help_(ui, cmd=None, with_version=False):
384 """show help for a given command or all commands"""
384 """show help for a given command or all commands"""
385 option_lists = []
385 option_lists = []
386 if cmd and cmd != 'shortlist':
386 if cmd and cmd != 'shortlist':
387 if with_version:
387 if with_version:
388 show_version(ui)
388 show_version(ui)
389 ui.write('\n')
389 ui.write('\n')
390 key, i = find(cmd)
390 key, i = find(cmd)
391 # synopsis
391 # synopsis
392 ui.write("%s\n\n" % i[2])
392 ui.write("%s\n\n" % i[2])
393
393
394 # description
394 # description
395 doc = i[0].__doc__
395 doc = i[0].__doc__
396 if ui.quiet:
396 if ui.quiet:
397 doc = doc.splitlines(0)[0]
397 doc = doc.splitlines(0)[0]
398 ui.write("%s\n" % doc.rstrip())
398 ui.write("%s\n" % doc.rstrip())
399
399
400 if not ui.quiet:
400 if not ui.quiet:
401 # aliases
401 # aliases
402 aliases = ', '.join(key.split('|')[1:])
402 aliases = ', '.join(key.split('|')[1:])
403 if aliases:
403 if aliases:
404 ui.write(_("\naliases: %s\n") % aliases)
404 ui.write(_("\naliases: %s\n") % aliases)
405
405
406 # options
406 # options
407 if i[1]:
407 if i[1]:
408 option_lists.append(("options", i[1]))
408 option_lists.append(("options", i[1]))
409
409
410 else:
410 else:
411 # program name
411 # program name
412 if ui.verbose or with_version:
412 if ui.verbose or with_version:
413 show_version(ui)
413 show_version(ui)
414 else:
414 else:
415 ui.status(_("Mercurial Distributed SCM\n"))
415 ui.status(_("Mercurial Distributed SCM\n"))
416 ui.status('\n')
416 ui.status('\n')
417
417
418 # list of commands
418 # list of commands
419 if cmd == "shortlist":
419 if cmd == "shortlist":
420 ui.status(_('basic commands (use "hg help" '
420 ui.status(_('basic commands (use "hg help" '
421 'for the full list or option "-v" for details):\n\n'))
421 'for the full list or option "-v" for details):\n\n'))
422 elif ui.verbose:
422 elif ui.verbose:
423 ui.status(_('list of commands:\n\n'))
423 ui.status(_('list of commands:\n\n'))
424 else:
424 else:
425 ui.status(_('list of commands (use "hg help -v" '
425 ui.status(_('list of commands (use "hg help -v" '
426 'to show aliases and global options):\n\n'))
426 'to show aliases and global options):\n\n'))
427
427
428 h = {}
428 h = {}
429 cmds = {}
429 cmds = {}
430 for c, e in table.items():
430 for c, e in table.items():
431 f = c.split("|")[0]
431 f = c.split("|")[0]
432 if cmd == "shortlist" and not f.startswith("^"):
432 if cmd == "shortlist" and not f.startswith("^"):
433 continue
433 continue
434 f = f.lstrip("^")
434 f = f.lstrip("^")
435 if not ui.debugflag and f.startswith("debug"):
435 if not ui.debugflag and f.startswith("debug"):
436 continue
436 continue
437 d = ""
437 d = ""
438 if e[0].__doc__:
438 if e[0].__doc__:
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
439 d = e[0].__doc__.splitlines(0)[0].rstrip()
440 h[f] = d
440 h[f] = d
441 cmds[f]=c.lstrip("^")
441 cmds[f]=c.lstrip("^")
442
442
443 fns = h.keys()
443 fns = h.keys()
444 fns.sort()
444 fns.sort()
445 m = max(map(len, fns))
445 m = max(map(len, fns))
446 for f in fns:
446 for f in fns:
447 if ui.verbose:
447 if ui.verbose:
448 commands = cmds[f].replace("|",", ")
448 commands = cmds[f].replace("|",", ")
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
449 ui.write(" %s:\n %s\n"%(commands,h[f]))
450 else:
450 else:
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
451 ui.write(' %-*s %s\n' % (m, f, h[f]))
452
452
453 # global options
453 # global options
454 if ui.verbose:
454 if ui.verbose:
455 option_lists.append(("global options", globalopts))
455 option_lists.append(("global options", globalopts))
456
456
457 # list all option lists
457 # list all option lists
458 opt_output = []
458 opt_output = []
459 for title, options in option_lists:
459 for title, options in option_lists:
460 opt_output.append(("\n%s:\n" % title, None))
460 opt_output.append(("\n%s:\n" % title, None))
461 for shortopt, longopt, default, desc in options:
461 for shortopt, longopt, default, desc in options:
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
462 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
463 longopt and " --%s" % longopt),
463 longopt and " --%s" % longopt),
464 "%s%s" % (desc,
464 "%s%s" % (desc,
465 default and _(" (default: %s)") % default
465 default and _(" (default: %s)") % default
466 or "")))
466 or "")))
467
467
468 if opt_output:
468 if opt_output:
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
469 opts_len = max([len(line[0]) for line in opt_output if line[1]])
470 for first, second in opt_output:
470 for first, second in opt_output:
471 if second:
471 if second:
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
472 ui.write(" %-*s %s\n" % (opts_len, first, second))
473 else:
473 else:
474 ui.write("%s\n" % first)
474 ui.write("%s\n" % first)
475
475
476 # Commands start here, listed alphabetically
476 # Commands start here, listed alphabetically
477
477
478 def add(ui, repo, *pats, **opts):
478 def add(ui, repo, *pats, **opts):
479 """add the specified files on the next commit
479 """add the specified files on the next commit
480
480
481 Schedule files to be version controlled and added to the repository.
481 Schedule files to be version controlled and added to the repository.
482
482
483 The files will be added to the repository at the next commit.
483 The files will be added to the repository at the next commit.
484
484
485 If no names are given, add all files in the current directory and
485 If no names are given, add all files in the current directory and
486 its subdirectories.
486 its subdirectories.
487 """
487 """
488
488
489 names = []
489 names = []
490 for src, abs, rel, exact in walk(repo, pats, opts):
490 for src, abs, rel, exact in walk(repo, pats, opts):
491 if exact:
491 if exact:
492 if ui.verbose: ui.status(_('adding %s\n') % rel)
492 if ui.verbose: ui.status(_('adding %s\n') % rel)
493 names.append(abs)
493 names.append(abs)
494 elif repo.dirstate.state(abs) == '?':
494 elif repo.dirstate.state(abs) == '?':
495 ui.status(_('adding %s\n') % rel)
495 ui.status(_('adding %s\n') % rel)
496 names.append(abs)
496 names.append(abs)
497 repo.add(names)
497 repo.add(names)
498
498
499 def addremove(ui, repo, *pats, **opts):
499 def addremove(ui, repo, *pats, **opts):
500 """add all new files, delete all missing files
500 """add all new files, delete all missing files
501
501
502 Add all new files and remove all missing files from the repository.
502 Add all new files and remove all missing files from the repository.
503
503
504 New files are ignored if they match any of the patterns in .hgignore. As
504 New files are ignored if they match any of the patterns in .hgignore. As
505 with add, these changes take effect at the next commit.
505 with add, these changes take effect at the next commit.
506 """
506 """
507 add, remove = [], []
507 add, remove = [], []
508 for src, abs, rel, exact in walk(repo, pats, opts):
508 for src, abs, rel, exact in walk(repo, pats, opts):
509 if src == 'f' and repo.dirstate.state(abs) == '?':
509 if src == 'f' and repo.dirstate.state(abs) == '?':
510 add.append(abs)
510 add.append(abs)
511 if ui.verbose or not exact:
511 if ui.verbose or not exact:
512 ui.status(_('adding %s\n') % rel)
512 ui.status(_('adding %s\n') % rel)
513 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
513 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
514 remove.append(abs)
514 remove.append(abs)
515 if ui.verbose or not exact:
515 if ui.verbose or not exact:
516 ui.status(_('removing %s\n') % rel)
516 ui.status(_('removing %s\n') % rel)
517 repo.add(add)
517 repo.add(add)
518 repo.remove(remove)
518 repo.remove(remove)
519
519
520 def annotate(ui, repo, *pats, **opts):
520 def annotate(ui, repo, *pats, **opts):
521 """show changeset information per file line
521 """show changeset information per file line
522
522
523 List changes in files, showing the revision id responsible for each line
523 List changes in files, showing the revision id responsible for each line
524
524
525 This command is useful to discover who did a change or when a change took
525 This command is useful to discover who did a change or when a change took
526 place.
526 place.
527
527
528 Without the -a option, annotate will avoid processing files it
528 Without the -a option, annotate will avoid processing files it
529 detects as binary. With -a, annotate will generate an annotation
529 detects as binary. With -a, annotate will generate an annotation
530 anyway, probably with undesirable results.
530 anyway, probably with undesirable results.
531 """
531 """
532 def getnode(rev):
532 def getnode(rev):
533 return short(repo.changelog.node(rev))
533 return short(repo.changelog.node(rev))
534
534
535 ucache = {}
535 ucache = {}
536 def getname(rev):
536 def getname(rev):
537 cl = repo.changelog.read(repo.changelog.node(rev))
537 cl = repo.changelog.read(repo.changelog.node(rev))
538 return trimuser(ui, cl[1], rev, ucache)
538 return trimuser(ui, cl[1], rev, ucache)
539
539
540 if not pats:
540 if not pats:
541 raise util.Abort(_('at least one file name or pattern required'))
541 raise util.Abort(_('at least one file name or pattern required'))
542
542
543 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
543 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
544 if not opts['user'] and not opts['changeset']:
544 if not opts['user'] and not opts['changeset']:
545 opts['number'] = 1
545 opts['number'] = 1
546
546
547 if opts['rev']:
547 if opts['rev']:
548 node = repo.changelog.lookup(opts['rev'])
548 node = repo.changelog.lookup(opts['rev'])
549 else:
549 else:
550 node = repo.dirstate.parents()[0]
550 node = repo.dirstate.parents()[0]
551 change = repo.changelog.read(node)
551 change = repo.changelog.read(node)
552 mmap = repo.manifest.read(change[0])
552 mmap = repo.manifest.read(change[0])
553
553
554 for src, abs, rel, exact in walk(repo, pats, opts):
554 for src, abs, rel, exact in walk(repo, pats, opts):
555 if abs not in mmap:
555 if abs not in mmap:
556 ui.warn(_("warning: %s is not in the repository!\n") % rel)
556 ui.warn(_("warning: %s is not in the repository!\n") % rel)
557 continue
557 continue
558
558
559 f = repo.file(abs)
559 f = repo.file(abs)
560 if not opts['text'] and util.binary(f.read(mmap[abs])):
560 if not opts['text'] and util.binary(f.read(mmap[abs])):
561 ui.write(_("%s: binary file\n") % rel)
561 ui.write(_("%s: binary file\n") % rel)
562 continue
562 continue
563
563
564 lines = f.annotate(mmap[abs])
564 lines = f.annotate(mmap[abs])
565 pieces = []
565 pieces = []
566
566
567 for o, f in opmap:
567 for o, f in opmap:
568 if opts[o]:
568 if opts[o]:
569 l = [f(n) for n, dummy in lines]
569 l = [f(n) for n, dummy in lines]
570 if l:
570 if l:
571 m = max(map(len, l))
571 m = max(map(len, l))
572 pieces.append(["%*s" % (m, x) for x in l])
572 pieces.append(["%*s" % (m, x) for x in l])
573
573
574 if pieces:
574 if pieces:
575 for p, l in zip(zip(*pieces), lines):
575 for p, l in zip(zip(*pieces), lines):
576 ui.write("%s: %s" % (" ".join(p), l[1]))
576 ui.write("%s: %s" % (" ".join(p), l[1]))
577
577
578 def bundle(ui, repo, fname, dest="default-push", **opts):
578 def bundle(ui, repo, fname, dest="default-push", **opts):
579 """create a changegroup file
579 """create a changegroup file
580
580
581 Generate a compressed changegroup file collecting all changesets
581 Generate a compressed changegroup file collecting all changesets
582 not found in the other repository.
582 not found in the other repository.
583
583
584 This file can then be transferred using conventional means and
584 This file can then be transferred using conventional means and
585 applied to another repository with the unbundle command. This is
585 applied to another repository with the unbundle command. This is
586 useful when native push and pull are not available or when
586 useful when native push and pull are not available or when
587 exporting an entire repository is undesirable. The standard file
587 exporting an entire repository is undesirable. The standard file
588 extension is ".hg".
588 extension is ".hg".
589
589
590 Unlike import/export, this exactly preserves all changeset
590 Unlike import/export, this exactly preserves all changeset
591 contents including permissions, rename data, and revision history.
591 contents including permissions, rename data, and revision history.
592 """
592 """
593 f = open(fname, "wb")
593 f = open(fname, "wb")
594 dest = ui.expandpath(dest)
594 dest = ui.expandpath(dest)
595 other = hg.repository(ui, dest)
595 other = hg.repository(ui, dest)
596 o = repo.findoutgoing(other)
596 o = repo.findoutgoing(other)
597 cg = repo.changegroup(o)
597 cg = repo.changegroup(o)
598
598
599 try:
599 try:
600 f.write("HG10")
600 f.write("HG10")
601 z = bz2.BZ2Compressor(9)
601 z = bz2.BZ2Compressor(9)
602 while 1:
602 while 1:
603 chunk = cg.read(4096)
603 chunk = cg.read(4096)
604 if not chunk:
604 if not chunk:
605 break
605 break
606 f.write(z.compress(chunk))
606 f.write(z.compress(chunk))
607 f.write(z.flush())
607 f.write(z.flush())
608 except:
608 except:
609 os.unlink(fname)
609 os.unlink(fname)
610 raise
610 raise
611
611
612 def cat(ui, repo, file1, *pats, **opts):
612 def cat(ui, repo, file1, *pats, **opts):
613 """output the latest or given revisions of files
613 """output the latest or given revisions of files
614
614
615 Print the specified files as they were at the given revision.
615 Print the specified files as they were at the given revision.
616 If no revision is given then the tip is used.
616 If no revision is given then the tip is used.
617
617
618 Output may be to a file, in which case the name of the file is
618 Output may be to a file, in which case the name of the file is
619 given using a format string. The formatting rules are the same as
619 given using a format string. The formatting rules are the same as
620 for the export command, with the following additions:
620 for the export command, with the following additions:
621
621
622 %s basename of file being printed
622 %s basename of file being printed
623 %d dirname of file being printed, or '.' if in repo root
623 %d dirname of file being printed, or '.' if in repo root
624 %p root-relative path name of file being printed
624 %p root-relative path name of file being printed
625 """
625 """
626 mf = {}
626 mf = {}
627 if opts['rev']:
627 if opts['rev']:
628 change = repo.changelog.read(repo.lookup(opts['rev']))
628 change = repo.changelog.read(repo.lookup(opts['rev']))
629 mf = repo.manifest.read(change[0])
629 mf = repo.manifest.read(change[0])
630 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
630 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
631 r = repo.file(abs)
631 r = repo.file(abs)
632 if opts['rev']:
632 if opts['rev']:
633 try:
633 try:
634 n = mf[abs]
634 n = mf[abs]
635 except (hg.RepoError, KeyError):
635 except (hg.RepoError, KeyError):
636 try:
636 try:
637 n = r.lookup(rev)
637 n = r.lookup(rev)
638 except KeyError, inst:
638 except KeyError, inst:
639 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
639 raise util.Abort(_('cannot find file %s in rev %s'), rel, rev)
640 else:
640 else:
641 n = r.tip()
641 n = r.tip()
642 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
642 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
643 fp.write(r.read(n))
643 fp.write(r.read(n))
644
644
645 def clone(ui, source, dest=None, **opts):
645 def clone(ui, source, dest=None, **opts):
646 """make a copy of an existing repository
646 """make a copy of an existing repository
647
647
648 Create a copy of an existing repository in a new directory.
648 Create a copy of an existing repository in a new directory.
649
649
650 If no destination directory name is specified, it defaults to the
650 If no destination directory name is specified, it defaults to the
651 basename of the source.
651 basename of the source.
652
652
653 The location of the source is added to the new repository's
653 The location of the source is added to the new repository's
654 .hg/hgrc file, as the default to be used for future pulls.
654 .hg/hgrc file, as the default to be used for future pulls.
655
655
656 For efficiency, hardlinks are used for cloning whenever the source
656 For efficiency, hardlinks are used for cloning whenever the source
657 and destination are on the same filesystem. Some filesystems,
657 and destination are on the same filesystem. Some filesystems,
658 such as AFS, implement hardlinking incorrectly, but do not report
658 such as AFS, implement hardlinking incorrectly, but do not report
659 errors. In these cases, use the --pull option to avoid
659 errors. In these cases, use the --pull option to avoid
660 hardlinking.
660 hardlinking.
661 """
661 """
662 if dest is None:
662 if dest is None:
663 dest = os.path.basename(os.path.normpath(source))
663 dest = os.path.basename(os.path.normpath(source))
664
664
665 if os.path.exists(dest):
665 if os.path.exists(dest):
666 raise util.Abort(_("destination '%s' already exists"), dest)
666 raise util.Abort(_("destination '%s' already exists"), dest)
667
667
668 dest = os.path.realpath(dest)
668 dest = os.path.realpath(dest)
669
669
670 class Dircleanup:
670 class Dircleanup:
671 def __init__(self, dir_):
671 def __init__(self, dir_):
672 self.rmtree = shutil.rmtree
672 self.rmtree = shutil.rmtree
673 self.dir_ = dir_
673 self.dir_ = dir_
674 os.mkdir(dir_)
674 os.mkdir(dir_)
675 def close(self):
675 def close(self):
676 self.dir_ = None
676 self.dir_ = None
677 def __del__(self):
677 def __del__(self):
678 if self.dir_:
678 if self.dir_:
679 self.rmtree(self.dir_, True)
679 self.rmtree(self.dir_, True)
680
680
681 if opts['ssh']:
681 if opts['ssh']:
682 ui.setconfig("ui", "ssh", opts['ssh'])
682 ui.setconfig("ui", "ssh", opts['ssh'])
683 if opts['remotecmd']:
683 if opts['remotecmd']:
684 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
684 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
685
685
686 if not os.path.exists(source):
686 if not os.path.exists(source):
687 source = ui.expandpath(source)
687 source = ui.expandpath(source)
688
688
689 d = Dircleanup(dest)
689 d = Dircleanup(dest)
690 abspath = source
690 abspath = source
691 other = hg.repository(ui, source)
691 other = hg.repository(ui, source)
692
692
693 copy = False
693 copy = False
694 if other.dev() != -1:
694 if other.dev() != -1:
695 abspath = os.path.abspath(source)
695 abspath = os.path.abspath(source)
696 if not opts['pull']:
696 if not opts['pull']:
697 copy = True
697 copy = True
698
698
699 if copy:
699 if copy:
700 try:
700 try:
701 # we use a lock here because if we race with commit, we
701 # we use a lock here because if we race with commit, we
702 # can end up with extra data in the cloned revlogs that's
702 # can end up with extra data in the cloned revlogs that's
703 # not pointed to by changesets, thus causing verify to
703 # not pointed to by changesets, thus causing verify to
704 # fail
704 # fail
705 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
705 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
706 except OSError:
706 except OSError:
707 copy = False
707 copy = False
708
708
709 if copy:
709 if copy:
710 # we lock here to avoid premature writing to the target
710 # we lock here to avoid premature writing to the target
711 os.mkdir(os.path.join(dest, ".hg"))
711 os.mkdir(os.path.join(dest, ".hg"))
712 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
712 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
713
713
714 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
714 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
715 for f in files.split():
715 for f in files.split():
716 src = os.path.join(source, ".hg", f)
716 src = os.path.join(source, ".hg", f)
717 dst = os.path.join(dest, ".hg", f)
717 dst = os.path.join(dest, ".hg", f)
718 util.copyfiles(src, dst)
718 util.copyfiles(src, dst)
719
719
720 repo = hg.repository(ui, dest)
720 repo = hg.repository(ui, dest)
721
721
722 else:
722 else:
723 repo = hg.repository(ui, dest, create=1)
723 repo = hg.repository(ui, dest, create=1)
724 repo.pull(other)
724 repo.pull(other)
725
725
726 f = repo.opener("hgrc", "w", text=True)
726 f = repo.opener("hgrc", "w", text=True)
727 f.write("[paths]\n")
727 f.write("[paths]\n")
728 f.write("default = %s\n" % abspath)
728 f.write("default = %s\n" % abspath)
729
729
730 if not opts['noupdate']:
730 if not opts['noupdate']:
731 update(ui, repo)
731 update(ui, repo)
732
732
733 d.close()
733 d.close()
734
734
735 def commit(ui, repo, *pats, **opts):
735 def commit(ui, repo, *pats, **opts):
736 """commit the specified files or all outstanding changes
736 """commit the specified files or all outstanding changes
737
737
738 Commit changes to the given files into the repository.
738 Commit changes to the given files into the repository.
739
739
740 If a list of files is omitted, all changes reported by "hg status"
740 If a list of files is omitted, all changes reported by "hg status"
741 from the root of the repository will be commited.
741 from the root of the repository will be commited.
742
742
743 The HGEDITOR or EDITOR environment variables are used to start an
743 The HGEDITOR or EDITOR environment variables are used to start an
744 editor to add a commit comment.
744 editor to add a commit comment.
745 """
745 """
746 if opts['text']:
746 if opts['text']:
747 ui.warn(_("Warning: -t and --text is deprecated,"
747 ui.warn(_("Warning: -t and --text is deprecated,"
748 " please use -m or --message instead.\n"))
748 " please use -m or --message instead.\n"))
749 message = opts['message'] or opts['text']
749 message = opts['message'] or opts['text']
750 logfile = opts['logfile']
750 logfile = opts['logfile']
751
751
752 if message and logfile:
752 if message and logfile:
753 raise util.Abort(_('options --message and --logfile are mutually '
753 raise util.Abort(_('options --message and --logfile are mutually '
754 'exclusive'))
754 'exclusive'))
755 if not message and logfile:
755 if not message and logfile:
756 try:
756 try:
757 if logfile == '-':
757 if logfile == '-':
758 message = sys.stdin.read()
758 message = sys.stdin.read()
759 else:
759 else:
760 message = open(logfile).read()
760 message = open(logfile).read()
761 except IOError, inst:
761 except IOError, inst:
762 raise util.Abort(_("can't read commit message '%s': %s") %
762 raise util.Abort(_("can't read commit message '%s': %s") %
763 (logfile, inst.strerror))
763 (logfile, inst.strerror))
764
764
765 if opts['addremove']:
765 if opts['addremove']:
766 addremove(ui, repo, *pats, **opts)
766 addremove(ui, repo, *pats, **opts)
767 cwd = repo.getcwd()
767 cwd = repo.getcwd()
768 if not pats and cwd:
768 if not pats and cwd:
769 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
769 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
770 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
770 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
771 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
771 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
772 pats, opts)
772 pats, opts)
773 if pats:
773 if pats:
774 c, a, d, u = repo.changes(files=fns, match=match)
774 c, a, d, u = repo.changes(files=fns, match=match)
775 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
775 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
776 else:
776 else:
777 files = []
777 files = []
778 try:
778 try:
779 repo.commit(files, message, opts['user'], opts['date'], match)
779 repo.commit(files, message, opts['user'], opts['date'], match)
780 except ValueError, inst:
780 except ValueError, inst:
781 raise util.Abort(str(inst))
781 raise util.Abort(str(inst))
782
782
783 def docopy(ui, repo, pats, opts):
783 def docopy(ui, repo, pats, opts):
784 if not pats:
784 if not pats:
785 raise util.Abort(_('no source or destination specified'))
785 raise util.Abort(_('no source or destination specified'))
786 elif len(pats) == 1:
786 elif len(pats) == 1:
787 raise util.Abort(_('no destination specified'))
787 raise util.Abort(_('no destination specified'))
788 pats = list(pats)
788 pats = list(pats)
789 dest = pats.pop()
789 dest = pats.pop()
790 sources = []
790 sources = []
791
791
792 def okaytocopy(abs, rel, exact):
792 def okaytocopy(abs, rel, exact):
793 reasons = {'?': _('is not managed'),
793 reasons = {'?': _('is not managed'),
794 'a': _('has been marked for add')}
794 'a': _('has been marked for add')}
795 reason = reasons.get(repo.dirstate.state(abs))
795 reason = reasons.get(repo.dirstate.state(abs))
796 if reason:
796 if reason:
797 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
797 if exact: ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
798 else:
798 else:
799 return True
799 return True
800
800
801 for src, abs, rel, exact in walk(repo, pats, opts):
801 for src, abs, rel, exact in walk(repo, pats, opts):
802 if okaytocopy(abs, rel, exact):
802 if okaytocopy(abs, rel, exact):
803 sources.append((abs, rel, exact))
803 sources.append((abs, rel, exact))
804 if not sources:
804 if not sources:
805 raise util.Abort(_('no files to copy'))
805 raise util.Abort(_('no files to copy'))
806
806
807 cwd = repo.getcwd()
807 cwd = repo.getcwd()
808 absdest = util.canonpath(repo.root, cwd, dest)
808 absdest = util.canonpath(repo.root, cwd, dest)
809 reldest = util.pathto(cwd, absdest)
809 reldest = util.pathto(cwd, absdest)
810 if os.path.exists(reldest):
810 if os.path.exists(reldest):
811 destisfile = not os.path.isdir(reldest)
811 destisfile = not os.path.isdir(reldest)
812 else:
812 else:
813 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
813 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
814
814
815 if destisfile:
815 if destisfile:
816 if opts['parents']:
816 if opts['parents']:
817 raise util.Abort(_('with --parents, destination must be a directory'))
817 raise util.Abort(_('with --parents, destination must be a directory'))
818 elif len(sources) > 1:
818 elif len(sources) > 1:
819 raise util.Abort(_('with multiple sources, destination must be a '
819 raise util.Abort(_('with multiple sources, destination must be a '
820 'directory'))
820 'directory'))
821 errs, copied = 0, []
821 errs, copied = 0, []
822 for abs, rel, exact in sources:
822 for abs, rel, exact in sources:
823 if opts['parents']:
823 if opts['parents']:
824 mydest = os.path.join(dest, rel)
824 mydest = os.path.join(dest, rel)
825 elif destisfile:
825 elif destisfile:
826 mydest = reldest
826 mydest = reldest
827 else:
827 else:
828 mydest = os.path.join(dest, os.path.basename(rel))
828 mydest = os.path.join(dest, os.path.basename(rel))
829 myabsdest = util.canonpath(repo.root, cwd, mydest)
829 myabsdest = util.canonpath(repo.root, cwd, mydest)
830 myreldest = util.pathto(cwd, myabsdest)
830 myreldest = util.pathto(cwd, myabsdest)
831 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
831 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
832 ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
832 ui.warn(_('%s: not overwriting - file already managed\n') % myreldest)
833 continue
833 continue
834 mydestdir = os.path.dirname(myreldest) or '.'
834 mydestdir = os.path.dirname(myreldest) or '.'
835 if not opts['after']:
835 if not opts['after']:
836 try:
836 try:
837 if opts['parents']: os.makedirs(mydestdir)
837 if opts['parents']: os.makedirs(mydestdir)
838 elif not destisfile: os.mkdir(mydestdir)
838 elif not destisfile: os.mkdir(mydestdir)
839 except OSError, inst:
839 except OSError, inst:
840 if inst.errno != errno.EEXIST: raise
840 if inst.errno != errno.EEXIST: raise
841 if ui.verbose or not exact:
841 if ui.verbose or not exact:
842 ui.status(_('copying %s to %s\n') % (rel, myreldest))
842 ui.status(_('copying %s to %s\n') % (rel, myreldest))
843 if not opts['after']:
843 if not opts['after']:
844 try:
844 try:
845 shutil.copyfile(rel, myreldest)
845 shutil.copyfile(rel, myreldest)
846 shutil.copymode(rel, myreldest)
846 shutil.copymode(rel, myreldest)
847 except shutil.Error, inst:
847 except shutil.Error, inst:
848 raise util.Abort(str(inst))
848 raise util.Abort(str(inst))
849 except IOError, inst:
849 except IOError, inst:
850 if inst.errno == errno.ENOENT:
850 if inst.errno == errno.ENOENT:
851 ui.warn(_('%s: deleted in working copy\n') % rel)
851 ui.warn(_('%s: deleted in working copy\n') % rel)
852 else:
852 else:
853 ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror))
853 ui.warn(_('%s: cannot copy - %s\n') % (rel, inst.strerror))
854 errs += 1
854 errs += 1
855 continue
855 continue
856 repo.copy(abs, myabsdest)
856 repo.copy(abs, myabsdest)
857 copied.append((abs, rel, exact))
857 copied.append((abs, rel, exact))
858 if errs:
858 if errs:
859 ui.warn(_('(consider using --after)\n'))
859 ui.warn(_('(consider using --after)\n'))
860 return errs, copied
860 return errs, copied
861
861
862 def copy(ui, repo, *pats, **opts):
862 def copy(ui, repo, *pats, **opts):
863 """mark files as copied for the next commit
863 """mark files as copied for the next commit
864
864
865 Mark dest as having copies of source files. If dest is a
865 Mark dest as having copies of source files. If dest is a
866 directory, copies are put in that directory. If dest is a file,
866 directory, copies are put in that directory. If dest is a file,
867 there can only be one source.
867 there can only be one source.
868
868
869 By default, this command copies the contents of files as they
869 By default, this command copies the contents of files as they
870 stand in the working directory. If invoked with --after, the
870 stand in the working directory. If invoked with --after, the
871 operation is recorded, but no copying is performed.
871 operation is recorded, but no copying is performed.
872
872
873 This command takes effect in the next commit.
873 This command takes effect in the next commit.
874
874
875 NOTE: This command should be treated as experimental. While it
875 NOTE: This command should be treated as experimental. While it
876 should properly record copied files, this information is not yet
876 should properly record copied files, this information is not yet
877 fully used by merge, nor fully reported by log.
877 fully used by merge, nor fully reported by log.
878 """
878 """
879 errs, copied = docopy(ui, repo, pats, opts)
879 errs, copied = docopy(ui, repo, pats, opts)
880 return errs
880 return errs
881
881
882 def debugancestor(ui, index, rev1, rev2):
882 def debugancestor(ui, index, rev1, rev2):
883 """find the ancestor revision of two revisions in a given index"""
883 """find the ancestor revision of two revisions in a given index"""
884 r = revlog.revlog(file, index, "")
884 r = revlog.revlog(file, index, "")
885 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
885 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
886 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
886 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
887
887
888 def debugcheckstate(ui, repo):
888 def debugcheckstate(ui, repo):
889 """validate the correctness of the current dirstate"""
889 """validate the correctness of the current dirstate"""
890 parent1, parent2 = repo.dirstate.parents()
890 parent1, parent2 = repo.dirstate.parents()
891 repo.dirstate.read()
891 repo.dirstate.read()
892 dc = repo.dirstate.map
892 dc = repo.dirstate.map
893 keys = dc.keys()
893 keys = dc.keys()
894 keys.sort()
894 keys.sort()
895 m1n = repo.changelog.read(parent1)[0]
895 m1n = repo.changelog.read(parent1)[0]
896 m2n = repo.changelog.read(parent2)[0]
896 m2n = repo.changelog.read(parent2)[0]
897 m1 = repo.manifest.read(m1n)
897 m1 = repo.manifest.read(m1n)
898 m2 = repo.manifest.read(m2n)
898 m2 = repo.manifest.read(m2n)
899 errors = 0
899 errors = 0
900 for f in dc:
900 for f in dc:
901 state = repo.dirstate.state(f)
901 state = repo.dirstate.state(f)
902 if state in "nr" and f not in m1:
902 if state in "nr" and f not in m1:
903 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
903 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
904 errors += 1
904 errors += 1
905 if state in "a" and f in m1:
905 if state in "a" and f in m1:
906 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
906 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
907 errors += 1
907 errors += 1
908 if state in "m" and f not in m1 and f not in m2:
908 if state in "m" and f not in m1 and f not in m2:
909 ui.warn(_("%s in state %s, but not in either manifest\n") %
909 ui.warn(_("%s in state %s, but not in either manifest\n") %
910 (f, state))
910 (f, state))
911 errors += 1
911 errors += 1
912 for f in m1:
912 for f in m1:
913 state = repo.dirstate.state(f)
913 state = repo.dirstate.state(f)
914 if state not in "nrm":
914 if state not in "nrm":
915 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
915 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
916 errors += 1
916 errors += 1
917 if errors:
917 if errors:
918 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
918 raise util.Abort(_(".hg/dirstate inconsistent with current parent's manifest"))
919
919
920 def debugconfig(ui):
920 def debugconfig(ui):
921 """show combined config settings from all hgrc files"""
921 """show combined config settings from all hgrc files"""
922 try:
922 try:
923 repo = hg.repository(ui)
923 repo = hg.repository(ui)
924 except hg.RepoError:
924 except hg.RepoError:
925 pass
925 pass
926 for section, name, value in ui.walkconfig():
926 for section, name, value in ui.walkconfig():
927 ui.write('%s.%s=%s\n' % (section, name, value))
927 ui.write('%s.%s=%s\n' % (section, name, value))
928
928
929 def debugsetparents(ui, repo, rev1, rev2=None):
929 def debugsetparents(ui, repo, rev1, rev2=None):
930 """
930 """
931 manually set the parents of the current working directory
931 manually set the parents of the current working directory
932
932
933 This is useful for writing repository conversion tools, but should
933 This is useful for writing repository conversion tools, but should
934 be used with care.
934 be used with care.
935 """
935 """
936
936
937 if not rev2:
937 if not rev2:
938 rev2 = hex(nullid)
938 rev2 = hex(nullid)
939
939
940 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
940 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
941
941
942 def debugstate(ui, repo):
942 def debugstate(ui, repo):
943 """show the contents of the current dirstate"""
943 """show the contents of the current dirstate"""
944 repo.dirstate.read()
944 repo.dirstate.read()
945 dc = repo.dirstate.map
945 dc = repo.dirstate.map
946 keys = dc.keys()
946 keys = dc.keys()
947 keys.sort()
947 keys.sort()
948 for file_ in keys:
948 for file_ in keys:
949 ui.write("%c %3o %10d %s %s\n"
949 ui.write("%c %3o %10d %s %s\n"
950 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
950 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
951 time.strftime("%x %X",
951 time.strftime("%x %X",
952 time.localtime(dc[file_][3])), file_))
952 time.localtime(dc[file_][3])), file_))
953 for f in repo.dirstate.copies:
953 for f in repo.dirstate.copies:
954 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
954 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
955
955
956 def debugdata(ui, file_, rev):
956 def debugdata(ui, file_, rev):
957 """dump the contents of an data file revision"""
957 """dump the contents of an data file revision"""
958 r = revlog.revlog(file, file_[:-2] + ".i", file_)
958 r = revlog.revlog(file, file_[:-2] + ".i", file_)
959 try:
959 try:
960 ui.write(r.revision(r.lookup(rev)))
960 ui.write(r.revision(r.lookup(rev)))
961 except KeyError:
961 except KeyError:
962 raise util.Abort(_('invalid revision identifier %s'), rev)
962 raise util.Abort(_('invalid revision identifier %s'), rev)
963
963
964 def debugindex(ui, file_):
964 def debugindex(ui, file_):
965 """dump the contents of an index file"""
965 """dump the contents of an index file"""
966 r = revlog.revlog(file, file_, "")
966 r = revlog.revlog(file, file_, "")
967 ui.write(" rev offset length base linkrev" +
967 ui.write(" rev offset length base linkrev" +
968 " nodeid p1 p2\n")
968 " nodeid p1 p2\n")
969 for i in range(r.count()):
969 for i in range(r.count()):
970 e = r.index[i]
970 e = r.index[i]
971 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
971 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
972 i, e[0], e[1], e[2], e[3],
972 i, e[0], e[1], e[2], e[3],
973 short(e[6]), short(e[4]), short(e[5])))
973 short(e[6]), short(e[4]), short(e[5])))
974
974
975 def debugindexdot(ui, file_):
975 def debugindexdot(ui, file_):
976 """dump an index DAG as a .dot file"""
976 """dump an index DAG as a .dot file"""
977 r = revlog.revlog(file, file_, "")
977 r = revlog.revlog(file, file_, "")
978 ui.write("digraph G {\n")
978 ui.write("digraph G {\n")
979 for i in range(r.count()):
979 for i in range(r.count()):
980 e = r.index[i]
980 e = r.index[i]
981 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
981 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
982 if e[5] != nullid:
982 if e[5] != nullid:
983 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
983 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
984 ui.write("}\n")
984 ui.write("}\n")
985
985
986 def debugrename(ui, repo, file, rev=None):
986 def debugrename(ui, repo, file, rev=None):
987 """dump rename information"""
987 """dump rename information"""
988 r = repo.file(relpath(repo, [file])[0])
988 r = repo.file(relpath(repo, [file])[0])
989 if rev:
989 if rev:
990 try:
990 try:
991 # assume all revision numbers are for changesets
991 # assume all revision numbers are for changesets
992 n = repo.lookup(rev)
992 n = repo.lookup(rev)
993 change = repo.changelog.read(n)
993 change = repo.changelog.read(n)
994 m = repo.manifest.read(change[0])
994 m = repo.manifest.read(change[0])
995 n = m[relpath(repo, [file])[0]]
995 n = m[relpath(repo, [file])[0]]
996 except hg.RepoError, KeyError:
996 except hg.RepoError, KeyError:
997 n = r.lookup(rev)
997 n = r.lookup(rev)
998 else:
998 else:
999 n = r.tip()
999 n = r.tip()
1000 m = r.renamed(n)
1000 m = r.renamed(n)
1001 if m:
1001 if m:
1002 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1002 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1003 else:
1003 else:
1004 ui.write(_("not renamed\n"))
1004 ui.write(_("not renamed\n"))
1005
1005
1006 def debugwalk(ui, repo, *pats, **opts):
1006 def debugwalk(ui, repo, *pats, **opts):
1007 """show how files match on given patterns"""
1007 """show how files match on given patterns"""
1008 items = list(walk(repo, pats, opts))
1008 items = list(walk(repo, pats, opts))
1009 if not items:
1009 if not items:
1010 return
1010 return
1011 fmt = '%%s %%-%ds %%-%ds %%s' % (
1011 fmt = '%%s %%-%ds %%-%ds %%s' % (
1012 max([len(abs) for (src, abs, rel, exact) in items]),
1012 max([len(abs) for (src, abs, rel, exact) in items]),
1013 max([len(rel) for (src, abs, rel, exact) in items]))
1013 max([len(rel) for (src, abs, rel, exact) in items]))
1014 for src, abs, rel, exact in items:
1014 for src, abs, rel, exact in items:
1015 line = fmt % (src, abs, rel, exact and 'exact' or '')
1015 line = fmt % (src, abs, rel, exact and 'exact' or '')
1016 ui.write("%s\n" % line.rstrip())
1016 ui.write("%s\n" % line.rstrip())
1017
1017
1018 def diff(ui, repo, *pats, **opts):
1018 def diff(ui, repo, *pats, **opts):
1019 """diff working directory (or selected files)
1019 """diff working directory (or selected files)
1020
1020
1021 Show differences between revisions for the specified files.
1021 Show differences between revisions for the specified files.
1022
1022
1023 Differences between files are shown using the unified diff format.
1023 Differences between files are shown using the unified diff format.
1024
1024
1025 When two revision arguments are given, then changes are shown
1025 When two revision arguments are given, then changes are shown
1026 between those revisions. If only one revision is specified then
1026 between those revisions. If only one revision is specified then
1027 that revision is compared to the working directory, and, when no
1027 that revision is compared to the working directory, and, when no
1028 revisions are specified, the working directory files are compared
1028 revisions are specified, the working directory files are compared
1029 to its parent.
1029 to its parent.
1030
1030
1031 Without the -a option, diff will avoid generating diffs of files
1031 Without the -a option, diff will avoid generating diffs of files
1032 it detects as binary. With -a, diff will generate a diff anyway,
1032 it detects as binary. With -a, diff will generate a diff anyway,
1033 probably with undesirable results.
1033 probably with undesirable results.
1034 """
1034 """
1035 node1, node2 = None, None
1035 node1, node2 = None, None
1036 revs = [repo.lookup(x) for x in opts['rev']]
1036 revs = [repo.lookup(x) for x in opts['rev']]
1037
1037
1038 if len(revs) > 0:
1038 if len(revs) > 0:
1039 node1 = revs[0]
1039 node1 = revs[0]
1040 if len(revs) > 1:
1040 if len(revs) > 1:
1041 node2 = revs[1]
1041 node2 = revs[1]
1042 if len(revs) > 2:
1042 if len(revs) > 2:
1043 raise util.Abort(_("too many revisions to diff"))
1043 raise util.Abort(_("too many revisions to diff"))
1044
1044
1045 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1045 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
1046
1046
1047 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1047 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1048 text=opts['text'])
1048 text=opts['text'])
1049
1049
1050 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1050 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1051 node = repo.lookup(changeset)
1051 node = repo.lookup(changeset)
1052 prev, other = repo.changelog.parents(node)
1052 prev, other = repo.changelog.parents(node)
1053 change = repo.changelog.read(node)
1053 change = repo.changelog.read(node)
1054
1054
1055 fp = make_file(repo, repo.changelog, opts['output'],
1055 fp = make_file(repo, repo.changelog, opts['output'],
1056 node=node, total=total, seqno=seqno,
1056 node=node, total=total, seqno=seqno,
1057 revwidth=revwidth)
1057 revwidth=revwidth)
1058 if fp != sys.stdout:
1058 if fp != sys.stdout:
1059 ui.note("%s\n" % fp.name)
1059 ui.note("%s\n" % fp.name)
1060
1060
1061 fp.write("# HG changeset patch\n")
1061 fp.write("# HG changeset patch\n")
1062 fp.write("# User %s\n" % change[1])
1062 fp.write("# User %s\n" % change[1])
1063 fp.write("# Node ID %s\n" % hex(node))
1063 fp.write("# Node ID %s\n" % hex(node))
1064 fp.write("# Parent %s\n" % hex(prev))
1064 fp.write("# Parent %s\n" % hex(prev))
1065 if other != nullid:
1065 if other != nullid:
1066 fp.write("# Parent %s\n" % hex(other))
1066 fp.write("# Parent %s\n" % hex(other))
1067 fp.write(change[4].rstrip())
1067 fp.write(change[4].rstrip())
1068 fp.write("\n\n")
1068 fp.write("\n\n")
1069
1069
1070 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1070 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1071 if fp != sys.stdout:
1071 if fp != sys.stdout:
1072 fp.close()
1072 fp.close()
1073
1073
1074 def export(ui, repo, *changesets, **opts):
1074 def export(ui, repo, *changesets, **opts):
1075 """dump the header and diffs for one or more changesets
1075 """dump the header and diffs for one or more changesets
1076
1076
1077 Print the changeset header and diffs for one or more revisions.
1077 Print the changeset header and diffs for one or more revisions.
1078
1078
1079 The information shown in the changeset header is: author,
1079 The information shown in the changeset header is: author,
1080 changeset hash, parent and commit comment.
1080 changeset hash, parent and commit comment.
1081
1081
1082 Output may be to a file, in which case the name of the file is
1082 Output may be to a file, in which case the name of the file is
1083 given using a format string. The formatting rules are as follows:
1083 given using a format string. The formatting rules are as follows:
1084
1084
1085 %% literal "%" character
1085 %% literal "%" character
1086 %H changeset hash (40 bytes of hexadecimal)
1086 %H changeset hash (40 bytes of hexadecimal)
1087 %N number of patches being generated
1087 %N number of patches being generated
1088 %R changeset revision number
1088 %R changeset revision number
1089 %b basename of the exporting repository
1089 %b basename of the exporting repository
1090 %h short-form changeset hash (12 bytes of hexadecimal)
1090 %h short-form changeset hash (12 bytes of hexadecimal)
1091 %n zero-padded sequence number, starting at 1
1091 %n zero-padded sequence number, starting at 1
1092 %r zero-padded changeset revision number
1092 %r zero-padded changeset revision number
1093
1093
1094 Without the -a option, export will avoid generating diffs of files
1094 Without the -a option, export will avoid generating diffs of files
1095 it detects as binary. With -a, export will generate a diff anyway,
1095 it detects as binary. With -a, export will generate a diff anyway,
1096 probably with undesirable results.
1096 probably with undesirable results.
1097 """
1097 """
1098 if not changesets:
1098 if not changesets:
1099 raise util.Abort(_("export requires at least one changeset"))
1099 raise util.Abort(_("export requires at least one changeset"))
1100 seqno = 0
1100 seqno = 0
1101 revs = list(revrange(ui, repo, changesets))
1101 revs = list(revrange(ui, repo, changesets))
1102 total = len(revs)
1102 total = len(revs)
1103 revwidth = max(map(len, revs))
1103 revwidth = max(map(len, revs))
1104 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1104 ui.note(len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n"))
1105 for cset in revs:
1105 for cset in revs:
1106 seqno += 1
1106 seqno += 1
1107 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1107 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1108
1108
1109 def forget(ui, repo, *pats, **opts):
1109 def forget(ui, repo, *pats, **opts):
1110 """don't add the specified files on the next commit
1110 """don't add the specified files on the next commit
1111
1111
1112 Undo an 'hg add' scheduled for the next commit.
1112 Undo an 'hg add' scheduled for the next commit.
1113 """
1113 """
1114 forget = []
1114 forget = []
1115 for src, abs, rel, exact in walk(repo, pats, opts):
1115 for src, abs, rel, exact in walk(repo, pats, opts):
1116 if repo.dirstate.state(abs) == 'a':
1116 if repo.dirstate.state(abs) == 'a':
1117 forget.append(abs)
1117 forget.append(abs)
1118 if ui.verbose or not exact:
1118 if ui.verbose or not exact:
1119 ui.status(_('forgetting %s\n') % rel)
1119 ui.status(_('forgetting %s\n') % rel)
1120 repo.forget(forget)
1120 repo.forget(forget)
1121
1121
1122 def grep(ui, repo, pattern, *pats, **opts):
1122 def grep(ui, repo, pattern, *pats, **opts):
1123 """search for a pattern in specified files and revisions
1123 """search for a pattern in specified files and revisions
1124
1124
1125 Search revisions of files for a regular expression.
1125 Search revisions of files for a regular expression.
1126
1126
1127 This command behaves differently than Unix grep. It only accepts
1127 This command behaves differently than Unix grep. It only accepts
1128 Python/Perl regexps. It searches repository history, not the
1128 Python/Perl regexps. It searches repository history, not the
1129 working directory. It always prints the revision number in which
1129 working directory. It always prints the revision number in which
1130 a match appears.
1130 a match appears.
1131
1131
1132 By default, grep only prints output for the first revision of a
1132 By default, grep only prints output for the first revision of a
1133 file in which it finds a match. To get it to print every revision
1133 file in which it finds a match. To get it to print every revision
1134 that contains a change in match status ("-" for a match that
1134 that contains a change in match status ("-" for a match that
1135 becomes a non-match, or "+" for a non-match that becomes a match),
1135 becomes a non-match, or "+" for a non-match that becomes a match),
1136 use the --all flag.
1136 use the --all flag.
1137 """
1137 """
1138 reflags = 0
1138 reflags = 0
1139 if opts['ignore_case']:
1139 if opts['ignore_case']:
1140 reflags |= re.I
1140 reflags |= re.I
1141 regexp = re.compile(pattern, reflags)
1141 regexp = re.compile(pattern, reflags)
1142 sep, eol = ':', '\n'
1142 sep, eol = ':', '\n'
1143 if opts['print0']:
1143 if opts['print0']:
1144 sep = eol = '\0'
1144 sep = eol = '\0'
1145
1145
1146 fcache = {}
1146 fcache = {}
1147 def getfile(fn):
1147 def getfile(fn):
1148 if fn not in fcache:
1148 if fn not in fcache:
1149 fcache[fn] = repo.file(fn)
1149 fcache[fn] = repo.file(fn)
1150 return fcache[fn]
1150 return fcache[fn]
1151
1151
1152 def matchlines(body):
1152 def matchlines(body):
1153 begin = 0
1153 begin = 0
1154 linenum = 0
1154 linenum = 0
1155 while True:
1155 while True:
1156 match = regexp.search(body, begin)
1156 match = regexp.search(body, begin)
1157 if not match:
1157 if not match:
1158 break
1158 break
1159 mstart, mend = match.span()
1159 mstart, mend = match.span()
1160 linenum += body.count('\n', begin, mstart) + 1
1160 linenum += body.count('\n', begin, mstart) + 1
1161 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1161 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1162 lend = body.find('\n', mend)
1162 lend = body.find('\n', mend)
1163 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1163 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1164 begin = lend + 1
1164 begin = lend + 1
1165
1165
1166 class linestate:
1166 class linestate:
1167 def __init__(self, line, linenum, colstart, colend):
1167 def __init__(self, line, linenum, colstart, colend):
1168 self.line = line
1168 self.line = line
1169 self.linenum = linenum
1169 self.linenum = linenum
1170 self.colstart = colstart
1170 self.colstart = colstart
1171 self.colend = colend
1171 self.colend = colend
1172 def __eq__(self, other):
1172 def __eq__(self, other):
1173 return self.line == other.line
1173 return self.line == other.line
1174 def __hash__(self):
1174 def __hash__(self):
1175 return hash(self.line)
1175 return hash(self.line)
1176
1176
1177 matches = {}
1177 matches = {}
1178 def grepbody(fn, rev, body):
1178 def grepbody(fn, rev, body):
1179 matches[rev].setdefault(fn, {})
1179 matches[rev].setdefault(fn, {})
1180 m = matches[rev][fn]
1180 m = matches[rev][fn]
1181 for lnum, cstart, cend, line in matchlines(body):
1181 for lnum, cstart, cend, line in matchlines(body):
1182 s = linestate(line, lnum, cstart, cend)
1182 s = linestate(line, lnum, cstart, cend)
1183 m[s] = s
1183 m[s] = s
1184
1184
1185 prev = {}
1185 prev = {}
1186 ucache = {}
1186 ucache = {}
1187 def display(fn, rev, states, prevstates):
1187 def display(fn, rev, states, prevstates):
1188 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1188 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1189 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1189 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1190 counts = {'-': 0, '+': 0}
1190 counts = {'-': 0, '+': 0}
1191 filerevmatches = {}
1191 filerevmatches = {}
1192 for l in diff:
1192 for l in diff:
1193 if incrementing or not opts['all']:
1193 if incrementing or not opts['all']:
1194 change = ((l in prevstates) and '-') or '+'
1194 change = ((l in prevstates) and '-') or '+'
1195 r = rev
1195 r = rev
1196 else:
1196 else:
1197 change = ((l in states) and '-') or '+'
1197 change = ((l in states) and '-') or '+'
1198 r = prev[fn]
1198 r = prev[fn]
1199 cols = [fn, str(rev)]
1199 cols = [fn, str(rev)]
1200 if opts['line_number']: cols.append(str(l.linenum))
1200 if opts['line_number']: cols.append(str(l.linenum))
1201 if opts['all']: cols.append(change)
1201 if opts['all']: cols.append(change)
1202 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1202 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1203 ucache))
1203 ucache))
1204 if opts['files_with_matches']:
1204 if opts['files_with_matches']:
1205 c = (fn, rev)
1205 c = (fn, rev)
1206 if c in filerevmatches: continue
1206 if c in filerevmatches: continue
1207 filerevmatches[c] = 1
1207 filerevmatches[c] = 1
1208 else:
1208 else:
1209 cols.append(l.line)
1209 cols.append(l.line)
1210 ui.write(sep.join(cols), eol)
1210 ui.write(sep.join(cols), eol)
1211 counts[change] += 1
1211 counts[change] += 1
1212 return counts['+'], counts['-']
1212 return counts['+'], counts['-']
1213
1213
1214 fstate = {}
1214 fstate = {}
1215 skip = {}
1215 skip = {}
1216 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1216 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1217 count = 0
1217 count = 0
1218 incrementing = False
1218 incrementing = False
1219 for st, rev, fns in changeiter:
1219 for st, rev, fns in changeiter:
1220 if st == 'window':
1220 if st == 'window':
1221 incrementing = rev
1221 incrementing = rev
1222 matches.clear()
1222 matches.clear()
1223 elif st == 'add':
1223 elif st == 'add':
1224 change = repo.changelog.read(repo.lookup(str(rev)))
1224 change = repo.changelog.read(repo.lookup(str(rev)))
1225 mf = repo.manifest.read(change[0])
1225 mf = repo.manifest.read(change[0])
1226 matches[rev] = {}
1226 matches[rev] = {}
1227 for fn in fns:
1227 for fn in fns:
1228 if fn in skip: continue
1228 if fn in skip: continue
1229 fstate.setdefault(fn, {})
1229 fstate.setdefault(fn, {})
1230 try:
1230 try:
1231 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1231 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1232 except KeyError:
1232 except KeyError:
1233 pass
1233 pass
1234 elif st == 'iter':
1234 elif st == 'iter':
1235 states = matches[rev].items()
1235 states = matches[rev].items()
1236 states.sort()
1236 states.sort()
1237 for fn, m in states:
1237 for fn, m in states:
1238 if fn in skip: continue
1238 if fn in skip: continue
1239 if incrementing or not opts['all'] or fstate[fn]:
1239 if incrementing or not opts['all'] or fstate[fn]:
1240 pos, neg = display(fn, rev, m, fstate[fn])
1240 pos, neg = display(fn, rev, m, fstate[fn])
1241 count += pos + neg
1241 count += pos + neg
1242 if pos and not opts['all']:
1242 if pos and not opts['all']:
1243 skip[fn] = True
1243 skip[fn] = True
1244 fstate[fn] = m
1244 fstate[fn] = m
1245 prev[fn] = rev
1245 prev[fn] = rev
1246
1246
1247 if not incrementing:
1247 if not incrementing:
1248 fstate = fstate.items()
1248 fstate = fstate.items()
1249 fstate.sort()
1249 fstate.sort()
1250 for fn, state in fstate:
1250 for fn, state in fstate:
1251 if fn in skip: continue
1251 if fn in skip: continue
1252 display(fn, rev, {}, state)
1252 display(fn, rev, {}, state)
1253 return (count == 0 and 1) or 0
1253 return (count == 0 and 1) or 0
1254
1254
1255 def heads(ui, repo, **opts):
1255 def heads(ui, repo, **opts):
1256 """show current repository heads
1256 """show current repository heads
1257
1257
1258 Show all repository head changesets.
1258 Show all repository head changesets.
1259
1259
1260 Repository "heads" are changesets that don't have children
1260 Repository "heads" are changesets that don't have children
1261 changesets. They are where development generally takes place and
1261 changesets. They are where development generally takes place and
1262 are the usual targets for update and merge operations.
1262 are the usual targets for update and merge operations.
1263 """
1263 """
1264 heads = repo.changelog.heads()
1264 heads = repo.changelog.heads()
1265 br = None
1265 br = None
1266 if opts['branches']:
1266 if opts['branches']:
1267 br = repo.branchlookup(heads)
1267 br = repo.branchlookup(heads)
1268 for n in repo.changelog.heads():
1268 for n in repo.changelog.heads():
1269 show_changeset(ui, repo, changenode=n, brinfo=br)
1269 show_changeset(ui, repo, changenode=n, brinfo=br)
1270
1270
1271 def identify(ui, repo):
1271 def identify(ui, repo):
1272 """print information about the working copy
1272 """print information about the working copy
1273 Print a short summary of the current state of the repo.
1273 Print a short summary of the current state of the repo.
1274
1274
1275 This summary identifies the repository state using one or two parent
1275 This summary identifies the repository state using one or two parent
1276 hash identifiers, followed by a "+" if there are uncommitted changes
1276 hash identifiers, followed by a "+" if there are uncommitted changes
1277 in the working directory, followed by a list of tags for this revision.
1277 in the working directory, followed by a list of tags for this revision.
1278 """
1278 """
1279 parents = [p for p in repo.dirstate.parents() if p != nullid]
1279 parents = [p for p in repo.dirstate.parents() if p != nullid]
1280 if not parents:
1280 if not parents:
1281 ui.write(_("unknown\n"))
1281 ui.write(_("unknown\n"))
1282 return
1282 return
1283
1283
1284 hexfunc = ui.verbose and hex or short
1284 hexfunc = ui.verbose and hex or short
1285 (c, a, d, u) = repo.changes()
1285 (c, a, d, u) = repo.changes()
1286 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1286 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1287 (c or a or d) and "+" or "")]
1287 (c or a or d) and "+" or "")]
1288
1288
1289 if not ui.quiet:
1289 if not ui.quiet:
1290 # multiple tags for a single parent separated by '/'
1290 # multiple tags for a single parent separated by '/'
1291 parenttags = ['/'.join(tags)
1291 parenttags = ['/'.join(tags)
1292 for tags in map(repo.nodetags, parents) if tags]
1292 for tags in map(repo.nodetags, parents) if tags]
1293 # tags for multiple parents separated by ' + '
1293 # tags for multiple parents separated by ' + '
1294 if parenttags:
1294 if parenttags:
1295 output.append(' + '.join(parenttags))
1295 output.append(' + '.join(parenttags))
1296
1296
1297 ui.write("%s\n" % ' '.join(output))
1297 ui.write("%s\n" % ' '.join(output))
1298
1298
1299 def import_(ui, repo, patch1, *patches, **opts):
1299 def import_(ui, repo, patch1, *patches, **opts):
1300 """import an ordered set of patches
1300 """import an ordered set of patches
1301
1301
1302 Import a list of patches and commit them individually.
1302 Import a list of patches and commit them individually.
1303
1303
1304 If there are outstanding changes in the working directory, import
1304 If there are outstanding changes in the working directory, import
1305 will abort unless given the -f flag.
1305 will abort unless given the -f flag.
1306
1306
1307 If a patch looks like a mail message (its first line starts with
1307 If a patch looks like a mail message (its first line starts with
1308 "From " or looks like an RFC822 header), it will not be applied
1308 "From " or looks like an RFC822 header), it will not be applied
1309 unless the -f option is used. The importer neither parses nor
1309 unless the -f option is used. The importer neither parses nor
1310 discards mail headers, so use -f only to override the "mailness"
1310 discards mail headers, so use -f only to override the "mailness"
1311 safety check, not to import a real mail message.
1311 safety check, not to import a real mail message.
1312 """
1312 """
1313 patches = (patch1,) + patches
1313 patches = (patch1,) + patches
1314
1314
1315 if not opts['force']:
1315 if not opts['force']:
1316 (c, a, d, u) = repo.changes()
1316 (c, a, d, u) = repo.changes()
1317 if c or a or d:
1317 if c or a or d:
1318 raise util.Abort(_("outstanding uncommitted changes"))
1318 raise util.Abort(_("outstanding uncommitted changes"))
1319
1319
1320 d = opts["base"]
1320 d = opts["base"]
1321 strip = opts["strip"]
1321 strip = opts["strip"]
1322
1322
1323 mailre = re.compile(r'(?:From |[\w-]+:)')
1323 mailre = re.compile(r'(?:From |[\w-]+:)')
1324
1324
1325 # attempt to detect the start of a patch
1325 # attempt to detect the start of a patch
1326 # (this heuristic is borrowed from quilt)
1326 # (this heuristic is borrowed from quilt)
1327 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1327 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1328 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1328 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1329 '(---|\*\*\*)[ \t])')
1329 '(---|\*\*\*)[ \t])')
1330
1330
1331 for patch in patches:
1331 for patch in patches:
1332 ui.status(_("applying %s\n") % patch)
1332 ui.status(_("applying %s\n") % patch)
1333 pf = os.path.join(d, patch)
1333 pf = os.path.join(d, patch)
1334
1334
1335 message = []
1335 message = []
1336 user = None
1336 user = None
1337 hgpatch = False
1337 hgpatch = False
1338 for line in file(pf):
1338 for line in file(pf):
1339 line = line.rstrip()
1339 line = line.rstrip()
1340 if (not message and not hgpatch and
1340 if (not message and not hgpatch and
1341 mailre.match(line) and not opts['force']):
1341 mailre.match(line) and not opts['force']):
1342 if len(line) > 35: line = line[:32] + '...'
1342 if len(line) > 35: line = line[:32] + '...'
1343 raise util.Abort(_('first line looks like a '
1343 raise util.Abort(_('first line looks like a '
1344 'mail header: ') + line)
1344 'mail header: ') + line)
1345 if diffre.match(line):
1345 if diffre.match(line):
1346 break
1346 break
1347 elif hgpatch:
1347 elif hgpatch:
1348 # parse values when importing the result of an hg export
1348 # parse values when importing the result of an hg export
1349 if line.startswith("# User "):
1349 if line.startswith("# User "):
1350 user = line[7:]
1350 user = line[7:]
1351 ui.debug(_('User: %s\n') % user)
1351 ui.debug(_('User: %s\n') % user)
1352 elif not line.startswith("# ") and line:
1352 elif not line.startswith("# ") and line:
1353 message.append(line)
1353 message.append(line)
1354 hgpatch = False
1354 hgpatch = False
1355 elif line == '# HG changeset patch':
1355 elif line == '# HG changeset patch':
1356 hgpatch = True
1356 hgpatch = True
1357 message = [] # We may have collected garbage
1357 message = [] # We may have collected garbage
1358 else:
1358 else:
1359 message.append(line)
1359 message.append(line)
1360
1360
1361 # make sure message isn't empty
1361 # make sure message isn't empty
1362 if not message:
1362 if not message:
1363 message = _("imported patch %s\n") % patch
1363 message = _("imported patch %s\n") % patch
1364 else:
1364 else:
1365 message = "%s\n" % '\n'.join(message)
1365 message = "%s\n" % '\n'.join(message)
1366 ui.debug(_('message:\n%s\n') % message)
1366 ui.debug(_('message:\n%s\n') % message)
1367
1367
1368 files = util.patch(strip, pf, ui)
1368 files = util.patch(strip, pf, ui)
1369
1369
1370 if len(files) > 0:
1370 if len(files) > 0:
1371 addremove(ui, repo, *files)
1371 addremove(ui, repo, *files)
1372 repo.commit(files, message, user)
1372 repo.commit(files, message, user)
1373
1373
1374 def incoming(ui, repo, source="default", **opts):
1374 def incoming(ui, repo, source="default", **opts):
1375 """show new changesets found in source
1375 """show new changesets found in source
1376
1376
1377 Show new changesets found in the specified repo or the default
1377 Show new changesets found in the specified repo or the default
1378 pull repo. These are the changesets that would be pulled if a pull
1378 pull repo. These are the changesets that would be pulled if a pull
1379 was requested.
1379 was requested.
1380
1380
1381 Currently only local repositories are supported.
1381 Currently only local repositories are supported.
1382 """
1382 """
1383 source = ui.expandpath(source)
1383 source = ui.expandpath(source)
1384 other = hg.repository(ui, source)
1384 other = hg.repository(ui, source)
1385 if not other.local():
1385 if not other.local():
1386 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1386 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1387 o = repo.findincoming(other)
1387 o = repo.findincoming(other)
1388 if not o:
1388 if not o:
1389 return
1389 return
1390 o = other.newer(o)
1390 o = other.newer(o)
1391 if opts['newest_first']:
1392 o.reverse()
1391 for n in o:
1393 for n in o:
1392 parents = [p for p in other.changelog.parents(n) if p != nullid]
1394 parents = [p for p in other.changelog.parents(n) if p != nullid]
1393 if opts['no_merges'] and len(parents) == 2:
1395 if opts['no_merges'] and len(parents) == 2:
1394 continue
1396 continue
1395 show_changeset(ui, other, changenode=n)
1397 show_changeset(ui, other, changenode=n)
1396 if opts['patch']:
1398 if opts['patch']:
1397 prev = (parents and parents[0]) or nullid
1399 prev = (parents and parents[0]) or nullid
1398 dodiff(ui, ui, other, prev, n)
1400 dodiff(ui, ui, other, prev, n)
1399 ui.write("\n")
1401 ui.write("\n")
1400
1402
1401 def init(ui, dest="."):
1403 def init(ui, dest="."):
1402 """create a new repository in the given directory
1404 """create a new repository in the given directory
1403
1405
1404 Initialize a new repository in the given directory. If the given
1406 Initialize a new repository in the given directory. If the given
1405 directory does not exist, it is created.
1407 directory does not exist, it is created.
1406
1408
1407 If no directory is given, the current directory is used.
1409 If no directory is given, the current directory is used.
1408 """
1410 """
1409 if not os.path.exists(dest):
1411 if not os.path.exists(dest):
1410 os.mkdir(dest)
1412 os.mkdir(dest)
1411 hg.repository(ui, dest, create=1)
1413 hg.repository(ui, dest, create=1)
1412
1414
1413 def locate(ui, repo, *pats, **opts):
1415 def locate(ui, repo, *pats, **opts):
1414 """locate files matching specific patterns
1416 """locate files matching specific patterns
1415
1417
1416 Print all files under Mercurial control whose names match the
1418 Print all files under Mercurial control whose names match the
1417 given patterns.
1419 given patterns.
1418
1420
1419 This command searches the current directory and its
1421 This command searches the current directory and its
1420 subdirectories. To search an entire repository, move to the root
1422 subdirectories. To search an entire repository, move to the root
1421 of the repository.
1423 of the repository.
1422
1424
1423 If no patterns are given to match, this command prints all file
1425 If no patterns are given to match, this command prints all file
1424 names.
1426 names.
1425
1427
1426 If you want to feed the output of this command into the "xargs"
1428 If you want to feed the output of this command into the "xargs"
1427 command, use the "-0" option to both this command and "xargs".
1429 command, use the "-0" option to both this command and "xargs".
1428 This will avoid the problem of "xargs" treating single filenames
1430 This will avoid the problem of "xargs" treating single filenames
1429 that contain white space as multiple filenames.
1431 that contain white space as multiple filenames.
1430 """
1432 """
1431 end = opts['print0'] and '\0' or '\n'
1433 end = opts['print0'] and '\0' or '\n'
1432
1434
1433 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1435 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1434 if repo.dirstate.state(abs) == '?':
1436 if repo.dirstate.state(abs) == '?':
1435 continue
1437 continue
1436 if opts['fullpath']:
1438 if opts['fullpath']:
1437 ui.write(os.path.join(repo.root, abs), end)
1439 ui.write(os.path.join(repo.root, abs), end)
1438 else:
1440 else:
1439 ui.write(rel, end)
1441 ui.write(rel, end)
1440
1442
1441 def log(ui, repo, *pats, **opts):
1443 def log(ui, repo, *pats, **opts):
1442 """show revision history of entire repository or files
1444 """show revision history of entire repository or files
1443
1445
1444 Print the revision history of the specified files or the entire project.
1446 Print the revision history of the specified files or the entire project.
1445
1447
1446 By default this command outputs: changeset id and hash, tags,
1448 By default this command outputs: changeset id and hash, tags,
1447 parents, user, date and time, and a summary for each commit. The
1449 parents, user, date and time, and a summary for each commit. The
1448 -v switch adds some more detail, such as changed files, manifest
1450 -v switch adds some more detail, such as changed files, manifest
1449 hashes or message signatures.
1451 hashes or message signatures.
1450 """
1452 """
1451 class dui:
1453 class dui:
1452 # Implement and delegate some ui protocol. Save hunks of
1454 # Implement and delegate some ui protocol. Save hunks of
1453 # output for later display in the desired order.
1455 # output for later display in the desired order.
1454 def __init__(self, ui):
1456 def __init__(self, ui):
1455 self.ui = ui
1457 self.ui = ui
1456 self.hunk = {}
1458 self.hunk = {}
1457 def bump(self, rev):
1459 def bump(self, rev):
1458 self.rev = rev
1460 self.rev = rev
1459 self.hunk[rev] = []
1461 self.hunk[rev] = []
1460 def note(self, *args):
1462 def note(self, *args):
1461 if self.verbose:
1463 if self.verbose:
1462 self.write(*args)
1464 self.write(*args)
1463 def status(self, *args):
1465 def status(self, *args):
1464 if not self.quiet:
1466 if not self.quiet:
1465 self.write(*args)
1467 self.write(*args)
1466 def write(self, *args):
1468 def write(self, *args):
1467 self.hunk[self.rev].append(args)
1469 self.hunk[self.rev].append(args)
1468 def debug(self, *args):
1470 def debug(self, *args):
1469 if self.debugflag:
1471 if self.debugflag:
1470 self.write(*args)
1472 self.write(*args)
1471 def __getattr__(self, key):
1473 def __getattr__(self, key):
1472 return getattr(self.ui, key)
1474 return getattr(self.ui, key)
1473 cwd = repo.getcwd()
1475 cwd = repo.getcwd()
1474 if not pats and cwd:
1476 if not pats and cwd:
1475 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1477 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1476 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1478 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1477 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1479 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1478 pats, opts)
1480 pats, opts)
1479 for st, rev, fns in changeiter:
1481 for st, rev, fns in changeiter:
1480 if st == 'window':
1482 if st == 'window':
1481 du = dui(ui)
1483 du = dui(ui)
1482 elif st == 'add':
1484 elif st == 'add':
1483 du.bump(rev)
1485 du.bump(rev)
1484 changenode = repo.changelog.node(rev)
1486 changenode = repo.changelog.node(rev)
1485 parents = [p for p in repo.changelog.parents(changenode)
1487 parents = [p for p in repo.changelog.parents(changenode)
1486 if p != nullid]
1488 if p != nullid]
1487 if opts['no_merges'] and len(parents) == 2:
1489 if opts['no_merges'] and len(parents) == 2:
1488 continue
1490 continue
1489 if opts['only_merges'] and len(parents) != 2:
1491 if opts['only_merges'] and len(parents) != 2:
1490 continue
1492 continue
1491
1493
1492 br = None
1494 br = None
1493 if opts['keyword']:
1495 if opts['keyword']:
1494 changes = repo.changelog.read(repo.changelog.node(rev))
1496 changes = repo.changelog.read(repo.changelog.node(rev))
1495 miss = 0
1497 miss = 0
1496 for k in [kw.lower() for kw in opts['keyword']]:
1498 for k in [kw.lower() for kw in opts['keyword']]:
1497 if not (k in changes[1].lower() or
1499 if not (k in changes[1].lower() or
1498 k in changes[4].lower() or
1500 k in changes[4].lower() or
1499 k in " ".join(changes[3][:20]).lower()):
1501 k in " ".join(changes[3][:20]).lower()):
1500 miss = 1
1502 miss = 1
1501 break
1503 break
1502 if miss:
1504 if miss:
1503 continue
1505 continue
1504
1506
1505 if opts['branch']:
1507 if opts['branch']:
1506 br = repo.branchlookup([repo.changelog.node(rev)])
1508 br = repo.branchlookup([repo.changelog.node(rev)])
1507
1509
1508 show_changeset(du, repo, rev, brinfo=br)
1510 show_changeset(du, repo, rev, brinfo=br)
1509 if opts['patch']:
1511 if opts['patch']:
1510 prev = (parents and parents[0]) or nullid
1512 prev = (parents and parents[0]) or nullid
1511 dodiff(du, du, repo, prev, changenode, fns)
1513 dodiff(du, du, repo, prev, changenode, fns)
1512 du.write("\n\n")
1514 du.write("\n\n")
1513 elif st == 'iter':
1515 elif st == 'iter':
1514 for args in du.hunk[rev]:
1516 for args in du.hunk[rev]:
1515 ui.write(*args)
1517 ui.write(*args)
1516
1518
1517 def manifest(ui, repo, rev=None):
1519 def manifest(ui, repo, rev=None):
1518 """output the latest or given revision of the project manifest
1520 """output the latest or given revision of the project manifest
1519
1521
1520 Print a list of version controlled files for the given revision.
1522 Print a list of version controlled files for the given revision.
1521
1523
1522 The manifest is the list of files being version controlled. If no revision
1524 The manifest is the list of files being version controlled. If no revision
1523 is given then the tip is used.
1525 is given then the tip is used.
1524 """
1526 """
1525 if rev:
1527 if rev:
1526 try:
1528 try:
1527 # assume all revision numbers are for changesets
1529 # assume all revision numbers are for changesets
1528 n = repo.lookup(rev)
1530 n = repo.lookup(rev)
1529 change = repo.changelog.read(n)
1531 change = repo.changelog.read(n)
1530 n = change[0]
1532 n = change[0]
1531 except hg.RepoError:
1533 except hg.RepoError:
1532 n = repo.manifest.lookup(rev)
1534 n = repo.manifest.lookup(rev)
1533 else:
1535 else:
1534 n = repo.manifest.tip()
1536 n = repo.manifest.tip()
1535 m = repo.manifest.read(n)
1537 m = repo.manifest.read(n)
1536 mf = repo.manifest.readflags(n)
1538 mf = repo.manifest.readflags(n)
1537 files = m.keys()
1539 files = m.keys()
1538 files.sort()
1540 files.sort()
1539
1541
1540 for f in files:
1542 for f in files:
1541 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1543 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1542
1544
1543 def outgoing(ui, repo, dest="default-push", **opts):
1545 def outgoing(ui, repo, dest="default-push", **opts):
1544 """show changesets not found in destination
1546 """show changesets not found in destination
1545
1547
1546 Show changesets not found in the specified destination repo or the
1548 Show changesets not found in the specified destination repo or the
1547 default push repo. These are the changesets that would be pushed
1549 default push repo. These are the changesets that would be pushed
1548 if a push was requested.
1550 if a push was requested.
1549 """
1551 """
1550 dest = ui.expandpath(dest)
1552 dest = ui.expandpath(dest)
1551 other = hg.repository(ui, dest)
1553 other = hg.repository(ui, dest)
1552 o = repo.findoutgoing(other)
1554 o = repo.findoutgoing(other)
1553 o = repo.newer(o)
1555 o = repo.newer(o)
1556 if opts['newest_first']:
1557 o.reverse()
1554 for n in o:
1558 for n in o:
1555 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1559 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1556 if opts['no_merges'] and len(parents) == 2:
1560 if opts['no_merges'] and len(parents) == 2:
1557 continue
1561 continue
1558 show_changeset(ui, repo, changenode=n)
1562 show_changeset(ui, repo, changenode=n)
1559 if opts['patch']:
1563 if opts['patch']:
1560 prev = (parents and parents[0]) or nullid
1564 prev = (parents and parents[0]) or nullid
1561 dodiff(ui, ui, repo, prev, n)
1565 dodiff(ui, ui, repo, prev, n)
1562 ui.write("\n")
1566 ui.write("\n")
1563
1567
1564 def parents(ui, repo, rev=None):
1568 def parents(ui, repo, rev=None):
1565 """show the parents of the working dir or revision
1569 """show the parents of the working dir or revision
1566
1570
1567 Print the working directory's parent revisions.
1571 Print the working directory's parent revisions.
1568 """
1572 """
1569 if rev:
1573 if rev:
1570 p = repo.changelog.parents(repo.lookup(rev))
1574 p = repo.changelog.parents(repo.lookup(rev))
1571 else:
1575 else:
1572 p = repo.dirstate.parents()
1576 p = repo.dirstate.parents()
1573
1577
1574 for n in p:
1578 for n in p:
1575 if n != nullid:
1579 if n != nullid:
1576 show_changeset(ui, repo, changenode=n)
1580 show_changeset(ui, repo, changenode=n)
1577
1581
1578 def paths(ui, search=None):
1582 def paths(ui, search=None):
1579 """show definition of symbolic path names
1583 """show definition of symbolic path names
1580
1584
1581 Show definition of symbolic path name NAME. If no name is given, show
1585 Show definition of symbolic path name NAME. If no name is given, show
1582 definition of available names.
1586 definition of available names.
1583
1587
1584 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1588 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1585 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1589 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1586 """
1590 """
1587 try:
1591 try:
1588 repo = hg.repository(ui=ui)
1592 repo = hg.repository(ui=ui)
1589 except hg.RepoError:
1593 except hg.RepoError:
1590 pass
1594 pass
1591
1595
1592 if search:
1596 if search:
1593 for name, path in ui.configitems("paths"):
1597 for name, path in ui.configitems("paths"):
1594 if name == search:
1598 if name == search:
1595 ui.write("%s\n" % path)
1599 ui.write("%s\n" % path)
1596 return
1600 return
1597 ui.warn(_("not found!\n"))
1601 ui.warn(_("not found!\n"))
1598 return 1
1602 return 1
1599 else:
1603 else:
1600 for name, path in ui.configitems("paths"):
1604 for name, path in ui.configitems("paths"):
1601 ui.write("%s = %s\n" % (name, path))
1605 ui.write("%s = %s\n" % (name, path))
1602
1606
1603 def pull(ui, repo, source="default", **opts):
1607 def pull(ui, repo, source="default", **opts):
1604 """pull changes from the specified source
1608 """pull changes from the specified source
1605
1609
1606 Pull changes from a remote repository to a local one.
1610 Pull changes from a remote repository to a local one.
1607
1611
1608 This finds all changes from the repository at the specified path
1612 This finds all changes from the repository at the specified path
1609 or URL and adds them to the local repository. By default, this
1613 or URL and adds them to the local repository. By default, this
1610 does not update the copy of the project in the working directory.
1614 does not update the copy of the project in the working directory.
1611
1615
1612 Valid URLs are of the form:
1616 Valid URLs are of the form:
1613
1617
1614 local/filesystem/path
1618 local/filesystem/path
1615 http://[user@]host[:port][/path]
1619 http://[user@]host[:port][/path]
1616 https://[user@]host[:port][/path]
1620 https://[user@]host[:port][/path]
1617 ssh://[user@]host[:port][/path]
1621 ssh://[user@]host[:port][/path]
1618
1622
1619 SSH requires an accessible shell account on the destination machine
1623 SSH requires an accessible shell account on the destination machine
1620 and a copy of hg in the remote path. With SSH, paths are relative
1624 and a copy of hg in the remote path. With SSH, paths are relative
1621 to the remote user's home directory by default; use two slashes at
1625 to the remote user's home directory by default; use two slashes at
1622 the start of a path to specify it as relative to the filesystem root.
1626 the start of a path to specify it as relative to the filesystem root.
1623 """
1627 """
1624 source = ui.expandpath(source)
1628 source = ui.expandpath(source)
1625 ui.status(_('pulling from %s\n') % (source))
1629 ui.status(_('pulling from %s\n') % (source))
1626
1630
1627 if opts['ssh']:
1631 if opts['ssh']:
1628 ui.setconfig("ui", "ssh", opts['ssh'])
1632 ui.setconfig("ui", "ssh", opts['ssh'])
1629 if opts['remotecmd']:
1633 if opts['remotecmd']:
1630 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1634 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1631
1635
1632 other = hg.repository(ui, source)
1636 other = hg.repository(ui, source)
1633 r = repo.pull(other)
1637 r = repo.pull(other)
1634 if not r:
1638 if not r:
1635 if opts['update']:
1639 if opts['update']:
1636 return update(ui, repo)
1640 return update(ui, repo)
1637 else:
1641 else:
1638 ui.status(_("(run 'hg update' to get a working copy)\n"))
1642 ui.status(_("(run 'hg update' to get a working copy)\n"))
1639
1643
1640 return r
1644 return r
1641
1645
1642 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1646 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1643 """push changes to the specified destination
1647 """push changes to the specified destination
1644
1648
1645 Push changes from the local repository to the given destination.
1649 Push changes from the local repository to the given destination.
1646
1650
1647 This is the symmetrical operation for pull. It helps to move
1651 This is the symmetrical operation for pull. It helps to move
1648 changes from the current repository to a different one. If the
1652 changes from the current repository to a different one. If the
1649 destination is local this is identical to a pull in that directory
1653 destination is local this is identical to a pull in that directory
1650 from the current one.
1654 from the current one.
1651
1655
1652 By default, push will refuse to run if it detects the result would
1656 By default, push will refuse to run if it detects the result would
1653 increase the number of remote heads. This generally indicates the
1657 increase the number of remote heads. This generally indicates the
1654 the client has forgotten to sync and merge before pushing.
1658 the client has forgotten to sync and merge before pushing.
1655
1659
1656 Valid URLs are of the form:
1660 Valid URLs are of the form:
1657
1661
1658 local/filesystem/path
1662 local/filesystem/path
1659 ssh://[user@]host[:port][/path]
1663 ssh://[user@]host[:port][/path]
1660
1664
1661 SSH requires an accessible shell account on the destination
1665 SSH requires an accessible shell account on the destination
1662 machine and a copy of hg in the remote path.
1666 machine and a copy of hg in the remote path.
1663 """
1667 """
1664 dest = ui.expandpath(dest)
1668 dest = ui.expandpath(dest)
1665 ui.status('pushing to %s\n' % (dest))
1669 ui.status('pushing to %s\n' % (dest))
1666
1670
1667 if ssh:
1671 if ssh:
1668 ui.setconfig("ui", "ssh", ssh)
1672 ui.setconfig("ui", "ssh", ssh)
1669 if remotecmd:
1673 if remotecmd:
1670 ui.setconfig("ui", "remotecmd", remotecmd)
1674 ui.setconfig("ui", "remotecmd", remotecmd)
1671
1675
1672 other = hg.repository(ui, dest)
1676 other = hg.repository(ui, dest)
1673 r = repo.push(other, force)
1677 r = repo.push(other, force)
1674 return r
1678 return r
1675
1679
1676 def rawcommit(ui, repo, *flist, **rc):
1680 def rawcommit(ui, repo, *flist, **rc):
1677 """raw commit interface
1681 """raw commit interface
1678
1682
1679 Lowlevel commit, for use in helper scripts.
1683 Lowlevel commit, for use in helper scripts.
1680
1684
1681 This command is not intended to be used by normal users, as it is
1685 This command is not intended to be used by normal users, as it is
1682 primarily useful for importing from other SCMs.
1686 primarily useful for importing from other SCMs.
1683 """
1687 """
1684 if rc['text']:
1688 if rc['text']:
1685 ui.warn(_("Warning: -t and --text is deprecated,"
1689 ui.warn(_("Warning: -t and --text is deprecated,"
1686 " please use -m or --message instead.\n"))
1690 " please use -m or --message instead.\n"))
1687 message = rc['message'] or rc['text']
1691 message = rc['message'] or rc['text']
1688 if not message and rc['logfile']:
1692 if not message and rc['logfile']:
1689 try:
1693 try:
1690 message = open(rc['logfile']).read()
1694 message = open(rc['logfile']).read()
1691 except IOError:
1695 except IOError:
1692 pass
1696 pass
1693 if not message and not rc['logfile']:
1697 if not message and not rc['logfile']:
1694 raise util.Abort(_("missing commit message"))
1698 raise util.Abort(_("missing commit message"))
1695
1699
1696 files = relpath(repo, list(flist))
1700 files = relpath(repo, list(flist))
1697 if rc['files']:
1701 if rc['files']:
1698 files += open(rc['files']).read().splitlines()
1702 files += open(rc['files']).read().splitlines()
1699
1703
1700 rc['parent'] = map(repo.lookup, rc['parent'])
1704 rc['parent'] = map(repo.lookup, rc['parent'])
1701
1705
1702 try:
1706 try:
1703 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1707 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1704 except ValueError, inst:
1708 except ValueError, inst:
1705 raise util.Abort(str(inst))
1709 raise util.Abort(str(inst))
1706
1710
1707 def recover(ui, repo):
1711 def recover(ui, repo):
1708 """roll back an interrupted transaction
1712 """roll back an interrupted transaction
1709
1713
1710 Recover from an interrupted commit or pull.
1714 Recover from an interrupted commit or pull.
1711
1715
1712 This command tries to fix the repository status after an interrupted
1716 This command tries to fix the repository status after an interrupted
1713 operation. It should only be necessary when Mercurial suggests it.
1717 operation. It should only be necessary when Mercurial suggests it.
1714 """
1718 """
1715 repo.recover()
1719 repo.recover()
1716
1720
1717 def remove(ui, repo, pat, *pats, **opts):
1721 def remove(ui, repo, pat, *pats, **opts):
1718 """remove the specified files on the next commit
1722 """remove the specified files on the next commit
1719
1723
1720 Schedule the indicated files for removal from the repository.
1724 Schedule the indicated files for removal from the repository.
1721
1725
1722 This command schedules the files to be removed at the next commit.
1726 This command schedules the files to be removed at the next commit.
1723 This only removes files from the current branch, not from the
1727 This only removes files from the current branch, not from the
1724 entire project history. If the files still exist in the working
1728 entire project history. If the files still exist in the working
1725 directory, they will be deleted from it.
1729 directory, they will be deleted from it.
1726 """
1730 """
1727 names = []
1731 names = []
1728 def okaytoremove(abs, rel, exact):
1732 def okaytoremove(abs, rel, exact):
1729 c, a, d, u = repo.changes(files = [abs])
1733 c, a, d, u = repo.changes(files = [abs])
1730 reason = None
1734 reason = None
1731 if c: reason = _('is modified')
1735 if c: reason = _('is modified')
1732 elif a: reason = _('has been marked for add')
1736 elif a: reason = _('has been marked for add')
1733 elif u: reason = _('is not managed')
1737 elif u: reason = _('is not managed')
1734 if reason:
1738 if reason:
1735 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1739 if exact: ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1736 else:
1740 else:
1737 return True
1741 return True
1738 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1742 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1739 if okaytoremove(abs, rel, exact):
1743 if okaytoremove(abs, rel, exact):
1740 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1744 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1741 names.append(abs)
1745 names.append(abs)
1742 repo.remove(names, unlink=True)
1746 repo.remove(names, unlink=True)
1743
1747
1744 def rename(ui, repo, *pats, **opts):
1748 def rename(ui, repo, *pats, **opts):
1745 """rename files; equivalent of copy + remove
1749 """rename files; equivalent of copy + remove
1746
1750
1747 Mark dest as copies of sources; mark sources for deletion. If
1751 Mark dest as copies of sources; mark sources for deletion. If
1748 dest is a directory, copies are put in that directory. If dest is
1752 dest is a directory, copies are put in that directory. If dest is
1749 a file, there can only be one source.
1753 a file, there can only be one source.
1750
1754
1751 By default, this command copies the contents of files as they
1755 By default, this command copies the contents of files as they
1752 stand in the working directory. If invoked with --after, the
1756 stand in the working directory. If invoked with --after, the
1753 operation is recorded, but no copying is performed.
1757 operation is recorded, but no copying is performed.
1754
1758
1755 This command takes effect in the next commit.
1759 This command takes effect in the next commit.
1756
1760
1757 NOTE: This command should be treated as experimental. While it
1761 NOTE: This command should be treated as experimental. While it
1758 should properly record rename files, this information is not yet
1762 should properly record rename files, this information is not yet
1759 fully used by merge, nor fully reported by log.
1763 fully used by merge, nor fully reported by log.
1760 """
1764 """
1761 errs, copied = docopy(ui, repo, pats, opts)
1765 errs, copied = docopy(ui, repo, pats, opts)
1762 names = []
1766 names = []
1763 for abs, rel, exact in copied:
1767 for abs, rel, exact in copied:
1764 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1768 if ui.verbose or not exact: ui.status(_('removing %s\n') % rel)
1765 names.append(abs)
1769 names.append(abs)
1766 repo.remove(names, unlink=True)
1770 repo.remove(names, unlink=True)
1767 return errs
1771 return errs
1768
1772
1769 def revert(ui, repo, *names, **opts):
1773 def revert(ui, repo, *names, **opts):
1770 """revert modified files or dirs back to their unmodified states
1774 """revert modified files or dirs back to their unmodified states
1771
1775
1772 Revert any uncommitted modifications made to the named files or
1776 Revert any uncommitted modifications made to the named files or
1773 directories. This restores the contents of the affected files to
1777 directories. This restores the contents of the affected files to
1774 an unmodified state.
1778 an unmodified state.
1775
1779
1776 If a file has been deleted, it is recreated. If the executable
1780 If a file has been deleted, it is recreated. If the executable
1777 mode of a file was changed, it is reset.
1781 mode of a file was changed, it is reset.
1778
1782
1779 If a directory is given, all files in that directory and its
1783 If a directory is given, all files in that directory and its
1780 subdirectories are reverted.
1784 subdirectories are reverted.
1781
1785
1782 If no arguments are given, all files in the current directory and
1786 If no arguments are given, all files in the current directory and
1783 its subdirectories are reverted.
1787 its subdirectories are reverted.
1784 """
1788 """
1785 node = opts['rev'] and repo.lookup(opts['rev']) or \
1789 node = opts['rev'] and repo.lookup(opts['rev']) or \
1786 repo.dirstate.parents()[0]
1790 repo.dirstate.parents()[0]
1787 root = os.path.realpath(repo.root)
1791 root = os.path.realpath(repo.root)
1788
1792
1789 def trimpath(p):
1793 def trimpath(p):
1790 p = os.path.realpath(p)
1794 p = os.path.realpath(p)
1791 if p.startswith(root):
1795 if p.startswith(root):
1792 rest = p[len(root):]
1796 rest = p[len(root):]
1793 if not rest:
1797 if not rest:
1794 return rest
1798 return rest
1795 if p.startswith(os.sep):
1799 if p.startswith(os.sep):
1796 return rest[1:]
1800 return rest[1:]
1797 return p
1801 return p
1798
1802
1799 relnames = map(trimpath, names or [os.getcwd()])
1803 relnames = map(trimpath, names or [os.getcwd()])
1800 chosen = {}
1804 chosen = {}
1801
1805
1802 def choose(name):
1806 def choose(name):
1803 def body(name):
1807 def body(name):
1804 for r in relnames:
1808 for r in relnames:
1805 if not name.startswith(r):
1809 if not name.startswith(r):
1806 continue
1810 continue
1807 rest = name[len(r):]
1811 rest = name[len(r):]
1808 if not rest:
1812 if not rest:
1809 return r, True
1813 return r, True
1810 depth = rest.count(os.sep)
1814 depth = rest.count(os.sep)
1811 if not r:
1815 if not r:
1812 if depth == 0 or not opts['nonrecursive']:
1816 if depth == 0 or not opts['nonrecursive']:
1813 return r, True
1817 return r, True
1814 elif rest[0] == os.sep:
1818 elif rest[0] == os.sep:
1815 if depth == 1 or not opts['nonrecursive']:
1819 if depth == 1 or not opts['nonrecursive']:
1816 return r, True
1820 return r, True
1817 return None, False
1821 return None, False
1818 relname, ret = body(name)
1822 relname, ret = body(name)
1819 if ret:
1823 if ret:
1820 chosen[relname] = 1
1824 chosen[relname] = 1
1821 return ret
1825 return ret
1822
1826
1823 r = repo.update(node, False, True, choose, False)
1827 r = repo.update(node, False, True, choose, False)
1824 for n in relnames:
1828 for n in relnames:
1825 if n not in chosen:
1829 if n not in chosen:
1826 ui.warn(_('error: no matches for %s\n') % n)
1830 ui.warn(_('error: no matches for %s\n') % n)
1827 r = 1
1831 r = 1
1828 sys.stdout.flush()
1832 sys.stdout.flush()
1829 return r
1833 return r
1830
1834
1831 def root(ui, repo):
1835 def root(ui, repo):
1832 """print the root (top) of the current working dir
1836 """print the root (top) of the current working dir
1833
1837
1834 Print the root directory of the current repository.
1838 Print the root directory of the current repository.
1835 """
1839 """
1836 ui.write(repo.root + "\n")
1840 ui.write(repo.root + "\n")
1837
1841
1838 def serve(ui, repo, **opts):
1842 def serve(ui, repo, **opts):
1839 """export the repository via HTTP
1843 """export the repository via HTTP
1840
1844
1841 Start a local HTTP repository browser and pull server.
1845 Start a local HTTP repository browser and pull server.
1842
1846
1843 By default, the server logs accesses to stdout and errors to
1847 By default, the server logs accesses to stdout and errors to
1844 stderr. Use the "-A" and "-E" options to log to files.
1848 stderr. Use the "-A" and "-E" options to log to files.
1845 """
1849 """
1846
1850
1847 if opts["stdio"]:
1851 if opts["stdio"]:
1848 fin, fout = sys.stdin, sys.stdout
1852 fin, fout = sys.stdin, sys.stdout
1849 sys.stdout = sys.stderr
1853 sys.stdout = sys.stderr
1850
1854
1851 # Prevent insertion/deletion of CRs
1855 # Prevent insertion/deletion of CRs
1852 util.set_binary(fin)
1856 util.set_binary(fin)
1853 util.set_binary(fout)
1857 util.set_binary(fout)
1854
1858
1855 def getarg():
1859 def getarg():
1856 argline = fin.readline()[:-1]
1860 argline = fin.readline()[:-1]
1857 arg, l = argline.split()
1861 arg, l = argline.split()
1858 val = fin.read(int(l))
1862 val = fin.read(int(l))
1859 return arg, val
1863 return arg, val
1860 def respond(v):
1864 def respond(v):
1861 fout.write("%d\n" % len(v))
1865 fout.write("%d\n" % len(v))
1862 fout.write(v)
1866 fout.write(v)
1863 fout.flush()
1867 fout.flush()
1864
1868
1865 lock = None
1869 lock = None
1866
1870
1867 while 1:
1871 while 1:
1868 cmd = fin.readline()[:-1]
1872 cmd = fin.readline()[:-1]
1869 if cmd == '':
1873 if cmd == '':
1870 return
1874 return
1871 if cmd == "heads":
1875 if cmd == "heads":
1872 h = repo.heads()
1876 h = repo.heads()
1873 respond(" ".join(map(hex, h)) + "\n")
1877 respond(" ".join(map(hex, h)) + "\n")
1874 if cmd == "lock":
1878 if cmd == "lock":
1875 lock = repo.lock()
1879 lock = repo.lock()
1876 respond("")
1880 respond("")
1877 if cmd == "unlock":
1881 if cmd == "unlock":
1878 if lock:
1882 if lock:
1879 lock.release()
1883 lock.release()
1880 lock = None
1884 lock = None
1881 respond("")
1885 respond("")
1882 elif cmd == "branches":
1886 elif cmd == "branches":
1883 arg, nodes = getarg()
1887 arg, nodes = getarg()
1884 nodes = map(bin, nodes.split(" "))
1888 nodes = map(bin, nodes.split(" "))
1885 r = []
1889 r = []
1886 for b in repo.branches(nodes):
1890 for b in repo.branches(nodes):
1887 r.append(" ".join(map(hex, b)) + "\n")
1891 r.append(" ".join(map(hex, b)) + "\n")
1888 respond("".join(r))
1892 respond("".join(r))
1889 elif cmd == "between":
1893 elif cmd == "between":
1890 arg, pairs = getarg()
1894 arg, pairs = getarg()
1891 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1895 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1892 r = []
1896 r = []
1893 for b in repo.between(pairs):
1897 for b in repo.between(pairs):
1894 r.append(" ".join(map(hex, b)) + "\n")
1898 r.append(" ".join(map(hex, b)) + "\n")
1895 respond("".join(r))
1899 respond("".join(r))
1896 elif cmd == "changegroup":
1900 elif cmd == "changegroup":
1897 nodes = []
1901 nodes = []
1898 arg, roots = getarg()
1902 arg, roots = getarg()
1899 nodes = map(bin, roots.split(" "))
1903 nodes = map(bin, roots.split(" "))
1900
1904
1901 cg = repo.changegroup(nodes)
1905 cg = repo.changegroup(nodes)
1902 while 1:
1906 while 1:
1903 d = cg.read(4096)
1907 d = cg.read(4096)
1904 if not d:
1908 if not d:
1905 break
1909 break
1906 fout.write(d)
1910 fout.write(d)
1907
1911
1908 fout.flush()
1912 fout.flush()
1909
1913
1910 elif cmd == "addchangegroup":
1914 elif cmd == "addchangegroup":
1911 if not lock:
1915 if not lock:
1912 respond("not locked")
1916 respond("not locked")
1913 continue
1917 continue
1914 respond("")
1918 respond("")
1915
1919
1916 r = repo.addchangegroup(fin)
1920 r = repo.addchangegroup(fin)
1917 respond("")
1921 respond("")
1918
1922
1919 optlist = "name templates style address port ipv6 accesslog errorlog"
1923 optlist = "name templates style address port ipv6 accesslog errorlog"
1920 for o in optlist.split():
1924 for o in optlist.split():
1921 if opts[o]:
1925 if opts[o]:
1922 ui.setconfig("web", o, opts[o])
1926 ui.setconfig("web", o, opts[o])
1923
1927
1924 try:
1928 try:
1925 httpd = hgweb.create_server(repo)
1929 httpd = hgweb.create_server(repo)
1926 except socket.error, inst:
1930 except socket.error, inst:
1927 raise util.Abort('cannot start server: ' + inst.args[1])
1931 raise util.Abort('cannot start server: ' + inst.args[1])
1928
1932
1929 if ui.verbose:
1933 if ui.verbose:
1930 addr, port = httpd.socket.getsockname()
1934 addr, port = httpd.socket.getsockname()
1931 if addr == '0.0.0.0':
1935 if addr == '0.0.0.0':
1932 addr = socket.gethostname()
1936 addr = socket.gethostname()
1933 else:
1937 else:
1934 try:
1938 try:
1935 addr = socket.gethostbyaddr(addr)[0]
1939 addr = socket.gethostbyaddr(addr)[0]
1936 except socket.error:
1940 except socket.error:
1937 pass
1941 pass
1938 if port != 80:
1942 if port != 80:
1939 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1943 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
1940 else:
1944 else:
1941 ui.status(_('listening at http://%s/\n') % addr)
1945 ui.status(_('listening at http://%s/\n') % addr)
1942 httpd.serve_forever()
1946 httpd.serve_forever()
1943
1947
1944 def status(ui, repo, *pats, **opts):
1948 def status(ui, repo, *pats, **opts):
1945 """show changed files in the working directory
1949 """show changed files in the working directory
1946
1950
1947 Show changed files in the working directory. If no names are
1951 Show changed files in the working directory. If no names are
1948 given, all files are shown. Otherwise, only files matching the
1952 given, all files are shown. Otherwise, only files matching the
1949 given names are shown.
1953 given names are shown.
1950
1954
1951 The codes used to show the status of files are:
1955 The codes used to show the status of files are:
1952 M = modified
1956 M = modified
1953 A = added
1957 A = added
1954 R = removed
1958 R = removed
1955 ? = not tracked
1959 ? = not tracked
1956 """
1960 """
1957
1961
1958 cwd = repo.getcwd()
1962 cwd = repo.getcwd()
1959 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1963 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1960 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1964 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1961 for n in repo.changes(files=files, match=matchfn)]
1965 for n in repo.changes(files=files, match=matchfn)]
1962
1966
1963 changetypes = [(_('modified'), 'M', c),
1967 changetypes = [(_('modified'), 'M', c),
1964 (_('added'), 'A', a),
1968 (_('added'), 'A', a),
1965 (_('removed'), 'R', d),
1969 (_('removed'), 'R', d),
1966 (_('unknown'), '?', u)]
1970 (_('unknown'), '?', u)]
1967
1971
1968 end = opts['print0'] and '\0' or '\n'
1972 end = opts['print0'] and '\0' or '\n'
1969
1973
1970 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1974 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1971 or changetypes):
1975 or changetypes):
1972 if opts['no_status']:
1976 if opts['no_status']:
1973 format = "%%s%s" % end
1977 format = "%%s%s" % end
1974 else:
1978 else:
1975 format = "%s %%s%s" % (char, end);
1979 format = "%s %%s%s" % (char, end);
1976
1980
1977 for f in changes:
1981 for f in changes:
1978 ui.write(format % f)
1982 ui.write(format % f)
1979
1983
1980 def tag(ui, repo, name, rev=None, **opts):
1984 def tag(ui, repo, name, rev=None, **opts):
1981 """add a tag for the current tip or a given revision
1985 """add a tag for the current tip or a given revision
1982
1986
1983 Name a particular revision using <name>.
1987 Name a particular revision using <name>.
1984
1988
1985 Tags are used to name particular revisions of the repository and are
1989 Tags are used to name particular revisions of the repository and are
1986 very useful to compare different revision, to go back to significant
1990 very useful to compare different revision, to go back to significant
1987 earlier versions or to mark branch points as releases, etc.
1991 earlier versions or to mark branch points as releases, etc.
1988
1992
1989 If no revision is given, the tip is used.
1993 If no revision is given, the tip is used.
1990
1994
1991 To facilitate version control, distribution, and merging of tags,
1995 To facilitate version control, distribution, and merging of tags,
1992 they are stored as a file named ".hgtags" which is managed
1996 they are stored as a file named ".hgtags" which is managed
1993 similarly to other project files and can be hand-edited if
1997 similarly to other project files and can be hand-edited if
1994 necessary.
1998 necessary.
1995 """
1999 """
1996 if opts['text']:
2000 if opts['text']:
1997 ui.warn(_("Warning: -t and --text is deprecated,"
2001 ui.warn(_("Warning: -t and --text is deprecated,"
1998 " please use -m or --message instead.\n"))
2002 " please use -m or --message instead.\n"))
1999 if name == "tip":
2003 if name == "tip":
2000 raise util.Abort(_("the name 'tip' is reserved"))
2004 raise util.Abort(_("the name 'tip' is reserved"))
2001 if rev:
2005 if rev:
2002 r = hex(repo.lookup(rev))
2006 r = hex(repo.lookup(rev))
2003 else:
2007 else:
2004 r = hex(repo.changelog.tip())
2008 r = hex(repo.changelog.tip())
2005
2009
2006 if name.find(revrangesep) >= 0:
2010 if name.find(revrangesep) >= 0:
2007 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
2011 raise util.Abort(_("'%s' cannot be used in a tag name") % revrangesep)
2008
2012
2009 if opts['local']:
2013 if opts['local']:
2010 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2014 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2011 return
2015 return
2012
2016
2013 (c, a, d, u) = repo.changes()
2017 (c, a, d, u) = repo.changes()
2014 for x in (c, a, d, u):
2018 for x in (c, a, d, u):
2015 if ".hgtags" in x:
2019 if ".hgtags" in x:
2016 raise util.Abort(_("working copy of .hgtags is changed "
2020 raise util.Abort(_("working copy of .hgtags is changed "
2017 "(please commit .hgtags manually)"))
2021 "(please commit .hgtags manually)"))
2018
2022
2019 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2023 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2020 if repo.dirstate.state(".hgtags") == '?':
2024 if repo.dirstate.state(".hgtags") == '?':
2021 repo.add([".hgtags"])
2025 repo.add([".hgtags"])
2022
2026
2023 message = (opts['message'] or opts['text'] or
2027 message = (opts['message'] or opts['text'] or
2024 _("Added tag %s for changeset %s") % (name, r))
2028 _("Added tag %s for changeset %s") % (name, r))
2025 try:
2029 try:
2026 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2030 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2027 except ValueError, inst:
2031 except ValueError, inst:
2028 raise util.Abort(str(inst))
2032 raise util.Abort(str(inst))
2029
2033
2030 def tags(ui, repo):
2034 def tags(ui, repo):
2031 """list repository tags
2035 """list repository tags
2032
2036
2033 List the repository tags.
2037 List the repository tags.
2034
2038
2035 This lists both regular and local tags.
2039 This lists both regular and local tags.
2036 """
2040 """
2037
2041
2038 l = repo.tagslist()
2042 l = repo.tagslist()
2039 l.reverse()
2043 l.reverse()
2040 for t, n in l:
2044 for t, n in l:
2041 try:
2045 try:
2042 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2046 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2043 except KeyError:
2047 except KeyError:
2044 r = " ?:?"
2048 r = " ?:?"
2045 ui.write("%-30s %s\n" % (t, r))
2049 ui.write("%-30s %s\n" % (t, r))
2046
2050
2047 def tip(ui, repo):
2051 def tip(ui, repo):
2048 """show the tip revision
2052 """show the tip revision
2049
2053
2050 Show the tip revision.
2054 Show the tip revision.
2051 """
2055 """
2052 n = repo.changelog.tip()
2056 n = repo.changelog.tip()
2053 show_changeset(ui, repo, changenode=n)
2057 show_changeset(ui, repo, changenode=n)
2054
2058
2055 def unbundle(ui, repo, fname):
2059 def unbundle(ui, repo, fname):
2056 """apply a changegroup file
2060 """apply a changegroup file
2057
2061
2058 Apply a compressed changegroup file generated by the bundle
2062 Apply a compressed changegroup file generated by the bundle
2059 command.
2063 command.
2060 """
2064 """
2061 f = urllib.urlopen(fname)
2065 f = urllib.urlopen(fname)
2062
2066
2063 if f.read(4) != "HG10":
2067 if f.read(4) != "HG10":
2064 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2068 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2065
2069
2066 def bzgenerator(f):
2070 def bzgenerator(f):
2067 zd = bz2.BZ2Decompressor()
2071 zd = bz2.BZ2Decompressor()
2068 for chunk in f:
2072 for chunk in f:
2069 yield zd.decompress(chunk)
2073 yield zd.decompress(chunk)
2070
2074
2071 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2075 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2072 repo.addchangegroup(util.chunkbuffer(bzgen))
2076 repo.addchangegroup(util.chunkbuffer(bzgen))
2073
2077
2074 def undo(ui, repo):
2078 def undo(ui, repo):
2075 """undo the last commit or pull
2079 """undo the last commit or pull
2076
2080
2077 Roll back the last pull or commit transaction on the
2081 Roll back the last pull or commit transaction on the
2078 repository, restoring the project to its earlier state.
2082 repository, restoring the project to its earlier state.
2079
2083
2080 This command should be used with care. There is only one level of
2084 This command should be used with care. There is only one level of
2081 undo and there is no redo.
2085 undo and there is no redo.
2082
2086
2083 This command is not intended for use on public repositories. Once
2087 This command is not intended for use on public repositories. Once
2084 a change is visible for pull by other users, undoing it locally is
2088 a change is visible for pull by other users, undoing it locally is
2085 ineffective.
2089 ineffective.
2086 """
2090 """
2087 repo.undo()
2091 repo.undo()
2088
2092
2089 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2093 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
2090 """update or merge working directory
2094 """update or merge working directory
2091
2095
2092 Update the working directory to the specified revision.
2096 Update the working directory to the specified revision.
2093
2097
2094 If there are no outstanding changes in the working directory and
2098 If there are no outstanding changes in the working directory and
2095 there is a linear relationship between the current version and the
2099 there is a linear relationship between the current version and the
2096 requested version, the result is the requested version.
2100 requested version, the result is the requested version.
2097
2101
2098 Otherwise the result is a merge between the contents of the
2102 Otherwise the result is a merge between the contents of the
2099 current working directory and the requested version. Files that
2103 current working directory and the requested version. Files that
2100 changed between either parent are marked as changed for the next
2104 changed between either parent are marked as changed for the next
2101 commit and a commit must be performed before any further updates
2105 commit and a commit must be performed before any further updates
2102 are allowed.
2106 are allowed.
2103
2107
2104 By default, update will refuse to run if doing so would require
2108 By default, update will refuse to run if doing so would require
2105 merging or discarding local changes.
2109 merging or discarding local changes.
2106 """
2110 """
2107 if branch:
2111 if branch:
2108 br = repo.branchlookup(branch=branch)
2112 br = repo.branchlookup(branch=branch)
2109 found = []
2113 found = []
2110 for x in br:
2114 for x in br:
2111 if branch in br[x]:
2115 if branch in br[x]:
2112 found.append(x)
2116 found.append(x)
2113 if len(found) > 1:
2117 if len(found) > 1:
2114 ui.warn(_("Found multiple heads for %s\n") % branch)
2118 ui.warn(_("Found multiple heads for %s\n") % branch)
2115 for x in found:
2119 for x in found:
2116 show_changeset(ui, repo, changenode=x, brinfo=br)
2120 show_changeset(ui, repo, changenode=x, brinfo=br)
2117 return 1
2121 return 1
2118 if len(found) == 1:
2122 if len(found) == 1:
2119 node = found[0]
2123 node = found[0]
2120 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2124 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2121 else:
2125 else:
2122 ui.warn(_("branch %s not found\n") % (branch))
2126 ui.warn(_("branch %s not found\n") % (branch))
2123 return 1
2127 return 1
2124 else:
2128 else:
2125 node = node and repo.lookup(node) or repo.changelog.tip()
2129 node = node and repo.lookup(node) or repo.changelog.tip()
2126 return repo.update(node, allow=merge, force=clean)
2130 return repo.update(node, allow=merge, force=clean)
2127
2131
2128 def verify(ui, repo):
2132 def verify(ui, repo):
2129 """verify the integrity of the repository
2133 """verify the integrity of the repository
2130
2134
2131 Verify the integrity of the current repository.
2135 Verify the integrity of the current repository.
2132
2136
2133 This will perform an extensive check of the repository's
2137 This will perform an extensive check of the repository's
2134 integrity, validating the hashes and checksums of each entry in
2138 integrity, validating the hashes and checksums of each entry in
2135 the changelog, manifest, and tracked files, as well as the
2139 the changelog, manifest, and tracked files, as well as the
2136 integrity of their crosslinks and indices.
2140 integrity of their crosslinks and indices.
2137 """
2141 """
2138 return repo.verify()
2142 return repo.verify()
2139
2143
2140 # Command options and aliases are listed here, alphabetically
2144 # Command options and aliases are listed here, alphabetically
2141
2145
2142 table = {
2146 table = {
2143 "^add":
2147 "^add":
2144 (add,
2148 (add,
2145 [('I', 'include', [], _('include names matching the given patterns')),
2149 [('I', 'include', [], _('include names matching the given patterns')),
2146 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2150 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2147 "hg add [OPTION]... [FILE]..."),
2151 "hg add [OPTION]... [FILE]..."),
2148 "addremove":
2152 "addremove":
2149 (addremove,
2153 (addremove,
2150 [('I', 'include', [], _('include names matching the given patterns')),
2154 [('I', 'include', [], _('include names matching the given patterns')),
2151 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2155 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2152 "hg addremove [OPTION]... [FILE]..."),
2156 "hg addremove [OPTION]... [FILE]..."),
2153 "^annotate":
2157 "^annotate":
2154 (annotate,
2158 (annotate,
2155 [('r', 'rev', '', _('annotate the specified revision')),
2159 [('r', 'rev', '', _('annotate the specified revision')),
2156 ('a', 'text', None, _('treat all files as text')),
2160 ('a', 'text', None, _('treat all files as text')),
2157 ('u', 'user', None, _('list the author')),
2161 ('u', 'user', None, _('list the author')),
2158 ('n', 'number', None, _('list the revision number (default)')),
2162 ('n', 'number', None, _('list the revision number (default)')),
2159 ('c', 'changeset', None, _('list the changeset')),
2163 ('c', 'changeset', None, _('list the changeset')),
2160 ('I', 'include', [], _('include names matching the given patterns')),
2164 ('I', 'include', [], _('include names matching the given patterns')),
2161 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2165 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2162 _('hg annotate [OPTION]... FILE...')),
2166 _('hg annotate [OPTION]... FILE...')),
2163 "bundle":
2167 "bundle":
2164 (bundle,
2168 (bundle,
2165 [],
2169 [],
2166 _('hg bundle FILE DEST')),
2170 _('hg bundle FILE DEST')),
2167 "cat":
2171 "cat":
2168 (cat,
2172 (cat,
2169 [('I', 'include', [], _('include names matching the given patterns')),
2173 [('I', 'include', [], _('include names matching the given patterns')),
2170 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2174 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2171 ('o', 'output', "", _('print output to file with formatted name')),
2175 ('o', 'output', "", _('print output to file with formatted name')),
2172 ('r', 'rev', '', _('print the given revision'))],
2176 ('r', 'rev', '', _('print the given revision'))],
2173 _('hg cat [OPTION]... FILE...')),
2177 _('hg cat [OPTION]... FILE...')),
2174 "^clone":
2178 "^clone":
2175 (clone,
2179 (clone,
2176 [('U', 'noupdate', None, _('do not update the new working directory')),
2180 [('U', 'noupdate', None, _('do not update the new working directory')),
2177 ('e', 'ssh', "", _('specify ssh command to use')),
2181 ('e', 'ssh', "", _('specify ssh command to use')),
2178 ('', 'pull', None, _('use pull protocol to copy metadata')),
2182 ('', 'pull', None, _('use pull protocol to copy metadata')),
2179 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2183 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2180 _('hg clone [OPTION]... SOURCE [DEST]')),
2184 _('hg clone [OPTION]... SOURCE [DEST]')),
2181 "^commit|ci":
2185 "^commit|ci":
2182 (commit,
2186 (commit,
2183 [('A', 'addremove', None, _('run addremove during commit')),
2187 [('A', 'addremove', None, _('run addremove during commit')),
2184 ('I', 'include', [], _('include names matching the given patterns')),
2188 ('I', 'include', [], _('include names matching the given patterns')),
2185 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2189 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2186 ('m', 'message', "", _('use <text> as commit message')),
2190 ('m', 'message', "", _('use <text> as commit message')),
2187 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2191 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2188 ('l', 'logfile', "", _('read the commit message from <file>')),
2192 ('l', 'logfile', "", _('read the commit message from <file>')),
2189 ('d', 'date', "", _('record datecode as commit date')),
2193 ('d', 'date', "", _('record datecode as commit date')),
2190 ('u', 'user', "", _('record user as commiter'))],
2194 ('u', 'user', "", _('record user as commiter'))],
2191 _('hg commit [OPTION]... [FILE]...')),
2195 _('hg commit [OPTION]... [FILE]...')),
2192 "copy|cp": (copy,
2196 "copy|cp": (copy,
2193 [('I', 'include', [], _('include names matching the given patterns')),
2197 [('I', 'include', [], _('include names matching the given patterns')),
2194 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2198 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2195 ('A', 'after', None, _('record a copy that has already occurred')),
2199 ('A', 'after', None, _('record a copy that has already occurred')),
2196 ('f', 'force', None, _('forcibly copy over an existing managed file')),
2200 ('f', 'force', None, _('forcibly copy over an existing managed file')),
2197 ('p', 'parents', None, _('append source path to dest'))],
2201 ('p', 'parents', None, _('append source path to dest'))],
2198 _('hg copy [OPTION]... [SOURCE]... DEST')),
2202 _('hg copy [OPTION]... [SOURCE]... DEST')),
2199 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2203 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2200 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2204 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2201 "debugconfig": (debugconfig, [], _('debugconfig')),
2205 "debugconfig": (debugconfig, [], _('debugconfig')),
2202 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2206 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2203 "debugstate": (debugstate, [], _('debugstate')),
2207 "debugstate": (debugstate, [], _('debugstate')),
2204 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2208 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2205 "debugindex": (debugindex, [], _('debugindex FILE')),
2209 "debugindex": (debugindex, [], _('debugindex FILE')),
2206 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2210 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2207 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2211 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2208 "debugwalk":
2212 "debugwalk":
2209 (debugwalk,
2213 (debugwalk,
2210 [('I', 'include', [], _('include names matching the given patterns')),
2214 [('I', 'include', [], _('include names matching the given patterns')),
2211 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2215 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2212 _('debugwalk [OPTION]... [FILE]...')),
2216 _('debugwalk [OPTION]... [FILE]...')),
2213 "^diff":
2217 "^diff":
2214 (diff,
2218 (diff,
2215 [('r', 'rev', [], _('revision')),
2219 [('r', 'rev', [], _('revision')),
2216 ('a', 'text', None, _('treat all files as text')),
2220 ('a', 'text', None, _('treat all files as text')),
2217 ('I', 'include', [], _('include names matching the given patterns')),
2221 ('I', 'include', [], _('include names matching the given patterns')),
2218 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2222 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2219 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2223 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2220 "^export":
2224 "^export":
2221 (export,
2225 (export,
2222 [('o', 'output', "", _('print output to file with formatted name')),
2226 [('o', 'output', "", _('print output to file with formatted name')),
2223 ('a', 'text', None, _('treat all files as text'))],
2227 ('a', 'text', None, _('treat all files as text'))],
2224 "hg export [-a] [-o OUTFILE] REV..."),
2228 "hg export [-a] [-o OUTFILE] REV..."),
2225 "forget":
2229 "forget":
2226 (forget,
2230 (forget,
2227 [('I', 'include', [], _('include names matching the given patterns')),
2231 [('I', 'include', [], _('include names matching the given patterns')),
2228 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2232 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2229 "hg forget [OPTION]... FILE..."),
2233 "hg forget [OPTION]... FILE..."),
2230 "grep":
2234 "grep":
2231 (grep,
2235 (grep,
2232 [('0', 'print0', None, _('end fields with NUL')),
2236 [('0', 'print0', None, _('end fields with NUL')),
2233 ('I', 'include', [], _('include names matching the given patterns')),
2237 ('I', 'include', [], _('include names matching the given patterns')),
2234 ('X', 'exclude', [], _('include names matching the given patterns')),
2238 ('X', 'exclude', [], _('include names matching the given patterns')),
2235 ('', 'all', None, _('print all revisions that match')),
2239 ('', 'all', None, _('print all revisions that match')),
2236 ('i', 'ignore-case', None, _('ignore case when matching')),
2240 ('i', 'ignore-case', None, _('ignore case when matching')),
2237 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2241 ('l', 'files-with-matches', None, _('print only filenames and revs that match')),
2238 ('n', 'line-number', None, _('print matching line numbers')),
2242 ('n', 'line-number', None, _('print matching line numbers')),
2239 ('r', 'rev', [], _('search in given revision range')),
2243 ('r', 'rev', [], _('search in given revision range')),
2240 ('u', 'user', None, _('print user who committed change'))],
2244 ('u', 'user', None, _('print user who committed change'))],
2241 "hg grep [OPTION]... PATTERN [FILE]..."),
2245 "hg grep [OPTION]... PATTERN [FILE]..."),
2242 "heads":
2246 "heads":
2243 (heads,
2247 (heads,
2244 [('b', 'branches', None, _('find branch info'))],
2248 [('b', 'branches', None, _('find branch info'))],
2245 _('hg heads [-b]')),
2249 _('hg heads [-b]')),
2246 "help": (help_, [], _('hg help [COMMAND]')),
2250 "help": (help_, [], _('hg help [COMMAND]')),
2247 "identify|id": (identify, [], _('hg identify')),
2251 "identify|id": (identify, [], _('hg identify')),
2248 "import|patch":
2252 "import|patch":
2249 (import_,
2253 (import_,
2250 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2254 [('p', 'strip', 1, _('directory strip option for patch. This has the same\n') +
2251 _('meaning as the corresponding patch option')),
2255 _('meaning as the corresponding patch option')),
2252 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2256 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
2253 ('b', 'base', "", _('base path'))],
2257 ('b', 'base', "", _('base path'))],
2254 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2258 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
2255 "incoming|in": (incoming,
2259 "incoming|in": (incoming,
2256 [('M', 'no-merges', None, _("do not show merges")),
2260 [('M', 'no-merges', None, _("do not show merges")),
2257 ('p', 'patch', None, _('show patch'))],
2261 ('p', 'patch', None, _('show patch')),
2258 _('hg incoming [-p] [SOURCE]')),
2262 ('n', 'newest-first', None, _('show newest record first'))],
2263 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2259 "^init": (init, [], _('hg init [DEST]')),
2264 "^init": (init, [], _('hg init [DEST]')),
2260 "locate":
2265 "locate":
2261 (locate,
2266 (locate,
2262 [('r', 'rev', '', _('search the repository as it stood at rev')),
2267 [('r', 'rev', '', _('search the repository as it stood at rev')),
2263 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2268 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2264 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2269 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
2265 ('I', 'include', [], _('include names matching the given patterns')),
2270 ('I', 'include', [], _('include names matching the given patterns')),
2266 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2271 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2267 _('hg locate [OPTION]... [PATTERN]...')),
2272 _('hg locate [OPTION]... [PATTERN]...')),
2268 "^log|history":
2273 "^log|history":
2269 (log,
2274 (log,
2270 [('I', 'include', [], _('include names matching the given patterns')),
2275 [('I', 'include', [], _('include names matching the given patterns')),
2271 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2276 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2272 ('b', 'branch', None, _('show branches')),
2277 ('b', 'branch', None, _('show branches')),
2273 ('k', 'keyword', [], _('search for a keyword')),
2278 ('k', 'keyword', [], _('search for a keyword')),
2274 ('r', 'rev', [], _('show the specified revision or range')),
2279 ('r', 'rev', [], _('show the specified revision or range')),
2275 ('M', 'no-merges', None, _("do not show merges")),
2280 ('M', 'no-merges', None, _("do not show merges")),
2276 ('m', 'only-merges', None, _("show only merges")),
2281 ('m', 'only-merges', None, _("show only merges")),
2277 ('p', 'patch', None, _('show patch'))],
2282 ('p', 'patch', None, _('show patch'))],
2278 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2283 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2279 "manifest": (manifest, [], _('hg manifest [REV]')),
2284 "manifest": (manifest, [], _('hg manifest [REV]')),
2280 "outgoing|out": (outgoing,
2285 "outgoing|out": (outgoing,
2281 [('M', 'no-merges', None, _("do not show merges")),
2286 [('M', 'no-merges', None, _("do not show merges")),
2282 ('p', 'patch', None, _('show patch'))],
2287 ('p', 'patch', None, _('show patch')),
2283 _('hg outgoing [-p] [DEST]')),
2288 ('n', 'newest-first', None, _('show newest record first'))],
2289 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2284 "parents": (parents, [], _('hg parents [REV]')),
2290 "parents": (parents, [], _('hg parents [REV]')),
2285 "paths": (paths, [], _('hg paths [NAME]')),
2291 "paths": (paths, [], _('hg paths [NAME]')),
2286 "^pull":
2292 "^pull":
2287 (pull,
2293 (pull,
2288 [('u', 'update', None, _('update the working directory to tip after pull')),
2294 [('u', 'update', None, _('update the working directory to tip after pull')),
2289 ('e', 'ssh', "", _('specify ssh command to use')),
2295 ('e', 'ssh', "", _('specify ssh command to use')),
2290 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2296 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2291 _('hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]')),
2297 _('hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]')),
2292 "^push":
2298 "^push":
2293 (push,
2299 (push,
2294 [('f', 'force', None, _('force push')),
2300 [('f', 'force', None, _('force push')),
2295 ('e', 'ssh', "", _('specify ssh command to use')),
2301 ('e', 'ssh', "", _('specify ssh command to use')),
2296 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2302 ('', 'remotecmd', "", _('specify hg command to run on the remote side'))],
2297 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2303 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2298 "rawcommit":
2304 "rawcommit":
2299 (rawcommit,
2305 (rawcommit,
2300 [('p', 'parent', [], _('parent')),
2306 [('p', 'parent', [], _('parent')),
2301 ('d', 'date', "", _('date code')),
2307 ('d', 'date', "", _('date code')),
2302 ('u', 'user', "", _('user')),
2308 ('u', 'user', "", _('user')),
2303 ('F', 'files', "", _('file list')),
2309 ('F', 'files', "", _('file list')),
2304 ('m', 'message', "", _('commit message')),
2310 ('m', 'message', "", _('commit message')),
2305 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2311 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2306 ('l', 'logfile', "", _('commit message file'))],
2312 ('l', 'logfile', "", _('commit message file'))],
2307 _('hg rawcommit [OPTION]... [FILE]...')),
2313 _('hg rawcommit [OPTION]... [FILE]...')),
2308 "recover": (recover, [], _("hg recover")),
2314 "recover": (recover, [], _("hg recover")),
2309 "^remove|rm": (remove,
2315 "^remove|rm": (remove,
2310 [('I', 'include', [], _('include names matching the given patterns')),
2316 [('I', 'include', [], _('include names matching the given patterns')),
2311 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2317 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2312 _("hg remove [OPTION]... FILE...")),
2318 _("hg remove [OPTION]... FILE...")),
2313 "rename|mv": (rename,
2319 "rename|mv": (rename,
2314 [('I', 'include', [], _('include names matching the given patterns')),
2320 [('I', 'include', [], _('include names matching the given patterns')),
2315 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2321 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2316 ('A', 'after', None, _('record a rename that has already occurred')),
2322 ('A', 'after', None, _('record a rename that has already occurred')),
2317 ('f', 'force', None, _('forcibly copy over an existing managed file')),
2323 ('f', 'force', None, _('forcibly copy over an existing managed file')),
2318 ('p', 'parents', None, _('append source path to dest'))],
2324 ('p', 'parents', None, _('append source path to dest'))],
2319 _('hg rename [OPTION]... [SOURCE]... DEST')),
2325 _('hg rename [OPTION]... [SOURCE]... DEST')),
2320 "^revert":
2326 "^revert":
2321 (revert,
2327 (revert,
2322 [("n", "nonrecursive", None, _("do not recurse into subdirectories")),
2328 [("n", "nonrecursive", None, _("do not recurse into subdirectories")),
2323 ("r", "rev", "", _("revision to revert to"))],
2329 ("r", "rev", "", _("revision to revert to"))],
2324 _("hg revert [-n] [-r REV] [NAME]...")),
2330 _("hg revert [-n] [-r REV] [NAME]...")),
2325 "root": (root, [], _("hg root")),
2331 "root": (root, [], _("hg root")),
2326 "^serve":
2332 "^serve":
2327 (serve,
2333 (serve,
2328 [('A', 'accesslog', '', _('name of access log file to write to')),
2334 [('A', 'accesslog', '', _('name of access log file to write to')),
2329 ('E', 'errorlog', '', _('name of error log file to write to')),
2335 ('E', 'errorlog', '', _('name of error log file to write to')),
2330 ('p', 'port', 0, _('port to use (default: 8000)')),
2336 ('p', 'port', 0, _('port to use (default: 8000)')),
2331 ('a', 'address', '', _('address to use')),
2337 ('a', 'address', '', _('address to use')),
2332 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2338 ('n', 'name', "", _('name to show in web pages (default: working dir)')),
2333 ('', 'stdio', None, _('for remote clients')),
2339 ('', 'stdio', None, _('for remote clients')),
2334 ('t', 'templates', "", _('web templates to use')),
2340 ('t', 'templates', "", _('web templates to use')),
2335 ('', 'style', "", _('template style to use')),
2341 ('', 'style', "", _('template style to use')),
2336 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2342 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2337 _("hg serve [OPTION]...")),
2343 _("hg serve [OPTION]...")),
2338 "^status":
2344 "^status":
2339 (status,
2345 (status,
2340 [('m', 'modified', None, _('show only modified files')),
2346 [('m', 'modified', None, _('show only modified files')),
2341 ('a', 'added', None, _('show only added files')),
2347 ('a', 'added', None, _('show only added files')),
2342 ('r', 'removed', None, _('show only removed files')),
2348 ('r', 'removed', None, _('show only removed files')),
2343 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2349 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2344 ('n', 'no-status', None, _('hide status prefix')),
2350 ('n', 'no-status', None, _('hide status prefix')),
2345 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2351 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2346 ('I', 'include', [], _('include names matching the given patterns')),
2352 ('I', 'include', [], _('include names matching the given patterns')),
2347 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2353 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2348 _("hg status [OPTION]... [FILE]...")),
2354 _("hg status [OPTION]... [FILE]...")),
2349 "tag":
2355 "tag":
2350 (tag,
2356 (tag,
2351 [('l', 'local', None, _('make the tag local')),
2357 [('l', 'local', None, _('make the tag local')),
2352 ('m', 'message', "", _('message for tag commit log entry')),
2358 ('m', 'message', "", _('message for tag commit log entry')),
2353 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2359 ('t', 'text', "", _('commit message (deprecated: use -m)')),
2354 ('d', 'date', "", _('record datecode as commit date')),
2360 ('d', 'date', "", _('record datecode as commit date')),
2355 ('u', 'user', "", _('record user as commiter'))],
2361 ('u', 'user', "", _('record user as commiter'))],
2356 _('hg tag [OPTION]... NAME [REV]')),
2362 _('hg tag [OPTION]... NAME [REV]')),
2357 "tags": (tags, [], _('hg tags')),
2363 "tags": (tags, [], _('hg tags')),
2358 "tip": (tip, [], _('hg tip')),
2364 "tip": (tip, [], _('hg tip')),
2359 "unbundle":
2365 "unbundle":
2360 (unbundle,
2366 (unbundle,
2361 [],
2367 [],
2362 _('hg unbundle FILE')),
2368 _('hg unbundle FILE')),
2363 "undo": (undo, [], _('hg undo')),
2369 "undo": (undo, [], _('hg undo')),
2364 "^update|up|checkout|co":
2370 "^update|up|checkout|co":
2365 (update,
2371 (update,
2366 [('b', 'branch', "", _('checkout the head of a specific branch')),
2372 [('b', 'branch', "", _('checkout the head of a specific branch')),
2367 ('m', 'merge', None, _('allow merging of branches')),
2373 ('m', 'merge', None, _('allow merging of branches')),
2368 ('C', 'clean', None, _('overwrite locally modified files'))],
2374 ('C', 'clean', None, _('overwrite locally modified files'))],
2369 _('hg update [-b TAG] [-m] [-C] [REV]')),
2375 _('hg update [-b TAG] [-m] [-C] [REV]')),
2370 "verify": (verify, [], _('hg verify')),
2376 "verify": (verify, [], _('hg verify')),
2371 "version": (show_version, [], _('hg version')),
2377 "version": (show_version, [], _('hg version')),
2372 }
2378 }
2373
2379
2374 globalopts = [
2380 globalopts = [
2375 ('R', 'repository', "", _("repository root directory")),
2381 ('R', 'repository', "", _("repository root directory")),
2376 ('', 'cwd', '', _("change working directory")),
2382 ('', 'cwd', '', _("change working directory")),
2377 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2383 ('y', 'noninteractive', None, _("do not prompt, assume 'yes' for any required answers")),
2378 ('q', 'quiet', None, _("suppress output")),
2384 ('q', 'quiet', None, _("suppress output")),
2379 ('v', 'verbose', None, _("enable additional output")),
2385 ('v', 'verbose', None, _("enable additional output")),
2380 ('', 'debug', None, _("enable debugging output")),
2386 ('', 'debug', None, _("enable debugging output")),
2381 ('', 'debugger', None, _("start debugger")),
2387 ('', 'debugger', None, _("start debugger")),
2382 ('', 'traceback', None, _("print traceback on exception")),
2388 ('', 'traceback', None, _("print traceback on exception")),
2383 ('', 'time', None, _("time how long the command takes")),
2389 ('', 'time', None, _("time how long the command takes")),
2384 ('', 'profile', None, _("print command execution profile")),
2390 ('', 'profile', None, _("print command execution profile")),
2385 ('', 'version', None, _("output version information and exit")),
2391 ('', 'version', None, _("output version information and exit")),
2386 ('h', 'help', None, _("display help and exit")),
2392 ('h', 'help', None, _("display help and exit")),
2387 ]
2393 ]
2388
2394
2389 norepo = ("clone init version help debugancestor debugconfig debugdata"
2395 norepo = ("clone init version help debugancestor debugconfig debugdata"
2390 " debugindex debugindexdot paths")
2396 " debugindex debugindexdot paths")
2391
2397
2392 def find(cmd):
2398 def find(cmd):
2393 for e in table.keys():
2399 for e in table.keys():
2394 if re.match("(%s)$" % e, cmd):
2400 if re.match("(%s)$" % e, cmd):
2395 return e, table[e]
2401 return e, table[e]
2396
2402
2397 raise UnknownCommand(cmd)
2403 raise UnknownCommand(cmd)
2398
2404
2399 class SignalInterrupt(Exception):
2405 class SignalInterrupt(Exception):
2400 """Exception raised on SIGTERM and SIGHUP."""
2406 """Exception raised on SIGTERM and SIGHUP."""
2401
2407
2402 def catchterm(*args):
2408 def catchterm(*args):
2403 raise SignalInterrupt
2409 raise SignalInterrupt
2404
2410
2405 def run():
2411 def run():
2406 sys.exit(dispatch(sys.argv[1:]))
2412 sys.exit(dispatch(sys.argv[1:]))
2407
2413
2408 class ParseError(Exception):
2414 class ParseError(Exception):
2409 """Exception raised on errors in parsing the command line."""
2415 """Exception raised on errors in parsing the command line."""
2410
2416
2411 def parse(args):
2417 def parse(args):
2412 options = {}
2418 options = {}
2413 cmdoptions = {}
2419 cmdoptions = {}
2414
2420
2415 try:
2421 try:
2416 args = fancyopts.fancyopts(args, globalopts, options)
2422 args = fancyopts.fancyopts(args, globalopts, options)
2417 except fancyopts.getopt.GetoptError, inst:
2423 except fancyopts.getopt.GetoptError, inst:
2418 raise ParseError(None, inst)
2424 raise ParseError(None, inst)
2419
2425
2420 if args:
2426 if args:
2421 cmd, args = args[0], args[1:]
2427 cmd, args = args[0], args[1:]
2422 i = find(cmd)[1]
2428 i = find(cmd)[1]
2423 c = list(i[1])
2429 c = list(i[1])
2424 else:
2430 else:
2425 cmd = None
2431 cmd = None
2426 c = []
2432 c = []
2427
2433
2428 # combine global options into local
2434 # combine global options into local
2429 for o in globalopts:
2435 for o in globalopts:
2430 c.append((o[0], o[1], options[o[1]], o[3]))
2436 c.append((o[0], o[1], options[o[1]], o[3]))
2431
2437
2432 try:
2438 try:
2433 args = fancyopts.fancyopts(args, c, cmdoptions)
2439 args = fancyopts.fancyopts(args, c, cmdoptions)
2434 except fancyopts.getopt.GetoptError, inst:
2440 except fancyopts.getopt.GetoptError, inst:
2435 raise ParseError(cmd, inst)
2441 raise ParseError(cmd, inst)
2436
2442
2437 # separate global options back out
2443 # separate global options back out
2438 for o in globalopts:
2444 for o in globalopts:
2439 n = o[1]
2445 n = o[1]
2440 options[n] = cmdoptions[n]
2446 options[n] = cmdoptions[n]
2441 del cmdoptions[n]
2447 del cmdoptions[n]
2442
2448
2443 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2449 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2444
2450
2445 def dispatch(args):
2451 def dispatch(args):
2446 signal.signal(signal.SIGTERM, catchterm)
2452 signal.signal(signal.SIGTERM, catchterm)
2447 try:
2453 try:
2448 signal.signal(signal.SIGHUP, catchterm)
2454 signal.signal(signal.SIGHUP, catchterm)
2449 except AttributeError:
2455 except AttributeError:
2450 pass
2456 pass
2451
2457
2452 u = ui.ui()
2458 u = ui.ui()
2453 external = []
2459 external = []
2454 for x in u.extensions():
2460 for x in u.extensions():
2455 def on_exception(Exception, inst):
2461 def on_exception(Exception, inst):
2456 u.warn(_("*** failed to import extension %s\n") % x[1])
2462 u.warn(_("*** failed to import extension %s\n") % x[1])
2457 u.warn("%s\n" % inst)
2463 u.warn("%s\n" % inst)
2458 if "--traceback" in sys.argv[1:]:
2464 if "--traceback" in sys.argv[1:]:
2459 traceback.print_exc()
2465 traceback.print_exc()
2460 if x[1]:
2466 if x[1]:
2461 try:
2467 try:
2462 mod = imp.load_source(x[0], x[1])
2468 mod = imp.load_source(x[0], x[1])
2463 except Exception, inst:
2469 except Exception, inst:
2464 on_exception(Exception, inst)
2470 on_exception(Exception, inst)
2465 continue
2471 continue
2466 else:
2472 else:
2467 def importh(name):
2473 def importh(name):
2468 mod = __import__(name)
2474 mod = __import__(name)
2469 components = name.split('.')
2475 components = name.split('.')
2470 for comp in components[1:]:
2476 for comp in components[1:]:
2471 mod = getattr(mod, comp)
2477 mod = getattr(mod, comp)
2472 return mod
2478 return mod
2473 try:
2479 try:
2474 mod = importh(x[0])
2480 mod = importh(x[0])
2475 except Exception, inst:
2481 except Exception, inst:
2476 on_exception(Exception, inst)
2482 on_exception(Exception, inst)
2477 continue
2483 continue
2478
2484
2479 external.append(mod)
2485 external.append(mod)
2480 for x in external:
2486 for x in external:
2481 cmdtable = getattr(x, 'cmdtable', {})
2487 cmdtable = getattr(x, 'cmdtable', {})
2482 for t in cmdtable:
2488 for t in cmdtable:
2483 if t in table:
2489 if t in table:
2484 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2490 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2485 table.update(cmdtable)
2491 table.update(cmdtable)
2486
2492
2487 try:
2493 try:
2488 cmd, func, args, options, cmdoptions = parse(args)
2494 cmd, func, args, options, cmdoptions = parse(args)
2489 except ParseError, inst:
2495 except ParseError, inst:
2490 if inst.args[0]:
2496 if inst.args[0]:
2491 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2497 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2492 help_(u, inst.args[0])
2498 help_(u, inst.args[0])
2493 else:
2499 else:
2494 u.warn(_("hg: %s\n") % inst.args[1])
2500 u.warn(_("hg: %s\n") % inst.args[1])
2495 help_(u, 'shortlist')
2501 help_(u, 'shortlist')
2496 sys.exit(-1)
2502 sys.exit(-1)
2497 except UnknownCommand, inst:
2503 except UnknownCommand, inst:
2498 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2504 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2499 help_(u, 'shortlist')
2505 help_(u, 'shortlist')
2500 sys.exit(1)
2506 sys.exit(1)
2501
2507
2502 if options["time"]:
2508 if options["time"]:
2503 def get_times():
2509 def get_times():
2504 t = os.times()
2510 t = os.times()
2505 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2511 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2506 t = (t[0], t[1], t[2], t[3], time.clock())
2512 t = (t[0], t[1], t[2], t[3], time.clock())
2507 return t
2513 return t
2508 s = get_times()
2514 s = get_times()
2509 def print_time():
2515 def print_time():
2510 t = get_times()
2516 t = get_times()
2511 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2517 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2512 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2518 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2513 atexit.register(print_time)
2519 atexit.register(print_time)
2514
2520
2515 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2521 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2516 not options["noninteractive"])
2522 not options["noninteractive"])
2517
2523
2518 # enter the debugger before command execution
2524 # enter the debugger before command execution
2519 if options['debugger']:
2525 if options['debugger']:
2520 pdb.set_trace()
2526 pdb.set_trace()
2521
2527
2522 try:
2528 try:
2523 try:
2529 try:
2524 if options['help']:
2530 if options['help']:
2525 help_(u, cmd, options['version'])
2531 help_(u, cmd, options['version'])
2526 sys.exit(0)
2532 sys.exit(0)
2527 elif options['version']:
2533 elif options['version']:
2528 show_version(u)
2534 show_version(u)
2529 sys.exit(0)
2535 sys.exit(0)
2530 elif not cmd:
2536 elif not cmd:
2531 help_(u, 'shortlist')
2537 help_(u, 'shortlist')
2532 sys.exit(0)
2538 sys.exit(0)
2533
2539
2534 if options['cwd']:
2540 if options['cwd']:
2535 try:
2541 try:
2536 os.chdir(options['cwd'])
2542 os.chdir(options['cwd'])
2537 except OSError, inst:
2543 except OSError, inst:
2538 raise util.Abort('%s: %s' %
2544 raise util.Abort('%s: %s' %
2539 (options['cwd'], inst.strerror))
2545 (options['cwd'], inst.strerror))
2540
2546
2541 if cmd not in norepo.split():
2547 if cmd not in norepo.split():
2542 path = options["repository"] or ""
2548 path = options["repository"] or ""
2543 repo = hg.repository(ui=u, path=path)
2549 repo = hg.repository(ui=u, path=path)
2544 for x in external:
2550 for x in external:
2545 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2551 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2546 d = lambda: func(u, repo, *args, **cmdoptions)
2552 d = lambda: func(u, repo, *args, **cmdoptions)
2547 else:
2553 else:
2548 d = lambda: func(u, *args, **cmdoptions)
2554 d = lambda: func(u, *args, **cmdoptions)
2549
2555
2550 if options['profile']:
2556 if options['profile']:
2551 import hotshot, hotshot.stats
2557 import hotshot, hotshot.stats
2552 prof = hotshot.Profile("hg.prof")
2558 prof = hotshot.Profile("hg.prof")
2553 r = prof.runcall(d)
2559 r = prof.runcall(d)
2554 prof.close()
2560 prof.close()
2555 stats = hotshot.stats.load("hg.prof")
2561 stats = hotshot.stats.load("hg.prof")
2556 stats.strip_dirs()
2562 stats.strip_dirs()
2557 stats.sort_stats('time', 'calls')
2563 stats.sort_stats('time', 'calls')
2558 stats.print_stats(40)
2564 stats.print_stats(40)
2559 return r
2565 return r
2560 else:
2566 else:
2561 return d()
2567 return d()
2562 except:
2568 except:
2563 # enter the debugger when we hit an exception
2569 # enter the debugger when we hit an exception
2564 if options['debugger']:
2570 if options['debugger']:
2565 pdb.post_mortem(sys.exc_info()[2])
2571 pdb.post_mortem(sys.exc_info()[2])
2566 if options['traceback']:
2572 if options['traceback']:
2567 traceback.print_exc()
2573 traceback.print_exc()
2568 raise
2574 raise
2569 except hg.RepoError, inst:
2575 except hg.RepoError, inst:
2570 u.warn(_("abort: "), inst, "!\n")
2576 u.warn(_("abort: "), inst, "!\n")
2571 except revlog.RevlogError, inst:
2577 except revlog.RevlogError, inst:
2572 u.warn(_("abort: "), inst, "!\n")
2578 u.warn(_("abort: "), inst, "!\n")
2573 except SignalInterrupt:
2579 except SignalInterrupt:
2574 u.warn(_("killed!\n"))
2580 u.warn(_("killed!\n"))
2575 except KeyboardInterrupt:
2581 except KeyboardInterrupt:
2576 try:
2582 try:
2577 u.warn(_("interrupted!\n"))
2583 u.warn(_("interrupted!\n"))
2578 except IOError, inst:
2584 except IOError, inst:
2579 if inst.errno == errno.EPIPE:
2585 if inst.errno == errno.EPIPE:
2580 if u.debugflag:
2586 if u.debugflag:
2581 u.warn(_("\nbroken pipe\n"))
2587 u.warn(_("\nbroken pipe\n"))
2582 else:
2588 else:
2583 raise
2589 raise
2584 except IOError, inst:
2590 except IOError, inst:
2585 if hasattr(inst, "code"):
2591 if hasattr(inst, "code"):
2586 u.warn(_("abort: %s\n") % inst)
2592 u.warn(_("abort: %s\n") % inst)
2587 elif hasattr(inst, "reason"):
2593 elif hasattr(inst, "reason"):
2588 u.warn(_("abort: error: %s\n") % inst.reason[1])
2594 u.warn(_("abort: error: %s\n") % inst.reason[1])
2589 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2595 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2590 if u.debugflag:
2596 if u.debugflag:
2591 u.warn(_("broken pipe\n"))
2597 u.warn(_("broken pipe\n"))
2592 elif getattr(inst, "strerror", None):
2598 elif getattr(inst, "strerror", None):
2593 if getattr(inst, "filename", None):
2599 if getattr(inst, "filename", None):
2594 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2600 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2595 else:
2601 else:
2596 u.warn(_("abort: %s\n") % inst.strerror)
2602 u.warn(_("abort: %s\n") % inst.strerror)
2597 else:
2603 else:
2598 raise
2604 raise
2599 except OSError, inst:
2605 except OSError, inst:
2600 if hasattr(inst, "filename"):
2606 if hasattr(inst, "filename"):
2601 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2607 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2602 else:
2608 else:
2603 u.warn(_("abort: %s\n") % inst.strerror)
2609 u.warn(_("abort: %s\n") % inst.strerror)
2604 except util.Abort, inst:
2610 except util.Abort, inst:
2605 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2611 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2606 sys.exit(1)
2612 sys.exit(1)
2607 except TypeError, inst:
2613 except TypeError, inst:
2608 # was this an argument error?
2614 # was this an argument error?
2609 tb = traceback.extract_tb(sys.exc_info()[2])
2615 tb = traceback.extract_tb(sys.exc_info()[2])
2610 if len(tb) > 2: # no
2616 if len(tb) > 2: # no
2611 raise
2617 raise
2612 u.debug(inst, "\n")
2618 u.debug(inst, "\n")
2613 u.warn(_("%s: invalid arguments\n") % cmd)
2619 u.warn(_("%s: invalid arguments\n") % cmd)
2614 help_(u, cmd)
2620 help_(u, cmd)
2615 except UnknownCommand, inst:
2621 except UnknownCommand, inst:
2616 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2622 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2617 help_(u, 'shortlist')
2623 help_(u, 'shortlist')
2618 except SystemExit:
2624 except SystemExit:
2619 # don't catch this in the catch-all below
2625 # don't catch this in the catch-all below
2620 raise
2626 raise
2621 except:
2627 except:
2622 u.warn(_("** unknown exception encountered, details follow\n"))
2628 u.warn(_("** unknown exception encountered, details follow\n"))
2623 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2629 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2624 raise
2630 raise
2625
2631
2626 sys.exit(-1)
2632 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now