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