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