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