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