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