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