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