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