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