##// END OF EJS Templates
hg help improvements...
mpm@selenic.com -
r293:11d64332 default
parent child Browse files
Show More
@@ -1,633 +1,650 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")
11 demandload(globals(), "mdiff time hgweb traceback")
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(repo, files = None, node1 = None, node2 = None):
35 def dodiff(repo, 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(repo.root, node1)
47 (c, a, d, u) = repo.diffdir(repo.root, 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 change = repo.changelog.read(node1)
52 change = repo.changelog.read(node1)
53 mmap = repo.manifest.read(change[0])
53 mmap = repo.manifest.read(change[0])
54 date1 = date(change)
54 date1 = date(change)
55
55
56 if files:
56 if files:
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
57 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
58
58
59 for f in c:
59 for f in c:
60 to = None
60 to = None
61 if f in mmap:
61 if f in mmap:
62 to = repo.file(f).read(mmap[f])
62 to = repo.file(f).read(mmap[f])
63 tn = read(f)
63 tn = read(f)
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
64 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
65 for f in a:
65 for f in a:
66 to = None
66 to = None
67 tn = read(f)
67 tn = read(f)
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
68 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
69 for f in d:
69 for f in d:
70 to = repo.file(f).read(mmap[f])
70 to = repo.file(f).read(mmap[f])
71 tn = None
71 tn = None
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
72 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f))
73
73
74 def help(ui, cmd=None):
74 def help(ui, cmd=None):
75 '''show help for a given command or all commands'''
75 '''show help for a given command or all commands'''
76 if cmd:
76 if cmd:
77 try:
77 try:
78 i = find(cmd)
78 i = find(cmd)
79 ui.write("%s\n\n" % i[2])
79 ui.write("%s\n\n" % i[2])
80
81 if i[1]:
82 for s, l, d, c in i[1]:
83 opt=' '
84 if s: opt = opt + '-' + s + ' '
85 if l: opt = opt + '--' + l + ' '
86 if d: opt = opt + '(' + str(d) + ')'
87 ui.write(opt, "\n")
88 if c: ui.write(' %s\n' % c)
89 ui.write("\n")
90
80 ui.write(i[0].__doc__, "\n")
91 ui.write(i[0].__doc__, "\n")
81 except UnknownCommand:
92 except UnknownCommand:
82 ui.warn("hg: unknown command %s\n" % cmd)
93 ui.warn("hg: unknown command %s\n" % cmd)
83 sys.exit(0)
94 sys.exit(0)
84 else:
95 else:
85 ui.status('hg commands:\n\n')
96 ui.status('hg commands:\n\n')
86
97
87 h = {}
98 h = {}
88 for e in table.values():
99 for e in table.values():
89 f = e[0]
100 f = e[0]
90 if f.__name__.startswith("debug"): continue
101 if f.__name__.startswith("debug"): continue
91 d = ""
102 d = ""
92 if f.__doc__:
103 if f.__doc__:
93 d = f.__doc__.splitlines(0)[0].rstrip()
104 d = f.__doc__.splitlines(0)[0].rstrip()
94 h[f.__name__] = d
105 h[f.__name__] = d
95
106
96 fns = h.keys()
107 fns = h.keys()
97 fns.sort()
108 fns.sort()
98 m = max(map(len, fns))
109 m = max(map(len, fns))
99 for f in fns:
110 for f in fns:
100 ui.status(' %-*s %s\n' % (m, f, h[f]))
111 ui.status(' %-*s %s\n' % (m, f, h[f]))
101
112
102 # Commands start here, listed alphabetically
113 # Commands start here, listed alphabetically
103
114
104 def add(ui, repo, file, *files):
115 def add(ui, repo, file, *files):
105 '''add the specified files on the next commit'''
116 '''add the specified files on the next commit'''
106 repo.add(relpath(repo, (file,) + files))
117 repo.add(relpath(repo, (file,) + files))
107
118
108 def addremove(ui, repo):
119 def addremove(ui, repo):
109 """add all new files, delete all missing files"""
120 """add all new files, delete all missing files"""
110 (c, a, d, u) = repo.diffdir(repo.root)
121 (c, a, d, u) = repo.diffdir(repo.root)
111 repo.add(u)
122 repo.add(u)
112 repo.remove(d)
123 repo.remove(d)
113
124
114 def annotate(u, repo, file, *files, **ops):
125 def annotate(u, repo, file, *files, **ops):
115 """show changeset information per file line"""
126 """show changeset information per file line"""
116 def getnode(rev):
127 def getnode(rev):
117 return hg.short(repo.changelog.node(rev))
128 return hg.short(repo.changelog.node(rev))
118
129
119 def getname(rev):
130 def getname(rev):
120 try:
131 try:
121 return bcache[rev]
132 return bcache[rev]
122 except KeyError:
133 except KeyError:
123 cl = repo.changelog.read(repo.changelog.node(rev))
134 cl = repo.changelog.read(repo.changelog.node(rev))
124 name = cl[1]
135 name = cl[1]
125 f = name.find('@')
136 f = name.find('@')
126 if f >= 0:
137 if f >= 0:
127 name = name[:f]
138 name = name[:f]
128 bcache[rev] = name
139 bcache[rev] = name
129 return name
140 return name
130
141
131 bcache = {}
142 bcache = {}
132 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
143 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
133 if not ops['user'] and not ops['changeset']:
144 if not ops['user'] and not ops['changeset']:
134 ops['number'] = 1
145 ops['number'] = 1
135
146
136 node = repo.dirstate.parents()[0]
147 node = repo.dirstate.parents()[0]
137 if ops['revision']:
148 if ops['revision']:
138 node = repo.changelog.lookup(ops['revision'])
149 node = repo.changelog.lookup(ops['revision'])
139 change = repo.changelog.read(node)
150 change = repo.changelog.read(node)
140 mmap = repo.manifest.read(change[0])
151 mmap = repo.manifest.read(change[0])
141 maxuserlen = 0
152 maxuserlen = 0
142 maxchangelen = 0
153 maxchangelen = 0
143 for f in relpath(repo, (file,) + files):
154 for f in relpath(repo, (file,) + files):
144 lines = repo.file(f).annotate(mmap[f])
155 lines = repo.file(f).annotate(mmap[f])
145 pieces = []
156 pieces = []
146
157
147 for o, f in opmap:
158 for o, f in opmap:
148 if ops[o]:
159 if ops[o]:
149 l = [ f(n) for n,t in lines ]
160 l = [ f(n) for n,t in lines ]
150 m = max(map(len, l))
161 m = max(map(len, l))
151 pieces.append([ "%*s" % (m, x) for x in l])
162 pieces.append([ "%*s" % (m, x) for x in l])
152
163
153 for p,l in zip(zip(*pieces), lines):
164 for p,l in zip(zip(*pieces), lines):
154 u.write(" ".join(p) + ": " + l[1])
165 u.write(" ".join(p) + ": " + l[1])
155
166
156 def cat(ui, repo, file, rev = []):
167 def cat(ui, repo, file, rev = []):
157 """output the latest or given revision of a file"""
168 """output the latest or given revision of a file"""
158 r = repo.file(relpath(repo, [file])[0])
169 r = repo.file(relpath(repo, [file])[0])
159 n = r.tip()
170 n = r.tip()
160 if rev: n = r.lookup(rev)
171 if rev: n = r.lookup(rev)
161 sys.stdout.write(r.read(n))
172 sys.stdout.write(r.read(n))
162
173
163 def commit(ui, repo, *files, **opts):
174 def commit(ui, repo, *files, **opts):
164 """commit the specified files or all outstanding changes"""
175 """commit the specified files or all outstanding changes"""
165 text = opts['text']
176 text = opts['text']
166 if not text and opts['logfile']:
177 if not text and opts['logfile']:
167 try: text = open(opts['logfile']).read()
178 try: text = open(opts['logfile']).read()
168 except IOError: pass
179 except IOError: pass
169
180
170 repo.commit(relpath(repo, files), text)
181 repo.commit(relpath(repo, files), text)
171
182
172 def debugaddchangegroup(ui, repo):
183 def debugaddchangegroup(ui, repo):
173 data = sys.stdin.read()
184 data = sys.stdin.read()
174 repo.addchangegroup(data)
185 repo.addchangegroup(data)
175
186
176 def debugchangegroup(ui, repo, roots):
187 def debugchangegroup(ui, repo, roots):
177 newer = repo.newer(map(repo.lookup, roots))
188 newer = repo.newer(map(repo.lookup, roots))
178 for chunk in repo.changegroup(newer):
189 for chunk in repo.changegroup(newer):
179 sys.stdout.write(chunk)
190 sys.stdout.write(chunk)
180
191
181 def debugindex(ui, file):
192 def debugindex(ui, file):
182 r = hg.revlog(open, file, "")
193 r = hg.revlog(open, file, "")
183 print " rev offset length base linkrev"+\
194 print " rev offset length base linkrev"+\
184 " p1 p2 nodeid"
195 " p1 p2 nodeid"
185 for i in range(r.count()):
196 for i in range(r.count()):
186 e = r.index[i]
197 e = r.index[i]
187 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
198 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
188 i, e[0], e[1], e[2], e[3],
199 i, e[0], e[1], e[2], e[3],
189 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
200 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
190
201
191 def debugindexdot(ui, file):
202 def debugindexdot(ui, file):
192 r = hg.revlog(open, file, "")
203 r = hg.revlog(open, file, "")
193 print "digraph G {"
204 print "digraph G {"
194 for i in range(r.count()):
205 for i in range(r.count()):
195 e = r.index[i]
206 e = r.index[i]
196 print "\t%d -> %d" % (r.rev(e[4]), i)
207 print "\t%d -> %d" % (r.rev(e[4]), i)
197 if e[5] != hg.nullid:
208 if e[5] != hg.nullid:
198 print "\t%d -> %d" % (r.rev(e[5]), i)
209 print "\t%d -> %d" % (r.rev(e[5]), i)
199 print "}"
210 print "}"
200
211
201 def diff(ui, repo, *files, **opts):
212 def diff(ui, repo, *files, **opts):
202 """diff working directory (or selected files)"""
213 """diff working directory (or selected files)"""
203 revs = []
214 revs = []
204 if opts['rev']:
215 if opts['rev']:
205 revs = map(lambda x: repo.lookup(x), opts['rev'])
216 revs = map(lambda x: repo.lookup(x), opts['rev'])
206
217
207 if len(revs) > 2:
218 if len(revs) > 2:
208 self.ui.warn("too many revisions to diff\n")
219 self.ui.warn("too many revisions to diff\n")
209 sys.exit(1)
220 sys.exit(1)
210
221
211 if files:
222 if files:
212 files = relpath(repo, files)
223 files = relpath(repo, files)
213 else:
224 else:
214 files = relpath(repo, [""])
225 files = relpath(repo, [""])
215
226
216 dodiff(repo, files, *revs)
227 dodiff(repo, files, *revs)
217
228
218 def export(ui, repo, changeset):
229 def export(ui, repo, changeset):
219 """dump the changeset header and diffs for a revision"""
230 """dump the changeset header and diffs for a revision"""
220 node = repo.lookup(changeset)
231 node = repo.lookup(changeset)
221 prev, other = repo.changelog.parents(node)
232 prev, other = repo.changelog.parents(node)
222 change = repo.changelog.read(node)
233 change = repo.changelog.read(node)
223 print "# HG changeset patch"
234 print "# HG changeset patch"
224 print "# User %s" % change[1]
235 print "# User %s" % change[1]
225 print "# Node ID %s" % hg.hex(node)
236 print "# Node ID %s" % hg.hex(node)
226 print "# Parent %s" % hg.hex(prev)
237 print "# Parent %s" % hg.hex(prev)
227 print
238 print
228 if other != hg.nullid:
239 if other != hg.nullid:
229 print "# Parent %s" % hg.hex(other)
240 print "# Parent %s" % hg.hex(other)
230 print change[4].rstrip()
241 print change[4].rstrip()
231 print
242 print
232
243
233 dodiff(repo, None, prev, node)
244 dodiff(repo, None, prev, node)
234
245
235 def forget(ui, repo, file, *files):
246 def forget(ui, repo, file, *files):
236 """don't add the specified files on the next commit"""
247 """don't add the specified files on the next commit"""
237 repo.forget(relpath(repo, (file,) + files))
248 repo.forget(relpath(repo, (file,) + files))
238
249
239 def heads(ui, repo):
250 def heads(ui, repo):
240 '''show current repository heads'''
251 '''show current repository heads'''
241 for n in repo.changelog.heads():
252 for n in repo.changelog.heads():
242 i = repo.changelog.rev(n)
253 i = repo.changelog.rev(n)
243 changes = repo.changelog.read(n)
254 changes = repo.changelog.read(n)
244 (p1, p2) = repo.changelog.parents(n)
255 (p1, p2) = repo.changelog.parents(n)
245 (h, h1, h2) = map(hg.hex, (n, p1, p2))
256 (h, h1, h2) = map(hg.hex, (n, p1, p2))
246 (i1, i2) = map(repo.changelog.rev, (p1, p2))
257 (i1, i2) = map(repo.changelog.rev, (p1, p2))
247 print "rev: %4d:%s" % (i, h)
258 print "rev: %4d:%s" % (i, h)
248 print "parents: %4d:%s" % (i1, h1)
259 print "parents: %4d:%s" % (i1, h1)
249 if i2: print " %4d:%s" % (i2, h2)
260 if i2: print " %4d:%s" % (i2, h2)
250 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
261 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
251 hg.hex(changes[0]))
262 hg.hex(changes[0]))
252 print "user:", changes[1]
263 print "user:", changes[1]
253 print "date:", time.asctime(
264 print "date:", time.asctime(
254 time.localtime(float(changes[2].split(' ')[0])))
265 time.localtime(float(changes[2].split(' ')[0])))
255 if ui.verbose: print "files:", " ".join(changes[3])
266 if ui.verbose: print "files:", " ".join(changes[3])
256 print "description:"
267 print "description:"
257 print changes[4]
268 print changes[4]
258
269
259 def history(ui, repo):
270 def history(ui, repo):
260 """show the changelog history"""
271 """show the changelog history"""
261 for i in range(repo.changelog.count() - 1, -1, -1):
272 for i in range(repo.changelog.count() - 1, -1, -1):
262 n = repo.changelog.node(i)
273 n = repo.changelog.node(i)
263 changes = repo.changelog.read(n)
274 changes = repo.changelog.read(n)
264 (p1, p2) = repo.changelog.parents(n)
275 (p1, p2) = repo.changelog.parents(n)
265 (h, h1, h2) = map(hg.hex, (n, p1, p2))
276 (h, h1, h2) = map(hg.hex, (n, p1, p2))
266 (i1, i2) = map(repo.changelog.rev, (p1, p2))
277 (i1, i2) = map(repo.changelog.rev, (p1, p2))
267 print "rev: %4d:%s" % (i, h)
278 print "rev: %4d:%s" % (i, h)
268 print "parents: %4d:%s" % (i1, h1)
279 print "parents: %4d:%s" % (i1, h1)
269 if i2: print " %4d:%s" % (i2, h2)
280 if i2: print " %4d:%s" % (i2, h2)
270 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
281 print "manifest: %4d:%s" % (repo.manifest.rev(changes[0]),
271 hg.hex(changes[0]))
282 hg.hex(changes[0]))
272 print "user:", changes[1]
283 print "user:", changes[1]
273 print "date:", time.asctime(
284 print "date:", time.asctime(
274 time.localtime(float(changes[2].split(' ')[0])))
285 time.localtime(float(changes[2].split(' ')[0])))
275 if ui.verbose: print "files:", " ".join(changes[3])
286 if ui.verbose: print "files:", " ".join(changes[3])
276 print "description:"
287 print "description:"
277 print changes[4]
288 print changes[4]
278
289
279 def init(ui, source=None):
290 def init(ui, source=None):
280 """create a new repository or copy an existing one"""
291 """create a new repository or copy an existing one"""
281
292
282 if source:
293 if source:
283 paths = {}
294 paths = {}
284 for name, path in ui.configitems("paths"):
295 for name, path in ui.configitems("paths"):
285 paths[name] = path
296 paths[name] = path
286
297
287 if source in paths: source = paths[source]
298 if source in paths: source = paths[source]
288
299
289 link = 0
300 link = 0
290 if not source.startswith("http://"):
301 if not source.startswith("http://"):
291 d1 = os.stat(os.getcwd()).st_dev
302 d1 = os.stat(os.getcwd()).st_dev
292 d2 = os.stat(source).st_dev
303 d2 = os.stat(source).st_dev
293 if d1 == d2: link = 1
304 if d1 == d2: link = 1
294
305
295 if link:
306 if link:
296 ui.debug("copying by hardlink\n")
307 ui.debug("copying by hardlink\n")
297 os.system("cp -al %s/.hg .hg" % source)
308 os.system("cp -al %s/.hg .hg" % source)
298 else:
309 else:
299 repo = hg.repository(ui, ".", create=1)
310 repo = hg.repository(ui, ".", create=1)
300 other = hg.repository(ui, source)
311 other = hg.repository(ui, source)
301 cg = repo.getchangegroup(other)
312 cg = repo.getchangegroup(other)
302 repo.addchangegroup(cg)
313 repo.addchangegroup(cg)
303 else:
314 else:
304 hg.repository(ui, ".", create=1)
315 hg.repository(ui, ".", create=1)
305
316
306 def log(ui, repo, f):
317 def log(ui, repo, f):
307 """show the revision history of a single file"""
318 """show the revision history of a single file"""
308 f = relpath(repo, [f])[0]
319 f = relpath(repo, [f])[0]
309
320
310 r = repo.file(f)
321 r = repo.file(f)
311 for i in range(r.count() - 1, -1, -1):
322 for i in range(r.count() - 1, -1, -1):
312 n = r.node(i)
323 n = r.node(i)
313 (p1, p2) = r.parents(n)
324 (p1, p2) = r.parents(n)
314 (h, h1, h2) = map(hg.hex, (n, p1, p2))
325 (h, h1, h2) = map(hg.hex, (n, p1, p2))
315 (i1, i2) = map(r.rev, (p1, p2))
326 (i1, i2) = map(r.rev, (p1, p2))
316 cr = r.linkrev(n)
327 cr = r.linkrev(n)
317 cn = hg.hex(repo.changelog.node(cr))
328 cn = hg.hex(repo.changelog.node(cr))
318 print "rev: %4d:%s" % (i, h)
329 print "rev: %4d:%s" % (i, h)
319 print "changeset: %4d:%s" % (cr, cn)
330 print "changeset: %4d:%s" % (cr, cn)
320 print "parents: %4d:%s" % (i1, h1)
331 print "parents: %4d:%s" % (i1, h1)
321 if i2: print " %4d:%s" % (i2, h2)
332 if i2: print " %4d:%s" % (i2, h2)
322 changes = repo.changelog.read(repo.changelog.node(cr))
333 changes = repo.changelog.read(repo.changelog.node(cr))
323 print "user: %s" % changes[1]
334 print "user: %s" % changes[1]
324 print "date: %s" % time.asctime(
335 print "date: %s" % time.asctime(
325 time.localtime(float(changes[2].split(' ')[0])))
336 time.localtime(float(changes[2].split(' ')[0])))
326 print "description:"
337 print "description:"
327 print changes[4].rstrip()
338 print changes[4].rstrip()
328 print
339 print
329
340
330 def manifest(ui, repo, rev = []):
341 def manifest(ui, repo, rev = []):
331 """output the latest or given revision of the project manifest"""
342 """output the latest or given revision of the project manifest"""
332 n = repo.manifest.tip()
343 n = repo.manifest.tip()
333 if rev:
344 if rev:
334 n = repo.manifest.lookup(rev)
345 n = repo.manifest.lookup(rev)
335 m = repo.manifest.read(n)
346 m = repo.manifest.read(n)
336 mf = repo.manifest.readflags(n)
347 mf = repo.manifest.readflags(n)
337 files = m.keys()
348 files = m.keys()
338 files.sort()
349 files.sort()
339
350
340 for f in files:
351 for f in files:
341 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
352 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
342
353
343 def parents(ui, repo, node = None):
354 def parents(ui, repo, node = None):
344 '''show the parents of the current working dir'''
355 '''show the parents of the current working dir'''
345 if node:
356 if node:
346 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
357 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
347 else:
358 else:
348 p = repo.dirstate.parents()
359 p = repo.dirstate.parents()
349
360
350 for n in p:
361 for n in p:
351 if n != hg.nullid:
362 if n != hg.nullid:
352 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
363 ui.write("%d:%s\n" % (repo.changelog.rev(n), hg.hex(n)))
353
364
354 def patch(ui, repo, patches, **opts):
365 def patch(ui, repo, patches, **opts):
355 """import an ordered set of patches"""
366 """import an ordered set of patches"""
356 try:
367 try:
357 import psyco
368 import psyco
358 psyco.full()
369 psyco.full()
359 except:
370 except:
360 pass
371 pass
361
372
362 d = opts["base"]
373 d = opts["base"]
363 strip = opts["strip"]
374 strip = opts["strip"]
364 quiet = opts["quiet"] and "> /dev/null" or ""
375 quiet = opts["quiet"] and "> /dev/null" or ""
365
376
366 for patch in patches:
377 for patch in patches:
367 ui.status("applying %s\n" % patch)
378 ui.status("applying %s\n" % patch)
368 pf = os.path.join(d, patch)
379 pf = os.path.join(d, patch)
369
380
370 text = ""
381 text = ""
371 for l in file(pf):
382 for l in file(pf):
372 if l[:4] == "--- ": break
383 if l[:4] == "--- ": break
373 text += l
384 text += l
374
385
375 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
386 f = os.popen("lsdiff --strip %d %s" % (strip, pf))
376 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
387 files = filter(None, map(lambda x: x.rstrip(), f.read().splitlines()))
377 f.close()
388 f.close()
378
389
379 if files:
390 if files:
380 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
391 if os.system("patch -p%d < %s %s" % (strip, pf, quiet)):
381 raise "patch failed!"
392 raise "patch failed!"
382 repo.commit(files, text)
393 repo.commit(files, text)
383
394
384 def pull(ui, repo, source):
395 def pull(ui, repo, source):
385 """pull changes from the specified source"""
396 """pull changes from the specified source"""
386 paths = {}
397 paths = {}
387 for name, path in ui.configitems("paths"):
398 for name, path in ui.configitems("paths"):
388 paths[name] = path
399 paths[name] = path
389
400
390 if source in paths: source = paths[source]
401 if source in paths: source = paths[source]
391
402
392 other = hg.repository(ui, source)
403 other = hg.repository(ui, source)
393 cg = repo.getchangegroup(other)
404 cg = repo.getchangegroup(other)
394 repo.addchangegroup(cg)
405 repo.addchangegroup(cg)
395
406
396 def rawcommit(ui, repo, files, **rc):
407 def rawcommit(ui, repo, files, **rc):
397 "raw commit interface"
408 "raw commit interface"
398
409
399 text = rc['text']
410 text = rc['text']
400 if not text and rc['logfile']:
411 if not text and rc['logfile']:
401 try: text = open(rc['logfile']).read()
412 try: text = open(rc['logfile']).read()
402 except IOError: pass
413 except IOError: pass
403 if not text and not rc['logfile']:
414 if not text and not rc['logfile']:
404 print "missing commit text"
415 print "missing commit text"
405 return 1
416 return 1
406
417
407 files = relpath(repo, files)
418 files = relpath(repo, files)
408 if rc['files']:
419 if rc['files']:
409 files += open(rc['files']).read().splitlines()
420 files += open(rc['files']).read().splitlines()
410
421
411 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
422 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
412
423
413 def recover(ui, repo):
424 def recover(ui, repo):
414 """roll back an interrupted transaction"""
425 """roll back an interrupted transaction"""
415 repo.recover()
426 repo.recover()
416
427
417 def remove(ui, repo, file, *files):
428 def remove(ui, repo, file, *files):
418 """remove the specified files on the next commit"""
429 """remove the specified files on the next commit"""
419 repo.remove(relpath(repo, (file,) + files))
430 repo.remove(relpath(repo, (file,) + files))
420
431
421 def serve(ui, repo, **opts):
432 def serve(ui, repo, **opts):
422 """export the repository via HTTP"""
433 """export the repository via HTTP"""
423 hgweb.server(repo.root, opts["name"], opts["templates"],
434 hgweb.server(repo.root, opts["name"], opts["templates"],
424 opts["address"], opts["port"])
435 opts["address"], opts["port"])
425
436
426 def status(ui, repo):
437 def status(ui, repo):
427 '''show changed files in the working directory
438 '''show changed files in the working directory
428
439
429 C = changed
440 C = changed
430 A = added
441 A = added
431 R = removed
442 R = removed
432 ? = not tracked'''
443 ? = not tracked'''
433
444
434 (c, a, d, u) = repo.diffdir(repo.root)
445 (c, a, d, u) = repo.diffdir(repo.root)
435 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
446 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
436
447
437 for f in c: print "C", f
448 for f in c: print "C", f
438 for f in a: print "A", f
449 for f in a: print "A", f
439 for f in d: print "R", f
450 for f in d: print "R", f
440 for f in u: print "?", f
451 for f in u: print "?", f
441
452
442 def tags(ui, repo):
453 def tags(ui, repo):
443 """list repository tags"""
454 """list repository tags"""
444 repo.lookup(0) # prime the cache
455 repo.lookup(0) # prime the cache
445 i = repo.tags.items()
456 i = repo.tags.items()
446 n = []
457 n = []
447 for e in i:
458 for e in i:
448 try:
459 try:
449 l = repo.changelog.rev(e[1])
460 l = repo.changelog.rev(e[1])
450 except KeyError:
461 except KeyError:
451 l = -2
462 l = -2
452 n.append((l, e))
463 n.append((l, e))
453
464
454 n.sort()
465 n.sort()
455 n.reverse()
466 n.reverse()
456 i = [ e[1] for e in n ]
467 i = [ e[1] for e in n ]
457 for k, n in i:
468 for k, n in i:
458 try:
469 try:
459 r = repo.changelog.rev(n)
470 r = repo.changelog.rev(n)
460 except KeyError:
471 except KeyError:
461 r = "?"
472 r = "?"
462 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
473 print "%-30s %5d:%s" % (k, repo.changelog.rev(n), hg.hex(n))
463
474
464 def tip(ui, repo):
475 def tip(ui, repo):
465 """show the tip revision"""
476 """show the tip revision"""
466 n = repo.changelog.tip()
477 n = repo.changelog.tip()
467 t = repo.changelog.rev(n)
478 t = repo.changelog.rev(n)
468 ui.status("%d:%s\n" % (t, hg.hex(n)))
479 ui.status("%d:%s\n" % (t, hg.hex(n)))
469
480
470 def undo(ui, repo):
481 def undo(ui, repo):
471 """undo the last transaction"""
482 """undo the last transaction"""
472 repo.undo()
483 repo.undo()
473
484
474 def update(ui, repo, node=None, merge=False, clean=False):
485 def update(ui, repo, node=None, merge=False, clean=False):
475 '''update or merge working directory
486 '''update or merge working directory
476
487
477 If there are no outstanding changes in the working directory and
488 If there are no outstanding changes in the working directory and
478 there is a linear relationship between the current version and the
489 there is a linear relationship between the current version and the
479 requested version, the result is the requested version.
490 requested version, the result is the requested version.
480
491
481 Otherwise the result is a merge between the contents of the
492 Otherwise the result is a merge between the contents of the
482 current working directory and the requested version. Files that
493 current working directory and the requested version. Files that
483 changed between either parent are marked as changed for the next
494 changed between either parent are marked as changed for the next
484 commit and a commit must be performed before any further updates
495 commit and a commit must be performed before any further updates
485 are allowed.
496 are allowed.
486 '''
497 '''
487 node = node and repo.lookup(node) or repo.changelog.tip()
498 node = node and repo.lookup(node) or repo.changelog.tip()
488 return repo.update(node, allow=merge, force=clean)
499 return repo.update(node, allow=merge, force=clean)
489
500
490 def verify(ui, repo):
501 def verify(ui, repo):
491 """verify the integrity of the repository"""
502 """verify the integrity of the repository"""
492 return repo.verify()
503 return repo.verify()
493
504
494 # Command options and aliases are listed here, alphabetically
505 # Command options and aliases are listed here, alphabetically
495
506
496 table = {
507 table = {
497 "add": (add, [], "hg add [files]"),
508 "add": (add, [], "hg add [files]"),
498 "addremove": (addremove, [], "hg addremove"),
509 "addremove": (addremove, [], "hg addremove"),
499 "ann|annotate": (annotate,
510 "ann|annotate": (annotate,
500 [('r', 'revision', '', 'revision'),
511 [('r', 'revision', '', 'revision'),
501 ('u', 'user', None, 'show user'),
512 ('u', 'user', None, 'show user'),
502 ('n', 'number', None, 'show revision number'),
513 ('n', 'number', None, 'show revision number'),
503 ('c', 'changeset', None, 'show changeset')],
514 ('c', 'changeset', None, 'show changeset')],
504 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
515 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
505 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
516 "cat|dump": (cat, [], 'hg cat <file> [rev]'),
506 "commit|ci": (commit,
517 "commit|ci": (commit,
507 [('t', 'text', "", 'commit text'),
518 [('t', 'text', "", 'commit text'),
508 ('l', 'logfile', "", 'commit text file')],
519 ('l', 'logfile', "", 'commit text file')],
509 'hg commit [files]'),
520 'hg commit [files]'),
510 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
521 "debugaddchangegroup": (debugaddchangegroup, [], 'debugaddchangegroup'),
511 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
522 "debugchangegroup": (debugchangegroup, [], 'debugchangegroup [roots]'),
512 "debugindex": (debugindex, [], 'debugindex <file>'),
523 "debugindex": (debugindex, [], 'debugindex <file>'),
513 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
524 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
514 "diff": (diff, [('r', 'rev', [], 'revision')],
525 "diff": (diff, [('r', 'rev', [], 'revision')],
515 'hg diff [-r A] [-r B] [files]'),
526 'hg diff [-r A] [-r B] [files]'),
516 "export": (export, [], "hg export <changeset>"),
527 "export": (export, [], "hg export <changeset>"),
517 "forget": (forget, [], "hg forget [files]"),
528 "forget": (forget, [], "hg forget [files]"),
518 "heads": (heads, [], 'hg heads'),
529 "heads": (heads, [], 'hg heads'),
519 "history": (history, [], 'hg history'),
530 "history": (history, [], 'hg history'),
520 "help": (help, [], 'hg help [command]'),
531 "help": (help, [], 'hg help [command]'),
521 "init": (init, [], 'hg init [url]'),
532 "init": (init, [], 'hg init [url]'),
522 "log": (log, [], 'hg log <file>'),
533 "log": (log, [], 'hg log <file>'),
523 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
534 "manifest|dumpmanifest": (manifest, [], 'hg manifest [rev]'),
524 "parents": (parents, [], 'hg parents [node]'),
535 "parents": (parents, [], 'hg parents [node]'),
525 "patch|import": (patch,
536 "patch|import": (patch,
526 [('p', 'strip', 1, 'path strip'),
537 [('p', 'strip', 1, 'path strip'),
527 ('b', 'base', "", 'base path'),
538 ('b', 'base', "", 'base path'),
528 ('q', 'quiet', "", 'silence diff')],
539 ('q', 'quiet', "", 'silence diff')],
529 "hg import [options] patches"),
540 "hg import [options] patches"),
530 "pull|merge": (pull, [], 'hg pull [source]'),
541 "pull|merge": (pull, [], 'hg pull [source]'),
531 "rawcommit": (rawcommit,
542 "rawcommit": (rawcommit,
532 [('p', 'parent', [], 'parent'),
543 [('p', 'parent', [], 'parent'),
533 ('d', 'date', "", 'data'),
544 ('d', 'date', "", 'data'),
534 ('u', 'user', "", 'user'),
545 ('u', 'user', "", 'user'),
535 ('F', 'files', "", 'file list'),
546 ('F', 'files', "", 'file list'),
536 ('t', 'text', "", 'commit text'),
547 ('t', 'text', "", 'commit text'),
537 ('l', 'logfile', "", 'commit text file')],
548 ('l', 'logfile', "", 'commit text file')],
538 'hg rawcommit [options] [files]'),
549 'hg rawcommit [options] [files]'),
539 "recover": (recover, [], "hg recover"),
550 "recover": (recover, [], "hg recover"),
540 "remove": (remove, [], "hg remove [files]"),
551 "remove": (remove, [], "hg remove [files]"),
541 "serve": (serve, [('p', 'port', 8000, 'listen port'),
552 "serve": (serve, [('p', 'port', 8000, 'listen port'),
542 ('a', 'address', '', 'interface address'),
553 ('a', 'address', '', 'interface address'),
543 ('n', 'name', os.getcwd(), 'repository name'),
554 ('n', 'name', os.getcwd(), 'repository name'),
544 ('t', 'templates', "", 'template map')],
555 ('t', 'templates', "", 'template map')],
545 "hg serve [options]"),
556 "hg serve [options]"),
546 "status": (status, [], 'hg status'),
557 "status": (status, [], 'hg status'),
547 "tags": (tags, [], 'hg tags'),
558 "tags": (tags, [], 'hg tags'),
548 "tip": (tip, [], 'hg tip'),
559 "tip": (tip, [], 'hg tip'),
549 "undo": (undo, [], 'hg undo'),
560 "undo": (undo, [], 'hg undo'),
550 "update|up|checkout|co|resolve": (update,
561 "update|up|checkout|co|resolve": (update,
551 [('m', 'merge', None,
562 [('m', 'merge', None,
552 'allow merging of conflicts'),
563 'allow merging of conflicts'),
553 ('C', 'clean', None,
564 ('C', 'clean', None,
554 'overwrite locally modified files')],
565 'overwrite locally modified files')],
555 'hg update [options] [node]'),
566 'hg update [options] [node]'),
556 "verify": (verify, [], 'hg verify'),
567 "verify": (verify, [], 'hg verify'),
557 }
568 }
558
569
559 norepo = "init branch help debugindex debugindexdot"
570 norepo = "init branch help debugindex debugindexdot"
560
571
561 def find(cmd):
572 def find(cmd):
562 i = None
573 i = None
563 for e in table.keys():
574 for e in table.keys():
564 if re.match(e + "$", cmd):
575 if re.match(e + "$", cmd):
565 return table[e]
576 return table[e]
566
577
567 raise UnknownCommand(cmd)
578 raise UnknownCommand(cmd)
568
579
569 class SignalInterrupt(Exception): pass
580 class SignalInterrupt(Exception): pass
570
581
571 def catchterm(*args):
582 def catchterm(*args):
572 raise SignalInterrupt
583 raise SignalInterrupt
573
584
574 def run():
585 def run():
575 sys.exit(dispatch(sys.argv[1:]))
586 sys.exit(dispatch(sys.argv[1:]))
576
587
577 def dispatch(args):
588 def dispatch(args):
578 options = {}
589 options = {}
579 opts = [('v', 'verbose', None, 'verbose'),
590 opts = [('v', 'verbose', None, 'verbose'),
580 ('d', 'debug', None, 'debug'),
591 ('d', 'debug', None, 'debug'),
581 ('q', 'quiet', None, 'quiet'),
592 ('q', 'quiet', None, 'quiet'),
582 ('y', 'noninteractive', None, 'run non-interactively'),
593 ('y', 'noninteractive', None, 'run non-interactively'),
583 ]
594 ]
584
595
585 args = fancyopts.fancyopts(args, opts, options,
596 args = fancyopts.fancyopts(args, opts, options,
586 'hg [options] <command> [options] [files]')
597 'hg [options] <command> [options] [files]')
587
598
588 if not args:
599 if not args:
589 cmd = "help"
600 cmd = "help"
590 else:
601 else:
591 cmd, args = args[0], args[1:]
602 cmd, args = args[0], args[1:]
592
603
593 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
604 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
594 not options["noninteractive"])
605 not options["noninteractive"])
595
606
596 try:
607 try:
597 i = find(cmd)
608 i = find(cmd)
598 except UnknownCommand:
609 except UnknownCommand:
599 u.warn("hg: unknown command '%s'\n" % cmd)
610 u.warn("hg: unknown command '%s'\n" % cmd)
600 help(u)
611 help(u)
601 sys.exit(1)
612 sys.exit(1)
602
613
603 signal.signal(signal.SIGTERM, catchterm)
614 signal.signal(signal.SIGTERM, catchterm)
604
615
605 cmdoptions = {}
616 cmdoptions = {}
606 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
617 try:
618 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
619 except fancyopts.getopt.GetoptError, inst:
620 u.warn("hg %s: %s\n" % (cmd, inst))
621 help(u, cmd)
622 sys.exit(-1)
607
623
608 if cmd not in norepo.split():
624 if cmd not in norepo.split():
609 repo = hg.repository(ui = u)
625 repo = hg.repository(ui = u)
610 d = lambda: i[0](u, repo, *args, **cmdoptions)
626 d = lambda: i[0](u, repo, *args, **cmdoptions)
611 else:
627 else:
612 d = lambda: i[0](u, *args, **cmdoptions)
628 d = lambda: i[0](u, *args, **cmdoptions)
613
629
614 try:
630 try:
615 return d()
631 return d()
616 except SignalInterrupt:
632 except SignalInterrupt:
617 u.warn("killed!\n")
633 u.warn("killed!\n")
618 except KeyboardInterrupt:
634 except KeyboardInterrupt:
619 u.warn("interrupted!\n")
635 u.warn("interrupted!\n")
620 except IOError, inst:
636 except IOError, inst:
621 if inst.errno == 32:
637 if inst.errno == 32:
622 u.warn("broken pipe\n")
638 u.warn("broken pipe\n")
623 else:
639 else:
624 raise
640 raise
625 except TypeError, inst:
641 except TypeError, inst:
626 # was this an argument error?
642 # was this an argument error?
627 tb = traceback.extract_tb(sys.exc_info()[2])
643 tb = traceback.extract_tb(sys.exc_info()[2])
628 if len(tb) > 2: # no
644 if len(tb) > 2: # no
629 raise
645 raise
630 raise
646 u.debug(inst, "\n")
631 u.warn("%s: invalid arguments\n" % i[0].__name__)
647 u.warn("%s: invalid arguments\n" % i[0].__name__)
632 u.warn("syntax: %s\n" % i[2])
648 help(u, cmd)
633 sys.exit(-1)
649 sys.exit(-1)
650
@@ -1,53 +1,30 b''
1 import sys, os, getopt
1 import sys, os, getopt
2
2
3 def fancyopts(args, options, state, syntax='', minlen = 0):
3 def fancyopts(args, options, state, syntax='', minlen = 0):
4 long=[]
4 long=[]
5 short=''
5 short=''
6 map={}
6 map={}
7 dt={}
7 dt={}
8
8
9 def help(state, opt, arg, options=options, syntax=syntax):
10 print "Usage: ", syntax
11
12 for s, l, d, c in options:
13 opt=' '
14 if s: opt = opt + '-' + s + ' '
15 if l: opt = opt + '--' + l + ' '
16 if d: opt = opt + '(' + str(d) + ')'
17 print opt
18 if c: print ' %s' % c
19 sys.exit(0)
20
21 if len(args) < minlen:
22 help(state, None, args)
23
24 options=[('h', 'help', help, 'Show usage info')] + options
25
26 for s, l, d, c in options:
9 for s, l, d, c in options:
27 map['-'+s] = map['--'+l]=l
10 map['-'+s] = map['--'+l]=l
28 state[l] = d
11 state[l] = d
29 dt[l] = type(d)
12 dt[l] = type(d)
30 if not d is None and not type(d) is type(help): s, l=s+':', l+'='
13 if not d is None and not callable(d): s, l=s+':', l+'='
31 if s: short = short + s
14 if s: short = short + s
32 if l: long.append(l)
15 if l: long.append(l)
33
16
34 if os.environ.has_key("HG_OPTS"):
17 if os.environ.has_key("HG_OPTS"):
35 args = os.environ["HG_OPTS"].split() + args
18 args = os.environ["HG_OPTS"].split() + args
36
19
37 try:
20 opts, args = getopt.getopt(args, short, long)
38 opts, args = getopt.getopt(args, short, long)
39 except getopt.GetoptError:
40 help(state, None, args)
41 sys.exit(-1)
42
21
43 for opt, arg in opts:
22 for opt, arg in opts:
44 if dt[map[opt]] is type(help): state[map[opt]](state,map[opt],arg)
23 if dt[map[opt]] is type(fancyopts): state[map[opt]](state,map[opt],arg)
45 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
24 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
46 elif dt[map[opt]] is type(''): state[map[opt]] = arg
25 elif dt[map[opt]] is type(''): state[map[opt]] = arg
47 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
26 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
48 elif dt[map[opt]] is type(None): state[map[opt]] = 1
27 elif dt[map[opt]] is type(None): state[map[opt]] = 1
49
28
50 del state["help"]
51
52 return args
29 return args
53
30
General Comments 0
You need to be logged in to leave comments. Login now