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