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