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