##// END OF EJS Templates
fix typo in debugrebuildstate
Benoit Boissinot -
r1760:13f8e068 default
parent child Browse files
Show More
@@ -1,2869 +1,2869
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 = self.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 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1614 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1615 for st, rev, fns in changeiter:
1615 for st, rev, fns in changeiter:
1616 if st == 'window':
1616 if st == 'window':
1617 du = dui(ui)
1617 du = dui(ui)
1618 elif st == 'add':
1618 elif st == 'add':
1619 du.bump(rev)
1619 du.bump(rev)
1620 changenode = repo.changelog.node(rev)
1620 changenode = repo.changelog.node(rev)
1621 parents = [p for p in repo.changelog.parents(changenode)
1621 parents = [p for p in repo.changelog.parents(changenode)
1622 if p != nullid]
1622 if p != nullid]
1623 if opts['no_merges'] and len(parents) == 2:
1623 if opts['no_merges'] and len(parents) == 2:
1624 continue
1624 continue
1625 if opts['only_merges'] and len(parents) != 2:
1625 if opts['only_merges'] and len(parents) != 2:
1626 continue
1626 continue
1627
1627
1628 br = None
1628 br = None
1629 if opts['keyword']:
1629 if opts['keyword']:
1630 changes = getchange(rev)
1630 changes = getchange(rev)
1631 miss = 0
1631 miss = 0
1632 for k in [kw.lower() for kw in opts['keyword']]:
1632 for k in [kw.lower() for kw in opts['keyword']]:
1633 if not (k in changes[1].lower() or
1633 if not (k in changes[1].lower() or
1634 k in changes[4].lower() or
1634 k in changes[4].lower() or
1635 k in " ".join(changes[3][:20]).lower()):
1635 k in " ".join(changes[3][:20]).lower()):
1636 miss = 1
1636 miss = 1
1637 break
1637 break
1638 if miss:
1638 if miss:
1639 continue
1639 continue
1640
1640
1641 if opts['branch']:
1641 if opts['branch']:
1642 br = repo.branchlookup([repo.changelog.node(rev)])
1642 br = repo.branchlookup([repo.changelog.node(rev)])
1643
1643
1644 show_changeset(du, repo, rev, brinfo=br)
1644 show_changeset(du, repo, rev, brinfo=br)
1645 if opts['patch']:
1645 if opts['patch']:
1646 prev = (parents and parents[0]) or nullid
1646 prev = (parents and parents[0]) or nullid
1647 dodiff(du, du, repo, prev, changenode, match=matchfn)
1647 dodiff(du, du, repo, prev, changenode, match=matchfn)
1648 du.write("\n\n")
1648 du.write("\n\n")
1649 elif st == 'iter':
1649 elif st == 'iter':
1650 for args in du.hunk[rev]:
1650 for args in du.hunk[rev]:
1651 ui.write(*args)
1651 ui.write(*args)
1652
1652
1653 def manifest(ui, repo, rev=None):
1653 def manifest(ui, repo, rev=None):
1654 """output the latest or given revision of the project manifest
1654 """output the latest or given revision of the project manifest
1655
1655
1656 Print a list of version controlled files for the given revision.
1656 Print a list of version controlled files for the given revision.
1657
1657
1658 The manifest is the list of files being version controlled. If no revision
1658 The manifest is the list of files being version controlled. If no revision
1659 is given then the tip is used.
1659 is given then the tip is used.
1660 """
1660 """
1661 if rev:
1661 if rev:
1662 try:
1662 try:
1663 # assume all revision numbers are for changesets
1663 # assume all revision numbers are for changesets
1664 n = repo.lookup(rev)
1664 n = repo.lookup(rev)
1665 change = repo.changelog.read(n)
1665 change = repo.changelog.read(n)
1666 n = change[0]
1666 n = change[0]
1667 except hg.RepoError:
1667 except hg.RepoError:
1668 n = repo.manifest.lookup(rev)
1668 n = repo.manifest.lookup(rev)
1669 else:
1669 else:
1670 n = repo.manifest.tip()
1670 n = repo.manifest.tip()
1671 m = repo.manifest.read(n)
1671 m = repo.manifest.read(n)
1672 mf = repo.manifest.readflags(n)
1672 mf = repo.manifest.readflags(n)
1673 files = m.keys()
1673 files = m.keys()
1674 files.sort()
1674 files.sort()
1675
1675
1676 for f in files:
1676 for f in files:
1677 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1677 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1678
1678
1679 def outgoing(ui, repo, dest="default-push", **opts):
1679 def outgoing(ui, repo, dest="default-push", **opts):
1680 """show changesets not found in destination
1680 """show changesets not found in destination
1681
1681
1682 Show changesets not found in the specified destination repo or the
1682 Show changesets not found in the specified destination repo or the
1683 default push repo. These are the changesets that would be pushed
1683 default push repo. These are the changesets that would be pushed
1684 if a push was requested.
1684 if a push was requested.
1685 """
1685 """
1686 dest = ui.expandpath(dest, repo.root)
1686 dest = ui.expandpath(dest, repo.root)
1687 other = hg.repository(ui, dest)
1687 other = hg.repository(ui, dest)
1688 o = repo.findoutgoing(other)
1688 o = repo.findoutgoing(other)
1689 o = repo.changelog.nodesbetween(o)[0]
1689 o = repo.changelog.nodesbetween(o)[0]
1690 if opts['newest_first']:
1690 if opts['newest_first']:
1691 o.reverse()
1691 o.reverse()
1692 for n in o:
1692 for n in o:
1693 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1693 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1694 if opts['no_merges'] and len(parents) == 2:
1694 if opts['no_merges'] and len(parents) == 2:
1695 continue
1695 continue
1696 show_changeset(ui, repo, changenode=n)
1696 show_changeset(ui, repo, changenode=n)
1697 if opts['patch']:
1697 if opts['patch']:
1698 prev = (parents and parents[0]) or nullid
1698 prev = (parents and parents[0]) or nullid
1699 dodiff(ui, ui, repo, prev, n)
1699 dodiff(ui, ui, repo, prev, n)
1700 ui.write("\n")
1700 ui.write("\n")
1701
1701
1702 def parents(ui, repo, rev=None, branch=None):
1702 def parents(ui, repo, rev=None, branch=None):
1703 """show the parents of the working dir or revision
1703 """show the parents of the working dir or revision
1704
1704
1705 Print the working directory's parent revisions.
1705 Print the working directory's parent revisions.
1706 """
1706 """
1707 if rev:
1707 if rev:
1708 p = repo.changelog.parents(repo.lookup(rev))
1708 p = repo.changelog.parents(repo.lookup(rev))
1709 else:
1709 else:
1710 p = repo.dirstate.parents()
1710 p = repo.dirstate.parents()
1711
1711
1712 br = None
1712 br = None
1713 if branch is not None:
1713 if branch is not None:
1714 br = repo.branchlookup(p)
1714 br = repo.branchlookup(p)
1715 for n in p:
1715 for n in p:
1716 if n != nullid:
1716 if n != nullid:
1717 show_changeset(ui, repo, changenode=n, brinfo=br)
1717 show_changeset(ui, repo, changenode=n, brinfo=br)
1718
1718
1719 def paths(ui, search=None):
1719 def paths(ui, search=None):
1720 """show definition of symbolic path names
1720 """show definition of symbolic path names
1721
1721
1722 Show definition of symbolic path name NAME. If no name is given, show
1722 Show definition of symbolic path name NAME. If no name is given, show
1723 definition of available names.
1723 definition of available names.
1724
1724
1725 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1725 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1726 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1726 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1727 """
1727 """
1728 try:
1728 try:
1729 repo = hg.repository(ui=ui)
1729 repo = hg.repository(ui=ui)
1730 except hg.RepoError:
1730 except hg.RepoError:
1731 pass
1731 pass
1732
1732
1733 if search:
1733 if search:
1734 for name, path in ui.configitems("paths"):
1734 for name, path in ui.configitems("paths"):
1735 if name == search:
1735 if name == search:
1736 ui.write("%s\n" % path)
1736 ui.write("%s\n" % path)
1737 return
1737 return
1738 ui.warn(_("not found!\n"))
1738 ui.warn(_("not found!\n"))
1739 return 1
1739 return 1
1740 else:
1740 else:
1741 for name, path in ui.configitems("paths"):
1741 for name, path in ui.configitems("paths"):
1742 ui.write("%s = %s\n" % (name, path))
1742 ui.write("%s = %s\n" % (name, path))
1743
1743
1744 def pull(ui, repo, source="default", **opts):
1744 def pull(ui, repo, source="default", **opts):
1745 """pull changes from the specified source
1745 """pull changes from the specified source
1746
1746
1747 Pull changes from a remote repository to a local one.
1747 Pull changes from a remote repository to a local one.
1748
1748
1749 This finds all changes from the repository at the specified path
1749 This finds all changes from the repository at the specified path
1750 or URL and adds them to the local repository. By default, this
1750 or URL and adds them to the local repository. By default, this
1751 does not update the copy of the project in the working directory.
1751 does not update the copy of the project in the working directory.
1752
1752
1753 Valid URLs are of the form:
1753 Valid URLs are of the form:
1754
1754
1755 local/filesystem/path
1755 local/filesystem/path
1756 http://[user@]host[:port][/path]
1756 http://[user@]host[:port][/path]
1757 https://[user@]host[:port][/path]
1757 https://[user@]host[:port][/path]
1758 ssh://[user@]host[:port][/path]
1758 ssh://[user@]host[:port][/path]
1759
1759
1760 SSH requires an accessible shell account on the destination machine
1760 SSH requires an accessible shell account on the destination machine
1761 and a copy of hg in the remote path. With SSH, paths are relative
1761 and a copy of hg in the remote path. With SSH, paths are relative
1762 to the remote user's home directory by default; use two slashes at
1762 to the remote user's home directory by default; use two slashes at
1763 the start of a path to specify it as relative to the filesystem root.
1763 the start of a path to specify it as relative to the filesystem root.
1764 """
1764 """
1765 source = ui.expandpath(source, repo.root)
1765 source = ui.expandpath(source, repo.root)
1766 ui.status(_('pulling from %s\n') % (source))
1766 ui.status(_('pulling from %s\n') % (source))
1767
1767
1768 if opts['ssh']:
1768 if opts['ssh']:
1769 ui.setconfig("ui", "ssh", opts['ssh'])
1769 ui.setconfig("ui", "ssh", opts['ssh'])
1770 if opts['remotecmd']:
1770 if opts['remotecmd']:
1771 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1771 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1772
1772
1773 other = hg.repository(ui, source)
1773 other = hg.repository(ui, source)
1774 revs = None
1774 revs = None
1775 if opts['rev'] and not other.local():
1775 if opts['rev'] and not other.local():
1776 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
1776 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
1777 elif opts['rev']:
1777 elif opts['rev']:
1778 revs = [other.lookup(rev) for rev in opts['rev']]
1778 revs = [other.lookup(rev) for rev in opts['rev']]
1779 r = repo.pull(other, heads=revs)
1779 r = repo.pull(other, heads=revs)
1780 if not r:
1780 if not r:
1781 if opts['update']:
1781 if opts['update']:
1782 return update(ui, repo)
1782 return update(ui, repo)
1783 else:
1783 else:
1784 ui.status(_("(run 'hg update' to get a working copy)\n"))
1784 ui.status(_("(run 'hg update' to get a working copy)\n"))
1785
1785
1786 return r
1786 return r
1787
1787
1788 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1788 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1789 """push changes to the specified destination
1789 """push changes to the specified destination
1790
1790
1791 Push changes from the local repository to the given destination.
1791 Push changes from the local repository to the given destination.
1792
1792
1793 This is the symmetrical operation for pull. It helps to move
1793 This is the symmetrical operation for pull. It helps to move
1794 changes from the current repository to a different one. If the
1794 changes from the current repository to a different one. If the
1795 destination is local this is identical to a pull in that directory
1795 destination is local this is identical to a pull in that directory
1796 from the current one.
1796 from the current one.
1797
1797
1798 By default, push will refuse to run if it detects the result would
1798 By default, push will refuse to run if it detects the result would
1799 increase the number of remote heads. This generally indicates the
1799 increase the number of remote heads. This generally indicates the
1800 the client has forgotten to sync and merge before pushing.
1800 the client has forgotten to sync and merge before pushing.
1801
1801
1802 Valid URLs are of the form:
1802 Valid URLs are of the form:
1803
1803
1804 local/filesystem/path
1804 local/filesystem/path
1805 ssh://[user@]host[:port][/path]
1805 ssh://[user@]host[:port][/path]
1806
1806
1807 SSH requires an accessible shell account on the destination
1807 SSH requires an accessible shell account on the destination
1808 machine and a copy of hg in the remote path.
1808 machine and a copy of hg in the remote path.
1809 """
1809 """
1810 dest = ui.expandpath(dest, repo.root)
1810 dest = ui.expandpath(dest, repo.root)
1811 ui.status('pushing to %s\n' % (dest))
1811 ui.status('pushing to %s\n' % (dest))
1812
1812
1813 if ssh:
1813 if ssh:
1814 ui.setconfig("ui", "ssh", ssh)
1814 ui.setconfig("ui", "ssh", ssh)
1815 if remotecmd:
1815 if remotecmd:
1816 ui.setconfig("ui", "remotecmd", remotecmd)
1816 ui.setconfig("ui", "remotecmd", remotecmd)
1817
1817
1818 other = hg.repository(ui, dest)
1818 other = hg.repository(ui, dest)
1819 r = repo.push(other, force)
1819 r = repo.push(other, force)
1820 return r
1820 return r
1821
1821
1822 def rawcommit(ui, repo, *flist, **rc):
1822 def rawcommit(ui, repo, *flist, **rc):
1823 """raw commit interface (DEPRECATED)
1823 """raw commit interface (DEPRECATED)
1824
1824
1825 Lowlevel commit, for use in helper scripts.
1825 Lowlevel commit, for use in helper scripts.
1826
1826
1827 This command is not intended to be used by normal users, as it is
1827 This command is not intended to be used by normal users, as it is
1828 primarily useful for importing from other SCMs.
1828 primarily useful for importing from other SCMs.
1829
1829
1830 This command is now deprecated and will be removed in a future
1830 This command is now deprecated and will be removed in a future
1831 release, please use debugsetparents and commit instead.
1831 release, please use debugsetparents and commit instead.
1832 """
1832 """
1833
1833
1834 ui.warn(_("(the rawcommit command is deprecated)\n"))
1834 ui.warn(_("(the rawcommit command is deprecated)\n"))
1835
1835
1836 message = rc['message']
1836 message = rc['message']
1837 if not message and rc['logfile']:
1837 if not message and rc['logfile']:
1838 try:
1838 try:
1839 message = open(rc['logfile']).read()
1839 message = open(rc['logfile']).read()
1840 except IOError:
1840 except IOError:
1841 pass
1841 pass
1842 if not message and not rc['logfile']:
1842 if not message and not rc['logfile']:
1843 raise util.Abort(_("missing commit message"))
1843 raise util.Abort(_("missing commit message"))
1844
1844
1845 files = relpath(repo, list(flist))
1845 files = relpath(repo, list(flist))
1846 if rc['files']:
1846 if rc['files']:
1847 files += open(rc['files']).read().splitlines()
1847 files += open(rc['files']).read().splitlines()
1848
1848
1849 rc['parent'] = map(repo.lookup, rc['parent'])
1849 rc['parent'] = map(repo.lookup, rc['parent'])
1850
1850
1851 try:
1851 try:
1852 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1852 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1853 except ValueError, inst:
1853 except ValueError, inst:
1854 raise util.Abort(str(inst))
1854 raise util.Abort(str(inst))
1855
1855
1856 def recover(ui, repo):
1856 def recover(ui, repo):
1857 """roll back an interrupted transaction
1857 """roll back an interrupted transaction
1858
1858
1859 Recover from an interrupted commit or pull.
1859 Recover from an interrupted commit or pull.
1860
1860
1861 This command tries to fix the repository status after an interrupted
1861 This command tries to fix the repository status after an interrupted
1862 operation. It should only be necessary when Mercurial suggests it.
1862 operation. It should only be necessary when Mercurial suggests it.
1863 """
1863 """
1864 if repo.recover():
1864 if repo.recover():
1865 return repo.verify()
1865 return repo.verify()
1866 return False
1866 return False
1867
1867
1868 def remove(ui, repo, pat, *pats, **opts):
1868 def remove(ui, repo, pat, *pats, **opts):
1869 """remove the specified files on the next commit
1869 """remove the specified files on the next commit
1870
1870
1871 Schedule the indicated files for removal from the repository.
1871 Schedule the indicated files for removal from the repository.
1872
1872
1873 This command schedules the files to be removed at the next commit.
1873 This command schedules the files to be removed at the next commit.
1874 This only removes files from the current branch, not from the
1874 This only removes files from the current branch, not from the
1875 entire project history. If the files still exist in the working
1875 entire project history. If the files still exist in the working
1876 directory, they will be deleted from it.
1876 directory, they will be deleted from it.
1877 """
1877 """
1878 names = []
1878 names = []
1879 def okaytoremove(abs, rel, exact):
1879 def okaytoremove(abs, rel, exact):
1880 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
1880 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
1881 reason = None
1881 reason = None
1882 if modified:
1882 if modified:
1883 reason = _('is modified')
1883 reason = _('is modified')
1884 elif added:
1884 elif added:
1885 reason = _('has been marked for add')
1885 reason = _('has been marked for add')
1886 elif unknown:
1886 elif unknown:
1887 reason = _('is not managed')
1887 reason = _('is not managed')
1888 if reason:
1888 if reason:
1889 if exact:
1889 if exact:
1890 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1890 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1891 else:
1891 else:
1892 return True
1892 return True
1893 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1893 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1894 if okaytoremove(abs, rel, exact):
1894 if okaytoremove(abs, rel, exact):
1895 if ui.verbose or not exact:
1895 if ui.verbose or not exact:
1896 ui.status(_('removing %s\n') % rel)
1896 ui.status(_('removing %s\n') % rel)
1897 names.append(abs)
1897 names.append(abs)
1898 repo.remove(names, unlink=True)
1898 repo.remove(names, unlink=True)
1899
1899
1900 def rename(ui, repo, *pats, **opts):
1900 def rename(ui, repo, *pats, **opts):
1901 """rename files; equivalent of copy + remove
1901 """rename files; equivalent of copy + remove
1902
1902
1903 Mark dest as copies of sources; mark sources for deletion. If
1903 Mark dest as copies of sources; mark sources for deletion. If
1904 dest is a directory, copies are put in that directory. If dest is
1904 dest is a directory, copies are put in that directory. If dest is
1905 a file, there can only be one source.
1905 a file, there can only be one source.
1906
1906
1907 By default, this command copies the contents of files as they
1907 By default, this command copies the contents of files as they
1908 stand in the working directory. If invoked with --after, the
1908 stand in the working directory. If invoked with --after, the
1909 operation is recorded, but no copying is performed.
1909 operation is recorded, but no copying is performed.
1910
1910
1911 This command takes effect in the next commit.
1911 This command takes effect in the next commit.
1912
1912
1913 NOTE: This command should be treated as experimental. While it
1913 NOTE: This command should be treated as experimental. While it
1914 should properly record rename files, this information is not yet
1914 should properly record rename files, this information is not yet
1915 fully used by merge, nor fully reported by log.
1915 fully used by merge, nor fully reported by log.
1916 """
1916 """
1917 errs, copied = docopy(ui, repo, pats, opts)
1917 errs, copied = docopy(ui, repo, pats, opts)
1918 names = []
1918 names = []
1919 for abs, rel, exact in copied:
1919 for abs, rel, exact in copied:
1920 if ui.verbose or not exact:
1920 if ui.verbose or not exact:
1921 ui.status(_('removing %s\n') % rel)
1921 ui.status(_('removing %s\n') % rel)
1922 names.append(abs)
1922 names.append(abs)
1923 repo.remove(names, unlink=True)
1923 repo.remove(names, unlink=True)
1924 return errs
1924 return errs
1925
1925
1926 def revert(ui, repo, *pats, **opts):
1926 def revert(ui, repo, *pats, **opts):
1927 """revert modified files or dirs back to their unmodified states
1927 """revert modified files or dirs back to their unmodified states
1928
1928
1929 Revert any uncommitted modifications made to the named files or
1929 Revert any uncommitted modifications made to the named files or
1930 directories. This restores the contents of the affected files to
1930 directories. This restores the contents of the affected files to
1931 an unmodified state.
1931 an unmodified state.
1932
1932
1933 If a file has been deleted, it is recreated. If the executable
1933 If a file has been deleted, it is recreated. If the executable
1934 mode of a file was changed, it is reset.
1934 mode of a file was changed, it is reset.
1935
1935
1936 If names are given, all files matching the names are reverted.
1936 If names are given, all files matching the names are reverted.
1937
1937
1938 If no arguments are given, all files in the repository are reverted.
1938 If no arguments are given, all files in the repository are reverted.
1939 """
1939 """
1940 node = opts['rev'] and repo.lookup(opts['rev']) or \
1940 node = opts['rev'] and repo.lookup(opts['rev']) or \
1941 repo.dirstate.parents()[0]
1941 repo.dirstate.parents()[0]
1942
1942
1943 files, choose, anypats = matchpats(repo, pats, opts)
1943 files, choose, anypats = matchpats(repo, pats, opts)
1944 modified, added, removed, deleted, unknown = repo.changes(match=choose)
1944 modified, added, removed, deleted, unknown = repo.changes(match=choose)
1945 repo.forget(added)
1945 repo.forget(added)
1946 repo.undelete(removed + deleted)
1946 repo.undelete(removed + deleted)
1947
1947
1948 return repo.update(node, False, True, choose, False)
1948 return repo.update(node, False, True, choose, False)
1949
1949
1950 def root(ui, repo):
1950 def root(ui, repo):
1951 """print the root (top) of the current working dir
1951 """print the root (top) of the current working dir
1952
1952
1953 Print the root directory of the current repository.
1953 Print the root directory of the current repository.
1954 """
1954 """
1955 ui.write(repo.root + "\n")
1955 ui.write(repo.root + "\n")
1956
1956
1957 def serve(ui, repo, **opts):
1957 def serve(ui, repo, **opts):
1958 """export the repository via HTTP
1958 """export the repository via HTTP
1959
1959
1960 Start a local HTTP repository browser and pull server.
1960 Start a local HTTP repository browser and pull server.
1961
1961
1962 By default, the server logs accesses to stdout and errors to
1962 By default, the server logs accesses to stdout and errors to
1963 stderr. Use the "-A" and "-E" options to log to files.
1963 stderr. Use the "-A" and "-E" options to log to files.
1964 """
1964 """
1965
1965
1966 if opts["stdio"]:
1966 if opts["stdio"]:
1967 fin, fout = sys.stdin, sys.stdout
1967 fin, fout = sys.stdin, sys.stdout
1968 sys.stdout = sys.stderr
1968 sys.stdout = sys.stderr
1969
1969
1970 # Prevent insertion/deletion of CRs
1970 # Prevent insertion/deletion of CRs
1971 util.set_binary(fin)
1971 util.set_binary(fin)
1972 util.set_binary(fout)
1972 util.set_binary(fout)
1973
1973
1974 def getarg():
1974 def getarg():
1975 argline = fin.readline()[:-1]
1975 argline = fin.readline()[:-1]
1976 arg, l = argline.split()
1976 arg, l = argline.split()
1977 val = fin.read(int(l))
1977 val = fin.read(int(l))
1978 return arg, val
1978 return arg, val
1979 def respond(v):
1979 def respond(v):
1980 fout.write("%d\n" % len(v))
1980 fout.write("%d\n" % len(v))
1981 fout.write(v)
1981 fout.write(v)
1982 fout.flush()
1982 fout.flush()
1983
1983
1984 lock = None
1984 lock = None
1985
1985
1986 while 1:
1986 while 1:
1987 cmd = fin.readline()[:-1]
1987 cmd = fin.readline()[:-1]
1988 if cmd == '':
1988 if cmd == '':
1989 return
1989 return
1990 if cmd == "heads":
1990 if cmd == "heads":
1991 h = repo.heads()
1991 h = repo.heads()
1992 respond(" ".join(map(hex, h)) + "\n")
1992 respond(" ".join(map(hex, h)) + "\n")
1993 if cmd == "lock":
1993 if cmd == "lock":
1994 lock = repo.lock()
1994 lock = repo.lock()
1995 respond("")
1995 respond("")
1996 if cmd == "unlock":
1996 if cmd == "unlock":
1997 if lock:
1997 if lock:
1998 lock.release()
1998 lock.release()
1999 lock = None
1999 lock = None
2000 respond("")
2000 respond("")
2001 elif cmd == "branches":
2001 elif cmd == "branches":
2002 arg, nodes = getarg()
2002 arg, nodes = getarg()
2003 nodes = map(bin, nodes.split(" "))
2003 nodes = map(bin, nodes.split(" "))
2004 r = []
2004 r = []
2005 for b in repo.branches(nodes):
2005 for b in repo.branches(nodes):
2006 r.append(" ".join(map(hex, b)) + "\n")
2006 r.append(" ".join(map(hex, b)) + "\n")
2007 respond("".join(r))
2007 respond("".join(r))
2008 elif cmd == "between":
2008 elif cmd == "between":
2009 arg, pairs = getarg()
2009 arg, pairs = getarg()
2010 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2010 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2011 r = []
2011 r = []
2012 for b in repo.between(pairs):
2012 for b in repo.between(pairs):
2013 r.append(" ".join(map(hex, b)) + "\n")
2013 r.append(" ".join(map(hex, b)) + "\n")
2014 respond("".join(r))
2014 respond("".join(r))
2015 elif cmd == "changegroup":
2015 elif cmd == "changegroup":
2016 nodes = []
2016 nodes = []
2017 arg, roots = getarg()
2017 arg, roots = getarg()
2018 nodes = map(bin, roots.split(" "))
2018 nodes = map(bin, roots.split(" "))
2019
2019
2020 cg = repo.changegroup(nodes, 'serve')
2020 cg = repo.changegroup(nodes, 'serve')
2021 while 1:
2021 while 1:
2022 d = cg.read(4096)
2022 d = cg.read(4096)
2023 if not d:
2023 if not d:
2024 break
2024 break
2025 fout.write(d)
2025 fout.write(d)
2026
2026
2027 fout.flush()
2027 fout.flush()
2028
2028
2029 elif cmd == "addchangegroup":
2029 elif cmd == "addchangegroup":
2030 if not lock:
2030 if not lock:
2031 respond("not locked")
2031 respond("not locked")
2032 continue
2032 continue
2033 respond("")
2033 respond("")
2034
2034
2035 r = repo.addchangegroup(fin)
2035 r = repo.addchangegroup(fin)
2036 respond("")
2036 respond("")
2037
2037
2038 optlist = "name templates style address port ipv6 accesslog errorlog"
2038 optlist = "name templates style address port ipv6 accesslog errorlog"
2039 for o in optlist.split():
2039 for o in optlist.split():
2040 if opts[o]:
2040 if opts[o]:
2041 ui.setconfig("web", o, opts[o])
2041 ui.setconfig("web", o, opts[o])
2042
2042
2043 if opts['daemon'] and not opts['daemon_pipefds']:
2043 if opts['daemon'] and not opts['daemon_pipefds']:
2044 rfd, wfd = os.pipe()
2044 rfd, wfd = os.pipe()
2045 args = sys.argv[:]
2045 args = sys.argv[:]
2046 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2046 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2047 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2047 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2048 args[0], args)
2048 args[0], args)
2049 os.close(wfd)
2049 os.close(wfd)
2050 os.read(rfd, 1)
2050 os.read(rfd, 1)
2051 os._exit(0)
2051 os._exit(0)
2052
2052
2053 try:
2053 try:
2054 httpd = hgweb.create_server(repo)
2054 httpd = hgweb.create_server(repo)
2055 except socket.error, inst:
2055 except socket.error, inst:
2056 raise util.Abort(_('cannot start server: ') + inst.args[1])
2056 raise util.Abort(_('cannot start server: ') + inst.args[1])
2057
2057
2058 if ui.verbose:
2058 if ui.verbose:
2059 addr, port = httpd.socket.getsockname()
2059 addr, port = httpd.socket.getsockname()
2060 if addr == '0.0.0.0':
2060 if addr == '0.0.0.0':
2061 addr = socket.gethostname()
2061 addr = socket.gethostname()
2062 else:
2062 else:
2063 try:
2063 try:
2064 addr = socket.gethostbyaddr(addr)[0]
2064 addr = socket.gethostbyaddr(addr)[0]
2065 except socket.error:
2065 except socket.error:
2066 pass
2066 pass
2067 if port != 80:
2067 if port != 80:
2068 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2068 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2069 else:
2069 else:
2070 ui.status(_('listening at http://%s/\n') % addr)
2070 ui.status(_('listening at http://%s/\n') % addr)
2071
2071
2072 if opts['pid_file']:
2072 if opts['pid_file']:
2073 fp = open(opts['pid_file'], 'w')
2073 fp = open(opts['pid_file'], 'w')
2074 fp.write(str(os.getpid()))
2074 fp.write(str(os.getpid()))
2075 fp.close()
2075 fp.close()
2076
2076
2077 if opts['daemon_pipefds']:
2077 if opts['daemon_pipefds']:
2078 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2078 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2079 os.close(rfd)
2079 os.close(rfd)
2080 os.write(wfd, 'y')
2080 os.write(wfd, 'y')
2081 os.close(wfd)
2081 os.close(wfd)
2082 sys.stdout.flush()
2082 sys.stdout.flush()
2083 sys.stderr.flush()
2083 sys.stderr.flush()
2084 fd = os.open(util.nulldev, os.O_RDWR)
2084 fd = os.open(util.nulldev, os.O_RDWR)
2085 if fd != 0: os.dup2(fd, 0)
2085 if fd != 0: os.dup2(fd, 0)
2086 if fd != 1: os.dup2(fd, 1)
2086 if fd != 1: os.dup2(fd, 1)
2087 if fd != 2: os.dup2(fd, 2)
2087 if fd != 2: os.dup2(fd, 2)
2088 if fd not in (0, 1, 2): os.close(fd)
2088 if fd not in (0, 1, 2): os.close(fd)
2089
2089
2090 httpd.serve_forever()
2090 httpd.serve_forever()
2091
2091
2092 def status(ui, repo, *pats, **opts):
2092 def status(ui, repo, *pats, **opts):
2093 """show changed files in the working directory
2093 """show changed files in the working directory
2094
2094
2095 Show changed files in the repository. If names are
2095 Show changed files in the repository. If names are
2096 given, only files that match are shown.
2096 given, only files that match are shown.
2097
2097
2098 The codes used to show the status of files are:
2098 The codes used to show the status of files are:
2099 M = modified
2099 M = modified
2100 A = added
2100 A = added
2101 R = removed
2101 R = removed
2102 ! = deleted, but still tracked
2102 ! = deleted, but still tracked
2103 ? = not tracked
2103 ? = not tracked
2104 """
2104 """
2105
2105
2106 files, matchfn, anypats = matchpats(repo, pats, opts)
2106 files, matchfn, anypats = matchpats(repo, pats, opts)
2107 cwd = (pats and repo.getcwd()) or ''
2107 cwd = (pats and repo.getcwd()) or ''
2108 modified, added, removed, deleted, unknown = [
2108 modified, added, removed, deleted, unknown = [
2109 [util.pathto(cwd, x) for x in n]
2109 [util.pathto(cwd, x) for x in n]
2110 for n in repo.changes(files=files, match=matchfn)]
2110 for n in repo.changes(files=files, match=matchfn)]
2111
2111
2112 changetypes = [(_('modified'), 'M', modified),
2112 changetypes = [(_('modified'), 'M', modified),
2113 (_('added'), 'A', added),
2113 (_('added'), 'A', added),
2114 (_('removed'), 'R', removed),
2114 (_('removed'), 'R', removed),
2115 (_('deleted'), '!', deleted),
2115 (_('deleted'), '!', deleted),
2116 (_('unknown'), '?', unknown)]
2116 (_('unknown'), '?', unknown)]
2117
2117
2118 end = opts['print0'] and '\0' or '\n'
2118 end = opts['print0'] and '\0' or '\n'
2119
2119
2120 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2120 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2121 or changetypes):
2121 or changetypes):
2122 if opts['no_status']:
2122 if opts['no_status']:
2123 format = "%%s%s" % end
2123 format = "%%s%s" % end
2124 else:
2124 else:
2125 format = "%s %%s%s" % (char, end);
2125 format = "%s %%s%s" % (char, end);
2126
2126
2127 for f in changes:
2127 for f in changes:
2128 ui.write(format % f)
2128 ui.write(format % f)
2129
2129
2130 def tag(ui, repo, name, rev_=None, **opts):
2130 def tag(ui, repo, name, rev_=None, **opts):
2131 """add a tag for the current tip or a given revision
2131 """add a tag for the current tip or a given revision
2132
2132
2133 Name a particular revision using <name>.
2133 Name a particular revision using <name>.
2134
2134
2135 Tags are used to name particular revisions of the repository and are
2135 Tags are used to name particular revisions of the repository and are
2136 very useful to compare different revision, to go back to significant
2136 very useful to compare different revision, to go back to significant
2137 earlier versions or to mark branch points as releases, etc.
2137 earlier versions or to mark branch points as releases, etc.
2138
2138
2139 If no revision is given, the tip is used.
2139 If no revision is given, the tip is used.
2140
2140
2141 To facilitate version control, distribution, and merging of tags,
2141 To facilitate version control, distribution, and merging of tags,
2142 they are stored as a file named ".hgtags" which is managed
2142 they are stored as a file named ".hgtags" which is managed
2143 similarly to other project files and can be hand-edited if
2143 similarly to other project files and can be hand-edited if
2144 necessary. The file '.hg/localtags' is used for local tags (not
2144 necessary. The file '.hg/localtags' is used for local tags (not
2145 shared among repositories).
2145 shared among repositories).
2146 """
2146 """
2147 if name == "tip":
2147 if name == "tip":
2148 raise util.Abort(_("the name 'tip' is reserved"))
2148 raise util.Abort(_("the name 'tip' is reserved"))
2149 if rev_ is not None:
2149 if rev_ is not None:
2150 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2150 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2151 "please use 'hg tag [-r REV] NAME' instead\n"))
2151 "please use 'hg tag [-r REV] NAME' instead\n"))
2152 if opts['rev']:
2152 if opts['rev']:
2153 raise util.Abort(_("use only one form to specify the revision"))
2153 raise util.Abort(_("use only one form to specify the revision"))
2154 if opts['rev']:
2154 if opts['rev']:
2155 rev_ = opts['rev']
2155 rev_ = opts['rev']
2156 if rev_:
2156 if rev_:
2157 r = hex(repo.lookup(rev_))
2157 r = hex(repo.lookup(rev_))
2158 else:
2158 else:
2159 r = hex(repo.changelog.tip())
2159 r = hex(repo.changelog.tip())
2160
2160
2161 disallowed = (revrangesep, '\r', '\n')
2161 disallowed = (revrangesep, '\r', '\n')
2162 for c in disallowed:
2162 for c in disallowed:
2163 if name.find(c) >= 0:
2163 if name.find(c) >= 0:
2164 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2164 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2165
2165
2166 repo.hook('pretag', throw=True, node=r, tag=name,
2166 repo.hook('pretag', throw=True, node=r, tag=name,
2167 local=int(not not opts['local']))
2167 local=int(not not opts['local']))
2168
2168
2169 if opts['local']:
2169 if opts['local']:
2170 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2170 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2171 repo.hook('tag', node=r, tag=name, local=1)
2171 repo.hook('tag', node=r, tag=name, local=1)
2172 return
2172 return
2173
2173
2174 for x in repo.changes():
2174 for x in repo.changes():
2175 if ".hgtags" in x:
2175 if ".hgtags" in x:
2176 raise util.Abort(_("working copy of .hgtags is changed "
2176 raise util.Abort(_("working copy of .hgtags is changed "
2177 "(please commit .hgtags manually)"))
2177 "(please commit .hgtags manually)"))
2178
2178
2179 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2179 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2180 if repo.dirstate.state(".hgtags") == '?':
2180 if repo.dirstate.state(".hgtags") == '?':
2181 repo.add([".hgtags"])
2181 repo.add([".hgtags"])
2182
2182
2183 message = (opts['message'] or
2183 message = (opts['message'] or
2184 _("Added tag %s for changeset %s") % (name, r))
2184 _("Added tag %s for changeset %s") % (name, r))
2185 try:
2185 try:
2186 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2186 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2187 repo.hook('tag', node=r, tag=name, local=0)
2187 repo.hook('tag', node=r, tag=name, local=0)
2188 except ValueError, inst:
2188 except ValueError, inst:
2189 raise util.Abort(str(inst))
2189 raise util.Abort(str(inst))
2190
2190
2191 def tags(ui, repo):
2191 def tags(ui, repo):
2192 """list repository tags
2192 """list repository tags
2193
2193
2194 List the repository tags.
2194 List the repository tags.
2195
2195
2196 This lists both regular and local tags.
2196 This lists both regular and local tags.
2197 """
2197 """
2198
2198
2199 l = repo.tagslist()
2199 l = repo.tagslist()
2200 l.reverse()
2200 l.reverse()
2201 for t, n in l:
2201 for t, n in l:
2202 try:
2202 try:
2203 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2203 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2204 except KeyError:
2204 except KeyError:
2205 r = " ?:?"
2205 r = " ?:?"
2206 ui.write("%-30s %s\n" % (t, r))
2206 ui.write("%-30s %s\n" % (t, r))
2207
2207
2208 def tip(ui, repo, **opts):
2208 def tip(ui, repo, **opts):
2209 """show the tip revision
2209 """show the tip revision
2210
2210
2211 Show the tip revision.
2211 Show the tip revision.
2212 """
2212 """
2213 n = repo.changelog.tip()
2213 n = repo.changelog.tip()
2214 show_changeset(ui, repo, changenode=n)
2214 show_changeset(ui, repo, changenode=n)
2215 if opts['patch']:
2215 if opts['patch']:
2216 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2216 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2217
2217
2218 def unbundle(ui, repo, fname, **opts):
2218 def unbundle(ui, repo, fname, **opts):
2219 """apply a changegroup file
2219 """apply a changegroup file
2220
2220
2221 Apply a compressed changegroup file generated by the bundle
2221 Apply a compressed changegroup file generated by the bundle
2222 command.
2222 command.
2223 """
2223 """
2224 f = urllib.urlopen(fname)
2224 f = urllib.urlopen(fname)
2225
2225
2226 if f.read(4) != "HG10":
2226 if f.read(4) != "HG10":
2227 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2227 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2228
2228
2229 def bzgenerator(f):
2229 def bzgenerator(f):
2230 zd = bz2.BZ2Decompressor()
2230 zd = bz2.BZ2Decompressor()
2231 for chunk in f:
2231 for chunk in f:
2232 yield zd.decompress(chunk)
2232 yield zd.decompress(chunk)
2233
2233
2234 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2234 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2235 if repo.addchangegroup(util.chunkbuffer(bzgen)):
2235 if repo.addchangegroup(util.chunkbuffer(bzgen)):
2236 return 1
2236 return 1
2237
2237
2238 if opts['update']:
2238 if opts['update']:
2239 return update(ui, repo)
2239 return update(ui, repo)
2240 else:
2240 else:
2241 ui.status(_("(run 'hg update' to get a working copy)\n"))
2241 ui.status(_("(run 'hg update' to get a working copy)\n"))
2242
2242
2243 def undo(ui, repo):
2243 def undo(ui, repo):
2244 """undo the last commit or pull
2244 """undo the last commit or pull
2245
2245
2246 Roll back the last pull or commit transaction on the
2246 Roll back the last pull or commit transaction on the
2247 repository, restoring the project to its earlier state.
2247 repository, restoring the project to its earlier state.
2248
2248
2249 This command should be used with care. There is only one level of
2249 This command should be used with care. There is only one level of
2250 undo and there is no redo.
2250 undo and there is no redo.
2251
2251
2252 This command is not intended for use on public repositories. Once
2252 This command is not intended for use on public repositories. Once
2253 a change is visible for pull by other users, undoing it locally is
2253 a change is visible for pull by other users, undoing it locally is
2254 ineffective.
2254 ineffective.
2255 """
2255 """
2256 repo.undo()
2256 repo.undo()
2257
2257
2258 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2258 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2259 branch=None):
2259 branch=None):
2260 """update or merge working directory
2260 """update or merge working directory
2261
2261
2262 Update the working directory to the specified revision.
2262 Update the working directory to the specified revision.
2263
2263
2264 If there are no outstanding changes in the working directory and
2264 If there are no outstanding changes in the working directory and
2265 there is a linear relationship between the current version and the
2265 there is a linear relationship between the current version and the
2266 requested version, the result is the requested version.
2266 requested version, the result is the requested version.
2267
2267
2268 Otherwise the result is a merge between the contents of the
2268 Otherwise the result is a merge between the contents of the
2269 current working directory and the requested version. Files that
2269 current working directory and the requested version. Files that
2270 changed between either parent are marked as changed for the next
2270 changed between either parent are marked as changed for the next
2271 commit and a commit must be performed before any further updates
2271 commit and a commit must be performed before any further updates
2272 are allowed.
2272 are allowed.
2273
2273
2274 By default, update will refuse to run if doing so would require
2274 By default, update will refuse to run if doing so would require
2275 merging or discarding local changes.
2275 merging or discarding local changes.
2276 """
2276 """
2277 if branch:
2277 if branch:
2278 br = repo.branchlookup(branch=branch)
2278 br = repo.branchlookup(branch=branch)
2279 found = []
2279 found = []
2280 for x in br:
2280 for x in br:
2281 if branch in br[x]:
2281 if branch in br[x]:
2282 found.append(x)
2282 found.append(x)
2283 if len(found) > 1:
2283 if len(found) > 1:
2284 ui.warn(_("Found multiple heads for %s\n") % branch)
2284 ui.warn(_("Found multiple heads for %s\n") % branch)
2285 for x in found:
2285 for x in found:
2286 show_changeset(ui, repo, changenode=x, brinfo=br)
2286 show_changeset(ui, repo, changenode=x, brinfo=br)
2287 return 1
2287 return 1
2288 if len(found) == 1:
2288 if len(found) == 1:
2289 node = found[0]
2289 node = found[0]
2290 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2290 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2291 else:
2291 else:
2292 ui.warn(_("branch %s not found\n") % (branch))
2292 ui.warn(_("branch %s not found\n") % (branch))
2293 return 1
2293 return 1
2294 else:
2294 else:
2295 node = node and repo.lookup(node) or repo.changelog.tip()
2295 node = node and repo.lookup(node) or repo.changelog.tip()
2296 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2296 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2297
2297
2298 def verify(ui, repo):
2298 def verify(ui, repo):
2299 """verify the integrity of the repository
2299 """verify the integrity of the repository
2300
2300
2301 Verify the integrity of the current repository.
2301 Verify the integrity of the current repository.
2302
2302
2303 This will perform an extensive check of the repository's
2303 This will perform an extensive check of the repository's
2304 integrity, validating the hashes and checksums of each entry in
2304 integrity, validating the hashes and checksums of each entry in
2305 the changelog, manifest, and tracked files, as well as the
2305 the changelog, manifest, and tracked files, as well as the
2306 integrity of their crosslinks and indices.
2306 integrity of their crosslinks and indices.
2307 """
2307 """
2308 return repo.verify()
2308 return repo.verify()
2309
2309
2310 # Command options and aliases are listed here, alphabetically
2310 # Command options and aliases are listed here, alphabetically
2311
2311
2312 table = {
2312 table = {
2313 "^add":
2313 "^add":
2314 (add,
2314 (add,
2315 [('I', 'include', [], _('include names matching the given patterns')),
2315 [('I', 'include', [], _('include names matching the given patterns')),
2316 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2316 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2317 _('hg add [OPTION]... [FILE]...')),
2317 _('hg add [OPTION]... [FILE]...')),
2318 "addremove":
2318 "addremove":
2319 (addremove,
2319 (addremove,
2320 [('I', 'include', [], _('include names matching the given patterns')),
2320 [('I', 'include', [], _('include names matching the given patterns')),
2321 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2321 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2322 _('hg addremove [OPTION]... [FILE]...')),
2322 _('hg addremove [OPTION]... [FILE]...')),
2323 "^annotate":
2323 "^annotate":
2324 (annotate,
2324 (annotate,
2325 [('r', 'rev', '', _('annotate the specified revision')),
2325 [('r', 'rev', '', _('annotate the specified revision')),
2326 ('a', 'text', None, _('treat all files as text')),
2326 ('a', 'text', None, _('treat all files as text')),
2327 ('u', 'user', None, _('list the author')),
2327 ('u', 'user', None, _('list the author')),
2328 ('d', 'date', None, _('list the date')),
2328 ('d', 'date', None, _('list the date')),
2329 ('n', 'number', None, _('list the revision number (default)')),
2329 ('n', 'number', None, _('list the revision number (default)')),
2330 ('c', 'changeset', None, _('list the changeset')),
2330 ('c', 'changeset', None, _('list the changeset')),
2331 ('I', 'include', [], _('include names matching the given patterns')),
2331 ('I', 'include', [], _('include names matching the given patterns')),
2332 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2332 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2333 _('hg annotate [OPTION]... FILE...')),
2333 _('hg annotate [OPTION]... FILE...')),
2334 "bundle":
2334 "bundle":
2335 (bundle,
2335 (bundle,
2336 [],
2336 [],
2337 _('hg bundle FILE DEST')),
2337 _('hg bundle FILE DEST')),
2338 "cat":
2338 "cat":
2339 (cat,
2339 (cat,
2340 [('I', 'include', [], _('include names matching the given patterns')),
2340 [('I', 'include', [], _('include names matching the given patterns')),
2341 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2341 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2342 ('o', 'output', '', _('print output to file with formatted name')),
2342 ('o', 'output', '', _('print output to file with formatted name')),
2343 ('r', 'rev', '', _('print the given revision'))],
2343 ('r', 'rev', '', _('print the given revision'))],
2344 _('hg cat [OPTION]... FILE...')),
2344 _('hg cat [OPTION]... FILE...')),
2345 "^clone":
2345 "^clone":
2346 (clone,
2346 (clone,
2347 [('U', 'noupdate', None, _('do not update the new working directory')),
2347 [('U', 'noupdate', None, _('do not update the new working directory')),
2348 ('e', 'ssh', '', _('specify ssh command to use')),
2348 ('e', 'ssh', '', _('specify ssh command to use')),
2349 ('', 'pull', None, _('use pull protocol to copy metadata')),
2349 ('', 'pull', None, _('use pull protocol to copy metadata')),
2350 ('r', 'rev', [],
2350 ('r', 'rev', [],
2351 _('a changeset you would like to have after cloning')),
2351 _('a changeset you would like to have after cloning')),
2352 ('', 'remotecmd', '',
2352 ('', 'remotecmd', '',
2353 _('specify hg command to run on the remote side'))],
2353 _('specify hg command to run on the remote side'))],
2354 _('hg clone [OPTION]... SOURCE [DEST]')),
2354 _('hg clone [OPTION]... SOURCE [DEST]')),
2355 "^commit|ci":
2355 "^commit|ci":
2356 (commit,
2356 (commit,
2357 [('A', 'addremove', None, _('run addremove during commit')),
2357 [('A', 'addremove', None, _('run addremove during commit')),
2358 ('I', 'include', [], _('include names matching the given patterns')),
2358 ('I', 'include', [], _('include names matching the given patterns')),
2359 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2359 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2360 ('m', 'message', '', _('use <text> as commit message')),
2360 ('m', 'message', '', _('use <text> as commit message')),
2361 ('l', 'logfile', '', _('read the commit message from <file>')),
2361 ('l', 'logfile', '', _('read the commit message from <file>')),
2362 ('d', 'date', '', _('record datecode as commit date')),
2362 ('d', 'date', '', _('record datecode as commit date')),
2363 ('u', 'user', '', _('record user as commiter'))],
2363 ('u', 'user', '', _('record user as commiter'))],
2364 _('hg commit [OPTION]... [FILE]...')),
2364 _('hg commit [OPTION]... [FILE]...')),
2365 "copy|cp":
2365 "copy|cp":
2366 (copy,
2366 (copy,
2367 [('I', 'include', [], _('include names matching the given patterns')),
2367 [('I', 'include', [], _('include names matching the given patterns')),
2368 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2368 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2369 ('A', 'after', None, _('record a copy that has already occurred')),
2369 ('A', 'after', None, _('record a copy that has already occurred')),
2370 ('f', 'force', None,
2370 ('f', 'force', None,
2371 _('forcibly copy over an existing managed file'))],
2371 _('forcibly copy over an existing managed file'))],
2372 _('hg copy [OPTION]... [SOURCE]... DEST')),
2372 _('hg copy [OPTION]... [SOURCE]... DEST')),
2373 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2373 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2374 "debugrebuildstate":
2374 "debugrebuildstate":
2375 (debugrebuildstate,
2375 (debugrebuildstate,
2376 [('r', 'rev', "", _("revision to rebuild to"))],
2376 [('r', 'rev', "", _("revision to rebuild to"))],
2377 _('debugrebuildstate [-r REV] [REV]')),
2377 _('debugrebuildstate [-r REV] [REV]')),
2378 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2378 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2379 "debugconfig": (debugconfig, [], _('debugconfig')),
2379 "debugconfig": (debugconfig, [], _('debugconfig')),
2380 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2380 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2381 "debugstate": (debugstate, [], _('debugstate')),
2381 "debugstate": (debugstate, [], _('debugstate')),
2382 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2382 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2383 "debugindex": (debugindex, [], _('debugindex FILE')),
2383 "debugindex": (debugindex, [], _('debugindex FILE')),
2384 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2384 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2385 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2385 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2386 "debugwalk":
2386 "debugwalk":
2387 (debugwalk,
2387 (debugwalk,
2388 [('I', 'include', [], _('include names matching the given patterns')),
2388 [('I', 'include', [], _('include names matching the given patterns')),
2389 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2389 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2390 _('debugwalk [OPTION]... [FILE]...')),
2390 _('debugwalk [OPTION]... [FILE]...')),
2391 "^diff":
2391 "^diff":
2392 (diff,
2392 (diff,
2393 [('r', 'rev', [], _('revision')),
2393 [('r', 'rev', [], _('revision')),
2394 ('a', 'text', None, _('treat all files as text')),
2394 ('a', 'text', None, _('treat all files as text')),
2395 ('I', 'include', [], _('include names matching the given patterns')),
2395 ('I', 'include', [], _('include names matching the given patterns')),
2396 ('p', 'show-function', None,
2396 ('p', 'show-function', None,
2397 _('show which function each change is in')),
2397 _('show which function each change is in')),
2398 ('w', 'ignore-all-space', None,
2398 ('w', 'ignore-all-space', None,
2399 _('ignore white space when comparing lines')),
2399 _('ignore white space when comparing lines')),
2400 ('X', 'exclude', [],
2400 ('X', 'exclude', [],
2401 _('exclude names matching the given patterns'))],
2401 _('exclude names matching the given patterns'))],
2402 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2402 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2403 "^export":
2403 "^export":
2404 (export,
2404 (export,
2405 [('o', 'output', '', _('print output to file with formatted name')),
2405 [('o', 'output', '', _('print output to file with formatted name')),
2406 ('a', 'text', None, _('treat all files as text')),
2406 ('a', 'text', None, _('treat all files as text')),
2407 ('', 'switch-parent', None, _('diff against the second parent'))],
2407 ('', 'switch-parent', None, _('diff against the second parent'))],
2408 _('hg export [-a] [-o OUTFILE] REV...')),
2408 _('hg export [-a] [-o OUTFILE] REV...')),
2409 "forget":
2409 "forget":
2410 (forget,
2410 (forget,
2411 [('I', 'include', [], _('include names matching the given patterns')),
2411 [('I', 'include', [], _('include names matching the given patterns')),
2412 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2412 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2413 _('hg forget [OPTION]... FILE...')),
2413 _('hg forget [OPTION]... FILE...')),
2414 "grep":
2414 "grep":
2415 (grep,
2415 (grep,
2416 [('0', 'print0', None, _('end fields with NUL')),
2416 [('0', 'print0', None, _('end fields with NUL')),
2417 ('I', 'include', [], _('include names matching the given patterns')),
2417 ('I', 'include', [], _('include names matching the given patterns')),
2418 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2418 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2419 ('', 'all', None, _('print all revisions that match')),
2419 ('', 'all', None, _('print all revisions that match')),
2420 ('i', 'ignore-case', None, _('ignore case when matching')),
2420 ('i', 'ignore-case', None, _('ignore case when matching')),
2421 ('l', 'files-with-matches', None,
2421 ('l', 'files-with-matches', None,
2422 _('print only filenames and revs that match')),
2422 _('print only filenames and revs that match')),
2423 ('n', 'line-number', None, _('print matching line numbers')),
2423 ('n', 'line-number', None, _('print matching line numbers')),
2424 ('r', 'rev', [], _('search in given revision range')),
2424 ('r', 'rev', [], _('search in given revision range')),
2425 ('u', 'user', None, _('print user who committed change'))],
2425 ('u', 'user', None, _('print user who committed change'))],
2426 _('hg grep [OPTION]... PATTERN [FILE]...')),
2426 _('hg grep [OPTION]... PATTERN [FILE]...')),
2427 "heads":
2427 "heads":
2428 (heads,
2428 (heads,
2429 [('b', 'branches', None, _('find branch info')),
2429 [('b', 'branches', None, _('find branch info')),
2430 ('r', 'rev', '', _('show only heads which are descendants of rev'))],
2430 ('r', 'rev', '', _('show only heads which are descendants of rev'))],
2431 _('hg heads [-b] [-r <rev>]')),
2431 _('hg heads [-b] [-r <rev>]')),
2432 "help": (help_, [], _('hg help [COMMAND]')),
2432 "help": (help_, [], _('hg help [COMMAND]')),
2433 "identify|id": (identify, [], _('hg identify')),
2433 "identify|id": (identify, [], _('hg identify')),
2434 "import|patch":
2434 "import|patch":
2435 (import_,
2435 (import_,
2436 [('p', 'strip', 1,
2436 [('p', 'strip', 1,
2437 _('directory strip option for patch. This has the same\n') +
2437 _('directory strip option for patch. This has the same\n') +
2438 _('meaning as the corresponding patch option')),
2438 _('meaning as the corresponding patch option')),
2439 ('f', 'force', None,
2439 ('f', 'force', None,
2440 _('skip check for outstanding uncommitted changes')),
2440 _('skip check for outstanding uncommitted changes')),
2441 ('b', 'base', '', _('base path'))],
2441 ('b', 'base', '', _('base path'))],
2442 _('hg import [-f] [-p NUM] [-b BASE] PATCH...')),
2442 _('hg import [-f] [-p NUM] [-b BASE] PATCH...')),
2443 "incoming|in": (incoming,
2443 "incoming|in": (incoming,
2444 [('M', 'no-merges', None, _('do not show merges')),
2444 [('M', 'no-merges', None, _('do not show merges')),
2445 ('p', 'patch', None, _('show patch')),
2445 ('p', 'patch', None, _('show patch')),
2446 ('n', 'newest-first', None, _('show newest record first'))],
2446 ('n', 'newest-first', None, _('show newest record first'))],
2447 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2447 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2448 "^init": (init, [], _('hg init [DEST]')),
2448 "^init": (init, [], _('hg init [DEST]')),
2449 "locate":
2449 "locate":
2450 (locate,
2450 (locate,
2451 [('r', 'rev', '', _('search the repository as it stood at rev')),
2451 [('r', 'rev', '', _('search the repository as it stood at rev')),
2452 ('0', 'print0', None,
2452 ('0', 'print0', None,
2453 _('end filenames with NUL, for use with xargs')),
2453 _('end filenames with NUL, for use with xargs')),
2454 ('f', 'fullpath', None,
2454 ('f', 'fullpath', None,
2455 _('print complete paths from the filesystem root')),
2455 _('print complete paths from the filesystem root')),
2456 ('I', 'include', [], _('include names matching the given patterns')),
2456 ('I', 'include', [], _('include names matching the given patterns')),
2457 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2457 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2458 _('hg locate [OPTION]... [PATTERN]...')),
2458 _('hg locate [OPTION]... [PATTERN]...')),
2459 "^log|history":
2459 "^log|history":
2460 (log,
2460 (log,
2461 [('I', 'include', [], _('include names matching the given patterns')),
2461 [('I', 'include', [], _('include names matching the given patterns')),
2462 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2462 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2463 ('b', 'branch', None, _('show branches')),
2463 ('b', 'branch', None, _('show branches')),
2464 ('k', 'keyword', [], _('search for a keyword')),
2464 ('k', 'keyword', [], _('search for a keyword')),
2465 ('r', 'rev', [], _('show the specified revision or range')),
2465 ('r', 'rev', [], _('show the specified revision or range')),
2466 ('M', 'no-merges', None, _('do not show merges')),
2466 ('M', 'no-merges', None, _('do not show merges')),
2467 ('m', 'only-merges', None, _('show only merges')),
2467 ('m', 'only-merges', None, _('show only merges')),
2468 ('p', 'patch', None, _('show patch'))],
2468 ('p', 'patch', None, _('show patch'))],
2469 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2469 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2470 "manifest": (manifest, [], _('hg manifest [REV]')),
2470 "manifest": (manifest, [], _('hg manifest [REV]')),
2471 "outgoing|out": (outgoing,
2471 "outgoing|out": (outgoing,
2472 [('M', 'no-merges', None, _('do not show merges')),
2472 [('M', 'no-merges', None, _('do not show merges')),
2473 ('p', 'patch', None, _('show patch')),
2473 ('p', 'patch', None, _('show patch')),
2474 ('n', 'newest-first', None, _('show newest record first'))],
2474 ('n', 'newest-first', None, _('show newest record first'))],
2475 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2475 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2476 "^parents":
2476 "^parents":
2477 (parents,
2477 (parents,
2478 [('b', 'branch', None, _('show branches'))],
2478 [('b', 'branch', None, _('show branches'))],
2479 _('hg parents [-b] [REV]')),
2479 _('hg parents [-b] [REV]')),
2480 "paths": (paths, [], _('hg paths [NAME]')),
2480 "paths": (paths, [], _('hg paths [NAME]')),
2481 "^pull":
2481 "^pull":
2482 (pull,
2482 (pull,
2483 [('u', 'update', None,
2483 [('u', 'update', None,
2484 _('update the working directory to tip after pull')),
2484 _('update the working directory to tip after pull')),
2485 ('e', 'ssh', '', _('specify ssh command to use')),
2485 ('e', 'ssh', '', _('specify ssh command to use')),
2486 ('r', 'rev', [], _('a specific revision you would like to pull')),
2486 ('r', 'rev', [], _('a specific revision you would like to pull')),
2487 ('', 'remotecmd', '',
2487 ('', 'remotecmd', '',
2488 _('specify hg command to run on the remote side'))],
2488 _('specify hg command to run on the remote side'))],
2489 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2489 _('hg pull [-u] [-e FILE] [-r rev] [--remotecmd FILE] [SOURCE]')),
2490 "^push":
2490 "^push":
2491 (push,
2491 (push,
2492 [('f', 'force', None, _('force push')),
2492 [('f', 'force', None, _('force push')),
2493 ('e', 'ssh', '', _('specify ssh command to use')),
2493 ('e', 'ssh', '', _('specify ssh command to use')),
2494 ('', 'remotecmd', '',
2494 ('', 'remotecmd', '',
2495 _('specify hg command to run on the remote side'))],
2495 _('specify hg command to run on the remote side'))],
2496 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2496 _('hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]')),
2497 "rawcommit":
2497 "rawcommit":
2498 (rawcommit,
2498 (rawcommit,
2499 [('p', 'parent', [], _('parent')),
2499 [('p', 'parent', [], _('parent')),
2500 ('d', 'date', '', _('date code')),
2500 ('d', 'date', '', _('date code')),
2501 ('u', 'user', '', _('user')),
2501 ('u', 'user', '', _('user')),
2502 ('F', 'files', '', _('file list')),
2502 ('F', 'files', '', _('file list')),
2503 ('m', 'message', '', _('commit message')),
2503 ('m', 'message', '', _('commit message')),
2504 ('l', 'logfile', '', _('commit message file'))],
2504 ('l', 'logfile', '', _('commit message file'))],
2505 _('hg rawcommit [OPTION]... [FILE]...')),
2505 _('hg rawcommit [OPTION]... [FILE]...')),
2506 "recover": (recover, [], _('hg recover')),
2506 "recover": (recover, [], _('hg recover')),
2507 "^remove|rm":
2507 "^remove|rm":
2508 (remove,
2508 (remove,
2509 [('I', 'include', [], _('include names matching the given patterns')),
2509 [('I', 'include', [], _('include names matching the given patterns')),
2510 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2510 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2511 _('hg remove [OPTION]... FILE...')),
2511 _('hg remove [OPTION]... FILE...')),
2512 "rename|mv":
2512 "rename|mv":
2513 (rename,
2513 (rename,
2514 [('I', 'include', [], _('include names matching the given patterns')),
2514 [('I', 'include', [], _('include names matching the given patterns')),
2515 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2515 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2516 ('A', 'after', None, _('record a rename that has already occurred')),
2516 ('A', 'after', None, _('record a rename that has already occurred')),
2517 ('f', 'force', None,
2517 ('f', 'force', None,
2518 _('forcibly copy over an existing managed file'))],
2518 _('forcibly copy over an existing managed file'))],
2519 _('hg rename [OPTION]... [SOURCE]... DEST')),
2519 _('hg rename [OPTION]... [SOURCE]... DEST')),
2520 "^revert":
2520 "^revert":
2521 (revert,
2521 (revert,
2522 [('I', 'include', [], _('include names matching the given patterns')),
2522 [('I', 'include', [], _('include names matching the given patterns')),
2523 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2523 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2524 ('r', 'rev', '', _('revision to revert to'))],
2524 ('r', 'rev', '', _('revision to revert to'))],
2525 _('hg revert [-n] [-r REV] [NAME]...')),
2525 _('hg revert [-n] [-r REV] [NAME]...')),
2526 "root": (root, [], _('hg root')),
2526 "root": (root, [], _('hg root')),
2527 "^serve":
2527 "^serve":
2528 (serve,
2528 (serve,
2529 [('A', 'accesslog', '', _('name of access log file to write to')),
2529 [('A', 'accesslog', '', _('name of access log file to write to')),
2530 ('d', 'daemon', None, _('run server in background')),
2530 ('d', 'daemon', None, _('run server in background')),
2531 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2531 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2532 ('E', 'errorlog', '', _('name of error log file to write to')),
2532 ('E', 'errorlog', '', _('name of error log file to write to')),
2533 ('p', 'port', 0, _('port to use (default: 8000)')),
2533 ('p', 'port', 0, _('port to use (default: 8000)')),
2534 ('a', 'address', '', _('address to use')),
2534 ('a', 'address', '', _('address to use')),
2535 ('n', 'name', '',
2535 ('n', 'name', '',
2536 _('name to show in web pages (default: working dir)')),
2536 _('name to show in web pages (default: working dir)')),
2537 ('', 'pid-file', '', _('name of file to write process ID to')),
2537 ('', 'pid-file', '', _('name of file to write process ID to')),
2538 ('', 'stdio', None, _('for remote clients')),
2538 ('', 'stdio', None, _('for remote clients')),
2539 ('t', 'templates', '', _('web templates to use')),
2539 ('t', 'templates', '', _('web templates to use')),
2540 ('', 'style', '', _('template style to use')),
2540 ('', 'style', '', _('template style to use')),
2541 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2541 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2542 _('hg serve [OPTION]...')),
2542 _('hg serve [OPTION]...')),
2543 "^status|st":
2543 "^status|st":
2544 (status,
2544 (status,
2545 [('m', 'modified', None, _('show only modified files')),
2545 [('m', 'modified', None, _('show only modified files')),
2546 ('a', 'added', None, _('show only added files')),
2546 ('a', 'added', None, _('show only added files')),
2547 ('r', 'removed', None, _('show only removed files')),
2547 ('r', 'removed', None, _('show only removed files')),
2548 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2548 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2549 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2549 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2550 ('n', 'no-status', None, _('hide status prefix')),
2550 ('n', 'no-status', None, _('hide status prefix')),
2551 ('0', 'print0', None,
2551 ('0', 'print0', None,
2552 _('end filenames with NUL, for use with xargs')),
2552 _('end filenames with NUL, for use with xargs')),
2553 ('I', 'include', [], _('include names matching the given patterns')),
2553 ('I', 'include', [], _('include names matching the given patterns')),
2554 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2554 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2555 _('hg status [OPTION]... [FILE]...')),
2555 _('hg status [OPTION]... [FILE]...')),
2556 "tag":
2556 "tag":
2557 (tag,
2557 (tag,
2558 [('l', 'local', None, _('make the tag local')),
2558 [('l', 'local', None, _('make the tag local')),
2559 ('m', 'message', '', _('message for tag commit log entry')),
2559 ('m', 'message', '', _('message for tag commit log entry')),
2560 ('d', 'date', '', _('record datecode as commit date')),
2560 ('d', 'date', '', _('record datecode as commit date')),
2561 ('u', 'user', '', _('record user as commiter')),
2561 ('u', 'user', '', _('record user as commiter')),
2562 ('r', 'rev', '', _('revision to tag'))],
2562 ('r', 'rev', '', _('revision to tag'))],
2563 _('hg tag [-r REV] [OPTION]... NAME')),
2563 _('hg tag [-r REV] [OPTION]... NAME')),
2564 "tags": (tags, [], _('hg tags')),
2564 "tags": (tags, [], _('hg tags')),
2565 "tip": (tip, [('p', 'patch', None, _('show patch'))], _('hg tip')),
2565 "tip": (tip, [('p', 'patch', None, _('show patch'))], _('hg tip')),
2566 "unbundle":
2566 "unbundle":
2567 (unbundle,
2567 (unbundle,
2568 [('u', 'update', None,
2568 [('u', 'update', None,
2569 _('update the working directory to tip after unbundle'))],
2569 _('update the working directory to tip after unbundle'))],
2570 _('hg unbundle [-u] FILE')),
2570 _('hg unbundle [-u] FILE')),
2571 "undo": (undo, [], _('hg undo')),
2571 "undo": (undo, [], _('hg undo')),
2572 "^update|up|checkout|co":
2572 "^update|up|checkout|co":
2573 (update,
2573 (update,
2574 [('b', 'branch', '', _('checkout the head of a specific branch')),
2574 [('b', 'branch', '', _('checkout the head of a specific branch')),
2575 ('m', 'merge', None, _('allow merging of branches')),
2575 ('m', 'merge', None, _('allow merging of branches')),
2576 ('C', 'clean', None, _('overwrite locally modified files')),
2576 ('C', 'clean', None, _('overwrite locally modified files')),
2577 ('f', 'force', None, _('force a merge with outstanding changes'))],
2577 ('f', 'force', None, _('force a merge with outstanding changes'))],
2578 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
2578 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
2579 "verify": (verify, [], _('hg verify')),
2579 "verify": (verify, [], _('hg verify')),
2580 "version": (show_version, [], _('hg version')),
2580 "version": (show_version, [], _('hg version')),
2581 }
2581 }
2582
2582
2583 globalopts = [
2583 globalopts = [
2584 ('R', 'repository', '', _('repository root directory')),
2584 ('R', 'repository', '', _('repository root directory')),
2585 ('', 'cwd', '', _('change working directory')),
2585 ('', 'cwd', '', _('change working directory')),
2586 ('y', 'noninteractive', None,
2586 ('y', 'noninteractive', None,
2587 _('do not prompt, assume \'yes\' for any required answers')),
2587 _('do not prompt, assume \'yes\' for any required answers')),
2588 ('q', 'quiet', None, _('suppress output')),
2588 ('q', 'quiet', None, _('suppress output')),
2589 ('v', 'verbose', None, _('enable additional output')),
2589 ('v', 'verbose', None, _('enable additional output')),
2590 ('', 'debug', None, _('enable debugging output')),
2590 ('', 'debug', None, _('enable debugging output')),
2591 ('', 'debugger', None, _('start debugger')),
2591 ('', 'debugger', None, _('start debugger')),
2592 ('', 'traceback', None, _('print traceback on exception')),
2592 ('', 'traceback', None, _('print traceback on exception')),
2593 ('', 'time', None, _('time how long the command takes')),
2593 ('', 'time', None, _('time how long the command takes')),
2594 ('', 'profile', None, _('print command execution profile')),
2594 ('', 'profile', None, _('print command execution profile')),
2595 ('', 'version', None, _('output version information and exit')),
2595 ('', 'version', None, _('output version information and exit')),
2596 ('h', 'help', None, _('display help and exit')),
2596 ('h', 'help', None, _('display help and exit')),
2597 ]
2597 ]
2598
2598
2599 norepo = ("clone init version help debugancestor debugconfig debugdata"
2599 norepo = ("clone init version help debugancestor debugconfig debugdata"
2600 " debugindex debugindexdot paths")
2600 " debugindex debugindexdot paths")
2601
2601
2602 def find(cmd):
2602 def find(cmd):
2603 """Return (aliases, command table entry) for command string."""
2603 """Return (aliases, command table entry) for command string."""
2604 choice = None
2604 choice = None
2605 count = 0
2605 count = 0
2606 for e in table.keys():
2606 for e in table.keys():
2607 aliases = e.lstrip("^").split("|")
2607 aliases = e.lstrip("^").split("|")
2608 if cmd in aliases:
2608 if cmd in aliases:
2609 return aliases, table[e]
2609 return aliases, table[e]
2610 for a in aliases:
2610 for a in aliases:
2611 if a.startswith(cmd):
2611 if a.startswith(cmd):
2612 count += 1
2612 count += 1
2613 choice = aliases, table[e]
2613 choice = aliases, table[e]
2614 break
2614 break
2615
2615
2616 if count > 1:
2616 if count > 1:
2617 raise AmbiguousCommand(cmd)
2617 raise AmbiguousCommand(cmd)
2618
2618
2619 if choice:
2619 if choice:
2620 return choice
2620 return choice
2621
2621
2622 raise UnknownCommand(cmd)
2622 raise UnknownCommand(cmd)
2623
2623
2624 class SignalInterrupt(Exception):
2624 class SignalInterrupt(Exception):
2625 """Exception raised on SIGTERM and SIGHUP."""
2625 """Exception raised on SIGTERM and SIGHUP."""
2626
2626
2627 def catchterm(*args):
2627 def catchterm(*args):
2628 raise SignalInterrupt
2628 raise SignalInterrupt
2629
2629
2630 def run():
2630 def run():
2631 sys.exit(dispatch(sys.argv[1:]))
2631 sys.exit(dispatch(sys.argv[1:]))
2632
2632
2633 class ParseError(Exception):
2633 class ParseError(Exception):
2634 """Exception raised on errors in parsing the command line."""
2634 """Exception raised on errors in parsing the command line."""
2635
2635
2636 def parse(ui, args):
2636 def parse(ui, args):
2637 options = {}
2637 options = {}
2638 cmdoptions = {}
2638 cmdoptions = {}
2639
2639
2640 try:
2640 try:
2641 args = fancyopts.fancyopts(args, globalopts, options)
2641 args = fancyopts.fancyopts(args, globalopts, options)
2642 except fancyopts.getopt.GetoptError, inst:
2642 except fancyopts.getopt.GetoptError, inst:
2643 raise ParseError(None, inst)
2643 raise ParseError(None, inst)
2644
2644
2645 if args:
2645 if args:
2646 cmd, args = args[0], args[1:]
2646 cmd, args = args[0], args[1:]
2647 aliases, i = find(cmd)
2647 aliases, i = find(cmd)
2648 cmd = aliases[0]
2648 cmd = aliases[0]
2649 defaults = ui.config("defaults", cmd)
2649 defaults = ui.config("defaults", cmd)
2650 if defaults:
2650 if defaults:
2651 args = defaults.split() + args
2651 args = defaults.split() + args
2652 c = list(i[1])
2652 c = list(i[1])
2653 else:
2653 else:
2654 cmd = None
2654 cmd = None
2655 c = []
2655 c = []
2656
2656
2657 # combine global options into local
2657 # combine global options into local
2658 for o in globalopts:
2658 for o in globalopts:
2659 c.append((o[0], o[1], options[o[1]], o[3]))
2659 c.append((o[0], o[1], options[o[1]], o[3]))
2660
2660
2661 try:
2661 try:
2662 args = fancyopts.fancyopts(args, c, cmdoptions)
2662 args = fancyopts.fancyopts(args, c, cmdoptions)
2663 except fancyopts.getopt.GetoptError, inst:
2663 except fancyopts.getopt.GetoptError, inst:
2664 raise ParseError(cmd, inst)
2664 raise ParseError(cmd, inst)
2665
2665
2666 # separate global options back out
2666 # separate global options back out
2667 for o in globalopts:
2667 for o in globalopts:
2668 n = o[1]
2668 n = o[1]
2669 options[n] = cmdoptions[n]
2669 options[n] = cmdoptions[n]
2670 del cmdoptions[n]
2670 del cmdoptions[n]
2671
2671
2672 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2672 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2673
2673
2674 def dispatch(args):
2674 def dispatch(args):
2675 signal.signal(signal.SIGTERM, catchterm)
2675 signal.signal(signal.SIGTERM, catchterm)
2676 try:
2676 try:
2677 signal.signal(signal.SIGHUP, catchterm)
2677 signal.signal(signal.SIGHUP, catchterm)
2678 except AttributeError:
2678 except AttributeError:
2679 pass
2679 pass
2680
2680
2681 try:
2681 try:
2682 u = ui.ui()
2682 u = ui.ui()
2683 except util.Abort, inst:
2683 except util.Abort, inst:
2684 sys.stderr.write(_("abort: %s\n") % inst)
2684 sys.stderr.write(_("abort: %s\n") % inst)
2685 sys.exit(1)
2685 sys.exit(1)
2686
2686
2687 external = []
2687 external = []
2688 for x in u.extensions():
2688 for x in u.extensions():
2689 def on_exception(exc, inst):
2689 def on_exception(exc, inst):
2690 u.warn(_("*** failed to import extension %s\n") % x[1])
2690 u.warn(_("*** failed to import extension %s\n") % x[1])
2691 u.warn("%s\n" % inst)
2691 u.warn("%s\n" % inst)
2692 if "--traceback" in sys.argv[1:]:
2692 if "--traceback" in sys.argv[1:]:
2693 traceback.print_exc()
2693 traceback.print_exc()
2694 if x[1]:
2694 if x[1]:
2695 try:
2695 try:
2696 mod = imp.load_source(x[0], x[1])
2696 mod = imp.load_source(x[0], x[1])
2697 except Exception, inst:
2697 except Exception, inst:
2698 on_exception(Exception, inst)
2698 on_exception(Exception, inst)
2699 continue
2699 continue
2700 else:
2700 else:
2701 def importh(name):
2701 def importh(name):
2702 mod = __import__(name)
2702 mod = __import__(name)
2703 components = name.split('.')
2703 components = name.split('.')
2704 for comp in components[1:]:
2704 for comp in components[1:]:
2705 mod = getattr(mod, comp)
2705 mod = getattr(mod, comp)
2706 return mod
2706 return mod
2707 try:
2707 try:
2708 mod = importh(x[0])
2708 mod = importh(x[0])
2709 except Exception, inst:
2709 except Exception, inst:
2710 on_exception(Exception, inst)
2710 on_exception(Exception, inst)
2711 continue
2711 continue
2712
2712
2713 external.append(mod)
2713 external.append(mod)
2714 for x in external:
2714 for x in external:
2715 cmdtable = getattr(x, 'cmdtable', {})
2715 cmdtable = getattr(x, 'cmdtable', {})
2716 for t in cmdtable:
2716 for t in cmdtable:
2717 if t in table:
2717 if t in table:
2718 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2718 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2719 table.update(cmdtable)
2719 table.update(cmdtable)
2720
2720
2721 try:
2721 try:
2722 cmd, func, args, options, cmdoptions = parse(u, args)
2722 cmd, func, args, options, cmdoptions = parse(u, args)
2723 except ParseError, inst:
2723 except ParseError, inst:
2724 if inst.args[0]:
2724 if inst.args[0]:
2725 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2725 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2726 help_(u, inst.args[0])
2726 help_(u, inst.args[0])
2727 else:
2727 else:
2728 u.warn(_("hg: %s\n") % inst.args[1])
2728 u.warn(_("hg: %s\n") % inst.args[1])
2729 help_(u, 'shortlist')
2729 help_(u, 'shortlist')
2730 sys.exit(-1)
2730 sys.exit(-1)
2731 except AmbiguousCommand, inst:
2731 except AmbiguousCommand, inst:
2732 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2732 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2733 sys.exit(1)
2733 sys.exit(1)
2734 except UnknownCommand, inst:
2734 except UnknownCommand, inst:
2735 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2735 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2736 help_(u, 'shortlist')
2736 help_(u, 'shortlist')
2737 sys.exit(1)
2737 sys.exit(1)
2738
2738
2739 if options["time"]:
2739 if options["time"]:
2740 def get_times():
2740 def get_times():
2741 t = os.times()
2741 t = os.times()
2742 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2742 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2743 t = (t[0], t[1], t[2], t[3], time.clock())
2743 t = (t[0], t[1], t[2], t[3], time.clock())
2744 return t
2744 return t
2745 s = get_times()
2745 s = get_times()
2746 def print_time():
2746 def print_time():
2747 t = get_times()
2747 t = get_times()
2748 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2748 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2749 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2749 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2750 atexit.register(print_time)
2750 atexit.register(print_time)
2751
2751
2752 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2752 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2753 not options["noninteractive"])
2753 not options["noninteractive"])
2754
2754
2755 # enter the debugger before command execution
2755 # enter the debugger before command execution
2756 if options['debugger']:
2756 if options['debugger']:
2757 pdb.set_trace()
2757 pdb.set_trace()
2758
2758
2759 try:
2759 try:
2760 try:
2760 try:
2761 if options['help']:
2761 if options['help']:
2762 help_(u, cmd, options['version'])
2762 help_(u, cmd, options['version'])
2763 sys.exit(0)
2763 sys.exit(0)
2764 elif options['version']:
2764 elif options['version']:
2765 show_version(u)
2765 show_version(u)
2766 sys.exit(0)
2766 sys.exit(0)
2767 elif not cmd:
2767 elif not cmd:
2768 help_(u, 'shortlist')
2768 help_(u, 'shortlist')
2769 sys.exit(0)
2769 sys.exit(0)
2770
2770
2771 if options['cwd']:
2771 if options['cwd']:
2772 try:
2772 try:
2773 os.chdir(options['cwd'])
2773 os.chdir(options['cwd'])
2774 except OSError, inst:
2774 except OSError, inst:
2775 raise util.Abort('%s: %s' %
2775 raise util.Abort('%s: %s' %
2776 (options['cwd'], inst.strerror))
2776 (options['cwd'], inst.strerror))
2777
2777
2778 if cmd not in norepo.split():
2778 if cmd not in norepo.split():
2779 path = options["repository"] or ""
2779 path = options["repository"] or ""
2780 repo = hg.repository(ui=u, path=path)
2780 repo = hg.repository(ui=u, path=path)
2781 for x in external:
2781 for x in external:
2782 if hasattr(x, 'reposetup'):
2782 if hasattr(x, 'reposetup'):
2783 x.reposetup(u, repo)
2783 x.reposetup(u, repo)
2784 d = lambda: func(u, repo, *args, **cmdoptions)
2784 d = lambda: func(u, repo, *args, **cmdoptions)
2785 else:
2785 else:
2786 d = lambda: func(u, *args, **cmdoptions)
2786 d = lambda: func(u, *args, **cmdoptions)
2787
2787
2788 if options['profile']:
2788 if options['profile']:
2789 import hotshot, hotshot.stats
2789 import hotshot, hotshot.stats
2790 prof = hotshot.Profile("hg.prof")
2790 prof = hotshot.Profile("hg.prof")
2791 r = prof.runcall(d)
2791 r = prof.runcall(d)
2792 prof.close()
2792 prof.close()
2793 stats = hotshot.stats.load("hg.prof")
2793 stats = hotshot.stats.load("hg.prof")
2794 stats.strip_dirs()
2794 stats.strip_dirs()
2795 stats.sort_stats('time', 'calls')
2795 stats.sort_stats('time', 'calls')
2796 stats.print_stats(40)
2796 stats.print_stats(40)
2797 return r
2797 return r
2798 else:
2798 else:
2799 return d()
2799 return d()
2800 except:
2800 except:
2801 # enter the debugger when we hit an exception
2801 # enter the debugger when we hit an exception
2802 if options['debugger']:
2802 if options['debugger']:
2803 pdb.post_mortem(sys.exc_info()[2])
2803 pdb.post_mortem(sys.exc_info()[2])
2804 if options['traceback']:
2804 if options['traceback']:
2805 traceback.print_exc()
2805 traceback.print_exc()
2806 raise
2806 raise
2807 except hg.RepoError, inst:
2807 except hg.RepoError, inst:
2808 u.warn(_("abort: "), inst, "!\n")
2808 u.warn(_("abort: "), inst, "!\n")
2809 except revlog.RevlogError, inst:
2809 except revlog.RevlogError, inst:
2810 u.warn(_("abort: "), inst, "!\n")
2810 u.warn(_("abort: "), inst, "!\n")
2811 except SignalInterrupt:
2811 except SignalInterrupt:
2812 u.warn(_("killed!\n"))
2812 u.warn(_("killed!\n"))
2813 except KeyboardInterrupt:
2813 except KeyboardInterrupt:
2814 try:
2814 try:
2815 u.warn(_("interrupted!\n"))
2815 u.warn(_("interrupted!\n"))
2816 except IOError, inst:
2816 except IOError, inst:
2817 if inst.errno == errno.EPIPE:
2817 if inst.errno == errno.EPIPE:
2818 if u.debugflag:
2818 if u.debugflag:
2819 u.warn(_("\nbroken pipe\n"))
2819 u.warn(_("\nbroken pipe\n"))
2820 else:
2820 else:
2821 raise
2821 raise
2822 except IOError, inst:
2822 except IOError, inst:
2823 if hasattr(inst, "code"):
2823 if hasattr(inst, "code"):
2824 u.warn(_("abort: %s\n") % inst)
2824 u.warn(_("abort: %s\n") % inst)
2825 elif hasattr(inst, "reason"):
2825 elif hasattr(inst, "reason"):
2826 u.warn(_("abort: error: %s\n") % inst.reason[1])
2826 u.warn(_("abort: error: %s\n") % inst.reason[1])
2827 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2827 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2828 if u.debugflag:
2828 if u.debugflag:
2829 u.warn(_("broken pipe\n"))
2829 u.warn(_("broken pipe\n"))
2830 elif getattr(inst, "strerror", None):
2830 elif getattr(inst, "strerror", None):
2831 if getattr(inst, "filename", None):
2831 if getattr(inst, "filename", None):
2832 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2832 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2833 else:
2833 else:
2834 u.warn(_("abort: %s\n") % inst.strerror)
2834 u.warn(_("abort: %s\n") % inst.strerror)
2835 else:
2835 else:
2836 raise
2836 raise
2837 except OSError, inst:
2837 except OSError, inst:
2838 if hasattr(inst, "filename"):
2838 if hasattr(inst, "filename"):
2839 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2839 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2840 else:
2840 else:
2841 u.warn(_("abort: %s\n") % inst.strerror)
2841 u.warn(_("abort: %s\n") % inst.strerror)
2842 except util.Abort, inst:
2842 except util.Abort, inst:
2843 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2843 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2844 sys.exit(1)
2844 sys.exit(1)
2845 except TypeError, inst:
2845 except TypeError, inst:
2846 # was this an argument error?
2846 # was this an argument error?
2847 tb = traceback.extract_tb(sys.exc_info()[2])
2847 tb = traceback.extract_tb(sys.exc_info()[2])
2848 if len(tb) > 2: # no
2848 if len(tb) > 2: # no
2849 raise
2849 raise
2850 u.debug(inst, "\n")
2850 u.debug(inst, "\n")
2851 u.warn(_("%s: invalid arguments\n") % cmd)
2851 u.warn(_("%s: invalid arguments\n") % cmd)
2852 help_(u, cmd)
2852 help_(u, cmd)
2853 except AmbiguousCommand, inst:
2853 except AmbiguousCommand, inst:
2854 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2854 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2855 help_(u, 'shortlist')
2855 help_(u, 'shortlist')
2856 except UnknownCommand, inst:
2856 except UnknownCommand, inst:
2857 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2857 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2858 help_(u, 'shortlist')
2858 help_(u, 'shortlist')
2859 except SystemExit:
2859 except SystemExit:
2860 # don't catch this in the catch-all below
2860 # don't catch this in the catch-all below
2861 raise
2861 raise
2862 except:
2862 except:
2863 u.warn(_("** unknown exception encountered, details follow\n"))
2863 u.warn(_("** unknown exception encountered, details follow\n"))
2864 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2864 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2865 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2865 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2866 % version.get_version())
2866 % version.get_version())
2867 raise
2867 raise
2868
2868
2869 sys.exit(-1)
2869 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now