##// END OF EJS Templates
Fix performance of hg diff....
Bryan O'Sullivan -
r837:a95c9b3f default
parent child Browse files
Show More
@@ -1,1445 +1,1452 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 demandload(globals(), "os re sys signal shutil")
9 demandload(globals(), "os re sys signal shutil")
10 demandload(globals(), "fancyopts ui hg util")
10 demandload(globals(), "fancyopts ui hg util")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version struct atexit")
12 demandload(globals(), "errno socket version struct atexit")
13
13
14 class UnknownCommand(Exception):
14 class UnknownCommand(Exception):
15 """Exception raised if command is not in the command table."""
15 """Exception raised if command is not in the command table."""
16
16
17 class Abort(Exception):
17 class Abort(Exception):
18 """Raised if a command needs to print an error and exit."""
18 """Raised if a command needs to print an error and exit."""
19
19
20 def filterfiles(filters, files):
20 def filterfiles(filters, files):
21 l = [x for x in files if x in filters]
21 l = [x for x in files if x in filters]
22
22
23 for t in filters:
23 for t in filters:
24 if t and t[-1] != "/":
24 if t and t[-1] != "/":
25 t += "/"
25 t += "/"
26 l += [x for x in files if x.startswith(t)]
26 l += [x for x in files if x.startswith(t)]
27 return l
27 return l
28
28
29 def relfilter(repo, files):
29 def relfilter(repo, files):
30 cwd = repo.getcwd()
30 cwd = repo.getcwd()
31 if cwd:
31 if cwd:
32 return filterfiles([util.pconvert(cwd)], files)
32 return filterfiles([util.pconvert(cwd)], files)
33 return files
33 return files
34
34
35 def relpath(repo, args):
35 def relpath(repo, args):
36 cwd = repo.getcwd()
36 cwd = repo.getcwd()
37 if cwd:
37 if cwd:
38 return [util.pconvert(os.path.normpath(os.path.join(cwd, x)))
38 return [util.pconvert(os.path.normpath(os.path.join(cwd, x)))
39 for x in args]
39 for x in args]
40 return args
40 return args
41
41
42 def matchpats(cwd, pats = [], opts = {}, head = ''):
42 def matchpats(cwd, pats = [], opts = {}, head = ''):
43 return util.matcher(cwd, pats or ['.'], opts.get('include'),
43 return util.matcher(cwd, pats or ['.'], opts.get('include'),
44 opts.get('exclude'), head)
44 opts.get('exclude'), head)
45
45
46 def pathto(n1, n2):
46 def pathto(n1, n2):
47 '''return the relative path from one place to another'''
47 '''return the relative path from one place to another'''
48 if not n1: return n2
48 if not n1: return n2
49 a, b = n1.split(os.sep), n2.split(os.sep)
49 a, b = n1.split(os.sep), n2.split(os.sep)
50 a.reverse(), b.reverse()
50 a.reverse(), b.reverse()
51 while a and b and a[-1] == b[-1]:
51 while a and b and a[-1] == b[-1]:
52 a.pop(), b.pop()
52 a.pop(), b.pop()
53 b.reverse()
53 b.reverse()
54 return os.sep.join((['..'] * len(a)) + b)
54 return os.sep.join((['..'] * len(a)) + b)
55
55
56 def walk(repo, pats, opts, head = ''):
56 def makewalk(repo, pats, opts, head = ''):
57 cwd = repo.getcwd()
57 cwd = repo.getcwd()
58 files, matchfn = matchpats(cwd, pats, opts, head)
58 files, matchfn = matchpats(cwd, pats, opts, head)
59 for src, fn in repo.walk(files = files, match = matchfn):
59 def walk():
60 yield src, fn, pathto(cwd, fn)
60 for src, fn in repo.walk(files = files, match = matchfn):
61 yield src, fn, pathto(cwd, fn)
62 return files, matchfn, walk()
63
64 def walk(repo, pats, opts, head = ''):
65 files, matchfn, results = makewalk(repo, pats, opts, head)
66 for r in results: yield r
61
67
62 revrangesep = ':'
68 revrangesep = ':'
63
69
64 def revrange(ui, repo, revs, revlog=None):
70 def revrange(ui, repo, revs, revlog=None):
65 if revlog is None:
71 if revlog is None:
66 revlog = repo.changelog
72 revlog = repo.changelog
67 revcount = revlog.count()
73 revcount = revlog.count()
68 def fix(val, defval):
74 def fix(val, defval):
69 if not val:
75 if not val:
70 return defval
76 return defval
71 try:
77 try:
72 num = int(val)
78 num = int(val)
73 if str(num) != val:
79 if str(num) != val:
74 raise ValueError
80 raise ValueError
75 if num < 0:
81 if num < 0:
76 num += revcount
82 num += revcount
77 if not (0 <= num < revcount):
83 if not (0 <= num < revcount):
78 raise ValueError
84 raise ValueError
79 except ValueError:
85 except ValueError:
80 try:
86 try:
81 num = repo.changelog.rev(repo.lookup(val))
87 num = repo.changelog.rev(repo.lookup(val))
82 except KeyError:
88 except KeyError:
83 try:
89 try:
84 num = revlog.rev(revlog.lookup(val))
90 num = revlog.rev(revlog.lookup(val))
85 except KeyError:
91 except KeyError:
86 raise Abort('invalid revision identifier %s', val)
92 raise Abort('invalid revision identifier %s', val)
87 return num
93 return num
88 for spec in revs:
94 for spec in revs:
89 if spec.find(revrangesep) >= 0:
95 if spec.find(revrangesep) >= 0:
90 start, end = spec.split(revrangesep, 1)
96 start, end = spec.split(revrangesep, 1)
91 start = fix(start, 0)
97 start = fix(start, 0)
92 end = fix(end, revcount - 1)
98 end = fix(end, revcount - 1)
93 if end > start:
99 if end > start:
94 end += 1
100 end += 1
95 step = 1
101 step = 1
96 else:
102 else:
97 end -= 1
103 end -= 1
98 step = -1
104 step = -1
99 for rev in xrange(start, end, step):
105 for rev in xrange(start, end, step):
100 yield str(rev)
106 yield str(rev)
101 else:
107 else:
102 yield spec
108 yield spec
103
109
104 def make_filename(repo, r, pat, node=None,
110 def make_filename(repo, r, pat, node=None,
105 total=None, seqno=None, revwidth=None):
111 total=None, seqno=None, revwidth=None):
106 node_expander = {
112 node_expander = {
107 'H': lambda: hg.hex(node),
113 'H': lambda: hg.hex(node),
108 'R': lambda: str(r.rev(node)),
114 'R': lambda: str(r.rev(node)),
109 'h': lambda: hg.short(node),
115 'h': lambda: hg.short(node),
110 }
116 }
111 expander = {
117 expander = {
112 '%': lambda: '%',
118 '%': lambda: '%',
113 'b': lambda: os.path.basename(repo.root),
119 'b': lambda: os.path.basename(repo.root),
114 }
120 }
115
121
116 try:
122 try:
117 if node:
123 if node:
118 expander.update(node_expander)
124 expander.update(node_expander)
119 if node and revwidth is not None:
125 if node and revwidth is not None:
120 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
126 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
121 if total is not None:
127 if total is not None:
122 expander['N'] = lambda: str(total)
128 expander['N'] = lambda: str(total)
123 if seqno is not None:
129 if seqno is not None:
124 expander['n'] = lambda: str(seqno)
130 expander['n'] = lambda: str(seqno)
125 if total is not None and seqno is not None:
131 if total is not None and seqno is not None:
126 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
132 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
127
133
128 newname = []
134 newname = []
129 patlen = len(pat)
135 patlen = len(pat)
130 i = 0
136 i = 0
131 while i < patlen:
137 while i < patlen:
132 c = pat[i]
138 c = pat[i]
133 if c == '%':
139 if c == '%':
134 i += 1
140 i += 1
135 c = pat[i]
141 c = pat[i]
136 c = expander[c]()
142 c = expander[c]()
137 newname.append(c)
143 newname.append(c)
138 i += 1
144 i += 1
139 return ''.join(newname)
145 return ''.join(newname)
140 except KeyError, inst:
146 except KeyError, inst:
141 raise Abort("invalid format spec '%%%s' in output file name",
147 raise Abort("invalid format spec '%%%s' in output file name",
142 inst.args[0])
148 inst.args[0])
143
149
144 def make_file(repo, r, pat, node=None,
150 def make_file(repo, r, pat, node=None,
145 total=None, seqno=None, revwidth=None, mode='wb'):
151 total=None, seqno=None, revwidth=None, mode='wb'):
146 if not pat or pat == '-':
152 if not pat or pat == '-':
147 if 'w' in mode: return sys.stdout
153 if 'w' in mode: return sys.stdout
148 else: return sys.stdin
154 else: return sys.stdin
149 if hasattr(pat, 'write') and 'w' in mode:
155 if hasattr(pat, 'write') and 'w' in mode:
150 return pat
156 return pat
151 if hasattr(pat, 'read') and 'r' in mode:
157 if hasattr(pat, 'read') and 'r' in mode:
152 return pat
158 return pat
153 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
159 return open(make_filename(repo, r, pat, node, total, seqno, revwidth),
154 mode)
160 mode)
155
161
156 def dodiff(fp, ui, repo, files=None, node1=None, node2=None):
162 def dodiff(fp, ui, repo, files=None, node1=None, node2=None, match=util.always):
157 def date(c):
163 def date(c):
158 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
164 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
159
165
160 (c, a, d, u) = repo.changes(node1, node2, files)
166 (c, a, d, u) = repo.changes(node1, node2, files, match = match)
161 if files:
167 if files:
162 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
168 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
163
169
164 if not c and not a and not d:
170 if not c and not a and not d:
165 return
171 return
166
172
167 if node2:
173 if node2:
168 change = repo.changelog.read(node2)
174 change = repo.changelog.read(node2)
169 mmap2 = repo.manifest.read(change[0])
175 mmap2 = repo.manifest.read(change[0])
170 date2 = date(change)
176 date2 = date(change)
171 def read(f):
177 def read(f):
172 return repo.file(f).read(mmap2[f])
178 return repo.file(f).read(mmap2[f])
173 else:
179 else:
174 date2 = time.asctime()
180 date2 = time.asctime()
175 if not node1:
181 if not node1:
176 node1 = repo.dirstate.parents()[0]
182 node1 = repo.dirstate.parents()[0]
177 def read(f):
183 def read(f):
178 return repo.wfile(f).read()
184 return repo.wfile(f).read()
179
185
180 if ui.quiet:
186 if ui.quiet:
181 r = None
187 r = None
182 else:
188 else:
183 hexfunc = ui.verbose and hg.hex or hg.short
189 hexfunc = ui.verbose and hg.hex or hg.short
184 r = [hexfunc(node) for node in [node1, node2] if node]
190 r = [hexfunc(node) for node in [node1, node2] if node]
185
191
186 change = repo.changelog.read(node1)
192 change = repo.changelog.read(node1)
187 mmap = repo.manifest.read(change[0])
193 mmap = repo.manifest.read(change[0])
188 date1 = date(change)
194 date1 = date(change)
189
195
190 for f in c:
196 for f in c:
191 to = None
197 to = None
192 if f in mmap:
198 if f in mmap:
193 to = repo.file(f).read(mmap[f])
199 to = repo.file(f).read(mmap[f])
194 tn = read(f)
200 tn = read(f)
195 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
201 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
196 for f in a:
202 for f in a:
197 to = None
203 to = None
198 tn = read(f)
204 tn = read(f)
199 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
205 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
200 for f in d:
206 for f in d:
201 to = repo.file(f).read(mmap[f])
207 to = repo.file(f).read(mmap[f])
202 tn = None
208 tn = None
203 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
209 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
204
210
205 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
211 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
206 """show a single changeset or file revision"""
212 """show a single changeset or file revision"""
207 changelog = repo.changelog
213 changelog = repo.changelog
208 if filelog:
214 if filelog:
209 log = filelog
215 log = filelog
210 filerev = rev
216 filerev = rev
211 node = filenode = filelog.node(filerev)
217 node = filenode = filelog.node(filerev)
212 changerev = filelog.linkrev(filenode)
218 changerev = filelog.linkrev(filenode)
213 changenode = changenode or changelog.node(changerev)
219 changenode = changenode or changelog.node(changerev)
214 else:
220 else:
215 log = changelog
221 log = changelog
216 changerev = rev
222 changerev = rev
217 if changenode is None:
223 if changenode is None:
218 changenode = changelog.node(changerev)
224 changenode = changelog.node(changerev)
219 elif not changerev:
225 elif not changerev:
220 rev = changerev = changelog.rev(changenode)
226 rev = changerev = changelog.rev(changenode)
221 node = changenode
227 node = changenode
222
228
223 if ui.quiet:
229 if ui.quiet:
224 ui.write("%d:%s\n" % (rev, hg.hex(node)))
230 ui.write("%d:%s\n" % (rev, hg.hex(node)))
225 return
231 return
226
232
227 changes = changelog.read(changenode)
233 changes = changelog.read(changenode)
228
234
229 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
235 parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
230 for p in log.parents(node)
236 for p in log.parents(node)
231 if ui.debugflag or p != hg.nullid]
237 if ui.debugflag or p != hg.nullid]
232 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
238 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
233 parents = []
239 parents = []
234
240
235 if ui.verbose:
241 if ui.verbose:
236 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
242 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
237 else:
243 else:
238 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
244 ui.write("changeset: %d:%s\n" % (changerev, hg.short(changenode)))
239
245
240 for tag in repo.nodetags(changenode):
246 for tag in repo.nodetags(changenode):
241 ui.status("tag: %s\n" % tag)
247 ui.status("tag: %s\n" % tag)
242 for parent in parents:
248 for parent in parents:
243 ui.write("parent: %d:%s\n" % parent)
249 ui.write("parent: %d:%s\n" % parent)
244 if filelog:
250 if filelog:
245 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
251 ui.debug("file rev: %d:%s\n" % (filerev, hg.hex(filenode)))
246
252
247 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
253 ui.debug("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
248 hg.hex(changes[0])))
254 hg.hex(changes[0])))
249 ui.status("user: %s\n" % changes[1])
255 ui.status("user: %s\n" % changes[1])
250 ui.status("date: %s\n" % time.asctime(
256 ui.status("date: %s\n" % time.asctime(
251 time.localtime(float(changes[2].split(' ')[0]))))
257 time.localtime(float(changes[2].split(' ')[0]))))
252
258
253 if ui.debugflag:
259 if ui.debugflag:
254 files = repo.changes(changelog.parents(changenode)[0], changenode)
260 files = repo.changes(changelog.parents(changenode)[0], changenode)
255 for key, value in zip(["files:", "files+:", "files-:"], files):
261 for key, value in zip(["files:", "files+:", "files-:"], files):
256 if value:
262 if value:
257 ui.note("%-12s %s\n" % (key, " ".join(value)))
263 ui.note("%-12s %s\n" % (key, " ".join(value)))
258 else:
264 else:
259 ui.note("files: %s\n" % " ".join(changes[3]))
265 ui.note("files: %s\n" % " ".join(changes[3]))
260
266
261 description = changes[4].strip()
267 description = changes[4].strip()
262 if description:
268 if description:
263 if ui.verbose:
269 if ui.verbose:
264 ui.status("description:\n")
270 ui.status("description:\n")
265 ui.status(description)
271 ui.status(description)
266 ui.status("\n\n")
272 ui.status("\n\n")
267 else:
273 else:
268 ui.status("summary: %s\n" % description.splitlines()[0])
274 ui.status("summary: %s\n" % description.splitlines()[0])
269 ui.status("\n")
275 ui.status("\n")
270
276
271 def show_version(ui):
277 def show_version(ui):
272 """output version and copyright information"""
278 """output version and copyright information"""
273 ui.write("Mercurial version %s\n" % version.get_version())
279 ui.write("Mercurial version %s\n" % version.get_version())
274 ui.status(
280 ui.status(
275 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
281 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
276 "This is free software; see the source for copying conditions. "
282 "This is free software; see the source for copying conditions. "
277 "There is NO\nwarranty; "
283 "There is NO\nwarranty; "
278 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
284 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
279 )
285 )
280
286
281 def help_(ui, cmd=None):
287 def help_(ui, cmd=None):
282 """show help for a given command or all commands"""
288 """show help for a given command or all commands"""
283 if cmd:
289 if cmd:
284 try:
290 try:
285 i = find(cmd)
291 i = find(cmd)
286 ui.write("%s\n\n" % i[2])
292 ui.write("%s\n\n" % i[2])
287
293
288 if i[1]:
294 if i[1]:
289 for s, l, d, c in i[1]:
295 for s, l, d, c in i[1]:
290 opt = ' '
296 opt = ' '
291 if s:
297 if s:
292 opt = opt + '-' + s + ' '
298 opt = opt + '-' + s + ' '
293 if l:
299 if l:
294 opt = opt + '--' + l + ' '
300 opt = opt + '--' + l + ' '
295 if d:
301 if d:
296 opt = opt + '(' + str(d) + ')'
302 opt = opt + '(' + str(d) + ')'
297 ui.write(opt, "\n")
303 ui.write(opt, "\n")
298 if c:
304 if c:
299 ui.write(' %s\n' % c)
305 ui.write(' %s\n' % c)
300 ui.write("\n")
306 ui.write("\n")
301
307
302 ui.write(i[0].__doc__, "\n")
308 ui.write(i[0].__doc__, "\n")
303 except UnknownCommand:
309 except UnknownCommand:
304 ui.warn("hg: unknown command %s\n" % cmd)
310 ui.warn("hg: unknown command %s\n" % cmd)
305 sys.exit(0)
311 sys.exit(0)
306 else:
312 else:
307 if ui.verbose:
313 if ui.verbose:
308 show_version(ui)
314 show_version(ui)
309 ui.write('\n')
315 ui.write('\n')
310 if ui.verbose:
316 if ui.verbose:
311 ui.write('hg commands:\n\n')
317 ui.write('hg commands:\n\n')
312 else:
318 else:
313 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
319 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
314
320
315 h = {}
321 h = {}
316 for c, e in table.items():
322 for c, e in table.items():
317 f = c.split("|")[0]
323 f = c.split("|")[0]
318 if not ui.verbose and not f.startswith("^"):
324 if not ui.verbose and not f.startswith("^"):
319 continue
325 continue
320 if not ui.debugflag and f.startswith("debug"):
326 if not ui.debugflag and f.startswith("debug"):
321 continue
327 continue
322 f = f.lstrip("^")
328 f = f.lstrip("^")
323 d = ""
329 d = ""
324 if e[0].__doc__:
330 if e[0].__doc__:
325 d = e[0].__doc__.splitlines(0)[0].rstrip()
331 d = e[0].__doc__.splitlines(0)[0].rstrip()
326 h[f] = d
332 h[f] = d
327
333
328 fns = h.keys()
334 fns = h.keys()
329 fns.sort()
335 fns.sort()
330 m = max(map(len, fns))
336 m = max(map(len, fns))
331 for f in fns:
337 for f in fns:
332 ui.write(' %-*s %s\n' % (m, f, h[f]))
338 ui.write(' %-*s %s\n' % (m, f, h[f]))
333
339
334 # Commands start here, listed alphabetically
340 # Commands start here, listed alphabetically
335
341
336 def add(ui, repo, *pats, **opts):
342 def add(ui, repo, *pats, **opts):
337 '''add the specified files on the next commit'''
343 '''add the specified files on the next commit'''
338 names = []
344 names = []
339 q = dict(zip(pats, pats))
345 q = dict(zip(pats, pats))
340 for src, abs, rel in walk(repo, pats, opts):
346 for src, abs, rel in walk(repo, pats, opts):
341 if rel in q or abs in q:
347 if rel in q or abs in q:
342 names.append(abs)
348 names.append(abs)
343 elif repo.dirstate.state(abs) == '?':
349 elif repo.dirstate.state(abs) == '?':
344 ui.status('adding %s\n' % rel)
350 ui.status('adding %s\n' % rel)
345 names.append(abs)
351 names.append(abs)
346 repo.add(names)
352 repo.add(names)
347
353
348 def addremove(ui, repo, *pats, **opts):
354 def addremove(ui, repo, *pats, **opts):
349 """add all new files, delete all missing files"""
355 """add all new files, delete all missing files"""
350 q = dict(zip(pats, pats))
356 q = dict(zip(pats, pats))
351 add, remove = [], []
357 add, remove = [], []
352 for src, abs, rel in walk(repo, pats, opts):
358 for src, abs, rel in walk(repo, pats, opts):
353 if src == 'f':
359 if src == 'f':
354 if repo.dirstate.state(abs) == '?':
360 if repo.dirstate.state(abs) == '?':
355 add.append(abs)
361 add.append(abs)
356 if rel not in q: ui.status('adding ', rel, '\n')
362 if rel not in q: ui.status('adding ', rel, '\n')
357 elif repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
363 elif repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
358 remove.append(abs)
364 remove.append(abs)
359 if rel not in q: ui.status('removing ', rel, '\n')
365 if rel not in q: ui.status('removing ', rel, '\n')
360 repo.add(add)
366 repo.add(add)
361 repo.remove(remove)
367 repo.remove(remove)
362
368
363 def annotate(ui, repo, *pats, **opts):
369 def annotate(ui, repo, *pats, **opts):
364 """show changeset information per file line"""
370 """show changeset information per file line"""
365 def getnode(rev):
371 def getnode(rev):
366 return hg.short(repo.changelog.node(rev))
372 return hg.short(repo.changelog.node(rev))
367
373
368 def getname(rev):
374 def getname(rev):
369 try:
375 try:
370 return bcache[rev]
376 return bcache[rev]
371 except KeyError:
377 except KeyError:
372 cl = repo.changelog.read(repo.changelog.node(rev))
378 cl = repo.changelog.read(repo.changelog.node(rev))
373 name = cl[1]
379 name = cl[1]
374 f = name.find('@')
380 f = name.find('@')
375 if f >= 0:
381 if f >= 0:
376 name = name[:f]
382 name = name[:f]
377 f = name.find('<')
383 f = name.find('<')
378 if f >= 0:
384 if f >= 0:
379 name = name[f+1:]
385 name = name[f+1:]
380 bcache[rev] = name
386 bcache[rev] = name
381 return name
387 return name
382
388
383 if not pats:
389 if not pats:
384 raise Abort('at least one file name or pattern required')
390 raise Abort('at least one file name or pattern required')
385
391
386 bcache = {}
392 bcache = {}
387 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
393 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
388 if not opts['user'] and not opts['changeset']:
394 if not opts['user'] and not opts['changeset']:
389 opts['number'] = 1
395 opts['number'] = 1
390
396
391 if opts['rev']:
397 if opts['rev']:
392 node = repo.changelog.lookup(opts['rev'])
398 node = repo.changelog.lookup(opts['rev'])
393 else:
399 else:
394 node = repo.dirstate.parents()[0]
400 node = repo.dirstate.parents()[0]
395 change = repo.changelog.read(node)
401 change = repo.changelog.read(node)
396 mmap = repo.manifest.read(change[0])
402 mmap = repo.manifest.read(change[0])
397 for src, abs, rel in walk(repo, pats, opts):
403 for src, abs, rel in walk(repo, pats, opts):
398 if abs not in mmap:
404 if abs not in mmap:
399 ui.warn("warning: %s is not in the repository!\n" % rel)
405 ui.warn("warning: %s is not in the repository!\n" % rel)
400 continue
406 continue
401
407
402 lines = repo.file(abs).annotate(mmap[abs])
408 lines = repo.file(abs).annotate(mmap[abs])
403 pieces = []
409 pieces = []
404
410
405 for o, f in opmap:
411 for o, f in opmap:
406 if opts[o]:
412 if opts[o]:
407 l = [f(n) for n, dummy in lines]
413 l = [f(n) for n, dummy in lines]
408 if l:
414 if l:
409 m = max(map(len, l))
415 m = max(map(len, l))
410 pieces.append(["%*s" % (m, x) for x in l])
416 pieces.append(["%*s" % (m, x) for x in l])
411
417
412 if pieces:
418 if pieces:
413 for p, l in zip(zip(*pieces), lines):
419 for p, l in zip(zip(*pieces), lines):
414 ui.write("%s: %s" % (" ".join(p), l[1]))
420 ui.write("%s: %s" % (" ".join(p), l[1]))
415
421
416 def cat(ui, repo, file1, rev=None, **opts):
422 def cat(ui, repo, file1, rev=None, **opts):
417 """output the latest or given revision of a file"""
423 """output the latest or given revision of a file"""
418 r = repo.file(relpath(repo, [file1])[0])
424 r = repo.file(relpath(repo, [file1])[0])
419 if rev:
425 if rev:
420 n = r.lookup(rev)
426 n = r.lookup(rev)
421 else:
427 else:
422 n = r.tip()
428 n = r.tip()
423 fp = make_file(repo, r, opts['output'], node=n)
429 fp = make_file(repo, r, opts['output'], node=n)
424 fp.write(r.read(n))
430 fp.write(r.read(n))
425
431
426 def clone(ui, source, dest=None, **opts):
432 def clone(ui, source, dest=None, **opts):
427 """make a copy of an existing repository"""
433 """make a copy of an existing repository"""
428 if dest is None:
434 if dest is None:
429 dest = os.path.basename(os.path.normpath(source))
435 dest = os.path.basename(os.path.normpath(source))
430
436
431 if os.path.exists(dest):
437 if os.path.exists(dest):
432 ui.warn("abort: destination '%s' already exists\n" % dest)
438 ui.warn("abort: destination '%s' already exists\n" % dest)
433 return 1
439 return 1
434
440
435 class Dircleanup:
441 class Dircleanup:
436 def __init__(self, dir_):
442 def __init__(self, dir_):
437 self.rmtree = shutil.rmtree
443 self.rmtree = shutil.rmtree
438 self.dir_ = dir_
444 self.dir_ = dir_
439 os.mkdir(dir_)
445 os.mkdir(dir_)
440 def close(self):
446 def close(self):
441 self.dir_ = None
447 self.dir_ = None
442 def __del__(self):
448 def __del__(self):
443 if self.dir_:
449 if self.dir_:
444 self.rmtree(self.dir_, True)
450 self.rmtree(self.dir_, True)
445
451
446 d = Dircleanup(dest)
452 d = Dircleanup(dest)
447 abspath = source
453 abspath = source
448 source = ui.expandpath(source)
454 source = ui.expandpath(source)
449 other = hg.repository(ui, source)
455 other = hg.repository(ui, source)
450
456
451 if other.dev() != -1:
457 if other.dev() != -1:
452 abspath = os.path.abspath(source)
458 abspath = os.path.abspath(source)
453 copyfile = (os.stat(dest).st_dev == other.dev()
459 copyfile = (os.stat(dest).st_dev == other.dev()
454 and getattr(os, 'link', None) or shutil.copy2)
460 and getattr(os, 'link', None) or shutil.copy2)
455 if copyfile is not shutil.copy2:
461 if copyfile is not shutil.copy2:
456 ui.note("cloning by hardlink\n")
462 ui.note("cloning by hardlink\n")
457 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
463 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
458 copyfile)
464 copyfile)
459 try:
465 try:
460 os.unlink(os.path.join(dest, ".hg", "dirstate"))
466 os.unlink(os.path.join(dest, ".hg", "dirstate"))
461 except OSError:
467 except OSError:
462 pass
468 pass
463
469
464 repo = hg.repository(ui, dest)
470 repo = hg.repository(ui, dest)
465
471
466 else:
472 else:
467 repo = hg.repository(ui, dest, create=1)
473 repo = hg.repository(ui, dest, create=1)
468 repo.pull(other)
474 repo.pull(other)
469
475
470 f = repo.opener("hgrc", "w")
476 f = repo.opener("hgrc", "w")
471 f.write("[paths]\n")
477 f.write("[paths]\n")
472 f.write("default = %s\n" % abspath)
478 f.write("default = %s\n" % abspath)
473
479
474 if not opts['noupdate']:
480 if not opts['noupdate']:
475 update(ui, repo)
481 update(ui, repo)
476
482
477 d.close()
483 d.close()
478
484
479 def commit(ui, repo, *pats, **opts):
485 def commit(ui, repo, *pats, **opts):
480 """commit the specified files or all outstanding changes"""
486 """commit the specified files or all outstanding changes"""
481 if opts['text']:
487 if opts['text']:
482 ui.warn("Warning: -t and --text is deprecated,"
488 ui.warn("Warning: -t and --text is deprecated,"
483 " please use -m or --message instead.\n")
489 " please use -m or --message instead.\n")
484 message = opts['message'] or opts['text']
490 message = opts['message'] or opts['text']
485 logfile = opts['logfile']
491 logfile = opts['logfile']
486 if not message and logfile:
492 if not message and logfile:
487 try:
493 try:
488 message = open(logfile).read()
494 message = open(logfile).read()
489 except IOError, why:
495 except IOError, why:
490 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
496 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
491
497
492 if opts['addremove']:
498 if opts['addremove']:
493 addremove(ui, repo, *pats, **opts)
499 addremove(ui, repo, *pats, **opts)
494 cwd = repo.getcwd()
500 cwd = repo.getcwd()
495 if not pats and cwd:
501 if not pats and cwd:
496 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
502 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
497 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
503 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
498 fns, match = matchpats((pats and repo.getcwd()) or '', pats, opts)
504 fns, match = matchpats((pats and repo.getcwd()) or '', pats, opts)
499 if pats:
505 if pats:
500 c, a, d, u = repo.changes(files = fns, match = match)
506 c, a, d, u = repo.changes(files = fns, match = match)
501 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
507 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
502 else:
508 else:
503 files = []
509 files = []
504 repo.commit(files, message, opts['user'], opts['date'], match)
510 repo.commit(files, message, opts['user'], opts['date'], match)
505
511
506 def copy(ui, repo, source, dest):
512 def copy(ui, repo, source, dest):
507 """mark a file as copied or renamed for the next commit"""
513 """mark a file as copied or renamed for the next commit"""
508 return repo.copy(*relpath(repo, (source, dest)))
514 return repo.copy(*relpath(repo, (source, dest)))
509
515
510 def debugcheckstate(ui, repo):
516 def debugcheckstate(ui, repo):
511 """validate the correctness of the current dirstate"""
517 """validate the correctness of the current dirstate"""
512 parent1, parent2 = repo.dirstate.parents()
518 parent1, parent2 = repo.dirstate.parents()
513 repo.dirstate.read()
519 repo.dirstate.read()
514 dc = repo.dirstate.map
520 dc = repo.dirstate.map
515 keys = dc.keys()
521 keys = dc.keys()
516 keys.sort()
522 keys.sort()
517 m1n = repo.changelog.read(parent1)[0]
523 m1n = repo.changelog.read(parent1)[0]
518 m2n = repo.changelog.read(parent2)[0]
524 m2n = repo.changelog.read(parent2)[0]
519 m1 = repo.manifest.read(m1n)
525 m1 = repo.manifest.read(m1n)
520 m2 = repo.manifest.read(m2n)
526 m2 = repo.manifest.read(m2n)
521 errors = 0
527 errors = 0
522 for f in dc:
528 for f in dc:
523 state = repo.dirstate.state(f)
529 state = repo.dirstate.state(f)
524 if state in "nr" and f not in m1:
530 if state in "nr" and f not in m1:
525 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
531 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
526 errors += 1
532 errors += 1
527 if state in "a" and f in m1:
533 if state in "a" and f in m1:
528 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
534 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
529 errors += 1
535 errors += 1
530 if state in "m" and f not in m1 and f not in m2:
536 if state in "m" and f not in m1 and f not in m2:
531 ui.warn("%s in state %s, but not in either manifest\n" %
537 ui.warn("%s in state %s, but not in either manifest\n" %
532 (f, state))
538 (f, state))
533 errors += 1
539 errors += 1
534 for f in m1:
540 for f in m1:
535 state = repo.dirstate.state(f)
541 state = repo.dirstate.state(f)
536 if state not in "nrm":
542 if state not in "nrm":
537 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
543 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
538 errors += 1
544 errors += 1
539 if errors:
545 if errors:
540 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
546 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
541
547
542 def debugstate(ui, repo):
548 def debugstate(ui, repo):
543 """show the contents of the current dirstate"""
549 """show the contents of the current dirstate"""
544 repo.dirstate.read()
550 repo.dirstate.read()
545 dc = repo.dirstate.map
551 dc = repo.dirstate.map
546 keys = dc.keys()
552 keys = dc.keys()
547 keys.sort()
553 keys.sort()
548 for file_ in keys:
554 for file_ in keys:
549 ui.write("%c %3o %10d %s %s\n"
555 ui.write("%c %3o %10d %s %s\n"
550 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
556 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
551 time.strftime("%x %X",
557 time.strftime("%x %X",
552 time.localtime(dc[file_][3])), file_))
558 time.localtime(dc[file_][3])), file_))
553
559
554 def debugindex(ui, file_):
560 def debugindex(ui, file_):
555 """dump the contents of an index file"""
561 """dump the contents of an index file"""
556 r = hg.revlog(hg.opener(""), file_, "")
562 r = hg.revlog(hg.opener(""), file_, "")
557 ui.write(" rev offset length base linkrev" +
563 ui.write(" rev offset length base linkrev" +
558 " p1 p2 nodeid\n")
564 " p1 p2 nodeid\n")
559 for i in range(r.count()):
565 for i in range(r.count()):
560 e = r.index[i]
566 e = r.index[i]
561 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
567 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
562 i, e[0], e[1], e[2], e[3],
568 i, e[0], e[1], e[2], e[3],
563 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
569 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
564
570
565 def debugindexdot(ui, file_):
571 def debugindexdot(ui, file_):
566 """dump an index DAG as a .dot file"""
572 """dump an index DAG as a .dot file"""
567 r = hg.revlog(hg.opener(""), file_, "")
573 r = hg.revlog(hg.opener(""), file_, "")
568 ui.write("digraph G {\n")
574 ui.write("digraph G {\n")
569 for i in range(r.count()):
575 for i in range(r.count()):
570 e = r.index[i]
576 e = r.index[i]
571 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
577 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
572 if e[5] != hg.nullid:
578 if e[5] != hg.nullid:
573 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
579 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
574 ui.write("}\n")
580 ui.write("}\n")
575
581
576 def debugwalk(ui, repo, *pats, **opts):
582 def debugwalk(ui, repo, *pats, **opts):
577 items = list(walk(repo, pats, opts))
583 items = list(walk(repo, pats, opts))
578 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
584 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
579 for i in items: print fmt % i
585 for i in items: print fmt % i
580
586
581 def diff(ui, repo, *pats, **opts):
587 def diff(ui, repo, *pats, **opts):
582 """diff working directory (or selected files)"""
588 """diff working directory (or selected files)"""
583 revs = []
589 revs = []
584 if opts['rev']:
590 if opts['rev']:
585 revs = map(lambda x: repo.lookup(x), opts['rev'])
591 revs = map(lambda x: repo.lookup(x), opts['rev'])
586
592
587 if len(revs) > 2:
593 if len(revs) > 2:
588 raise Abort("too many revisions to diff")
594 raise Abort("too many revisions to diff")
589
595
590 files = []
596 files = []
591 for src, abs, rel in walk(repo, pats, opts):
597 roots, match, results = makewalk(repo, pats, opts)
598 for src, abs, rel in results:
592 files.append(abs)
599 files.append(abs)
593 dodiff(sys.stdout, ui, repo, files, *revs)
600 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
594
601
595 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
602 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
596 node = repo.lookup(changeset)
603 node = repo.lookup(changeset)
597 prev, other = repo.changelog.parents(node)
604 prev, other = repo.changelog.parents(node)
598 change = repo.changelog.read(node)
605 change = repo.changelog.read(node)
599
606
600 fp = make_file(repo, repo.changelog, opts['output'],
607 fp = make_file(repo, repo.changelog, opts['output'],
601 node=node, total=total, seqno=seqno,
608 node=node, total=total, seqno=seqno,
602 revwidth=revwidth)
609 revwidth=revwidth)
603 if fp != sys.stdout:
610 if fp != sys.stdout:
604 ui.note("%s\n" % fp.name)
611 ui.note("%s\n" % fp.name)
605
612
606 fp.write("# HG changeset patch\n")
613 fp.write("# HG changeset patch\n")
607 fp.write("# User %s\n" % change[1])
614 fp.write("# User %s\n" % change[1])
608 fp.write("# Node ID %s\n" % hg.hex(node))
615 fp.write("# Node ID %s\n" % hg.hex(node))
609 fp.write("# Parent %s\n" % hg.hex(prev))
616 fp.write("# Parent %s\n" % hg.hex(prev))
610 if other != hg.nullid:
617 if other != hg.nullid:
611 fp.write("# Parent %s\n" % hg.hex(other))
618 fp.write("# Parent %s\n" % hg.hex(other))
612 fp.write(change[4].rstrip())
619 fp.write(change[4].rstrip())
613 fp.write("\n\n")
620 fp.write("\n\n")
614
621
615 dodiff(fp, ui, repo, None, prev, node)
622 dodiff(fp, ui, repo, None, prev, node)
616 if fp != sys.stdout: fp.close()
623 if fp != sys.stdout: fp.close()
617
624
618 def export(ui, repo, *changesets, **opts):
625 def export(ui, repo, *changesets, **opts):
619 """dump the header and diffs for one or more changesets"""
626 """dump the header and diffs for one or more changesets"""
620 if not changesets:
627 if not changesets:
621 raise Abort("export requires at least one changeset")
628 raise Abort("export requires at least one changeset")
622 seqno = 0
629 seqno = 0
623 revs = list(revrange(ui, repo, changesets))
630 revs = list(revrange(ui, repo, changesets))
624 total = len(revs)
631 total = len(revs)
625 revwidth = max(len(revs[0]), len(revs[-1]))
632 revwidth = max(len(revs[0]), len(revs[-1]))
626 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
633 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
627 for cset in revs:
634 for cset in revs:
628 seqno += 1
635 seqno += 1
629 doexport(ui, repo, cset, seqno, total, revwidth, opts)
636 doexport(ui, repo, cset, seqno, total, revwidth, opts)
630
637
631 def forget(ui, repo, *pats, **opts):
638 def forget(ui, repo, *pats, **opts):
632 """don't add the specified files on the next commit"""
639 """don't add the specified files on the next commit"""
633 q = dict(zip(pats, pats))
640 q = dict(zip(pats, pats))
634 forget = []
641 forget = []
635 for src, abs, rel in walk(repo, pats, opts):
642 for src, abs, rel in walk(repo, pats, opts):
636 if repo.dirstate.state(abs) == 'a':
643 if repo.dirstate.state(abs) == 'a':
637 forget.append(abs)
644 forget.append(abs)
638 if rel not in q: ui.status('forgetting ', rel, '\n')
645 if rel not in q: ui.status('forgetting ', rel, '\n')
639 repo.forget(forget)
646 repo.forget(forget)
640
647
641 def heads(ui, repo):
648 def heads(ui, repo):
642 """show current repository heads"""
649 """show current repository heads"""
643 for n in repo.changelog.heads():
650 for n in repo.changelog.heads():
644 show_changeset(ui, repo, changenode=n)
651 show_changeset(ui, repo, changenode=n)
645
652
646 def identify(ui, repo):
653 def identify(ui, repo):
647 """print information about the working copy"""
654 """print information about the working copy"""
648 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
655 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
649 if not parents:
656 if not parents:
650 ui.write("unknown\n")
657 ui.write("unknown\n")
651 return
658 return
652
659
653 hexfunc = ui.verbose and hg.hex or hg.short
660 hexfunc = ui.verbose and hg.hex or hg.short
654 (c, a, d, u) = repo.changes()
661 (c, a, d, u) = repo.changes()
655 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
662 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
656 (c or a or d) and "+" or "")]
663 (c or a or d) and "+" or "")]
657
664
658 if not ui.quiet:
665 if not ui.quiet:
659 # multiple tags for a single parent separated by '/'
666 # multiple tags for a single parent separated by '/'
660 parenttags = ['/'.join(tags)
667 parenttags = ['/'.join(tags)
661 for tags in map(repo.nodetags, parents) if tags]
668 for tags in map(repo.nodetags, parents) if tags]
662 # tags for multiple parents separated by ' + '
669 # tags for multiple parents separated by ' + '
663 if parenttags:
670 if parenttags:
664 output.append(' + '.join(parenttags))
671 output.append(' + '.join(parenttags))
665
672
666 ui.write("%s\n" % ' '.join(output))
673 ui.write("%s\n" % ' '.join(output))
667
674
668 def import_(ui, repo, patch1, *patches, **opts):
675 def import_(ui, repo, patch1, *patches, **opts):
669 """import an ordered set of patches"""
676 """import an ordered set of patches"""
670 patches = (patch1,) + patches
677 patches = (patch1,) + patches
671
678
672 d = opts["base"]
679 d = opts["base"]
673 strip = opts["strip"]
680 strip = opts["strip"]
674
681
675 for patch in patches:
682 for patch in patches:
676 ui.status("applying %s\n" % patch)
683 ui.status("applying %s\n" % patch)
677 pf = os.path.join(d, patch)
684 pf = os.path.join(d, patch)
678
685
679 message = []
686 message = []
680 user = None
687 user = None
681 hgpatch = False
688 hgpatch = False
682 for line in file(pf):
689 for line in file(pf):
683 line = line.rstrip()
690 line = line.rstrip()
684 if line.startswith("--- ") or line.startswith("diff -r"):
691 if line.startswith("--- ") or line.startswith("diff -r"):
685 break
692 break
686 elif hgpatch:
693 elif hgpatch:
687 # parse values when importing the result of an hg export
694 # parse values when importing the result of an hg export
688 if line.startswith("# User "):
695 if line.startswith("# User "):
689 user = line[7:]
696 user = line[7:]
690 ui.debug('User: %s\n' % user)
697 ui.debug('User: %s\n' % user)
691 elif not line.startswith("# ") and line:
698 elif not line.startswith("# ") and line:
692 message.append(line)
699 message.append(line)
693 hgpatch = False
700 hgpatch = False
694 elif line == '# HG changeset patch':
701 elif line == '# HG changeset patch':
695 hgpatch = True
702 hgpatch = True
696 else:
703 else:
697 message.append(line)
704 message.append(line)
698
705
699 # make sure message isn't empty
706 # make sure message isn't empty
700 if not message:
707 if not message:
701 message = "imported patch %s\n" % patch
708 message = "imported patch %s\n" % patch
702 else:
709 else:
703 message = "%s\n" % '\n'.join(message)
710 message = "%s\n" % '\n'.join(message)
704 ui.debug('message:\n%s\n' % message)
711 ui.debug('message:\n%s\n' % message)
705
712
706 f = os.popen("patch -p%d < %s" % (strip, pf))
713 f = os.popen("patch -p%d < %s" % (strip, pf))
707 files = []
714 files = []
708 for l in f.read().splitlines():
715 for l in f.read().splitlines():
709 l.rstrip('\r\n');
716 l.rstrip('\r\n');
710 ui.status("%s\n" % l)
717 ui.status("%s\n" % l)
711 if l.startswith('patching file '):
718 if l.startswith('patching file '):
712 pf = l[14:]
719 pf = l[14:]
713 if pf not in files:
720 if pf not in files:
714 files.append(pf)
721 files.append(pf)
715 patcherr = f.close()
722 patcherr = f.close()
716 if patcherr:
723 if patcherr:
717 raise Abort("patch failed")
724 raise Abort("patch failed")
718
725
719 if len(files) > 0:
726 if len(files) > 0:
720 addremove(ui, repo, *files)
727 addremove(ui, repo, *files)
721 repo.commit(files, message, user)
728 repo.commit(files, message, user)
722
729
723 def init(ui, source=None):
730 def init(ui, source=None):
724 """create a new repository in the current directory"""
731 """create a new repository in the current directory"""
725
732
726 if source:
733 if source:
727 raise Abort("no longer supported: use \"hg clone\" instead")
734 raise Abort("no longer supported: use \"hg clone\" instead")
728 hg.repository(ui, ".", create=1)
735 hg.repository(ui, ".", create=1)
729
736
730 def locate(ui, repo, *pats, **opts):
737 def locate(ui, repo, *pats, **opts):
731 """locate files matching specific patterns"""
738 """locate files matching specific patterns"""
732 end = '\n'
739 end = '\n'
733 if opts['print0']: end = '\0'
740 if opts['print0']: end = '\0'
734
741
735 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
742 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
736 if repo.dirstate.state(abs) == '?': continue
743 if repo.dirstate.state(abs) == '?': continue
737 if opts['fullpath']:
744 if opts['fullpath']:
738 ui.write(os.path.join(repo.root, abs), end)
745 ui.write(os.path.join(repo.root, abs), end)
739 else:
746 else:
740 ui.write(rel, end)
747 ui.write(rel, end)
741
748
742 def log(ui, repo, f=None, **opts):
749 def log(ui, repo, f=None, **opts):
743 """show the revision history of the repository or a single file"""
750 """show the revision history of the repository or a single file"""
744 if f:
751 if f:
745 files = relpath(repo, [f])
752 files = relpath(repo, [f])
746 filelog = repo.file(files[0])
753 filelog = repo.file(files[0])
747 log = filelog
754 log = filelog
748 lookup = filelog.lookup
755 lookup = filelog.lookup
749 else:
756 else:
750 files = None
757 files = None
751 filelog = None
758 filelog = None
752 log = repo.changelog
759 log = repo.changelog
753 lookup = repo.lookup
760 lookup = repo.lookup
754 revlist = []
761 revlist = []
755 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
762 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
756 while revs:
763 while revs:
757 if len(revs) == 1:
764 if len(revs) == 1:
758 revlist.append(revs.pop(0))
765 revlist.append(revs.pop(0))
759 else:
766 else:
760 a = revs.pop(0)
767 a = revs.pop(0)
761 b = revs.pop(0)
768 b = revs.pop(0)
762 off = a > b and -1 or 1
769 off = a > b and -1 or 1
763 revlist.extend(range(a, b + off, off))
770 revlist.extend(range(a, b + off, off))
764
771
765 for i in revlist or range(log.count() - 1, -1, -1):
772 for i in revlist or range(log.count() - 1, -1, -1):
766 show_changeset(ui, repo, filelog=filelog, rev=i)
773 show_changeset(ui, repo, filelog=filelog, rev=i)
767 if opts['patch']:
774 if opts['patch']:
768 if filelog:
775 if filelog:
769 filenode = filelog.node(i)
776 filenode = filelog.node(i)
770 i = filelog.linkrev(filenode)
777 i = filelog.linkrev(filenode)
771 changenode = repo.changelog.node(i)
778 changenode = repo.changelog.node(i)
772 prev, other = repo.changelog.parents(changenode)
779 prev, other = repo.changelog.parents(changenode)
773 dodiff(sys.stdout, ui, repo, files, prev, changenode)
780 dodiff(sys.stdout, ui, repo, files, prev, changenode)
774 ui.write("\n\n")
781 ui.write("\n\n")
775
782
776 def manifest(ui, repo, rev=None):
783 def manifest(ui, repo, rev=None):
777 """output the latest or given revision of the project manifest"""
784 """output the latest or given revision of the project manifest"""
778 if rev:
785 if rev:
779 try:
786 try:
780 # assume all revision numbers are for changesets
787 # assume all revision numbers are for changesets
781 n = repo.lookup(rev)
788 n = repo.lookup(rev)
782 change = repo.changelog.read(n)
789 change = repo.changelog.read(n)
783 n = change[0]
790 n = change[0]
784 except hg.RepoError:
791 except hg.RepoError:
785 n = repo.manifest.lookup(rev)
792 n = repo.manifest.lookup(rev)
786 else:
793 else:
787 n = repo.manifest.tip()
794 n = repo.manifest.tip()
788 m = repo.manifest.read(n)
795 m = repo.manifest.read(n)
789 mf = repo.manifest.readflags(n)
796 mf = repo.manifest.readflags(n)
790 files = m.keys()
797 files = m.keys()
791 files.sort()
798 files.sort()
792
799
793 for f in files:
800 for f in files:
794 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
801 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
795
802
796 def parents(ui, repo, rev=None):
803 def parents(ui, repo, rev=None):
797 """show the parents of the working dir or revision"""
804 """show the parents of the working dir or revision"""
798 if rev:
805 if rev:
799 p = repo.changelog.parents(repo.lookup(rev))
806 p = repo.changelog.parents(repo.lookup(rev))
800 else:
807 else:
801 p = repo.dirstate.parents()
808 p = repo.dirstate.parents()
802
809
803 for n in p:
810 for n in p:
804 if n != hg.nullid:
811 if n != hg.nullid:
805 show_changeset(ui, repo, changenode=n)
812 show_changeset(ui, repo, changenode=n)
806
813
807 def paths(ui, repo, search = None):
814 def paths(ui, repo, search = None):
808 """show path or list of available paths"""
815 """show path or list of available paths"""
809 if search:
816 if search:
810 for name, path in ui.configitems("paths"):
817 for name, path in ui.configitems("paths"):
811 if name == search:
818 if name == search:
812 ui.write("%s\n" % path)
819 ui.write("%s\n" % path)
813 return
820 return
814 ui.warn("not found!\n")
821 ui.warn("not found!\n")
815 return 1
822 return 1
816 else:
823 else:
817 for name, path in ui.configitems("paths"):
824 for name, path in ui.configitems("paths"):
818 ui.write("%s = %s\n" % (name, path))
825 ui.write("%s = %s\n" % (name, path))
819
826
820 def pull(ui, repo, source="default", **opts):
827 def pull(ui, repo, source="default", **opts):
821 """pull changes from the specified source"""
828 """pull changes from the specified source"""
822 source = ui.expandpath(source)
829 source = ui.expandpath(source)
823 ui.status('pulling from %s\n' % (source))
830 ui.status('pulling from %s\n' % (source))
824
831
825 other = hg.repository(ui, source)
832 other = hg.repository(ui, source)
826 r = repo.pull(other)
833 r = repo.pull(other)
827 if not r:
834 if not r:
828 if opts['update']:
835 if opts['update']:
829 return update(ui, repo)
836 return update(ui, repo)
830 else:
837 else:
831 ui.status("(run 'hg update' to get a working copy)\n")
838 ui.status("(run 'hg update' to get a working copy)\n")
832
839
833 return r
840 return r
834
841
835 def push(ui, repo, dest="default-push"):
842 def push(ui, repo, dest="default-push"):
836 """push changes to the specified destination"""
843 """push changes to the specified destination"""
837 dest = ui.expandpath(dest)
844 dest = ui.expandpath(dest)
838 ui.status('pushing to %s\n' % (dest))
845 ui.status('pushing to %s\n' % (dest))
839
846
840 other = hg.repository(ui, dest)
847 other = hg.repository(ui, dest)
841 r = repo.push(other)
848 r = repo.push(other)
842 return r
849 return r
843
850
844 def rawcommit(ui, repo, *flist, **rc):
851 def rawcommit(ui, repo, *flist, **rc):
845 "raw commit interface"
852 "raw commit interface"
846 if rc['text']:
853 if rc['text']:
847 ui.warn("Warning: -t and --text is deprecated,"
854 ui.warn("Warning: -t and --text is deprecated,"
848 " please use -m or --message instead.\n")
855 " please use -m or --message instead.\n")
849 message = rc['message'] or rc['text']
856 message = rc['message'] or rc['text']
850 if not message and rc['logfile']:
857 if not message and rc['logfile']:
851 try:
858 try:
852 message = open(rc['logfile']).read()
859 message = open(rc['logfile']).read()
853 except IOError:
860 except IOError:
854 pass
861 pass
855 if not message and not rc['logfile']:
862 if not message and not rc['logfile']:
856 ui.warn("abort: missing commit message\n")
863 ui.warn("abort: missing commit message\n")
857 return 1
864 return 1
858
865
859 files = relpath(repo, list(flist))
866 files = relpath(repo, list(flist))
860 if rc['files']:
867 if rc['files']:
861 files += open(rc['files']).read().splitlines()
868 files += open(rc['files']).read().splitlines()
862
869
863 rc['parent'] = map(repo.lookup, rc['parent'])
870 rc['parent'] = map(repo.lookup, rc['parent'])
864
871
865 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
872 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
866
873
867 def recover(ui, repo):
874 def recover(ui, repo):
868 """roll back an interrupted transaction"""
875 """roll back an interrupted transaction"""
869 repo.recover()
876 repo.recover()
870
877
871 def remove(ui, repo, file1, *files):
878 def remove(ui, repo, file1, *files):
872 """remove the specified files on the next commit"""
879 """remove the specified files on the next commit"""
873 repo.remove(relpath(repo, (file1,) + files))
880 repo.remove(relpath(repo, (file1,) + files))
874
881
875 def revert(ui, repo, *names, **opts):
882 def revert(ui, repo, *names, **opts):
876 """revert modified files or dirs back to their unmodified states"""
883 """revert modified files or dirs back to their unmodified states"""
877 node = opts['rev'] and repo.lookup(opts['rev']) or \
884 node = opts['rev'] and repo.lookup(opts['rev']) or \
878 repo.dirstate.parents()[0]
885 repo.dirstate.parents()[0]
879 root = os.path.realpath(repo.root)
886 root = os.path.realpath(repo.root)
880
887
881 def trimpath(p):
888 def trimpath(p):
882 p = os.path.realpath(p)
889 p = os.path.realpath(p)
883 if p.startswith(root):
890 if p.startswith(root):
884 rest = p[len(root):]
891 rest = p[len(root):]
885 if not rest:
892 if not rest:
886 return rest
893 return rest
887 if p.startswith(os.sep):
894 if p.startswith(os.sep):
888 return rest[1:]
895 return rest[1:]
889 return p
896 return p
890
897
891 relnames = map(trimpath, names or [os.getcwd()])
898 relnames = map(trimpath, names or [os.getcwd()])
892 chosen = {}
899 chosen = {}
893
900
894 def choose(name):
901 def choose(name):
895 def body(name):
902 def body(name):
896 for r in relnames:
903 for r in relnames:
897 if not name.startswith(r):
904 if not name.startswith(r):
898 continue
905 continue
899 rest = name[len(r):]
906 rest = name[len(r):]
900 if not rest:
907 if not rest:
901 return r, True
908 return r, True
902 depth = rest.count(os.sep)
909 depth = rest.count(os.sep)
903 if not r:
910 if not r:
904 if depth == 0 or not opts['nonrecursive']:
911 if depth == 0 or not opts['nonrecursive']:
905 return r, True
912 return r, True
906 elif rest[0] == os.sep:
913 elif rest[0] == os.sep:
907 if depth == 1 or not opts['nonrecursive']:
914 if depth == 1 or not opts['nonrecursive']:
908 return r, True
915 return r, True
909 return None, False
916 return None, False
910 relname, ret = body(name)
917 relname, ret = body(name)
911 if ret:
918 if ret:
912 chosen[relname] = 1
919 chosen[relname] = 1
913 return ret
920 return ret
914
921
915 r = repo.update(node, False, True, choose, False)
922 r = repo.update(node, False, True, choose, False)
916 for n in relnames:
923 for n in relnames:
917 if n not in chosen:
924 if n not in chosen:
918 ui.warn('error: no matches for %s\n' % n)
925 ui.warn('error: no matches for %s\n' % n)
919 r = 1
926 r = 1
920 sys.stdout.flush()
927 sys.stdout.flush()
921 return r
928 return r
922
929
923 def root(ui, repo):
930 def root(ui, repo):
924 """print the root (top) of the current working dir"""
931 """print the root (top) of the current working dir"""
925 ui.write(repo.root + "\n")
932 ui.write(repo.root + "\n")
926
933
927 def serve(ui, repo, **opts):
934 def serve(ui, repo, **opts):
928 """export the repository via HTTP"""
935 """export the repository via HTTP"""
929
936
930 if opts["stdio"]:
937 if opts["stdio"]:
931 fin, fout = sys.stdin, sys.stdout
938 fin, fout = sys.stdin, sys.stdout
932 sys.stdout = sys.stderr
939 sys.stdout = sys.stderr
933
940
934 def getarg():
941 def getarg():
935 argline = fin.readline()[:-1]
942 argline = fin.readline()[:-1]
936 arg, l = argline.split()
943 arg, l = argline.split()
937 val = fin.read(int(l))
944 val = fin.read(int(l))
938 return arg, val
945 return arg, val
939 def respond(v):
946 def respond(v):
940 fout.write("%d\n" % len(v))
947 fout.write("%d\n" % len(v))
941 fout.write(v)
948 fout.write(v)
942 fout.flush()
949 fout.flush()
943
950
944 lock = None
951 lock = None
945
952
946 while 1:
953 while 1:
947 cmd = fin.readline()[:-1]
954 cmd = fin.readline()[:-1]
948 if cmd == '':
955 if cmd == '':
949 return
956 return
950 if cmd == "heads":
957 if cmd == "heads":
951 h = repo.heads()
958 h = repo.heads()
952 respond(" ".join(map(hg.hex, h)) + "\n")
959 respond(" ".join(map(hg.hex, h)) + "\n")
953 if cmd == "lock":
960 if cmd == "lock":
954 lock = repo.lock()
961 lock = repo.lock()
955 respond("")
962 respond("")
956 if cmd == "unlock":
963 if cmd == "unlock":
957 if lock:
964 if lock:
958 lock.release()
965 lock.release()
959 lock = None
966 lock = None
960 respond("")
967 respond("")
961 elif cmd == "branches":
968 elif cmd == "branches":
962 arg, nodes = getarg()
969 arg, nodes = getarg()
963 nodes = map(hg.bin, nodes.split(" "))
970 nodes = map(hg.bin, nodes.split(" "))
964 r = []
971 r = []
965 for b in repo.branches(nodes):
972 for b in repo.branches(nodes):
966 r.append(" ".join(map(hg.hex, b)) + "\n")
973 r.append(" ".join(map(hg.hex, b)) + "\n")
967 respond("".join(r))
974 respond("".join(r))
968 elif cmd == "between":
975 elif cmd == "between":
969 arg, pairs = getarg()
976 arg, pairs = getarg()
970 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
977 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
971 r = []
978 r = []
972 for b in repo.between(pairs):
979 for b in repo.between(pairs):
973 r.append(" ".join(map(hg.hex, b)) + "\n")
980 r.append(" ".join(map(hg.hex, b)) + "\n")
974 respond("".join(r))
981 respond("".join(r))
975 elif cmd == "changegroup":
982 elif cmd == "changegroup":
976 nodes = []
983 nodes = []
977 arg, roots = getarg()
984 arg, roots = getarg()
978 nodes = map(hg.bin, roots.split(" "))
985 nodes = map(hg.bin, roots.split(" "))
979
986
980 cg = repo.changegroup(nodes)
987 cg = repo.changegroup(nodes)
981 while 1:
988 while 1:
982 d = cg.read(4096)
989 d = cg.read(4096)
983 if not d:
990 if not d:
984 break
991 break
985 fout.write(d)
992 fout.write(d)
986
993
987 fout.flush()
994 fout.flush()
988
995
989 elif cmd == "addchangegroup":
996 elif cmd == "addchangegroup":
990 if not lock:
997 if not lock:
991 respond("not locked")
998 respond("not locked")
992 continue
999 continue
993 respond("")
1000 respond("")
994
1001
995 r = repo.addchangegroup(fin)
1002 r = repo.addchangegroup(fin)
996 respond("")
1003 respond("")
997
1004
998 def openlog(opt, default):
1005 def openlog(opt, default):
999 if opts[opt] and opts[opt] != '-':
1006 if opts[opt] and opts[opt] != '-':
1000 return open(opts[opt], 'w')
1007 return open(opts[opt], 'w')
1001 else:
1008 else:
1002 return default
1009 return default
1003
1010
1004 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1011 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1005 opts["address"], opts["port"],
1012 opts["address"], opts["port"],
1006 openlog('accesslog', sys.stdout),
1013 openlog('accesslog', sys.stdout),
1007 openlog('errorlog', sys.stderr))
1014 openlog('errorlog', sys.stderr))
1008 if ui.verbose:
1015 if ui.verbose:
1009 addr, port = httpd.socket.getsockname()
1016 addr, port = httpd.socket.getsockname()
1010 if addr == '0.0.0.0':
1017 if addr == '0.0.0.0':
1011 addr = socket.gethostname()
1018 addr = socket.gethostname()
1012 else:
1019 else:
1013 try:
1020 try:
1014 addr = socket.gethostbyaddr(addr)[0]
1021 addr = socket.gethostbyaddr(addr)[0]
1015 except socket.error:
1022 except socket.error:
1016 pass
1023 pass
1017 if port != 80:
1024 if port != 80:
1018 ui.status('listening at http://%s:%d/\n' % (addr, port))
1025 ui.status('listening at http://%s:%d/\n' % (addr, port))
1019 else:
1026 else:
1020 ui.status('listening at http://%s/\n' % addr)
1027 ui.status('listening at http://%s/\n' % addr)
1021 httpd.serve_forever()
1028 httpd.serve_forever()
1022
1029
1023 def status(ui, repo, *pats, **opts):
1030 def status(ui, repo, *pats, **opts):
1024 '''show changed files in the working directory
1031 '''show changed files in the working directory
1025
1032
1026 M = modified
1033 M = modified
1027 A = added
1034 A = added
1028 R = removed
1035 R = removed
1029 ? = not tracked'''
1036 ? = not tracked'''
1030
1037
1031 cwd = repo.getcwd()
1038 cwd = repo.getcwd()
1032 files, matchfn = matchpats(cwd, pats, opts)
1039 files, matchfn = matchpats(cwd, pats, opts)
1033 (c, a, d, u) = [[pathto(cwd, x) for x in n]
1040 (c, a, d, u) = [[pathto(cwd, x) for x in n]
1034 for n in repo.changes(files=files, match=matchfn)]
1041 for n in repo.changes(files=files, match=matchfn)]
1035
1042
1036 for f in c:
1043 for f in c:
1037 ui.write("M ", f, "\n")
1044 ui.write("M ", f, "\n")
1038 for f in a:
1045 for f in a:
1039 ui.write("A ", f, "\n")
1046 ui.write("A ", f, "\n")
1040 for f in d:
1047 for f in d:
1041 ui.write("R ", f, "\n")
1048 ui.write("R ", f, "\n")
1042 for f in u:
1049 for f in u:
1043 ui.write("? ", f, "\n")
1050 ui.write("? ", f, "\n")
1044
1051
1045 def tag(ui, repo, name, rev=None, **opts):
1052 def tag(ui, repo, name, rev=None, **opts):
1046 """add a tag for the current tip or a given revision"""
1053 """add a tag for the current tip or a given revision"""
1047 if opts['text']:
1054 if opts['text']:
1048 ui.warn("Warning: -t and --text is deprecated,"
1055 ui.warn("Warning: -t and --text is deprecated,"
1049 " please use -m or --message instead.\n")
1056 " please use -m or --message instead.\n")
1050 if name == "tip":
1057 if name == "tip":
1051 ui.warn("abort: 'tip' is a reserved name!\n")
1058 ui.warn("abort: 'tip' is a reserved name!\n")
1052 return -1
1059 return -1
1053 if rev:
1060 if rev:
1054 r = hg.hex(repo.lookup(rev))
1061 r = hg.hex(repo.lookup(rev))
1055 else:
1062 else:
1056 r = hg.hex(repo.changelog.tip())
1063 r = hg.hex(repo.changelog.tip())
1057
1064
1058 if name.find(revrangesep) >= 0:
1065 if name.find(revrangesep) >= 0:
1059 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1066 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1060 return -1
1067 return -1
1061
1068
1062 if opts['local']:
1069 if opts['local']:
1063 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1070 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1064 return
1071 return
1065
1072
1066 (c, a, d, u) = repo.changes()
1073 (c, a, d, u) = repo.changes()
1067 for x in (c, a, d, u):
1074 for x in (c, a, d, u):
1068 if ".hgtags" in x:
1075 if ".hgtags" in x:
1069 ui.warn("abort: working copy of .hgtags is changed!\n")
1076 ui.warn("abort: working copy of .hgtags is changed!\n")
1070 ui.status("(please commit .hgtags manually)\n")
1077 ui.status("(please commit .hgtags manually)\n")
1071 return -1
1078 return -1
1072
1079
1073 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1080 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1074 if repo.dirstate.state(".hgtags") == '?':
1081 if repo.dirstate.state(".hgtags") == '?':
1075 repo.add([".hgtags"])
1082 repo.add([".hgtags"])
1076
1083
1077 message = (opts['message'] or opts['text'] or
1084 message = (opts['message'] or opts['text'] or
1078 "Added tag %s for changeset %s" % (name, r))
1085 "Added tag %s for changeset %s" % (name, r))
1079 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1086 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1080
1087
1081 def tags(ui, repo):
1088 def tags(ui, repo):
1082 """list repository tags"""
1089 """list repository tags"""
1083
1090
1084 l = repo.tagslist()
1091 l = repo.tagslist()
1085 l.reverse()
1092 l.reverse()
1086 for t, n in l:
1093 for t, n in l:
1087 try:
1094 try:
1088 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1095 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1089 except KeyError:
1096 except KeyError:
1090 r = " ?:?"
1097 r = " ?:?"
1091 ui.write("%-30s %s\n" % (t, r))
1098 ui.write("%-30s %s\n" % (t, r))
1092
1099
1093 def tip(ui, repo):
1100 def tip(ui, repo):
1094 """show the tip revision"""
1101 """show the tip revision"""
1095 n = repo.changelog.tip()
1102 n = repo.changelog.tip()
1096 show_changeset(ui, repo, changenode=n)
1103 show_changeset(ui, repo, changenode=n)
1097
1104
1098 def undo(ui, repo):
1105 def undo(ui, repo):
1099 """undo the last commit or pull
1106 """undo the last commit or pull
1100
1107
1101 Roll back the last pull or commit transaction on the
1108 Roll back the last pull or commit transaction on the
1102 repository, restoring the project to its earlier state.
1109 repository, restoring the project to its earlier state.
1103
1110
1104 This command should be used with care. There is only one level of
1111 This command should be used with care. There is only one level of
1105 undo and there is no redo.
1112 undo and there is no redo.
1106
1113
1107 This command is not intended for use on public repositories. Once
1114 This command is not intended for use on public repositories. Once
1108 a change is visible for pull by other users, undoing it locally is
1115 a change is visible for pull by other users, undoing it locally is
1109 ineffective.
1116 ineffective.
1110 """
1117 """
1111 repo.undo()
1118 repo.undo()
1112
1119
1113 def update(ui, repo, node=None, merge=False, clean=False):
1120 def update(ui, repo, node=None, merge=False, clean=False):
1114 '''update or merge working directory
1121 '''update or merge working directory
1115
1122
1116 If there are no outstanding changes in the working directory and
1123 If there are no outstanding changes in the working directory and
1117 there is a linear relationship between the current version and the
1124 there is a linear relationship between the current version and the
1118 requested version, the result is the requested version.
1125 requested version, the result is the requested version.
1119
1126
1120 Otherwise the result is a merge between the contents of the
1127 Otherwise the result is a merge between the contents of the
1121 current working directory and the requested version. Files that
1128 current working directory and the requested version. Files that
1122 changed between either parent are marked as changed for the next
1129 changed between either parent are marked as changed for the next
1123 commit and a commit must be performed before any further updates
1130 commit and a commit must be performed before any further updates
1124 are allowed.
1131 are allowed.
1125 '''
1132 '''
1126 node = node and repo.lookup(node) or repo.changelog.tip()
1133 node = node and repo.lookup(node) or repo.changelog.tip()
1127 return repo.update(node, allow=merge, force=clean)
1134 return repo.update(node, allow=merge, force=clean)
1128
1135
1129 def verify(ui, repo):
1136 def verify(ui, repo):
1130 """verify the integrity of the repository"""
1137 """verify the integrity of the repository"""
1131 return repo.verify()
1138 return repo.verify()
1132
1139
1133 # Command options and aliases are listed here, alphabetically
1140 # Command options and aliases are listed here, alphabetically
1134
1141
1135 table = {
1142 table = {
1136 "^add": (add,
1143 "^add": (add,
1137 [('I', 'include', [], 'include path in search'),
1144 [('I', 'include', [], 'include path in search'),
1138 ('X', 'exclude', [], 'exclude path from search')],
1145 ('X', 'exclude', [], 'exclude path from search')],
1139 "hg add [FILE]..."),
1146 "hg add [FILE]..."),
1140 "addremove": (addremove,
1147 "addremove": (addremove,
1141 [('I', 'include', [], 'include path in search'),
1148 [('I', 'include', [], 'include path in search'),
1142 ('X', 'exclude', [], 'exclude path from search')],
1149 ('X', 'exclude', [], 'exclude path from search')],
1143 "hg addremove [OPTION]... [FILE]..."),
1150 "hg addremove [OPTION]... [FILE]..."),
1144 "^annotate":
1151 "^annotate":
1145 (annotate,
1152 (annotate,
1146 [('r', 'rev', '', 'revision'),
1153 [('r', 'rev', '', 'revision'),
1147 ('u', 'user', None, 'show user'),
1154 ('u', 'user', None, 'show user'),
1148 ('n', 'number', None, 'show revision number'),
1155 ('n', 'number', None, 'show revision number'),
1149 ('c', 'changeset', None, 'show changeset'),
1156 ('c', 'changeset', None, 'show changeset'),
1150 ('I', 'include', [], 'include path in search'),
1157 ('I', 'include', [], 'include path in search'),
1151 ('X', 'exclude', [], 'exclude path from search')],
1158 ('X', 'exclude', [], 'exclude path from search')],
1152 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1159 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1153 "cat":
1160 "cat":
1154 (cat,
1161 (cat,
1155 [('o', 'output', "", 'output to file')],
1162 [('o', 'output', "", 'output to file')],
1156 'hg cat [-o OUTFILE] FILE [REV]'),
1163 'hg cat [-o OUTFILE] FILE [REV]'),
1157 "^clone":
1164 "^clone":
1158 (clone,
1165 (clone,
1159 [('U', 'noupdate', None, 'skip update after cloning')],
1166 [('U', 'noupdate', None, 'skip update after cloning')],
1160 'hg clone [-U] SOURCE [DEST]'),
1167 'hg clone [-U] SOURCE [DEST]'),
1161 "^commit|ci":
1168 "^commit|ci":
1162 (commit,
1169 (commit,
1163 [('A', 'addremove', None, 'run add/remove during commit'),
1170 [('A', 'addremove', None, 'run add/remove during commit'),
1164 ('I', 'include', [], 'include path in search'),
1171 ('I', 'include', [], 'include path in search'),
1165 ('X', 'exclude', [], 'exclude path from search'),
1172 ('X', 'exclude', [], 'exclude path from search'),
1166 ('m', 'message', "", 'commit message'),
1173 ('m', 'message', "", 'commit message'),
1167 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1174 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1168 ('l', 'logfile', "", 'commit message file'),
1175 ('l', 'logfile', "", 'commit message file'),
1169 ('d', 'date', "", 'date code'),
1176 ('d', 'date', "", 'date code'),
1170 ('u', 'user', "", 'user')],
1177 ('u', 'user', "", 'user')],
1171 'hg commit [OPTION]... [FILE]...'),
1178 'hg commit [OPTION]... [FILE]...'),
1172 "copy": (copy, [], 'hg copy SOURCE DEST'),
1179 "copy": (copy, [], 'hg copy SOURCE DEST'),
1173 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1180 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1174 "debugstate": (debugstate, [], 'debugstate'),
1181 "debugstate": (debugstate, [], 'debugstate'),
1175 "debugindex": (debugindex, [], 'debugindex FILE'),
1182 "debugindex": (debugindex, [], 'debugindex FILE'),
1176 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1183 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1177 "debugwalk": (debugwalk,
1184 "debugwalk": (debugwalk,
1178 [('I', 'include', [], 'include path in search'),
1185 [('I', 'include', [], 'include path in search'),
1179 ('X', 'exclude', [], 'exclude path from search')],
1186 ('X', 'exclude', [], 'exclude path from search')],
1180 'debugwalk [OPTIONS]... [FILE]...'),
1187 'debugwalk [OPTIONS]... [FILE]...'),
1181 "^diff":
1188 "^diff":
1182 (diff,
1189 (diff,
1183 [('r', 'rev', [], 'revision'),
1190 [('r', 'rev', [], 'revision'),
1184 ('I', 'include', [], 'include path in search'),
1191 ('I', 'include', [], 'include path in search'),
1185 ('X', 'exclude', [], 'exclude path from search')],
1192 ('X', 'exclude', [], 'exclude path from search')],
1186 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1193 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1187 "^export":
1194 "^export":
1188 (export,
1195 (export,
1189 [('o', 'output', "", 'output to file')],
1196 [('o', 'output', "", 'output to file')],
1190 "hg export [-o OUTFILE] REV..."),
1197 "hg export [-o OUTFILE] REV..."),
1191 "forget": (forget,
1198 "forget": (forget,
1192 [('I', 'include', [], 'include path in search'),
1199 [('I', 'include', [], 'include path in search'),
1193 ('X', 'exclude', [], 'exclude path from search')],
1200 ('X', 'exclude', [], 'exclude path from search')],
1194 "hg forget FILE..."),
1201 "hg forget FILE..."),
1195 "heads": (heads, [], 'hg heads'),
1202 "heads": (heads, [], 'hg heads'),
1196 "help": (help_, [], 'hg help [COMMAND]'),
1203 "help": (help_, [], 'hg help [COMMAND]'),
1197 "identify|id": (identify, [], 'hg identify'),
1204 "identify|id": (identify, [], 'hg identify'),
1198 "import|patch":
1205 "import|patch":
1199 (import_,
1206 (import_,
1200 [('p', 'strip', 1, 'path strip'),
1207 [('p', 'strip', 1, 'path strip'),
1201 ('b', 'base', "", 'base path')],
1208 ('b', 'base', "", 'base path')],
1202 "hg import [-p NUM] [-b BASE] PATCH..."),
1209 "hg import [-p NUM] [-b BASE] PATCH..."),
1203 "^init": (init, [], 'hg init'),
1210 "^init": (init, [], 'hg init'),
1204 "locate":
1211 "locate":
1205 (locate,
1212 (locate,
1206 [('r', 'rev', '', 'revision'),
1213 [('r', 'rev', '', 'revision'),
1207 ('0', 'print0', None, 'end records with NUL'),
1214 ('0', 'print0', None, 'end records with NUL'),
1208 ('f', 'fullpath', None, 'print complete paths'),
1215 ('f', 'fullpath', None, 'print complete paths'),
1209 ('I', 'include', [], 'include path in search'),
1216 ('I', 'include', [], 'include path in search'),
1210 ('X', 'exclude', [], 'exclude path from search')],
1217 ('X', 'exclude', [], 'exclude path from search')],
1211 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1218 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1212 "^log|history":
1219 "^log|history":
1213 (log,
1220 (log,
1214 [('r', 'rev', [], 'revision'),
1221 [('r', 'rev', [], 'revision'),
1215 ('p', 'patch', None, 'show patch')],
1222 ('p', 'patch', None, 'show patch')],
1216 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1223 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1217 "manifest": (manifest, [], 'hg manifest [REV]'),
1224 "manifest": (manifest, [], 'hg manifest [REV]'),
1218 "parents": (parents, [], 'hg parents [REV]'),
1225 "parents": (parents, [], 'hg parents [REV]'),
1219 "paths": (paths, [], 'hg paths [name]'),
1226 "paths": (paths, [], 'hg paths [name]'),
1220 "^pull":
1227 "^pull":
1221 (pull,
1228 (pull,
1222 [('u', 'update', None, 'update working directory')],
1229 [('u', 'update', None, 'update working directory')],
1223 'hg pull [-u] [SOURCE]'),
1230 'hg pull [-u] [SOURCE]'),
1224 "^push": (push, [], 'hg push [DEST]'),
1231 "^push": (push, [], 'hg push [DEST]'),
1225 "rawcommit":
1232 "rawcommit":
1226 (rawcommit,
1233 (rawcommit,
1227 [('p', 'parent', [], 'parent'),
1234 [('p', 'parent', [], 'parent'),
1228 ('d', 'date', "", 'date code'),
1235 ('d', 'date', "", 'date code'),
1229 ('u', 'user', "", 'user'),
1236 ('u', 'user', "", 'user'),
1230 ('F', 'files', "", 'file list'),
1237 ('F', 'files', "", 'file list'),
1231 ('m', 'message', "", 'commit message'),
1238 ('m', 'message', "", 'commit message'),
1232 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1239 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1233 ('l', 'logfile', "", 'commit message file')],
1240 ('l', 'logfile', "", 'commit message file')],
1234 'hg rawcommit [OPTION]... [FILE]...'),
1241 'hg rawcommit [OPTION]... [FILE]...'),
1235 "recover": (recover, [], "hg recover"),
1242 "recover": (recover, [], "hg recover"),
1236 "^remove|rm": (remove, [], "hg remove FILE..."),
1243 "^remove|rm": (remove, [], "hg remove FILE..."),
1237 "^revert":
1244 "^revert":
1238 (revert,
1245 (revert,
1239 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1246 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1240 ("r", "rev", "", "revision")],
1247 ("r", "rev", "", "revision")],
1241 "hg revert [-n] [-r REV] [NAME]..."),
1248 "hg revert [-n] [-r REV] [NAME]..."),
1242 "root": (root, [], "hg root"),
1249 "root": (root, [], "hg root"),
1243 "^serve":
1250 "^serve":
1244 (serve,
1251 (serve,
1245 [('A', 'accesslog', '', 'access log file'),
1252 [('A', 'accesslog', '', 'access log file'),
1246 ('E', 'errorlog', '', 'error log file'),
1253 ('E', 'errorlog', '', 'error log file'),
1247 ('p', 'port', 8000, 'listen port'),
1254 ('p', 'port', 8000, 'listen port'),
1248 ('a', 'address', '', 'interface address'),
1255 ('a', 'address', '', 'interface address'),
1249 ('n', 'name', os.getcwd(), 'repository name'),
1256 ('n', 'name', os.getcwd(), 'repository name'),
1250 ('', 'stdio', None, 'for remote clients'),
1257 ('', 'stdio', None, 'for remote clients'),
1251 ('t', 'templates', "", 'template map')],
1258 ('t', 'templates', "", 'template map')],
1252 "hg serve [OPTION]..."),
1259 "hg serve [OPTION]..."),
1253 "^status": (status,
1260 "^status": (status,
1254 [('I', 'include', [], 'include path in search'),
1261 [('I', 'include', [], 'include path in search'),
1255 ('X', 'exclude', [], 'exclude path from search')],
1262 ('X', 'exclude', [], 'exclude path from search')],
1256 'hg status [FILE]...'),
1263 'hg status [FILE]...'),
1257 "tag":
1264 "tag":
1258 (tag,
1265 (tag,
1259 [('l', 'local', None, 'make the tag local'),
1266 [('l', 'local', None, 'make the tag local'),
1260 ('m', 'message', "", 'commit message'),
1267 ('m', 'message', "", 'commit message'),
1261 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1268 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1262 ('d', 'date', "", 'date code'),
1269 ('d', 'date', "", 'date code'),
1263 ('u', 'user', "", 'user')],
1270 ('u', 'user', "", 'user')],
1264 'hg tag [OPTION]... NAME [REV]'),
1271 'hg tag [OPTION]... NAME [REV]'),
1265 "tags": (tags, [], 'hg tags'),
1272 "tags": (tags, [], 'hg tags'),
1266 "tip": (tip, [], 'hg tip'),
1273 "tip": (tip, [], 'hg tip'),
1267 "undo": (undo, [], 'hg undo'),
1274 "undo": (undo, [], 'hg undo'),
1268 "^update|up|checkout|co":
1275 "^update|up|checkout|co":
1269 (update,
1276 (update,
1270 [('m', 'merge', None, 'allow merging of conflicts'),
1277 [('m', 'merge', None, 'allow merging of conflicts'),
1271 ('C', 'clean', None, 'overwrite locally modified files')],
1278 ('C', 'clean', None, 'overwrite locally modified files')],
1272 'hg update [-m] [-C] [REV]'),
1279 'hg update [-m] [-C] [REV]'),
1273 "verify": (verify, [], 'hg verify'),
1280 "verify": (verify, [], 'hg verify'),
1274 "version": (show_version, [], 'hg version'),
1281 "version": (show_version, [], 'hg version'),
1275 }
1282 }
1276
1283
1277 globalopts = [('v', 'verbose', None, 'verbose'),
1284 globalopts = [('v', 'verbose', None, 'verbose'),
1278 ('', 'debug', None, 'debug'),
1285 ('', 'debug', None, 'debug'),
1279 ('q', 'quiet', None, 'quiet'),
1286 ('q', 'quiet', None, 'quiet'),
1280 ('', 'profile', None, 'profile'),
1287 ('', 'profile', None, 'profile'),
1281 ('R', 'repository', "", 'repository root directory'),
1288 ('R', 'repository', "", 'repository root directory'),
1282 ('', 'traceback', None, 'print traceback on exception'),
1289 ('', 'traceback', None, 'print traceback on exception'),
1283 ('y', 'noninteractive', None, 'run non-interactively'),
1290 ('y', 'noninteractive', None, 'run non-interactively'),
1284 ('', 'version', None, 'output version information and exit'),
1291 ('', 'version', None, 'output version information and exit'),
1285 ('', 'time', None, 'time how long the command takes'),
1292 ('', 'time', None, 'time how long the command takes'),
1286 ]
1293 ]
1287
1294
1288 norepo = "clone init version help debugindex debugindexdot"
1295 norepo = "clone init version help debugindex debugindexdot"
1289
1296
1290 def find(cmd):
1297 def find(cmd):
1291 for e in table.keys():
1298 for e in table.keys():
1292 if re.match("(%s)$" % e, cmd):
1299 if re.match("(%s)$" % e, cmd):
1293 return table[e]
1300 return table[e]
1294
1301
1295 raise UnknownCommand(cmd)
1302 raise UnknownCommand(cmd)
1296
1303
1297 class SignalInterrupt(Exception):
1304 class SignalInterrupt(Exception):
1298 """Exception raised on SIGTERM and SIGHUP."""
1305 """Exception raised on SIGTERM and SIGHUP."""
1299
1306
1300 def catchterm(*args):
1307 def catchterm(*args):
1301 raise SignalInterrupt
1308 raise SignalInterrupt
1302
1309
1303 def run():
1310 def run():
1304 sys.exit(dispatch(sys.argv[1:]))
1311 sys.exit(dispatch(sys.argv[1:]))
1305
1312
1306 class ParseError(Exception):
1313 class ParseError(Exception):
1307 """Exception raised on errors in parsing the command line."""
1314 """Exception raised on errors in parsing the command line."""
1308
1315
1309 def parse(args):
1316 def parse(args):
1310 options = {}
1317 options = {}
1311 cmdoptions = {}
1318 cmdoptions = {}
1312
1319
1313 try:
1320 try:
1314 args = fancyopts.fancyopts(args, globalopts, options)
1321 args = fancyopts.fancyopts(args, globalopts, options)
1315 except fancyopts.getopt.GetoptError, inst:
1322 except fancyopts.getopt.GetoptError, inst:
1316 raise ParseError(None, inst)
1323 raise ParseError(None, inst)
1317
1324
1318 if options["version"]:
1325 if options["version"]:
1319 return ("version", show_version, [], options, cmdoptions)
1326 return ("version", show_version, [], options, cmdoptions)
1320 elif not args:
1327 elif not args:
1321 return ("help", help_, [], options, cmdoptions)
1328 return ("help", help_, [], options, cmdoptions)
1322 else:
1329 else:
1323 cmd, args = args[0], args[1:]
1330 cmd, args = args[0], args[1:]
1324
1331
1325 i = find(cmd)
1332 i = find(cmd)
1326
1333
1327 # combine global options into local
1334 # combine global options into local
1328 c = list(i[1])
1335 c = list(i[1])
1329 for o in globalopts:
1336 for o in globalopts:
1330 c.append((o[0], o[1], options[o[1]], o[3]))
1337 c.append((o[0], o[1], options[o[1]], o[3]))
1331
1338
1332 try:
1339 try:
1333 args = fancyopts.fancyopts(args, c, cmdoptions)
1340 args = fancyopts.fancyopts(args, c, cmdoptions)
1334 except fancyopts.getopt.GetoptError, inst:
1341 except fancyopts.getopt.GetoptError, inst:
1335 raise ParseError(cmd, inst)
1342 raise ParseError(cmd, inst)
1336
1343
1337 # separate global options back out
1344 # separate global options back out
1338 for o in globalopts:
1345 for o in globalopts:
1339 n = o[1]
1346 n = o[1]
1340 options[n] = cmdoptions[n]
1347 options[n] = cmdoptions[n]
1341 del cmdoptions[n]
1348 del cmdoptions[n]
1342
1349
1343 return (cmd, i[0], args, options, cmdoptions)
1350 return (cmd, i[0], args, options, cmdoptions)
1344
1351
1345 def dispatch(args):
1352 def dispatch(args):
1346 signal.signal(signal.SIGTERM, catchterm)
1353 signal.signal(signal.SIGTERM, catchterm)
1347 try:
1354 try:
1348 signal.signal(signal.SIGHUP, catchterm)
1355 signal.signal(signal.SIGHUP, catchterm)
1349 except AttributeError:
1356 except AttributeError:
1350 pass
1357 pass
1351
1358
1352 try:
1359 try:
1353 cmd, func, args, options, cmdoptions = parse(args)
1360 cmd, func, args, options, cmdoptions = parse(args)
1354 except ParseError, inst:
1361 except ParseError, inst:
1355 u = ui.ui()
1362 u = ui.ui()
1356 if inst.args[0]:
1363 if inst.args[0]:
1357 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1364 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1358 help_(u, inst.args[0])
1365 help_(u, inst.args[0])
1359 else:
1366 else:
1360 u.warn("hg: %s\n" % inst.args[1])
1367 u.warn("hg: %s\n" % inst.args[1])
1361 help_(u)
1368 help_(u)
1362 sys.exit(-1)
1369 sys.exit(-1)
1363 except UnknownCommand, inst:
1370 except UnknownCommand, inst:
1364 u = ui.ui()
1371 u = ui.ui()
1365 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1372 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1366 help_(u)
1373 help_(u)
1367 sys.exit(1)
1374 sys.exit(1)
1368
1375
1369 if options["time"]:
1376 if options["time"]:
1370 def get_times():
1377 def get_times():
1371 t = os.times()
1378 t = os.times()
1372 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1379 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1373 t = (t[0], t[1], t[2], t[3], time.clock())
1380 t = (t[0], t[1], t[2], t[3], time.clock())
1374 return t
1381 return t
1375 s = get_times()
1382 s = get_times()
1376 def print_time():
1383 def print_time():
1377 t = get_times()
1384 t = get_times()
1378 u = ui.ui()
1385 u = ui.ui()
1379 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1386 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1380 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1387 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1381 atexit.register(print_time)
1388 atexit.register(print_time)
1382
1389
1383 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1390 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1384 not options["noninteractive"])
1391 not options["noninteractive"])
1385
1392
1386 try:
1393 try:
1387 try:
1394 try:
1388 if cmd not in norepo.split():
1395 if cmd not in norepo.split():
1389 path = options["repository"] or ""
1396 path = options["repository"] or ""
1390 repo = hg.repository(ui=u, path=path)
1397 repo = hg.repository(ui=u, path=path)
1391 d = lambda: func(u, repo, *args, **cmdoptions)
1398 d = lambda: func(u, repo, *args, **cmdoptions)
1392 else:
1399 else:
1393 d = lambda: func(u, *args, **cmdoptions)
1400 d = lambda: func(u, *args, **cmdoptions)
1394
1401
1395 if options['profile']:
1402 if options['profile']:
1396 import hotshot, hotshot.stats
1403 import hotshot, hotshot.stats
1397 prof = hotshot.Profile("hg.prof")
1404 prof = hotshot.Profile("hg.prof")
1398 r = prof.runcall(d)
1405 r = prof.runcall(d)
1399 prof.close()
1406 prof.close()
1400 stats = hotshot.stats.load("hg.prof")
1407 stats = hotshot.stats.load("hg.prof")
1401 stats.strip_dirs()
1408 stats.strip_dirs()
1402 stats.sort_stats('time', 'calls')
1409 stats.sort_stats('time', 'calls')
1403 stats.print_stats(40)
1410 stats.print_stats(40)
1404 return r
1411 return r
1405 else:
1412 else:
1406 return d()
1413 return d()
1407 except:
1414 except:
1408 if options['traceback']:
1415 if options['traceback']:
1409 traceback.print_exc()
1416 traceback.print_exc()
1410 raise
1417 raise
1411 except util.CommandError, inst:
1418 except util.CommandError, inst:
1412 u.warn("abort: %s\n" % inst.args)
1419 u.warn("abort: %s\n" % inst.args)
1413 except hg.RepoError, inst:
1420 except hg.RepoError, inst:
1414 u.warn("abort: ", inst, "!\n")
1421 u.warn("abort: ", inst, "!\n")
1415 except SignalInterrupt:
1422 except SignalInterrupt:
1416 u.warn("killed!\n")
1423 u.warn("killed!\n")
1417 except KeyboardInterrupt:
1424 except KeyboardInterrupt:
1418 u.warn("interrupted!\n")
1425 u.warn("interrupted!\n")
1419 except IOError, inst:
1426 except IOError, inst:
1420 if hasattr(inst, "code"):
1427 if hasattr(inst, "code"):
1421 u.warn("abort: %s\n" % inst)
1428 u.warn("abort: %s\n" % inst)
1422 elif hasattr(inst, "reason"):
1429 elif hasattr(inst, "reason"):
1423 u.warn("abort: error: %s\n" % inst.reason[1])
1430 u.warn("abort: error: %s\n" % inst.reason[1])
1424 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1431 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1425 if u.debugflag: u.warn("broken pipe\n")
1432 if u.debugflag: u.warn("broken pipe\n")
1426 else:
1433 else:
1427 raise
1434 raise
1428 except OSError, inst:
1435 except OSError, inst:
1429 if hasattr(inst, "filename"):
1436 if hasattr(inst, "filename"):
1430 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1437 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1431 else:
1438 else:
1432 u.warn("abort: %s\n" % inst.strerror)
1439 u.warn("abort: %s\n" % inst.strerror)
1433 except Abort, inst:
1440 except Abort, inst:
1434 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1441 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1435 sys.exit(1)
1442 sys.exit(1)
1436 except TypeError, inst:
1443 except TypeError, inst:
1437 # was this an argument error?
1444 # was this an argument error?
1438 tb = traceback.extract_tb(sys.exc_info()[2])
1445 tb = traceback.extract_tb(sys.exc_info()[2])
1439 if len(tb) > 2: # no
1446 if len(tb) > 2: # no
1440 raise
1447 raise
1441 u.debug(inst, "\n")
1448 u.debug(inst, "\n")
1442 u.warn("%s: invalid arguments\n" % cmd)
1449 u.warn("%s: invalid arguments\n" % cmd)
1443 help_(u, cmd)
1450 help_(u, cmd)
1444
1451
1445 sys.exit(-1)
1452 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now