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