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