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