##// END OF EJS Templates
A bunch of parsing/help updates...
mpm@selenic.com -
r596:9a8daeff default
parent child Browse files
Show More
@@ -1,1108 +1,1129 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 import os, re, sys, signal
8 import os, re, sys, signal
9 import fancyopts, ui, hg, util
9 import fancyopts, ui, hg, util
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "mdiff time hgweb traceback random signal errno version")
11 demandload(globals(), "mdiff time hgweb traceback random signal errno version")
12
12
13 class UnknownCommand(Exception): pass
13 class UnknownCommand(Exception): pass
14
14
15 def filterfiles(filters, files):
15 def filterfiles(filters, files):
16 l = [ x for x in files if x in filters ]
16 l = [ x for x in files if x in filters ]
17
17
18 for t in filters:
18 for t in filters:
19 if t and t[-1] != "/": t += "/"
19 if t and t[-1] != "/": t += "/"
20 l += [ x for x in files if x.startswith(t) ]
20 l += [ x for x in files if x.startswith(t) ]
21 return l
21 return l
22
22
23 def relfilter(repo, files):
23 def relfilter(repo, files):
24 if os.getcwd() != repo.root:
24 if os.getcwd() != repo.root:
25 p = os.getcwd()[len(repo.root) + 1: ]
25 p = os.getcwd()[len(repo.root) + 1: ]
26 return filterfiles([util.pconvert(p)], files)
26 return filterfiles([util.pconvert(p)], files)
27 return files
27 return files
28
28
29 def relpath(repo, args):
29 def relpath(repo, args):
30 if os.getcwd() != repo.root:
30 if os.getcwd() != repo.root:
31 p = os.getcwd()[len(repo.root) + 1: ]
31 p = os.getcwd()[len(repo.root) + 1: ]
32 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
32 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
33 for x in args ]
33 for x in args ]
34 return args
34 return args
35
35
36 revrangesep = ':'
36 revrangesep = ':'
37
37
38 def revrange(ui, repo, revs = [], revlog = None):
38 def revrange(ui, repo, revs = [], revlog = None):
39 if revlog is None:
39 if revlog is None:
40 revlog = repo.changelog
40 revlog = repo.changelog
41 revcount = revlog.count()
41 revcount = revlog.count()
42 def fix(val, defval):
42 def fix(val, defval):
43 if not val: return defval
43 if not val: return defval
44 try:
44 try:
45 num = int(val)
45 num = int(val)
46 if str(num) != val: raise ValueError
46 if str(num) != val: raise ValueError
47 if num < 0: num += revcount
47 if num < 0: num += revcount
48 if not (0 <= num < revcount):
48 if not (0 <= num < revcount):
49 raise ValueError
49 raise ValueError
50 except ValueError:
50 except ValueError:
51 try:
51 try:
52 num = repo.changelog.rev(repo.lookup(val))
52 num = repo.changelog.rev(repo.lookup(val))
53 except KeyError:
53 except KeyError:
54 try:
54 try:
55 num = revlog.rev(revlog.lookup(val))
55 num = revlog.rev(revlog.lookup(val))
56 except KeyError:
56 except KeyError:
57 ui.warn('abort: invalid revision identifier %s\n' % val)
57 ui.warn('abort: invalid revision identifier %s\n' % val)
58 sys.exit(1)
58 sys.exit(1)
59 return num
59 return num
60 for spec in revs:
60 for spec in revs:
61 if spec.find(revrangesep) >= 0:
61 if spec.find(revrangesep) >= 0:
62 start, end = spec.split(revrangesep, 1)
62 start, end = spec.split(revrangesep, 1)
63 start = fix(start, 0)
63 start = fix(start, 0)
64 end = fix(end, revcount - 1)
64 end = fix(end, revcount - 1)
65 if end > start:
65 if end > start:
66 end += 1
66 end += 1
67 step = 1
67 step = 1
68 else:
68 else:
69 end -= 1
69 end -= 1
70 step = -1
70 step = -1
71 for rev in xrange(start, end, step):
71 for rev in xrange(start, end, step):
72 yield str(rev)
72 yield str(rev)
73 else:
73 else:
74 yield spec
74 yield spec
75
75
76 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
76 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
77 def date(c):
77 def date(c):
78 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
78 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
79
79
80 (c, a, d, u) = repo.changes(node1, node2, files)
80 (c, a, d, u) = repo.changes(node1, node2, files)
81 if files:
81 if files:
82 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
82 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
83
83
84 if not c and not a and not d:
84 if not c and not a and not d:
85 return
85 return
86
86
87 if node2:
87 if node2:
88 change = repo.changelog.read(node2)
88 change = repo.changelog.read(node2)
89 mmap2 = repo.manifest.read(change[0])
89 mmap2 = repo.manifest.read(change[0])
90 def read(f): return repo.file(f).read(mmap2[f])
90 def read(f): return repo.file(f).read(mmap2[f])
91 date2 = date(change)
91 date2 = date(change)
92 else:
92 else:
93 date2 = time.asctime()
93 date2 = time.asctime()
94 if not node1:
94 if not node1:
95 node1 = repo.dirstate.parents()[0]
95 node1 = repo.dirstate.parents()[0]
96 def read(f): return repo.wfile(f).read()
96 def read(f): return repo.wfile(f).read()
97
97
98 if ui.quiet:
98 if ui.quiet:
99 r = None
99 r = None
100 else:
100 else:
101 hexfunc = ui.verbose and hg.hex or hg.short
101 hexfunc = ui.verbose and hg.hex or hg.short
102 r = [hexfunc(node) for node in [node1, node2] if node]
102 r = [hexfunc(node) for node in [node1, node2] if node]
103
103
104 change = repo.changelog.read(node1)
104 change = repo.changelog.read(node1)
105 mmap = repo.manifest.read(change[0])
105 mmap = repo.manifest.read(change[0])
106 date1 = date(change)
106 date1 = date(change)
107
107
108 for f in c:
108 for f in c:
109 to = None
109 to = None
110 if f in mmap:
110 if f in mmap:
111 to = repo.file(f).read(mmap[f])
111 to = repo.file(f).read(mmap[f])
112 tn = read(f)
112 tn = read(f)
113 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
113 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
114 for f in a:
114 for f in a:
115 to = None
115 to = None
116 tn = read(f)
116 tn = read(f)
117 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
117 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
118 for f in d:
118 for f in d:
119 to = repo.file(f).read(mmap[f])
119 to = repo.file(f).read(mmap[f])
120 tn = None
120 tn = None
121 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
121 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
122
122
123 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
123 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
124 """show a single changeset or file revision"""
124 """show a single changeset or file revision"""
125 changelog = repo.changelog
125 changelog = repo.changelog
126 if filelog:
126 if filelog:
127 log = filelog
127 log = filelog
128 filerev = rev
128 filerev = rev
129 node = filenode = filelog.node(filerev)
129 node = filenode = filelog.node(filerev)
130 changerev = filelog.linkrev(filenode)
130 changerev = filelog.linkrev(filenode)
131 changenode = changenode or changelog.node(changerev)
131 changenode = changenode or changelog.node(changerev)
132 else:
132 else:
133 log = changelog
133 log = changelog
134 changerev = rev
134 changerev = rev
135 if changenode is None:
135 if changenode is None:
136 changenode = changelog.node(changerev)
136 changenode = changelog.node(changerev)
137 elif not changerev:
137 elif not changerev:
138 rev = changerev = changelog.rev(changenode)
138 rev = changerev = changelog.rev(changenode)
139 node = changenode
139 node = changenode
140
140
141 if ui.quiet:
141 if ui.quiet:
142 ui.write("%d:%s\n" % (rev, hg.hex(node)))
142 ui.write("%d:%s\n" % (rev, hg.hex(node)))
143 return
143 return
144
144
145 changes = changelog.read(changenode)
145 changes = changelog.read(changenode)
146
146
147 parents = [(log.rev(parent), hg.hex(parent))
147 parents = [(log.rev(parent), hg.hex(parent))
148 for parent in log.parents(node)
148 for parent in log.parents(node)
149 if ui.debugflag or parent != hg.nullid]
149 if ui.debugflag or parent != hg.nullid]
150 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
150 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
151 parents = []
151 parents = []
152
152
153 if filelog:
153 if filelog:
154 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
154 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
155 for parent in parents:
155 for parent in parents:
156 ui.write("parent: %d:%s\n" % parent)
156 ui.write("parent: %d:%s\n" % parent)
157 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
157 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
158 else:
158 else:
159 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
159 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
160 for tag in repo.nodetags(changenode):
160 for tag in repo.nodetags(changenode):
161 ui.status("tag: %s\n" % tag)
161 ui.status("tag: %s\n" % tag)
162 for parent in parents:
162 for parent in parents:
163 ui.write("parent: %d:%s\n" % parent)
163 ui.write("parent: %d:%s\n" % parent)
164 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
164 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
165 hg.hex(changes[0])))
165 hg.hex(changes[0])))
166 ui.status("user: %s\n" % changes[1])
166 ui.status("user: %s\n" % changes[1])
167 ui.status("date: %s\n" % time.asctime(
167 ui.status("date: %s\n" % time.asctime(
168 time.localtime(float(changes[2].split(' ')[0]))))
168 time.localtime(float(changes[2].split(' ')[0]))))
169 if ui.debugflag:
169 if ui.debugflag:
170 files = repo.changes(changelog.parents(changenode)[0], changenode)
170 files = repo.changes(changelog.parents(changenode)[0], changenode)
171 for key, value in zip(["files:", "files+:", "files-:"], files):
171 for key, value in zip(["files:", "files+:", "files-:"], files):
172 if value:
172 if value:
173 ui.note("%-12s %s\n" % (key, " ".join(value)))
173 ui.note("%-12s %s\n" % (key, " ".join(value)))
174 else:
174 else:
175 ui.note("files: %s\n" % " ".join(changes[3]))
175 ui.note("files: %s\n" % " ".join(changes[3]))
176 description = changes[4].strip()
176 description = changes[4].strip()
177 if description:
177 if description:
178 if ui.verbose:
178 if ui.verbose:
179 ui.status("description:\n")
179 ui.status("description:\n")
180 ui.status(description)
180 ui.status(description)
181 ui.status("\n\n")
181 ui.status("\n\n")
182 else:
182 else:
183 ui.status("summary: %s\n" % description.splitlines()[0])
183 ui.status("summary: %s\n" % description.splitlines()[0])
184 ui.status("\n")
184 ui.status("\n")
185
185
186 def show_version(ui):
186 def show_version(ui):
187 """output version and copyright information"""
187 """output version and copyright information"""
188 ui.write("Mercurial version %s\n" % version.get_version())
188 ui.write("Mercurial version %s\n" % version.get_version())
189 ui.status(
189 ui.status(
190 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
190 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
191 "This is free software; see the source for copying conditions. "
191 "This is free software; see the source for copying conditions. "
192 "There is NO\nwarranty; "
192 "There is NO\nwarranty; "
193 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
193 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
194 )
194 )
195
195
196 def help(ui, cmd=None):
196 def help(ui, cmd=None):
197 '''show help for a given command or all commands'''
197 '''show help for a given command or all commands'''
198 if cmd:
198 if cmd:
199 try:
199 try:
200 i = find(cmd)
200 i = find(cmd)
201 ui.write("%s\n\n" % i[2])
201 ui.write("%s\n\n" % i[2])
202
202
203 if i[1]:
203 if i[1]:
204 for s, l, d, c in i[1]:
204 for s, l, d, c in i[1]:
205 opt=' '
205 opt=' '
206 if s: opt = opt + '-' + s + ' '
206 if s: opt = opt + '-' + s + ' '
207 if l: opt = opt + '--' + l + ' '
207 if l: opt = opt + '--' + l + ' '
208 if d: opt = opt + '(' + str(d) + ')'
208 if d: opt = opt + '(' + str(d) + ')'
209 ui.write(opt, "\n")
209 ui.write(opt, "\n")
210 if c: ui.write(' %s\n' % c)
210 if c: ui.write(' %s\n' % c)
211 ui.write("\n")
211 ui.write("\n")
212
212
213 ui.write(i[0].__doc__, "\n")
213 ui.write(i[0].__doc__, "\n")
214 except UnknownCommand:
214 except UnknownCommand:
215 ui.warn("hg: unknown command %s\n" % cmd)
215 ui.warn("hg: unknown command %s\n" % cmd)
216 sys.exit(0)
216 sys.exit(0)
217 else:
217 else:
218 if ui.verbose:
218 if ui.verbose:
219 show_version(ui)
219 show_version(ui)
220 ui.write('\n')
220 ui.write('\n')
221 if ui.verbose:
221 if ui.verbose:
222 ui.write('hg commands:\n\n')
222 ui.write('hg commands:\n\n')
223 else:
223 else:
224 ui.write('basic hg commands (use -v for long list):\n\n')
224 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
225
225
226 h = {}
226 h = {}
227 for c, e in table.items():
227 for c, e in table.items():
228 f = c.split("|")[0]
228 f = c.split("|")[0]
229 if not ui.verbose and not f.startswith("^"):
229 if not ui.verbose and not f.startswith("^"):
230 continue
230 continue
231 if not ui.debugflag and f.startswith("debug"):
231 if not ui.debugflag and f.startswith("debug"):
232 continue
232 continue
233 f = f.lstrip("^")
233 f = f.lstrip("^")
234 d = ""
234 d = ""
235 if e[0].__doc__:
235 if e[0].__doc__:
236 d = e[0].__doc__.splitlines(0)[0].rstrip()
236 d = e[0].__doc__.splitlines(0)[0].rstrip()
237 h[f] = d
237 h[f] = d
238
238
239 fns = h.keys()
239 fns = h.keys()
240 fns.sort()
240 fns.sort()
241 m = max(map(len, fns))
241 m = max(map(len, fns))
242 for f in fns:
242 for f in fns:
243 ui.write(' %-*s %s\n' % (m, f, h[f]))
243 ui.write(' %-*s %s\n' % (m, f, h[f]))
244
244
245 # Commands start here, listed alphabetically
245 # Commands start here, listed alphabetically
246
246
247 def add(ui, repo, file, *files):
247 def add(ui, repo, file, *files):
248 '''add the specified files on the next commit'''
248 '''add the specified files on the next commit'''
249 repo.add(relpath(repo, (file,) + files))
249 repo.add(relpath(repo, (file,) + files))
250
250
251 def addremove(ui, repo, *files):
251 def addremove(ui, repo, *files):
252 """add all new files, delete all missing files"""
252 """add all new files, delete all missing files"""
253 if files:
253 if files:
254 files = relpath(repo, files)
254 files = relpath(repo, files)
255 d = []
255 d = []
256 u = []
256 u = []
257 for f in files:
257 for f in files:
258 p = repo.wjoin(f)
258 p = repo.wjoin(f)
259 s = repo.dirstate.state(f)
259 s = repo.dirstate.state(f)
260 isfile = os.path.isfile(p)
260 isfile = os.path.isfile(p)
261 if s != 'r' and not isfile:
261 if s != 'r' and not isfile:
262 d.append(f)
262 d.append(f)
263 elif s not in 'nmai' and isfile:
263 elif s not in 'nmai' and isfile:
264 u.append(f)
264 u.append(f)
265 else:
265 else:
266 (c, a, d, u) = repo.changes(None, None)
266 (c, a, d, u) = repo.changes(None, None)
267 repo.add(u)
267 repo.add(u)
268 repo.remove(d)
268 repo.remove(d)
269
269
270 def annotate(u, repo, file, *files, **ops):
270 def annotate(u, repo, file, *files, **ops):
271 """show changeset information per file line"""
271 """show changeset information per file line"""
272 def getnode(rev):
272 def getnode(rev):
273 return hg.short(repo.changelog.node(rev))
273 return hg.short(repo.changelog.node(rev))
274
274
275 def getname(rev):
275 def getname(rev):
276 try:
276 try:
277 return bcache[rev]
277 return bcache[rev]
278 except KeyError:
278 except KeyError:
279 cl = repo.changelog.read(repo.changelog.node(rev))
279 cl = repo.changelog.read(repo.changelog.node(rev))
280 name = cl[1]
280 name = cl[1]
281 f = name.find('@')
281 f = name.find('@')
282 if f >= 0:
282 if f >= 0:
283 name = name[:f]
283 name = name[:f]
284 f = name.find('<')
284 f = name.find('<')
285 if f >= 0:
285 if f >= 0:
286 name = name[f+1:]
286 name = name[f+1:]
287 bcache[rev] = name
287 bcache[rev] = name
288 return name
288 return name
289
289
290 bcache = {}
290 bcache = {}
291 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
291 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
292 if not ops['user'] and not ops['changeset']:
292 if not ops['user'] and not ops['changeset']:
293 ops['number'] = 1
293 ops['number'] = 1
294
294
295 node = repo.dirstate.parents()[0]
295 node = repo.dirstate.parents()[0]
296 if ops['revision']:
296 if ops['revision']:
297 node = repo.changelog.lookup(ops['revision'])
297 node = repo.changelog.lookup(ops['revision'])
298 change = repo.changelog.read(node)
298 change = repo.changelog.read(node)
299 mmap = repo.manifest.read(change[0])
299 mmap = repo.manifest.read(change[0])
300 for f in relpath(repo, (file,) + files):
300 for f in relpath(repo, (file,) + files):
301 lines = repo.file(f).annotate(mmap[f])
301 lines = repo.file(f).annotate(mmap[f])
302 pieces = []
302 pieces = []
303
303
304 for o, f in opmap:
304 for o, f in opmap:
305 if ops[o]:
305 if ops[o]:
306 l = [ f(n) for n,t in lines ]
306 l = [ f(n) for n,t in lines ]
307 m = max(map(len, l))
307 m = max(map(len, l))
308 pieces.append([ "%*s" % (m, x) for x in l])
308 pieces.append([ "%*s" % (m, x) for x in l])
309
309
310 for p,l in zip(zip(*pieces), lines):
310 for p,l in zip(zip(*pieces), lines):
311 u.write(" ".join(p) + ": " + l[1])
311 u.write(" ".join(p) + ": " + l[1])
312
312
313 def cat(ui, repo, file, rev = []):
313 def cat(ui, repo, file, rev = []):
314 """output the latest or given revision of a file"""
314 """output the latest or given revision of a file"""
315 r = repo.file(relpath(repo, [file])[0])
315 r = repo.file(relpath(repo, [file])[0])
316 n = r.tip()
316 n = r.tip()
317 if rev: n = r.lookup(rev)
317 if rev: n = r.lookup(rev)
318 sys.stdout.write(r.read(n))
318 sys.stdout.write(r.read(n))
319
319
320 def clone(ui, source, dest = None, **opts):
320 def clone(ui, source, dest = None, **opts):
321 """make a copy of an existing repository"""
321 """make a copy of an existing repository"""
322 source = ui.expandpath(source)
322 source = ui.expandpath(source)
323
323
324 if dest is None:
324 if dest is None:
325 dest = os.path.basename(os.path.normpath(source))
325 dest = os.path.basename(os.path.normpath(source))
326
326
327 if os.path.exists(dest):
327 if os.path.exists(dest):
328 ui.warn("abort: destination '%s' already exists\n" % dest)
328 ui.warn("abort: destination '%s' already exists\n" % dest)
329 return 1
329 return 1
330
330
331 class dircleanup:
331 class dircleanup:
332 def __init__(self, dir):
332 def __init__(self, dir):
333 self.dir = dir
333 self.dir = dir
334 os.mkdir(dir)
334 os.mkdir(dir)
335 def close(self):
335 def close(self):
336 self.dir = None
336 self.dir = None
337 def __del__(self):
337 def __del__(self):
338 if self.dir:
338 if self.dir:
339 import shutil
339 import shutil
340 shutil.rmtree(self.dir, True)
340 shutil.rmtree(self.dir, True)
341
341
342 d = dircleanup(dest)
342 d = dircleanup(dest)
343
343
344 link = 0
344 link = 0
345 abspath = source
345 abspath = source
346 if not (source.startswith("http://") or
346 if not (source.startswith("http://") or
347 source.startswith("hg://") or
347 source.startswith("hg://") or
348 source.startswith("old-http://")):
348 source.startswith("old-http://")):
349 abspath = os.path.abspath(source)
349 abspath = os.path.abspath(source)
350 d1 = os.stat(dest).st_dev
350 d1 = os.stat(dest).st_dev
351 d2 = os.stat(source).st_dev
351 d2 = os.stat(source).st_dev
352 if d1 == d2: link = 1
352 if d1 == d2: link = 1
353
353
354 if link:
354 if link:
355 ui.note("copying by hardlink\n")
355 ui.note("copying by hardlink\n")
356 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
356 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
357 try:
357 try:
358 os.remove(os.path.join(dest, ".hg", "dirstate"))
358 os.remove(os.path.join(dest, ".hg", "dirstate"))
359 except: pass
359 except: pass
360
360
361 repo = hg.repository(ui, dest)
361 repo = hg.repository(ui, dest)
362
362
363 else:
363 else:
364 repo = hg.repository(ui, dest, create=1)
364 repo = hg.repository(ui, dest, create=1)
365 other = hg.repository(ui, source)
365 other = hg.repository(ui, source)
366 fetch = repo.findincoming(other)
366 fetch = repo.findincoming(other)
367 if fetch:
367 if fetch:
368 cg = other.changegroup(fetch)
368 cg = other.changegroup(fetch)
369 repo.addchangegroup(cg)
369 repo.addchangegroup(cg)
370
370
371 f = repo.opener("hgrc", "w")
371 f = repo.opener("hgrc", "w")
372 f.write("[paths]\n")
372 f.write("[paths]\n")
373 f.write("default = %s\n" % abspath)
373 f.write("default = %s\n" % abspath)
374
374
375 if not opts['noupdate']:
375 if not opts['noupdate']:
376 update(ui, repo)
376 update(ui, repo)
377
377
378 d.close()
378 d.close()
379
379
380 def commit(ui, repo, *files, **opts):
380 def commit(ui, repo, *files, **opts):
381 """commit the specified files or all outstanding changes"""
381 """commit the specified files or all outstanding changes"""
382 text = opts['text']
382 text = opts['text']
383 if not text and opts['logfile']:
383 if not text and opts['logfile']:
384 try: text = open(opts['logfile']).read()
384 try: text = open(opts['logfile']).read()
385 except IOError: pass
385 except IOError: pass
386
386
387 if opts['addremove']:
387 if opts['addremove']:
388 addremove(ui, repo, *files)
388 addremove(ui, repo, *files)
389 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
389 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
390
390
391 def copy(ui, repo, source, dest):
391 def copy(ui, repo, source, dest):
392 """mark a file as copied or renamed for the next commit"""
392 """mark a file as copied or renamed for the next commit"""
393 return repo.copy(*relpath(repo, (source, dest)))
393 return repo.copy(*relpath(repo, (source, dest)))
394
394
395 def debugcheckdirstate(ui, repo):
395 def debugcheckstate(ui, repo):
396 """validate the correctness of the current dirstate"""
396 parent1, parent2 = repo.dirstate.parents()
397 parent1, parent2 = repo.dirstate.parents()
397 repo.dirstate.read()
398 repo.dirstate.read()
398 dc = repo.dirstate.map
399 dc = repo.dirstate.map
399 keys = dc.keys()
400 keys = dc.keys()
400 keys.sort()
401 keys.sort()
401 m1n = repo.changelog.read(parent1)[0]
402 m1n = repo.changelog.read(parent1)[0]
402 m2n = repo.changelog.read(parent2)[0]
403 m2n = repo.changelog.read(parent2)[0]
403 m1 = repo.manifest.read(m1n)
404 m1 = repo.manifest.read(m1n)
404 m2 = repo.manifest.read(m2n)
405 m2 = repo.manifest.read(m2n)
405 errors = 0
406 errors = 0
406 for f in dc:
407 for f in dc:
407 state = repo.dirstate.state(f)
408 state = repo.dirstate.state(f)
408 if state in "nr" and f not in m1:
409 if state in "nr" and f not in m1:
409 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
410 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
410 errors += 1
411 errors += 1
411 if state in "a" and f in m1:
412 if state in "a" and f in m1:
412 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
413 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
413 errors += 1
414 errors += 1
414 if state in "m" and f not in m1 and f not in m2:
415 if state in "m" and f not in m1 and f not in m2:
415 ui.warn("%s in state %s, but not in either manifest\n" %
416 ui.warn("%s in state %s, but not in either manifest\n" %
416 (f, state))
417 (f, state))
417 errors += 1
418 errors += 1
418 for f in m1:
419 for f in m1:
419 state = repo.dirstate.state(f)
420 state = repo.dirstate.state(f)
420 if state not in "nrm":
421 if state not in "nrm":
421 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
422 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
422 errors += 1
423 errors += 1
423 if errors:
424 if errors:
424 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
425 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
425 sys.exit(1)
426 sys.exit(1)
426
427
427 def debugdumpdirstate(ui, repo):
428 def debugstate(ui, repo):
429 """show the contents of the current dirstate"""
428 repo.dirstate.read()
430 repo.dirstate.read()
429 dc = repo.dirstate.map
431 dc = repo.dirstate.map
430 keys = dc.keys()
432 keys = dc.keys()
431 keys.sort()
433 keys.sort()
432 for file in keys:
434 for file in keys:
433 ui.write("%c %s\n" % (dc[file][0], file))
435 ui.write("%c %s\n" % (dc[file][0], file))
434
436
435 def debugindex(ui, file):
437 def debugindex(ui, file):
438 """dump the contents of an index file"""
436 r = hg.revlog(hg.opener(""), file, "")
439 r = hg.revlog(hg.opener(""), file, "")
437 ui.write(" rev offset length base linkrev" +
440 ui.write(" rev offset length base linkrev" +
438 " p1 p2 nodeid\n")
441 " p1 p2 nodeid\n")
439 for i in range(r.count()):
442 for i in range(r.count()):
440 e = r.index[i]
443 e = r.index[i]
441 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
444 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
442 i, e[0], e[1], e[2], e[3],
445 i, e[0], e[1], e[2], e[3],
443 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
446 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
444
447
445 def debugindexdot(ui, file):
448 def debugindexdot(ui, file):
449 """dump an index DAG as a .dot file"""
446 r = hg.revlog(hg.opener(""), file, "")
450 r = hg.revlog(hg.opener(""), file, "")
447 ui.write("digraph G {\n")
451 ui.write("digraph G {\n")
448 for i in range(r.count()):
452 for i in range(r.count()):
449 e = r.index[i]
453 e = r.index[i]
450 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
454 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
451 if e[5] != hg.nullid:
455 if e[5] != hg.nullid:
452 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
456 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
453 ui.write("}\n")
457 ui.write("}\n")
454
458
455 def diff(ui, repo, *files, **opts):
459 def diff(ui, repo, *files, **opts):
456 """diff working directory (or selected files)"""
460 """diff working directory (or selected files)"""
457 revs = []
461 revs = []
458 if opts['rev']:
462 if opts['rev']:
459 revs = map(lambda x: repo.lookup(x), opts['rev'])
463 revs = map(lambda x: repo.lookup(x), opts['rev'])
460
464
461 if len(revs) > 2:
465 if len(revs) > 2:
462 ui.warn("too many revisions to diff\n")
466 ui.warn("too many revisions to diff\n")
463 sys.exit(1)
467 sys.exit(1)
464
468
465 if files:
469 if files:
466 files = relpath(repo, files)
470 files = relpath(repo, files)
467 else:
471 else:
468 files = relpath(repo, [""])
472 files = relpath(repo, [""])
469
473
470 dodiff(sys.stdout, ui, repo, files, *revs)
474 dodiff(sys.stdout, ui, repo, files, *revs)
471
475
472 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
476 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
473 node = repo.lookup(changeset)
477 node = repo.lookup(changeset)
474 prev, other = repo.changelog.parents(node)
478 prev, other = repo.changelog.parents(node)
475 change = repo.changelog.read(node)
479 change = repo.changelog.read(node)
476
480
477 def expand(name):
481 def expand(name):
478 expansions = {
482 expansions = {
479 '%': lambda: '%',
483 '%': lambda: '%',
480 'H': lambda: hg.hex(node),
484 'H': lambda: hg.hex(node),
481 'N': lambda: str(total),
485 'N': lambda: str(total),
482 'R': lambda: str(repo.changelog.rev(node)),
486 'R': lambda: str(repo.changelog.rev(node)),
483 'b': lambda: os.path.basename(repo.root),
487 'b': lambda: os.path.basename(repo.root),
484 'h': lambda: hg.short(node),
488 'h': lambda: hg.short(node),
485 'n': lambda: str(seqno).zfill(len(str(total))),
489 'n': lambda: str(seqno).zfill(len(str(total))),
486 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
490 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
487 }
491 }
488 newname = []
492 newname = []
489 namelen = len(name)
493 namelen = len(name)
490 i = 0
494 i = 0
491 while i < namelen:
495 while i < namelen:
492 c = name[i]
496 c = name[i]
493 if c == '%':
497 if c == '%':
494 i += 1
498 i += 1
495 c = name[i]
499 c = name[i]
496 c = expansions[c]()
500 c = expansions[c]()
497 newname.append(c)
501 newname.append(c)
498 i += 1
502 i += 1
499 return ''.join(newname)
503 return ''.join(newname)
500
504
501 if opts['output'] and opts['output'] != '-':
505 if opts['output'] and opts['output'] != '-':
502 try:
506 try:
503 fp = open(expand(opts['output']), 'w')
507 fp = open(expand(opts['output']), 'w')
504 except KeyError, inst:
508 except KeyError, inst:
505 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
509 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
506 inst.args[0])
510 inst.args[0])
507 sys.exit(1)
511 sys.exit(1)
508 else:
512 else:
509 fp = sys.stdout
513 fp = sys.stdout
510
514
511 fp.write("# HG changeset patch\n")
515 fp.write("# HG changeset patch\n")
512 fp.write("# User %s\n" % change[1])
516 fp.write("# User %s\n" % change[1])
513 fp.write("# Node ID %s\n" % hg.hex(node))
517 fp.write("# Node ID %s\n" % hg.hex(node))
514 fp.write("# Parent %s\n" % hg.hex(prev))
518 fp.write("# Parent %s\n" % hg.hex(prev))
515 if other != hg.nullid:
519 if other != hg.nullid:
516 fp.write("# Parent %s\n" % hg.hex(other))
520 fp.write("# Parent %s\n" % hg.hex(other))
517 fp.write(change[4].rstrip())
521 fp.write(change[4].rstrip())
518 fp.write("\n\n")
522 fp.write("\n\n")
519
523
520 dodiff(fp, ui, repo, None, prev, node)
524 dodiff(fp, ui, repo, None, prev, node)
521
525
522 def export(ui, repo, *changesets, **opts):
526 def export(ui, repo, *changesets, **opts):
523 """dump the header and diffs for one or more changesets"""
527 """dump the header and diffs for one or more changesets"""
524 seqno = 0
528 seqno = 0
525 revs = list(revrange(ui, repo, changesets))
529 revs = list(revrange(ui, repo, changesets))
526 total = len(revs)
530 total = len(revs)
527 revwidth = max(len(revs[0]), len(revs[-1]))
531 revwidth = max(len(revs[0]), len(revs[-1]))
528 for cset in revs:
532 for cset in revs:
529 seqno += 1
533 seqno += 1
530 doexport(ui, repo, cset, seqno, total, revwidth, opts)
534 doexport(ui, repo, cset, seqno, total, revwidth, opts)
531
535
532 def forget(ui, repo, file, *files):
536 def forget(ui, repo, file, *files):
533 """don't add the specified files on the next commit"""
537 """don't add the specified files on the next commit"""
534 repo.forget(relpath(repo, (file,) + files))
538 repo.forget(relpath(repo, (file,) + files))
535
539
536 def heads(ui, repo):
540 def heads(ui, repo):
537 """show current repository heads"""
541 """show current repository heads"""
538 for n in repo.changelog.heads():
542 for n in repo.changelog.heads():
539 show_changeset(ui, repo, changenode=n)
543 show_changeset(ui, repo, changenode=n)
540
544
541 def identify(ui, repo):
545 def identify(ui, repo):
542 """print information about the working copy"""
546 """print information about the working copy"""
543 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
547 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
544 if not parents:
548 if not parents:
545 ui.write("unknown\n")
549 ui.write("unknown\n")
546 return
550 return
547
551
548 hexfunc = ui.verbose and hg.hex or hg.short
552 hexfunc = ui.verbose and hg.hex or hg.short
549 (c, a, d, u) = repo.changes(None, None)
553 (c, a, d, u) = repo.changes(None, None)
550 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
554 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
551 (c or a or d) and "+" or "")]
555 (c or a or d) and "+" or "")]
552
556
553 if not ui.quiet:
557 if not ui.quiet:
554 # multiple tags for a single parent separated by '/'
558 # multiple tags for a single parent separated by '/'
555 parenttags = ['/'.join(tags)
559 parenttags = ['/'.join(tags)
556 for tags in map(repo.nodetags, parents) if tags]
560 for tags in map(repo.nodetags, parents) if tags]
557 # tags for multiple parents separated by ' + '
561 # tags for multiple parents separated by ' + '
558 output.append(' + '.join(parenttags))
562 output.append(' + '.join(parenttags))
559
563
560 ui.write("%s\n" % ' '.join(output))
564 ui.write("%s\n" % ' '.join(output))
561
565
562 def import_(ui, repo, patch1, *patches, **opts):
566 def import_(ui, repo, patch1, *patches, **opts):
563 """import an ordered set of patches"""
567 """import an ordered set of patches"""
564 try:
568 try:
565 import psyco
569 import psyco
566 psyco.full()
570 psyco.full()
567 except:
571 except:
568 pass
572 pass
569
573
570 patches = (patch1,) + patches
574 patches = (patch1,) + patches
571
575
572 d = opts["base"]
576 d = opts["base"]
573 strip = opts["strip"]
577 strip = opts["strip"]
574
578
575 for patch in patches:
579 for patch in patches:
576 ui.status("applying %s\n" % patch)
580 ui.status("applying %s\n" % patch)
577 pf = os.path.join(d, patch)
581 pf = os.path.join(d, patch)
578
582
579 text = ""
583 text = ""
580 for l in file(pf):
584 for l in file(pf):
581 if l[:4] == "--- ": break
585 if l[:4] == "--- ": break
582 text += l
586 text += l
583
587
584 # make sure text isn't empty
588 # make sure text isn't empty
585 if not text: text = "imported patch %s\n" % patch
589 if not text: text = "imported patch %s\n" % patch
586
590
587 f = os.popen("patch -p%d < %s" % (strip, pf))
591 f = os.popen("patch -p%d < %s" % (strip, pf))
588 files = []
592 files = []
589 for l in f.read().splitlines():
593 for l in f.read().splitlines():
590 l.rstrip('\r\n');
594 l.rstrip('\r\n');
591 ui.status("%s\n" % l)
595 ui.status("%s\n" % l)
592 if l[:14] == 'patching file ':
596 if l[:14] == 'patching file ':
593 pf = l[14:]
597 pf = l[14:]
594 if pf not in files:
598 if pf not in files:
595 files.append(pf)
599 files.append(pf)
596 patcherr = f.close()
600 patcherr = f.close()
597 if patcherr:
601 if patcherr:
598 sys.stderr.write("patch failed")
602 sys.stderr.write("patch failed")
599 sys.exit(1)
603 sys.exit(1)
600
604
601 if len(files) > 0:
605 if len(files) > 0:
602 addremove(ui, repo, *files)
606 addremove(ui, repo, *files)
603 repo.commit(files, text)
607 repo.commit(files, text)
604
608
605 def init(ui, source=None):
609 def init(ui, source=None):
606 """create a new repository in the current directory"""
610 """create a new repository in the current directory"""
607
611
608 if source:
612 if source:
609 ui.warn("no longer supported: use \"hg clone\" instead\n")
613 ui.warn("no longer supported: use \"hg clone\" instead\n")
610 sys.exit(1)
614 sys.exit(1)
611 repo = hg.repository(ui, ".", create=1)
615 repo = hg.repository(ui, ".", create=1)
612
616
613 def log(ui, repo, f=None, **opts):
617 def log(ui, repo, f=None, **opts):
614 """show the revision history of the repository or a single file"""
618 """show the revision history of the repository or a single file"""
615 if f:
619 if f:
616 filelog = repo.file(relpath(repo, [f])[0])
620 filelog = repo.file(relpath(repo, [f])[0])
617 log = filelog
621 log = filelog
618 lookup = filelog.lookup
622 lookup = filelog.lookup
619 else:
623 else:
620 filelog = None
624 filelog = None
621 log = repo.changelog
625 log = repo.changelog
622 lookup = repo.lookup
626 lookup = repo.lookup
623 revlist = []
627 revlist = []
624 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
628 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
625 while revs:
629 while revs:
626 if len(revs) == 1:
630 if len(revs) == 1:
627 revlist.append(revs.pop(0))
631 revlist.append(revs.pop(0))
628 else:
632 else:
629 a = revs.pop(0)
633 a = revs.pop(0)
630 b = revs.pop(0)
634 b = revs.pop(0)
631 off = a > b and -1 or 1
635 off = a > b and -1 or 1
632 revlist.extend(range(a, b + off, off))
636 revlist.extend(range(a, b + off, off))
633 for i in revlist or range(log.count() - 1, -1, -1):
637 for i in revlist or range(log.count() - 1, -1, -1):
634 show_changeset(ui, repo, filelog=filelog, rev=i)
638 show_changeset(ui, repo, filelog=filelog, rev=i)
635
639
636 def manifest(ui, repo, rev = []):
640 def manifest(ui, repo, rev = []):
637 """output the latest or given revision of the project manifest"""
641 """output the latest or given revision of the project manifest"""
638 n = repo.manifest.tip()
642 n = repo.manifest.tip()
639 if rev:
643 if rev:
640 n = repo.manifest.lookup(rev)
644 n = repo.manifest.lookup(rev)
641 m = repo.manifest.read(n)
645 m = repo.manifest.read(n)
642 mf = repo.manifest.readflags(n)
646 mf = repo.manifest.readflags(n)
643 files = m.keys()
647 files = m.keys()
644 files.sort()
648 files.sort()
645
649
646 for f in files:
650 for f in files:
647 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
651 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
648
652
649 def parents(ui, repo, node = None):
653 def parents(ui, repo, node = None):
650 '''show the parents of the current working dir'''
654 '''show the parents of the current working dir'''
651 if node:
655 if node:
652 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
656 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
653 else:
657 else:
654 p = repo.dirstate.parents()
658 p = repo.dirstate.parents()
655
659
656 for n in p:
660 for n in p:
657 if n != hg.nullid:
661 if n != hg.nullid:
658 show_changeset(ui, repo, changenode=n)
662 show_changeset(ui, repo, changenode=n)
659
663
660 def pull(ui, repo, source="default", **opts):
664 def pull(ui, repo, source="default", **opts):
661 """pull changes from the specified source"""
665 """pull changes from the specified source"""
662 source = ui.expandpath(source)
666 source = ui.expandpath(source)
663
667
664 ui.status('pulling from %s\n' % (source))
668 ui.status('pulling from %s\n' % (source))
665
669
666 other = hg.repository(ui, source)
670 other = hg.repository(ui, source)
667 fetch = repo.findincoming(other)
671 fetch = repo.findincoming(other)
668 if not fetch:
672 if not fetch:
669 ui.status("no changes found\n")
673 ui.status("no changes found\n")
670 return
674 return
671
675
672 cg = other.changegroup(fetch)
676 cg = other.changegroup(fetch)
673 r = repo.addchangegroup(cg)
677 r = repo.addchangegroup(cg)
674 if cg and not r:
678 if cg and not r:
675 if opts['update']:
679 if opts['update']:
676 return update(ui, repo)
680 return update(ui, repo)
677 else:
681 else:
678 ui.status("(run 'hg update' to get a working copy)\n")
682 ui.status("(run 'hg update' to get a working copy)\n")
679
683
680 return r
684 return r
681
685
682 def push(ui, repo, dest="default-push"):
686 def push(ui, repo, dest="default-push"):
683 """push changes to the specified destination"""
687 """push changes to the specified destination"""
684 dest = ui.expandpath(dest)
688 dest = ui.expandpath(dest)
685
689
686 if not dest.startswith("ssh://"):
690 if not dest.startswith("ssh://"):
687 ui.warn("abort: can only push to ssh:// destinations currently\n")
691 ui.warn("abort: can only push to ssh:// destinations currently\n")
688 return 1
692 return 1
689
693
690 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
694 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
691 if not m:
695 if not m:
692 ui.warn("abort: couldn't parse destination %s\n" % dest)
696 ui.warn("abort: couldn't parse destination %s\n" % dest)
693 return 1
697 return 1
694
698
695 user, host, port, path = map(m.group, (2, 3, 5, 7))
699 user, host, port, path = map(m.group, (2, 3, 5, 7))
696 uhost = user and ("%s@%s" % (user, host)) or host
700 uhost = user and ("%s@%s" % (user, host)) or host
697 port = port and (" -p %s") % port or ""
701 port = port and (" -p %s") % port or ""
698 path = path or ""
702 path = path or ""
699
703
700 sport = random.randrange(30000, 60000)
704 sport = random.randrange(30000, 60000)
701 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
705 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
702 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
706 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
703
707
704 child = os.fork()
708 child = os.fork()
705 if not child:
709 if not child:
706 sys.stdout = file("/dev/null", "w")
710 sys.stdout = file("/dev/null", "w")
707 sys.stderr = sys.stdout
711 sys.stderr = sys.stdout
708 hgweb.server(repo.root, "pull", "", "localhost", sport)
712 hgweb.server(repo.root, "pull", "", "localhost", sport)
709 else:
713 else:
710 ui.status("connecting to %s\n" % host)
714 ui.status("connecting to %s\n" % host)
711 r = os.system(cmd)
715 r = os.system(cmd)
712 os.kill(child, signal.SIGTERM)
716 os.kill(child, signal.SIGTERM)
713 return r
717 return r
714
718
715 def rawcommit(ui, repo, *flist, **rc):
719 def rawcommit(ui, repo, *flist, **rc):
716 "raw commit interface"
720 "raw commit interface"
717
721
718 text = rc['text']
722 text = rc['text']
719 if not text and rc['logfile']:
723 if not text and rc['logfile']:
720 try: text = open(rc['logfile']).read()
724 try: text = open(rc['logfile']).read()
721 except IOError: pass
725 except IOError: pass
722 if not text and not rc['logfile']:
726 if not text and not rc['logfile']:
723 ui.warn("abort: missing commit text\n")
727 ui.warn("abort: missing commit text\n")
724 return 1
728 return 1
725
729
726 files = relpath(repo, list(flist))
730 files = relpath(repo, list(flist))
727 if rc['files']:
731 if rc['files']:
728 files += open(rc['files']).read().splitlines()
732 files += open(rc['files']).read().splitlines()
729
733
730 rc['parent'] = map(repo.lookup, rc['parent'])
734 rc['parent'] = map(repo.lookup, rc['parent'])
731
735
732 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
736 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
733
737
734 def recover(ui, repo):
738 def recover(ui, repo):
735 """roll back an interrupted transaction"""
739 """roll back an interrupted transaction"""
736 repo.recover()
740 repo.recover()
737
741
738 def remove(ui, repo, file, *files):
742 def remove(ui, repo, file, *files):
739 """remove the specified files on the next commit"""
743 """remove the specified files on the next commit"""
740 repo.remove(relpath(repo, (file,) + files))
744 repo.remove(relpath(repo, (file,) + files))
741
745
742 def revert(ui, repo, *names, **opts):
746 def revert(ui, repo, *names, **opts):
743 """revert modified files or dirs back to their unmodified states"""
747 """revert modified files or dirs back to their unmodified states"""
744 node = opts['rev'] and repo.lookup(opts['rev']) or \
748 node = opts['rev'] and repo.lookup(opts['rev']) or \
745 repo.dirstate.parents()[0]
749 repo.dirstate.parents()[0]
746 root = os.path.realpath(repo.root)
750 root = os.path.realpath(repo.root)
747
751
748 def trimpath(p):
752 def trimpath(p):
749 p = os.path.realpath(p)
753 p = os.path.realpath(p)
750 if p.startswith(root):
754 if p.startswith(root):
751 rest = p[len(root):]
755 rest = p[len(root):]
752 if not rest:
756 if not rest:
753 return rest
757 return rest
754 if p.startswith(os.sep):
758 if p.startswith(os.sep):
755 return rest[1:]
759 return rest[1:]
756 return p
760 return p
757
761
758 relnames = map(trimpath, names or [os.getcwd()])
762 relnames = map(trimpath, names or [os.getcwd()])
759 chosen = {}
763 chosen = {}
760
764
761 def choose(name):
765 def choose(name):
762 def body(name):
766 def body(name):
763 for r in relnames:
767 for r in relnames:
764 if not name.startswith(r): continue
768 if not name.startswith(r): continue
765 rest = name[len(r):]
769 rest = name[len(r):]
766 if not rest: return r, True
770 if not rest: return r, True
767 depth = rest.count(os.sep)
771 depth = rest.count(os.sep)
768 if not r:
772 if not r:
769 if depth == 0 or not opts['nonrecursive']: return r, True
773 if depth == 0 or not opts['nonrecursive']: return r, True
770 elif rest[0] == os.sep:
774 elif rest[0] == os.sep:
771 if depth == 1 or not opts['nonrecursive']: return r, True
775 if depth == 1 or not opts['nonrecursive']: return r, True
772 return None, False
776 return None, False
773 relname, ret = body(name)
777 relname, ret = body(name)
774 if ret:
778 if ret:
775 chosen[relname] = 1
779 chosen[relname] = 1
776 return ret
780 return ret
777
781
778 r = repo.update(node, False, True, choose, False)
782 r = repo.update(node, False, True, choose, False)
779 for n in relnames:
783 for n in relnames:
780 if n not in chosen:
784 if n not in chosen:
781 ui.warn('error: no matches for %s\n' % n)
785 ui.warn('error: no matches for %s\n' % n)
782 r = 1
786 r = 1
783 sys.stdout.flush()
787 sys.stdout.flush()
784 return r
788 return r
785
789
786 def root(ui, repo):
790 def root(ui, repo):
787 """print the root (top) of the current working dir"""
791 """print the root (top) of the current working dir"""
788 ui.write(repo.root + "\n")
792 ui.write(repo.root + "\n")
789
793
790 def serve(ui, repo, **opts):
794 def serve(ui, repo, **opts):
791 """export the repository via HTTP"""
795 """export the repository via HTTP"""
792 hgweb.server(repo.root, opts["name"], opts["templates"],
796 hgweb.server(repo.root, opts["name"], opts["templates"],
793 opts["address"], opts["port"])
797 opts["address"], opts["port"])
794
798
795 def status(ui, repo):
799 def status(ui, repo):
796 '''show changed files in the working directory
800 '''show changed files in the working directory
797
801
798 C = changed
802 C = changed
799 A = added
803 A = added
800 R = removed
804 R = removed
801 ? = not tracked'''
805 ? = not tracked'''
802
806
803 (c, a, d, u) = repo.changes(None, None)
807 (c, a, d, u) = repo.changes(None, None)
804 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
808 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
805
809
806 for f in c: ui.write("C ", f, "\n")
810 for f in c: ui.write("C ", f, "\n")
807 for f in a: ui.write("A ", f, "\n")
811 for f in a: ui.write("A ", f, "\n")
808 for f in d: ui.write("R ", f, "\n")
812 for f in d: ui.write("R ", f, "\n")
809 for f in u: ui.write("? ", f, "\n")
813 for f in u: ui.write("? ", f, "\n")
810
814
811 def tag(ui, repo, name, rev = None, **opts):
815 def tag(ui, repo, name, rev = None, **opts):
812 """add a tag for the current tip or a given revision"""
816 """add a tag for the current tip or a given revision"""
813
817
814 if name == "tip":
818 if name == "tip":
815 ui.warn("abort: 'tip' is a reserved name!\n")
819 ui.warn("abort: 'tip' is a reserved name!\n")
816 return -1
820 return -1
817 if name.find(revrangesep) >= 0:
821 if name.find(revrangesep) >= 0:
818 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
822 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
819 return -1
823 return -1
820
824
821 (c, a, d, u) = repo.changes(None, None)
825 (c, a, d, u) = repo.changes(None, None)
822 for x in (c, a, d, u):
826 for x in (c, a, d, u):
823 if ".hgtags" in x:
827 if ".hgtags" in x:
824 ui.warn("abort: working copy of .hgtags is changed!\n")
828 ui.warn("abort: working copy of .hgtags is changed!\n")
825 ui.status("(please commit .hgtags manually)\n")
829 ui.status("(please commit .hgtags manually)\n")
826 return -1
830 return -1
827
831
828 if rev:
832 if rev:
829 r = hg.hex(repo.lookup(rev))
833 r = hg.hex(repo.lookup(rev))
830 else:
834 else:
831 r = hg.hex(repo.changelog.tip())
835 r = hg.hex(repo.changelog.tip())
832
836
833 add = 0
837 add = 0
834 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
838 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
835 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
839 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
836 if add: repo.add([".hgtags"])
840 if add: repo.add([".hgtags"])
837
841
838 if not opts['text']:
842 if not opts['text']:
839 opts['text'] = "Added tag %s for changeset %s" % (name, r)
843 opts['text'] = "Added tag %s for changeset %s" % (name, r)
840
844
841 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
845 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
842
846
843 def tags(ui, repo):
847 def tags(ui, repo):
844 """list repository tags"""
848 """list repository tags"""
845
849
846 l = repo.tagslist()
850 l = repo.tagslist()
847 l.reverse()
851 l.reverse()
848 for t, n in l:
852 for t, n in l:
849 try:
853 try:
850 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
854 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
851 except KeyError:
855 except KeyError:
852 r = " ?:?"
856 r = " ?:?"
853 ui.write("%-30s %s\n" % (t, r))
857 ui.write("%-30s %s\n" % (t, r))
854
858
855 def tip(ui, repo):
859 def tip(ui, repo):
856 """show the tip revision"""
860 """show the tip revision"""
857 n = repo.changelog.tip()
861 n = repo.changelog.tip()
858 show_changeset(ui, repo, changenode=n)
862 show_changeset(ui, repo, changenode=n)
859
863
860 def undo(ui, repo):
864 def undo(ui, repo):
861 """undo the last transaction"""
865 """undo the last commit or pull
866
867 Roll back the last pull or commit transaction on the
868 repository, restoring the project to its earlier state.
869
870 This command should be used with care. There is only one level of
871 undo and there is no redo.
872
873 This command is not intended for use on public repositories. Once
874 a change is visible for pull by other users, undoing it locally is
875 ineffective.
876 """
862 repo.undo()
877 repo.undo()
863
878
864 def update(ui, repo, node=None, merge=False, clean=False):
879 def update(ui, repo, node=None, merge=False, clean=False):
865 '''update or merge working directory
880 '''update or merge working directory
866
881
867 If there are no outstanding changes in the working directory and
882 If there are no outstanding changes in the working directory and
868 there is a linear relationship between the current version and the
883 there is a linear relationship between the current version and the
869 requested version, the result is the requested version.
884 requested version, the result is the requested version.
870
885
871 Otherwise the result is a merge between the contents of the
886 Otherwise the result is a merge between the contents of the
872 current working directory and the requested version. Files that
887 current working directory and the requested version. Files that
873 changed between either parent are marked as changed for the next
888 changed between either parent are marked as changed for the next
874 commit and a commit must be performed before any further updates
889 commit and a commit must be performed before any further updates
875 are allowed.
890 are allowed.
876 '''
891 '''
877 node = node and repo.lookup(node) or repo.changelog.tip()
892 node = node and repo.lookup(node) or repo.changelog.tip()
878 return repo.update(node, allow=merge, force=clean)
893 return repo.update(node, allow=merge, force=clean)
879
894
880 def verify(ui, repo):
895 def verify(ui, repo):
881 """verify the integrity of the repository"""
896 """verify the integrity of the repository"""
882 return repo.verify()
897 return repo.verify()
883
898
884 # Command options and aliases are listed here, alphabetically
899 # Command options and aliases are listed here, alphabetically
885
900
886 table = {
901 table = {
887 "^add": (add, [], "hg add [files]"),
902 "^add": (add, [], "hg add [files]"),
888 "addremove": (addremove, [], "hg addremove [files]"),
903 "addremove": (addremove, [], "hg addremove [files]"),
889 "annotate": (annotate,
904 "^annotate": (annotate,
890 [('r', 'revision', '', 'revision'),
905 [('r', 'revision', '', 'revision'),
891 ('u', 'user', None, 'show user'),
906 ('u', 'user', None, 'show user'),
892 ('n', 'number', None, 'show revision number'),
907 ('n', 'number', None, 'show revision number'),
893 ('c', 'changeset', None, 'show changeset')],
908 ('c', 'changeset', None, 'show changeset')],
894 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
909 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
895 "cat": (cat, [], 'hg cat <file> [rev]'),
910 "cat": (cat, [], 'hg cat <file> [rev]'),
896 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
911 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
897 'hg clone [options] <source> [dest]'),
912 'hg clone [options] <source> [dest]'),
898 "^commit|ci": (commit,
913 "^commit|ci": (commit,
899 [('t', 'text', "", 'commit text'),
914 [('t', 'text', "", 'commit text'),
900 ('A', 'addremove', None, 'run add/remove during commit'),
915 ('A', 'addremove', None, 'run add/remove during commit'),
901 ('l', 'logfile', "", 'commit text file'),
916 ('l', 'logfile', "", 'commit text file'),
902 ('d', 'date', "", 'date code'),
917 ('d', 'date', "", 'date code'),
903 ('u', 'user', "", 'user')],
918 ('u', 'user', "", 'user')],
904 'hg commit [files]'),
919 'hg commit [files]'),
905 "copy": (copy, [], 'hg copy <source> <dest>'),
920 "copy": (copy, [], 'hg copy <source> <dest>'),
906 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
921 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
907 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
922 "debugstate": (debugstate, [], 'debugstate'),
908 "debugindex": (debugindex, [], 'debugindex <file>'),
923 "debugindex": (debugindex, [], 'debugindex <file>'),
909 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
924 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
910 "^diff": (diff, [('r', 'rev', [], 'revision')],
925 "^diff": (diff, [('r', 'rev', [], 'revision')],
911 'hg diff [-r A] [-r B] [files]'),
926 'hg diff [-r A] [-r B] [files]'),
912 "export": (export, [('o', 'output', "", 'output to file')],
927 "^export": (export, [('o', 'output', "", 'output to file')],
913 "hg export [-o file] <changeset> ..."),
928 "hg export [-o file] <changeset> ..."),
914 "forget": (forget, [], "hg forget [files]"),
929 "forget": (forget, [], "hg forget [files]"),
915 "heads": (heads, [], 'hg heads'),
930 "heads": (heads, [], 'hg heads'),
916 "help": (help, [], 'hg help [command]'),
931 "help": (help, [], 'hg help [command]'),
917 "identify|id": (identify, [], 'hg identify'),
932 "identify|id": (identify, [], 'hg identify'),
918 "import|patch": (import_,
933 "import|patch": (import_,
919 [('p', 'strip', 1, 'path strip'),
934 [('p', 'strip', 1, 'path strip'),
920 ('b', 'base', "", 'base path')],
935 ('b', 'base', "", 'base path')],
921 "hg import [options] <patches>"),
936 "hg import [options] <patches>"),
922 "^init": (init, [], 'hg init'),
937 "^init": (init, [], 'hg init'),
923 "^log|history": (log,
938 "^log|history": (log,
924 [('r', 'rev', [], 'revision')],
939 [('r', 'rev', [], 'revision')],
925 'hg log [-r A] [-r B] [file]'),
940 'hg log [-r A] [-r B] [file]'),
926 "manifest": (manifest, [], 'hg manifest [rev]'),
941 "manifest": (manifest, [], 'hg manifest [rev]'),
927 "parents": (parents, [], 'hg parents [node]'),
942 "parents": (parents, [], 'hg parents [node]'),
928 "^pull": (pull,
943 "^pull": (pull,
929 [('u', 'update', None, 'update working directory')],
944 [('u', 'update', None, 'update working directory')],
930 'hg pull [options] [source]'),
945 'hg pull [options] [source]'),
931 "^push": (push, [], 'hg push <destination>'),
946 "^push": (push, [], 'hg push <destination>'),
932 "rawcommit": (rawcommit,
947 "rawcommit": (rawcommit,
933 [('p', 'parent', [], 'parent'),
948 [('p', 'parent', [], 'parent'),
934 ('d', 'date', "", 'date code'),
949 ('d', 'date', "", 'date code'),
935 ('u', 'user', "", 'user'),
950 ('u', 'user', "", 'user'),
936 ('F', 'files', "", 'file list'),
951 ('F', 'files', "", 'file list'),
937 ('t', 'text', "", 'commit text'),
952 ('t', 'text', "", 'commit text'),
938 ('l', 'logfile', "", 'commit text file')],
953 ('l', 'logfile', "", 'commit text file')],
939 'hg rawcommit [options] [files]'),
954 'hg rawcommit [options] [files]'),
940 "recover": (recover, [], "hg recover"),
955 "recover": (recover, [], "hg recover"),
941 "^remove|rm": (remove, [], "hg remove [files]"),
956 "^remove|rm": (remove, [], "hg remove [files]"),
942 "revert": (revert,
957 "^revert": (revert,
943 [("n", "nonrecursive", None, "don't recurse into subdirs"),
958 [("n", "nonrecursive", None, "don't recurse into subdirs"),
944 ("r", "rev", "", "revision")],
959 ("r", "rev", "", "revision")],
945 "hg revert [files|dirs]"),
960 "hg revert [files|dirs]"),
946 "root": (root, [], "hg root"),
961 "root": (root, [], "hg root"),
947 "^serve": (serve, [('p', 'port', 8000, 'listen port'),
962 "^serve": (serve, [('p', 'port', 8000, 'listen port'),
948 ('a', 'address', '', 'interface address'),
963 ('a', 'address', '', 'interface address'),
949 ('n', 'name', os.getcwd(), 'repository name'),
964 ('n', 'name', os.getcwd(), 'repository name'),
950 ('t', 'templates', "", 'template map')],
965 ('t', 'templates', "", 'template map')],
951 "hg serve [options]"),
966 "hg serve [options]"),
952 "^status": (status, [], 'hg status'),
967 "^status": (status, [], 'hg status'),
953 "tag": (tag, [('t', 'text', "", 'commit text'),
968 "tag": (tag, [('t', 'text', "", 'commit text'),
954 ('d', 'date', "", 'date code'),
969 ('d', 'date', "", 'date code'),
955 ('u', 'user', "", 'user')],
970 ('u', 'user', "", 'user')],
956 'hg tag [options] <name> [rev]'),
971 'hg tag [options] <name> [rev]'),
957 "tags": (tags, [], 'hg tags'),
972 "tags": (tags, [], 'hg tags'),
958 "tip": (tip, [], 'hg tip'),
973 "tip": (tip, [], 'hg tip'),
959 "undo": (undo, [], 'hg undo'),
974 "undo": (undo, [], 'hg undo'),
960 "^update|up|checkout|co":
975 "^update|up|checkout|co":
961 (update,
976 (update,
962 [('m', 'merge', None, 'allow merging of conflicts'),
977 [('m', 'merge', None, 'allow merging of conflicts'),
963 ('C', 'clean', None, 'overwrite locally modified files')],
978 ('C', 'clean', None, 'overwrite locally modified files')],
964 'hg update [options] [node]'),
979 'hg update [options] [node]'),
965 "verify": (verify, [], 'hg verify'),
980 "verify": (verify, [], 'hg verify'),
966 "version": (show_version, [], 'hg version'),
981 "version": (show_version, [], 'hg version'),
967 }
982 }
968
983
984 globalopts = [('v', 'verbose', None, 'verbose'),
985 ('', 'debug', None, 'debug'),
986 ('q', 'quiet', None, 'quiet'),
987 ('', 'profile', None, 'profile'),
988 ('R', 'repository', "", 'repository root directory'),
989 ('', 'traceback', None, 'print traceback on exception'),
990 ('y', 'noninteractive', None, 'run non-interactively'),
991 ('', 'version', None, 'output version information and exit'),
992 ]
993
969 norepo = "clone init version help debugindex debugindexdot"
994 norepo = "clone init version help debugindex debugindexdot"
970
995
971 def find(cmd):
996 def find(cmd):
972 for e in table.keys():
997 for e in table.keys():
973 if re.match("(%s)$" % e, cmd):
998 if re.match("(%s)$" % e, cmd):
974 return table[e]
999 return table[e]
975
1000
976 raise UnknownCommand(cmd)
1001 raise UnknownCommand(cmd)
977
1002
978 class SignalInterrupt(Exception): pass
1003 class SignalInterrupt(Exception): pass
979
1004
980 def catchterm(*args):
1005 def catchterm(*args):
981 raise SignalInterrupt
1006 raise SignalInterrupt
982
1007
983 def run():
1008 def run():
984 sys.exit(dispatch(sys.argv[1:]))
1009 sys.exit(dispatch(sys.argv[1:]))
985
1010
986 def dispatch(args):
1011 class ParseError(Exception): pass
987 signal.signal(signal.SIGTERM, catchterm)
988
1012
989 def get_ui():
1013 def parse(args):
990 return ui.ui(options["verbose"], options["debug"], options["quiet"],
991 not options["noninteractive"])
992
993 options = {}
1014 options = {}
994 opts = [('v', 'verbose', None, 'verbose'),
1015 cmdoptions = {}
995 ('', 'debug', None, 'debug'),
996 ('q', 'quiet', None, 'quiet'),
997 ('', 'profile', None, 'profile'),
998 ('R', 'repository', "", 'repository root directory'),
999 ('', 'traceback', None, 'print traceback on exception'),
1000 ('y', 'noninteractive', None, 'run non-interactively'),
1001 ('', 'version', None, 'output version information and exit'),
1002 ]
1003
1016
1004 try:
1017 try:
1005 args = fancyopts.fancyopts(args, opts, options,
1018 args = fancyopts.fancyopts(args, globalopts, options)
1006 'hg [options] <command> [options] [files]')
1007 except fancyopts.getopt.GetoptError, inst:
1019 except fancyopts.getopt.GetoptError, inst:
1008 u = ui.ui()
1020 raise ParseError(cmd, inst)
1009 u.warn("hg: %s\n" % (inst))
1010 sys.exit(-1)
1011
1021
1012 if not args:
1022 if options["version"]:
1013 cmd = "help"
1023 return ("version", show_version, [], options, cmdoptions)
1024 elif not args:
1025 return ("help", help, [], options, cmdoptions)
1014 else:
1026 else:
1015 cmd, args = args[0], args[1:]
1027 cmd, args = args[0], args[1:]
1016
1028
1017 if options["version"]:
1029 i = find(cmd)
1018 show_version(get_ui())
1019 sys.exit(0)
1020
1021 try:
1022 i = find(cmd)
1023 except UnknownCommand:
1024 u = get_ui()
1025 u.warn("hg: unknown command '%s'\n" % cmd)
1026 help(u)
1027 sys.exit(1)
1028
1030
1029 # combine global options into local
1031 # combine global options into local
1030 c = list(i[1])
1032 c = list(i[1])
1031 l = len(c)
1033 l = len(c)
1032 for o in opts:
1034 for o in globalopts:
1033 c.append((o[0], o[1], options[o[1]], o[3]))
1035 c.append((o[0], o[1], options[o[1]], o[3]))
1034
1036
1035 cmdoptions = {}
1036 try:
1037 try:
1037 args = fancyopts.fancyopts(args, c, cmdoptions, i[2])
1038 args = fancyopts.fancyopts(args, c, cmdoptions)
1038 except fancyopts.getopt.GetoptError, inst:
1039 except fancyopts.getopt.GetoptError, inst:
1039 u = get_ui()
1040 raise ParseError(cmd, inst)
1040 u.warn("hg %s: %s\n" % (cmd, inst))
1041 help(u, cmd)
1042 sys.exit(-1)
1043
1041
1044 # separate global options back out
1042 # separate global options back out
1045 for o in opts:
1043 for o in globalopts:
1046 n = o[1]
1044 n = o[1]
1047 options[n] = cmdoptions[n]
1045 options[n] = cmdoptions[n]
1048 del cmdoptions[n]
1046 del cmdoptions[n]
1049
1047
1050 u = get_ui()
1048 return (cmd, i[0], args, options, cmdoptions)
1049
1050 def dispatch(args):
1051 signal.signal(signal.SIGTERM, catchterm)
1052
1053 try:
1054 cmd, func, args, options, cmdoptions = parse(args)
1055 except ParseError, inst:
1056 u = ui.ui()
1057 if inst.args[0]:
1058 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1059 help(u, inst.args[0])
1060 else:
1061 u.warn("hg: %s\n" % inst.args[1])
1062 help(u)
1063 sys.exit(-1)
1064 except UnknownCommand, inst:
1065 u = ui.ui()
1066 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1067 help(u)
1068 sys.exit(1)
1069
1070 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1071 not options["noninteractive"])
1051
1072
1052 try:
1073 try:
1053 try:
1074 try:
1054 if cmd not in norepo.split():
1075 if cmd not in norepo.split():
1055 path = options["repository"] or ""
1076 path = options["repository"] or ""
1056 repo = hg.repository(ui=u, path=path)
1077 repo = hg.repository(ui=u, path=path)
1057 d = lambda: i[0](u, repo, *args, **cmdoptions)
1078 d = lambda: func(u, repo, *args, **cmdoptions)
1058 else:
1079 else:
1059 d = lambda: i[0](u, *args, **cmdoptions)
1080 d = lambda: func(u, *args, **cmdoptions)
1060
1081
1061 if options['profile']:
1082 if options['profile']:
1062 import hotshot, hotshot.stats
1083 import hotshot, hotshot.stats
1063 prof = hotshot.Profile("hg.prof")
1084 prof = hotshot.Profile("hg.prof")
1064 r = prof.runcall(d)
1085 r = prof.runcall(d)
1065 prof.close()
1086 prof.close()
1066 stats = hotshot.stats.load("hg.prof")
1087 stats = hotshot.stats.load("hg.prof")
1067 stats.strip_dirs()
1088 stats.strip_dirs()
1068 stats.sort_stats('time', 'calls')
1089 stats.sort_stats('time', 'calls')
1069 stats.print_stats(40)
1090 stats.print_stats(40)
1070 return r
1091 return r
1071 else:
1092 else:
1072 return d()
1093 return d()
1073 except:
1094 except:
1074 if options['traceback']:
1095 if options['traceback']:
1075 traceback.print_exc()
1096 traceback.print_exc()
1076 raise
1097 raise
1077 except util.CommandError, inst:
1098 except util.CommandError, inst:
1078 u.warn("abort: %s\n" % inst.args)
1099 u.warn("abort: %s\n" % inst.args)
1079 except hg.RepoError, inst:
1100 except hg.RepoError, inst:
1080 u.warn("abort: ", inst, "!\n")
1101 u.warn("abort: ", inst, "!\n")
1081 except SignalInterrupt:
1102 except SignalInterrupt:
1082 u.warn("killed!\n")
1103 u.warn("killed!\n")
1083 except KeyboardInterrupt:
1104 except KeyboardInterrupt:
1084 u.warn("interrupted!\n")
1105 u.warn("interrupted!\n")
1085 except IOError, inst:
1106 except IOError, inst:
1086 if hasattr(inst, "code"):
1107 if hasattr(inst, "code"):
1087 u.warn("abort: %s\n" % inst)
1108 u.warn("abort: %s\n" % inst)
1088 elif hasattr(inst, "reason"):
1109 elif hasattr(inst, "reason"):
1089 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1110 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1090 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1111 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1091 u.warn("broken pipe\n")
1112 u.warn("broken pipe\n")
1092 else:
1113 else:
1093 raise
1114 raise
1094 except OSError, inst:
1115 except OSError, inst:
1095 if hasattr(inst, "filename"):
1116 if hasattr(inst, "filename"):
1096 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1117 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1097 else:
1118 else:
1098 u.warn("abort: %s\n" % inst.strerror)
1119 u.warn("abort: %s\n" % inst.strerror)
1099 except TypeError, inst:
1120 except TypeError, inst:
1100 # was this an argument error?
1121 # was this an argument error?
1101 tb = traceback.extract_tb(sys.exc_info()[2])
1122 tb = traceback.extract_tb(sys.exc_info()[2])
1102 if len(tb) > 2: # no
1123 if len(tb) > 2: # no
1103 raise
1124 raise
1104 u.debug(inst, "\n")
1125 u.debug(inst, "\n")
1105 u.warn("%s: invalid arguments\n" % i[0].__name__)
1126 u.warn("%s: invalid arguments\n" % cmd)
1106 help(u, cmd)
1127 help(u, cmd)
1107
1128
1108 sys.exit(-1)
1129 sys.exit(-1)
@@ -1,30 +1,30 b''
1 import os, getopt
1 import os, getopt
2
2
3 def fancyopts(args, options, state, syntax='', minlen = 0):
3 def fancyopts(args, options, state):
4 long=[]
4 long=[]
5 short=''
5 short=''
6 map={}
6 map={}
7 dt={}
7 dt={}
8
8
9 for s, l, d, c in options:
9 for s, l, d, c in options:
10 map['-'+s] = map['--'+l]=l
10 map['-'+s] = map['--'+l]=l
11 state[l] = d
11 state[l] = d
12 dt[l] = type(d)
12 dt[l] = type(d)
13 if not d is None and not callable(d): s, l=s+':', l+'='
13 if not d is None and not callable(d): s, l=s+':', l+'='
14 if s: short = short + s
14 if s: short = short + s
15 if l: long.append(l)
15 if l: long.append(l)
16
16
17 if os.environ.has_key("HG_OPTS"):
17 if os.environ.has_key("HG_OPTS"):
18 args = os.environ["HG_OPTS"].split() + args
18 args = os.environ["HG_OPTS"].split() + args
19
19
20 opts, args = getopt.getopt(args, short, long)
20 opts, args = getopt.getopt(args, short, long)
21
21
22 for opt, arg in opts:
22 for opt, arg in opts:
23 if dt[map[opt]] is type(fancyopts): state[map[opt]](state,map[opt],arg)
23 if dt[map[opt]] is type(fancyopts): state[map[opt]](state,map[opt],arg)
24 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
24 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
25 elif dt[map[opt]] is type(''): state[map[opt]] = arg
25 elif dt[map[opt]] is type(''): state[map[opt]] = arg
26 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
26 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
27 elif dt[map[opt]] is type(None): state[map[opt]] = 1
27 elif dt[map[opt]] is type(None): state[map[opt]] = 1
28
28
29 return args
29 return args
30
30
@@ -1,11 +1,11 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 set -x
3 hg help
4
5 hg -q help
4 hg -q help
6 hg add -h
5 hg add -h
6 hg add --skjdfks
7 hg help diff
7 hg help diff
8 hg help foo
8 hg help foo
9 hg -q commands
9 hg -q commands
10
10
11 exit 0
11 exit 0
@@ -1,46 +1,67 b''
1 + hg -q help
1 basic hg commands (use "hg help -v" for more):
2 basic hg commands (use -v for long list):
3
2
4 add add the specified files on the next commit
3 add add the specified files on the next commit
5 clone make a copy of an existing repository
4 annotate show changeset information per file line
6 commit commit the specified files or all outstanding changes
5 clone make a copy of an existing repository
7 diff diff working directory (or selected files)
6 commit commit the specified files or all outstanding changes
8 init create a new repository in the current directory
7 diff diff working directory (or selected files)
9 log show the revision history of the repository or a single file
8 export dump the header and diffs for one or more changesets
10 pull pull changes from the specified source
9 init create a new repository in the current directory
11 push push changes to the specified destination
10 log show the revision history of the repository or a single file
12 remove remove the specified files on the next commit
11 pull pull changes from the specified source
13 serve export the repository via HTTP
12 push push changes to the specified destination
14 status show changed files in the working directory
13 remove remove the specified files on the next commit
15 update update or merge working directory
14 revert revert modified files or dirs back to their unmodified states
16 + hg add -h
15 serve export the repository via HTTP
16 status show changed files in the working directory
17 update update or merge working directory
18 basic hg commands (use "hg help -v" for more):
19
20 add add the specified files on the next commit
21 annotate show changeset information per file line
22 clone make a copy of an existing repository
23 commit commit the specified files or all outstanding changes
24 diff diff working directory (or selected files)
25 export dump the header and diffs for one or more changesets
26 init create a new repository in the current directory
27 log show the revision history of the repository or a single file
28 pull pull changes from the specified source
29 push push changes to the specified destination
30 remove remove the specified files on the next commit
31 revert revert modified files or dirs back to their unmodified states
32 serve export the repository via HTTP
33 status show changed files in the working directory
34 update update or merge working directory
17 hg add: option -h not recognized
35 hg add: option -h not recognized
18 hg add [files]
36 hg add [files]
19
37
20 add the specified files on the next commit
38 add the specified files on the next commit
21 + hg help diff
39 hg add: option --skjdfks not recognized
40 hg add [files]
41
42 add the specified files on the next commit
22 hg diff [-r A] [-r B] [files]
43 hg diff [-r A] [-r B] [files]
23
44
24 -r --rev
45 -r --rev
25 revision
46 revision
26
47
27 diff working directory (or selected files)
48 diff working directory (or selected files)
28 + hg help foo
29 hg: unknown command foo
49 hg: unknown command foo
30 + hg -q commands
31 hg: unknown command 'commands'
50 hg: unknown command 'commands'
32 basic hg commands (use -v for long list):
51 basic hg commands (use "hg help -v" for more):
33
52
34 add add the specified files on the next commit
53 add add the specified files on the next commit
35 clone make a copy of an existing repository
54 annotate show changeset information per file line
36 commit commit the specified files or all outstanding changes
55 clone make a copy of an existing repository
37 diff diff working directory (or selected files)
56 commit commit the specified files or all outstanding changes
38 init create a new repository in the current directory
57 diff diff working directory (or selected files)
39 log show the revision history of the repository or a single file
58 export dump the header and diffs for one or more changesets
40 pull pull changes from the specified source
59 init create a new repository in the current directory
41 push push changes to the specified destination
60 log show the revision history of the repository or a single file
42 remove remove the specified files on the next commit
61 pull pull changes from the specified source
43 serve export the repository via HTTP
62 push push changes to the specified destination
44 status show changed files in the working directory
63 remove remove the specified files on the next commit
45 update update or merge working directory
64 revert revert modified files or dirs back to their unmodified states
46 + exit 0
65 serve export the repository via HTTP
66 status show changed files in the working directory
67 update update or merge working directory
General Comments 0
You need to be logged in to leave comments. Login now