##// END OF EJS Templates
check export options for changeset before running...
shaleh@speakeasy.net -
r610:4c02464c default
parent child Browse files
Show More
@@ -1,1170 +1,1173 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import os, re, sys, signal
8 import os, re, sys, signal
9 import fancyopts, ui, hg, util
9 import fancyopts, ui, hg, util
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "mdiff time hgweb traceback random signal")
11 demandload(globals(), "mdiff time hgweb traceback random signal")
12 demandload(globals(), "socket errno version")
12 demandload(globals(), "socket errno version")
13
13
14 class UnknownCommand(Exception): pass
14 class UnknownCommand(Exception): pass
15
15
16 def filterfiles(filters, files):
16 def filterfiles(filters, files):
17 l = [ x for x in files if x in filters ]
17 l = [ x for x in files if x in filters ]
18
18
19 for t in filters:
19 for t in filters:
20 if t and t[-1] != "/": t += "/"
20 if t and t[-1] != "/": t += "/"
21 l += [ x for x in files if x.startswith(t) ]
21 l += [ x for x in files if x.startswith(t) ]
22 return l
22 return l
23
23
24 def relfilter(repo, files):
24 def relfilter(repo, files):
25 if os.getcwd() != repo.root:
25 if os.getcwd() != repo.root:
26 p = os.getcwd()[len(repo.root) + 1: ]
26 p = os.getcwd()[len(repo.root) + 1: ]
27 return filterfiles([util.pconvert(p)], files)
27 return filterfiles([util.pconvert(p)], files)
28 return files
28 return files
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 if os.getcwd() != repo.root:
31 if os.getcwd() != repo.root:
32 p = os.getcwd()[len(repo.root) + 1: ]
32 p = os.getcwd()[len(repo.root) + 1: ]
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
34 for x in args ]
34 for x in args ]
35 return args
35 return args
36
36
37 revrangesep = ':'
37 revrangesep = ':'
38
38
39 def revrange(ui, repo, revs = [], revlog = None):
39 def revrange(ui, repo, revs = [], revlog = None):
40 if revlog is None:
40 if revlog is None:
41 revlog = repo.changelog
41 revlog = repo.changelog
42 revcount = revlog.count()
42 revcount = revlog.count()
43 def fix(val, defval):
43 def fix(val, defval):
44 if not val: return defval
44 if not val: return defval
45 try:
45 try:
46 num = int(val)
46 num = int(val)
47 if str(num) != val: raise ValueError
47 if str(num) != val: raise ValueError
48 if num < 0: num += revcount
48 if num < 0: num += revcount
49 if not (0 <= num < revcount):
49 if not (0 <= num < revcount):
50 raise ValueError
50 raise ValueError
51 except ValueError:
51 except ValueError:
52 try:
52 try:
53 num = repo.changelog.rev(repo.lookup(val))
53 num = repo.changelog.rev(repo.lookup(val))
54 except KeyError:
54 except KeyError:
55 try:
55 try:
56 num = revlog.rev(revlog.lookup(val))
56 num = revlog.rev(revlog.lookup(val))
57 except KeyError:
57 except KeyError:
58 ui.warn('abort: invalid revision identifier %s\n' % val)
58 ui.warn('abort: invalid revision identifier %s\n' % val)
59 sys.exit(1)
59 sys.exit(1)
60 return num
60 return num
61 for spec in revs:
61 for spec in revs:
62 if spec.find(revrangesep) >= 0:
62 if spec.find(revrangesep) >= 0:
63 start, end = spec.split(revrangesep, 1)
63 start, end = spec.split(revrangesep, 1)
64 start = fix(start, 0)
64 start = fix(start, 0)
65 end = fix(end, revcount - 1)
65 end = fix(end, revcount - 1)
66 if end > start:
66 if end > start:
67 end += 1
67 end += 1
68 step = 1
68 step = 1
69 else:
69 else:
70 end -= 1
70 end -= 1
71 step = -1
71 step = -1
72 for rev in xrange(start, end, step):
72 for rev in xrange(start, end, step):
73 yield str(rev)
73 yield str(rev)
74 else:
74 else:
75 yield spec
75 yield spec
76
76
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
78 def date(c):
78 def date(c):
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
80
80
81 (c, a, d, u) = repo.changes(node1, node2, files)
81 (c, a, d, u) = repo.changes(node1, node2, files)
82 if files:
82 if files:
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
84
84
85 if not c and not a and not d:
85 if not c and not a and not d:
86 return
86 return
87
87
88 if node2:
88 if node2:
89 change = repo.changelog.read(node2)
89 change = repo.changelog.read(node2)
90 mmap2 = repo.manifest.read(change[0])
90 mmap2 = repo.manifest.read(change[0])
91 def read(f): return repo.file(f).read(mmap2[f])
91 def read(f): return repo.file(f).read(mmap2[f])
92 date2 = date(change)
92 date2 = date(change)
93 else:
93 else:
94 date2 = time.asctime()
94 date2 = time.asctime()
95 if not node1:
95 if not node1:
96 node1 = repo.dirstate.parents()[0]
96 node1 = repo.dirstate.parents()[0]
97 def read(f): return repo.wfile(f).read()
97 def read(f): return repo.wfile(f).read()
98
98
99 if ui.quiet:
99 if ui.quiet:
100 r = None
100 r = None
101 else:
101 else:
102 hexfunc = ui.verbose and hg.hex or hg.short
102 hexfunc = ui.verbose and hg.hex or hg.short
103 r = [hexfunc(node) for node in [node1, node2] if node]
103 r = [hexfunc(node) for node in [node1, node2] if node]
104
104
105 change = repo.changelog.read(node1)
105 change = repo.changelog.read(node1)
106 mmap = repo.manifest.read(change[0])
106 mmap = repo.manifest.read(change[0])
107 date1 = date(change)
107 date1 = date(change)
108
108
109 for f in c:
109 for f in c:
110 to = None
110 to = None
111 if f in mmap:
111 if f in mmap:
112 to = repo.file(f).read(mmap[f])
112 to = repo.file(f).read(mmap[f])
113 tn = read(f)
113 tn = read(f)
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
115 for f in a:
115 for f in a:
116 to = None
116 to = None
117 tn = read(f)
117 tn = read(f)
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
119 for f in d:
119 for f in d:
120 to = repo.file(f).read(mmap[f])
120 to = repo.file(f).read(mmap[f])
121 tn = None
121 tn = None
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
123
123
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
125 """show a single changeset or file revision"""
125 """show a single changeset or file revision"""
126 changelog = repo.changelog
126 changelog = repo.changelog
127 if filelog:
127 if filelog:
128 log = filelog
128 log = filelog
129 filerev = rev
129 filerev = rev
130 node = filenode = filelog.node(filerev)
130 node = filenode = filelog.node(filerev)
131 changerev = filelog.linkrev(filenode)
131 changerev = filelog.linkrev(filenode)
132 changenode = changenode or changelog.node(changerev)
132 changenode = changenode or changelog.node(changerev)
133 else:
133 else:
134 log = changelog
134 log = changelog
135 changerev = rev
135 changerev = rev
136 if changenode is None:
136 if changenode is None:
137 changenode = changelog.node(changerev)
137 changenode = changelog.node(changerev)
138 elif not changerev:
138 elif not changerev:
139 rev = changerev = changelog.rev(changenode)
139 rev = changerev = changelog.rev(changenode)
140 node = changenode
140 node = changenode
141
141
142 if ui.quiet:
142 if ui.quiet:
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
144 return
144 return
145
145
146 changes = changelog.read(changenode)
146 changes = changelog.read(changenode)
147
147
148 parents = [(log.rev(parent), hg.hex(parent))
148 parents = [(log.rev(parent), hg.hex(parent))
149 for parent in log.parents(node)
149 for parent in log.parents(node)
150 if ui.debugflag or parent != hg.nullid]
150 if ui.debugflag or parent != hg.nullid]
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
152 parents = []
152 parents = []
153
153
154 if filelog:
154 if filelog:
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
156 for parent in parents:
156 for parent in parents:
157 ui.write("parent: %d:%s\n" % parent)
157 ui.write("parent: %d:%s\n" % parent)
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
159 else:
159 else:
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
161 for tag in repo.nodetags(changenode):
161 for tag in repo.nodetags(changenode):
162 ui.status("tag: %s\n" % tag)
162 ui.status("tag: %s\n" % tag)
163 for parent in parents:
163 for parent in parents:
164 ui.write("parent: %d:%s\n" % parent)
164 ui.write("parent: %d:%s\n" % parent)
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
166 hg.hex(changes[0])))
166 hg.hex(changes[0])))
167 ui.status("user: %s\n" % changes[1])
167 ui.status("user: %s\n" % changes[1])
168 ui.status("date: %s\n" % time.asctime(
168 ui.status("date: %s\n" % time.asctime(
169 time.localtime(float(changes[2].split(' ')[0]))))
169 time.localtime(float(changes[2].split(' ')[0]))))
170 if ui.debugflag:
170 if ui.debugflag:
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
172 for key, value in zip(["files:", "files+:", "files-:"], files):
172 for key, value in zip(["files:", "files+:", "files-:"], files):
173 if value:
173 if value:
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
175 else:
175 else:
176 ui.note("files: %s\n" % " ".join(changes[3]))
176 ui.note("files: %s\n" % " ".join(changes[3]))
177 description = changes[4].strip()
177 description = changes[4].strip()
178 if description:
178 if description:
179 if ui.verbose:
179 if ui.verbose:
180 ui.status("description:\n")
180 ui.status("description:\n")
181 ui.status(description)
181 ui.status(description)
182 ui.status("\n\n")
182 ui.status("\n\n")
183 else:
183 else:
184 ui.status("summary: %s\n" % description.splitlines()[0])
184 ui.status("summary: %s\n" % description.splitlines()[0])
185 ui.status("\n")
185 ui.status("\n")
186
186
187 def show_version(ui):
187 def show_version(ui):
188 """output version and copyright information"""
188 """output version and copyright information"""
189 ui.write("Mercurial version %s\n" % version.get_version())
189 ui.write("Mercurial version %s\n" % version.get_version())
190 ui.status(
190 ui.status(
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
192 "This is free software; see the source for copying conditions. "
192 "This is free software; see the source for copying conditions. "
193 "There is NO\nwarranty; "
193 "There is NO\nwarranty; "
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
195 )
195 )
196
196
197 def help(ui, cmd=None):
197 def help(ui, cmd=None):
198 '''show help for a given command or all commands'''
198 '''show help for a given command or all commands'''
199 if cmd:
199 if cmd:
200 try:
200 try:
201 i = find(cmd)
201 i = find(cmd)
202 ui.write("%s\n\n" % i[2])
202 ui.write("%s\n\n" % i[2])
203
203
204 if i[1]:
204 if i[1]:
205 for s, l, d, c in i[1]:
205 for s, l, d, c in i[1]:
206 opt=' '
206 opt=' '
207 if s: opt = opt + '-' + s + ' '
207 if s: opt = opt + '-' + s + ' '
208 if l: opt = opt + '--' + l + ' '
208 if l: opt = opt + '--' + l + ' '
209 if d: opt = opt + '(' + str(d) + ')'
209 if d: opt = opt + '(' + str(d) + ')'
210 ui.write(opt, "\n")
210 ui.write(opt, "\n")
211 if c: ui.write(' %s\n' % c)
211 if c: ui.write(' %s\n' % c)
212 ui.write("\n")
212 ui.write("\n")
213
213
214 ui.write(i[0].__doc__, "\n")
214 ui.write(i[0].__doc__, "\n")
215 except UnknownCommand:
215 except UnknownCommand:
216 ui.warn("hg: unknown command %s\n" % cmd)
216 ui.warn("hg: unknown command %s\n" % cmd)
217 sys.exit(0)
217 sys.exit(0)
218 else:
218 else:
219 if ui.verbose:
219 if ui.verbose:
220 show_version(ui)
220 show_version(ui)
221 ui.write('\n')
221 ui.write('\n')
222 if ui.verbose:
222 if ui.verbose:
223 ui.write('hg commands:\n\n')
223 ui.write('hg commands:\n\n')
224 else:
224 else:
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
226
226
227 h = {}
227 h = {}
228 for c, e in table.items():
228 for c, e in table.items():
229 f = c.split("|")[0]
229 f = c.split("|")[0]
230 if not ui.verbose and not f.startswith("^"):
230 if not ui.verbose and not f.startswith("^"):
231 continue
231 continue
232 if not ui.debugflag and f.startswith("debug"):
232 if not ui.debugflag and f.startswith("debug"):
233 continue
233 continue
234 f = f.lstrip("^")
234 f = f.lstrip("^")
235 d = ""
235 d = ""
236 if e[0].__doc__:
236 if e[0].__doc__:
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
238 h[f] = d
238 h[f] = d
239
239
240 fns = h.keys()
240 fns = h.keys()
241 fns.sort()
241 fns.sort()
242 m = max(map(len, fns))
242 m = max(map(len, fns))
243 for f in fns:
243 for f in fns:
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
245
245
246 # Commands start here, listed alphabetically
246 # Commands start here, listed alphabetically
247
247
248 def add(ui, repo, file, *files):
248 def add(ui, repo, file, *files):
249 '''add the specified files on the next commit'''
249 '''add the specified files on the next commit'''
250 repo.add(relpath(repo, (file,) + files))
250 repo.add(relpath(repo, (file,) + files))
251
251
252 def addremove(ui, repo, *files):
252 def addremove(ui, repo, *files):
253 """add all new files, delete all missing files"""
253 """add all new files, delete all missing files"""
254 if files:
254 if files:
255 files = relpath(repo, files)
255 files = relpath(repo, files)
256 d = []
256 d = []
257 u = []
257 u = []
258 for f in files:
258 for f in files:
259 p = repo.wjoin(f)
259 p = repo.wjoin(f)
260 s = repo.dirstate.state(f)
260 s = repo.dirstate.state(f)
261 isfile = os.path.isfile(p)
261 isfile = os.path.isfile(p)
262 if s != 'r' and not isfile:
262 if s != 'r' and not isfile:
263 d.append(f)
263 d.append(f)
264 elif s not in 'nmai' and isfile:
264 elif s not in 'nmai' and isfile:
265 u.append(f)
265 u.append(f)
266 else:
266 else:
267 (c, a, d, u) = repo.changes(None, None)
267 (c, a, d, u) = repo.changes(None, None)
268 repo.add(u)
268 repo.add(u)
269 repo.remove(d)
269 repo.remove(d)
270
270
271 def annotate(u, repo, file, *files, **ops):
271 def annotate(u, repo, file, *files, **ops):
272 """show changeset information per file line"""
272 """show changeset information per file line"""
273 def getnode(rev):
273 def getnode(rev):
274 return hg.short(repo.changelog.node(rev))
274 return hg.short(repo.changelog.node(rev))
275
275
276 def getname(rev):
276 def getname(rev):
277 try:
277 try:
278 return bcache[rev]
278 return bcache[rev]
279 except KeyError:
279 except KeyError:
280 cl = repo.changelog.read(repo.changelog.node(rev))
280 cl = repo.changelog.read(repo.changelog.node(rev))
281 name = cl[1]
281 name = cl[1]
282 f = name.find('@')
282 f = name.find('@')
283 if f >= 0:
283 if f >= 0:
284 name = name[:f]
284 name = name[:f]
285 f = name.find('<')
285 f = name.find('<')
286 if f >= 0:
286 if f >= 0:
287 name = name[f+1:]
287 name = name[f+1:]
288 bcache[rev] = name
288 bcache[rev] = name
289 return name
289 return name
290
290
291 bcache = {}
291 bcache = {}
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
293 if not ops['user'] and not ops['changeset']:
293 if not ops['user'] and not ops['changeset']:
294 ops['number'] = 1
294 ops['number'] = 1
295
295
296 node = repo.dirstate.parents()[0]
296 node = repo.dirstate.parents()[0]
297 if ops['revision']:
297 if ops['revision']:
298 node = repo.changelog.lookup(ops['revision'])
298 node = repo.changelog.lookup(ops['revision'])
299 change = repo.changelog.read(node)
299 change = repo.changelog.read(node)
300 mmap = repo.manifest.read(change[0])
300 mmap = repo.manifest.read(change[0])
301 for f in relpath(repo, (file,) + files):
301 for f in relpath(repo, (file,) + files):
302 lines = repo.file(f).annotate(mmap[f])
302 lines = repo.file(f).annotate(mmap[f])
303 pieces = []
303 pieces = []
304
304
305 for o, f in opmap:
305 for o, f in opmap:
306 if ops[o]:
306 if ops[o]:
307 l = [ f(n) for n,t in lines ]
307 l = [ f(n) for n,t in lines ]
308 m = max(map(len, l))
308 m = max(map(len, l))
309 pieces.append([ "%*s" % (m, x) for x in l])
309 pieces.append([ "%*s" % (m, x) for x in l])
310
310
311 for p,l in zip(zip(*pieces), lines):
311 for p,l in zip(zip(*pieces), lines):
312 u.write(" ".join(p) + ": " + l[1])
312 u.write(" ".join(p) + ": " + l[1])
313
313
314 def cat(ui, repo, file, rev = []):
314 def cat(ui, repo, file, rev = []):
315 """output the latest or given revision of a file"""
315 """output the latest or given revision of a file"""
316 r = repo.file(relpath(repo, [file])[0])
316 r = repo.file(relpath(repo, [file])[0])
317 n = r.tip()
317 n = r.tip()
318 if rev: n = r.lookup(rev)
318 if rev: n = r.lookup(rev)
319 sys.stdout.write(r.read(n))
319 sys.stdout.write(r.read(n))
320
320
321 def clone(ui, source, dest = None, **opts):
321 def clone(ui, source, dest = None, **opts):
322 """make a copy of an existing repository"""
322 """make a copy of an existing repository"""
323 source = ui.expandpath(source)
323 source = ui.expandpath(source)
324
324
325 if dest is None:
325 if dest is None:
326 dest = os.path.basename(os.path.normpath(source))
326 dest = os.path.basename(os.path.normpath(source))
327
327
328 if os.path.exists(dest):
328 if os.path.exists(dest):
329 ui.warn("abort: destination '%s' already exists\n" % dest)
329 ui.warn("abort: destination '%s' already exists\n" % dest)
330 return 1
330 return 1
331
331
332 class dircleanup:
332 class dircleanup:
333 def __init__(self, dir):
333 def __init__(self, dir):
334 self.dir = dir
334 self.dir = dir
335 os.mkdir(dir)
335 os.mkdir(dir)
336 def close(self):
336 def close(self):
337 self.dir = None
337 self.dir = None
338 def __del__(self):
338 def __del__(self):
339 if self.dir:
339 if self.dir:
340 import shutil
340 import shutil
341 shutil.rmtree(self.dir, True)
341 shutil.rmtree(self.dir, True)
342
342
343 d = dircleanup(dest)
343 d = dircleanup(dest)
344
344
345 link = 0
345 link = 0
346 abspath = source
346 abspath = source
347 if not (source.startswith("http://") or
347 if not (source.startswith("http://") or
348 source.startswith("hg://") or
348 source.startswith("hg://") or
349 source.startswith("old-http://")):
349 source.startswith("old-http://")):
350 abspath = os.path.abspath(source)
350 abspath = os.path.abspath(source)
351 d1 = os.stat(dest).st_dev
351 d1 = os.stat(dest).st_dev
352 d2 = os.stat(source).st_dev
352 d2 = os.stat(source).st_dev
353 if d1 == d2: link = 1
353 if d1 == d2: link = 1
354
354
355 if link:
355 if link:
356 ui.note("copying by hardlink\n")
356 ui.note("copying by hardlink\n")
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
358 try:
358 try:
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
360 except: pass
360 except: pass
361
361
362 repo = hg.repository(ui, dest)
362 repo = hg.repository(ui, dest)
363
363
364 else:
364 else:
365 repo = hg.repository(ui, dest, create=1)
365 repo = hg.repository(ui, dest, create=1)
366 other = hg.repository(ui, source)
366 other = hg.repository(ui, source)
367 fetch = repo.findincoming(other)
367 fetch = repo.findincoming(other)
368 if fetch:
368 if fetch:
369 cg = other.changegroup(fetch)
369 cg = other.changegroup(fetch)
370 repo.addchangegroup(cg)
370 repo.addchangegroup(cg)
371
371
372 f = repo.opener("hgrc", "w")
372 f = repo.opener("hgrc", "w")
373 f.write("[paths]\n")
373 f.write("[paths]\n")
374 f.write("default = %s\n" % abspath)
374 f.write("default = %s\n" % abspath)
375
375
376 if not opts['noupdate']:
376 if not opts['noupdate']:
377 update(ui, repo)
377 update(ui, repo)
378
378
379 d.close()
379 d.close()
380
380
381 def commit(ui, repo, *files, **opts):
381 def commit(ui, repo, *files, **opts):
382 """commit the specified files or all outstanding changes"""
382 """commit the specified files or all outstanding changes"""
383 text = opts['text']
383 text = opts['text']
384 if not text and opts['logfile']:
384 if not text and opts['logfile']:
385 try: text = open(opts['logfile']).read()
385 try: text = open(opts['logfile']).read()
386 except IOError: pass
386 except IOError: pass
387
387
388 if opts['addremove']:
388 if opts['addremove']:
389 addremove(ui, repo, *files)
389 addremove(ui, repo, *files)
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
391
391
392 def copy(ui, repo, source, dest):
392 def copy(ui, repo, source, dest):
393 """mark a file as copied or renamed for the next commit"""
393 """mark a file as copied or renamed for the next commit"""
394 return repo.copy(*relpath(repo, (source, dest)))
394 return repo.copy(*relpath(repo, (source, dest)))
395
395
396 def debugcheckstate(ui, repo):
396 def debugcheckstate(ui, repo):
397 """validate the correctness of the current dirstate"""
397 """validate the correctness of the current dirstate"""
398 parent1, parent2 = repo.dirstate.parents()
398 parent1, parent2 = repo.dirstate.parents()
399 repo.dirstate.read()
399 repo.dirstate.read()
400 dc = repo.dirstate.map
400 dc = repo.dirstate.map
401 keys = dc.keys()
401 keys = dc.keys()
402 keys.sort()
402 keys.sort()
403 m1n = repo.changelog.read(parent1)[0]
403 m1n = repo.changelog.read(parent1)[0]
404 m2n = repo.changelog.read(parent2)[0]
404 m2n = repo.changelog.read(parent2)[0]
405 m1 = repo.manifest.read(m1n)
405 m1 = repo.manifest.read(m1n)
406 m2 = repo.manifest.read(m2n)
406 m2 = repo.manifest.read(m2n)
407 errors = 0
407 errors = 0
408 for f in dc:
408 for f in dc:
409 state = repo.dirstate.state(f)
409 state = repo.dirstate.state(f)
410 if state in "nr" and f not in m1:
410 if state in "nr" and f not in m1:
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
412 errors += 1
412 errors += 1
413 if state in "a" and f in m1:
413 if state in "a" and f in m1:
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
415 errors += 1
415 errors += 1
416 if state in "m" and f not in m1 and f not in m2:
416 if state in "m" and f not in m1 and f not in m2:
417 ui.warn("%s in state %s, but not in either manifest\n" %
417 ui.warn("%s in state %s, but not in either manifest\n" %
418 (f, state))
418 (f, state))
419 errors += 1
419 errors += 1
420 for f in m1:
420 for f in m1:
421 state = repo.dirstate.state(f)
421 state = repo.dirstate.state(f)
422 if state not in "nrm":
422 if state not in "nrm":
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
424 errors += 1
424 errors += 1
425 if errors:
425 if errors:
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
427 sys.exit(1)
427 sys.exit(1)
428
428
429 def debugstate(ui, repo):
429 def debugstate(ui, repo):
430 """show the contents of the current dirstate"""
430 """show the contents of the current dirstate"""
431 repo.dirstate.read()
431 repo.dirstate.read()
432 dc = repo.dirstate.map
432 dc = repo.dirstate.map
433 keys = dc.keys()
433 keys = dc.keys()
434 keys.sort()
434 keys.sort()
435 for file in keys:
435 for file in keys:
436 ui.write("%c %s\n" % (dc[file][0], file))
436 ui.write("%c %s\n" % (dc[file][0], file))
437
437
438 def debugindex(ui, file):
438 def debugindex(ui, file):
439 """dump the contents of an index file"""
439 """dump the contents of an index file"""
440 r = hg.revlog(hg.opener(""), file, "")
440 r = hg.revlog(hg.opener(""), file, "")
441 ui.write(" rev offset length base linkrev" +
441 ui.write(" rev offset length base linkrev" +
442 " p1 p2 nodeid\n")
442 " p1 p2 nodeid\n")
443 for i in range(r.count()):
443 for i in range(r.count()):
444 e = r.index[i]
444 e = r.index[i]
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
446 i, e[0], e[1], e[2], e[3],
446 i, e[0], e[1], e[2], e[3],
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
448
448
449 def debugindexdot(ui, file):
449 def debugindexdot(ui, file):
450 """dump an index DAG as a .dot file"""
450 """dump an index DAG as a .dot file"""
451 r = hg.revlog(hg.opener(""), file, "")
451 r = hg.revlog(hg.opener(""), file, "")
452 ui.write("digraph G {\n")
452 ui.write("digraph G {\n")
453 for i in range(r.count()):
453 for i in range(r.count()):
454 e = r.index[i]
454 e = r.index[i]
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
456 if e[5] != hg.nullid:
456 if e[5] != hg.nullid:
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
458 ui.write("}\n")
458 ui.write("}\n")
459
459
460 def diff(ui, repo, *files, **opts):
460 def diff(ui, repo, *files, **opts):
461 """diff working directory (or selected files)"""
461 """diff working directory (or selected files)"""
462 revs = []
462 revs = []
463 if opts['rev']:
463 if opts['rev']:
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
465
465
466 if len(revs) > 2:
466 if len(revs) > 2:
467 ui.warn("too many revisions to diff\n")
467 ui.warn("too many revisions to diff\n")
468 sys.exit(1)
468 sys.exit(1)
469
469
470 if files:
470 if files:
471 files = relpath(repo, files)
471 files = relpath(repo, files)
472 else:
472 else:
473 files = relpath(repo, [""])
473 files = relpath(repo, [""])
474
474
475 dodiff(sys.stdout, ui, repo, files, *revs)
475 dodiff(sys.stdout, ui, repo, files, *revs)
476
476
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
478 node = repo.lookup(changeset)
478 node = repo.lookup(changeset)
479 prev, other = repo.changelog.parents(node)
479 prev, other = repo.changelog.parents(node)
480 change = repo.changelog.read(node)
480 change = repo.changelog.read(node)
481
481
482 def expand(name):
482 def expand(name):
483 expansions = {
483 expansions = {
484 '%': lambda: '%',
484 '%': lambda: '%',
485 'H': lambda: hg.hex(node),
485 'H': lambda: hg.hex(node),
486 'N': lambda: str(total),
486 'N': lambda: str(total),
487 'R': lambda: str(repo.changelog.rev(node)),
487 'R': lambda: str(repo.changelog.rev(node)),
488 'b': lambda: os.path.basename(repo.root),
488 'b': lambda: os.path.basename(repo.root),
489 'h': lambda: hg.short(node),
489 'h': lambda: hg.short(node),
490 'n': lambda: str(seqno).zfill(len(str(total))),
490 'n': lambda: str(seqno).zfill(len(str(total))),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
492 }
492 }
493 newname = []
493 newname = []
494 namelen = len(name)
494 namelen = len(name)
495 i = 0
495 i = 0
496 while i < namelen:
496 while i < namelen:
497 c = name[i]
497 c = name[i]
498 if c == '%':
498 if c == '%':
499 i += 1
499 i += 1
500 c = name[i]
500 c = name[i]
501 c = expansions[c]()
501 c = expansions[c]()
502 newname.append(c)
502 newname.append(c)
503 i += 1
503 i += 1
504 return ''.join(newname)
504 return ''.join(newname)
505
505
506 if opts['output'] and opts['output'] != '-':
506 if opts['output'] and opts['output'] != '-':
507 try:
507 try:
508 fp = open(expand(opts['output']), 'w')
508 fp = open(expand(opts['output']), 'w')
509 except KeyError, inst:
509 except KeyError, inst:
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
511 inst.args[0])
511 inst.args[0])
512 sys.exit(1)
512 sys.exit(1)
513 else:
513 else:
514 fp = sys.stdout
514 fp = sys.stdout
515
515
516 fp.write("# HG changeset patch\n")
516 fp.write("# HG changeset patch\n")
517 fp.write("# User %s\n" % change[1])
517 fp.write("# User %s\n" % change[1])
518 fp.write("# Node ID %s\n" % hg.hex(node))
518 fp.write("# Node ID %s\n" % hg.hex(node))
519 fp.write("# Parent %s\n" % hg.hex(prev))
519 fp.write("# Parent %s\n" % hg.hex(prev))
520 if other != hg.nullid:
520 if other != hg.nullid:
521 fp.write("# Parent %s\n" % hg.hex(other))
521 fp.write("# Parent %s\n" % hg.hex(other))
522 fp.write(change[4].rstrip())
522 fp.write(change[4].rstrip())
523 fp.write("\n\n")
523 fp.write("\n\n")
524
524
525 dodiff(fp, ui, repo, None, prev, node)
525 dodiff(fp, ui, repo, None, prev, node)
526
526
527 def export(ui, repo, *changesets, **opts):
527 def export(ui, repo, *changesets, **opts):
528 """dump the header and diffs for one or more changesets"""
528 """dump the header and diffs for one or more changesets"""
529 if not changesets:
530 ui.warn("error: export requires at least one changeset\n")
531 sys.exit(1)
529 seqno = 0
532 seqno = 0
530 revs = list(revrange(ui, repo, changesets))
533 revs = list(revrange(ui, repo, changesets))
531 total = len(revs)
534 total = len(revs)
532 revwidth = max(len(revs[0]), len(revs[-1]))
535 revwidth = max(len(revs[0]), len(revs[-1]))
533 for cset in revs:
536 for cset in revs:
534 seqno += 1
537 seqno += 1
535 doexport(ui, repo, cset, seqno, total, revwidth, opts)
538 doexport(ui, repo, cset, seqno, total, revwidth, opts)
536
539
537 def forget(ui, repo, file, *files):
540 def forget(ui, repo, file, *files):
538 """don't add the specified files on the next commit"""
541 """don't add the specified files on the next commit"""
539 repo.forget(relpath(repo, (file,) + files))
542 repo.forget(relpath(repo, (file,) + files))
540
543
541 def heads(ui, repo):
544 def heads(ui, repo):
542 """show current repository heads"""
545 """show current repository heads"""
543 for n in repo.changelog.heads():
546 for n in repo.changelog.heads():
544 show_changeset(ui, repo, changenode=n)
547 show_changeset(ui, repo, changenode=n)
545
548
546 def identify(ui, repo):
549 def identify(ui, repo):
547 """print information about the working copy"""
550 """print information about the working copy"""
548 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
551 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
549 if not parents:
552 if not parents:
550 ui.write("unknown\n")
553 ui.write("unknown\n")
551 return
554 return
552
555
553 hexfunc = ui.verbose and hg.hex or hg.short
556 hexfunc = ui.verbose and hg.hex or hg.short
554 (c, a, d, u) = repo.changes(None, None)
557 (c, a, d, u) = repo.changes(None, None)
555 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
558 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
556 (c or a or d) and "+" or "")]
559 (c or a or d) and "+" or "")]
557
560
558 if not ui.quiet:
561 if not ui.quiet:
559 # multiple tags for a single parent separated by '/'
562 # multiple tags for a single parent separated by '/'
560 parenttags = ['/'.join(tags)
563 parenttags = ['/'.join(tags)
561 for tags in map(repo.nodetags, parents) if tags]
564 for tags in map(repo.nodetags, parents) if tags]
562 # tags for multiple parents separated by ' + '
565 # tags for multiple parents separated by ' + '
563 output.append(' + '.join(parenttags))
566 output.append(' + '.join(parenttags))
564
567
565 ui.write("%s\n" % ' '.join(output))
568 ui.write("%s\n" % ' '.join(output))
566
569
567 def import_(ui, repo, patch1, *patches, **opts):
570 def import_(ui, repo, patch1, *patches, **opts):
568 """import an ordered set of patches"""
571 """import an ordered set of patches"""
569 try:
572 try:
570 import psyco
573 import psyco
571 psyco.full()
574 psyco.full()
572 except:
575 except:
573 pass
576 pass
574
577
575 patches = (patch1,) + patches
578 patches = (patch1,) + patches
576
579
577 d = opts["base"]
580 d = opts["base"]
578 strip = opts["strip"]
581 strip = opts["strip"]
579
582
580 for patch in patches:
583 for patch in patches:
581 ui.status("applying %s\n" % patch)
584 ui.status("applying %s\n" % patch)
582 pf = os.path.join(d, patch)
585 pf = os.path.join(d, patch)
583
586
584 text = ""
587 text = ""
585 for l in file(pf):
588 for l in file(pf):
586 if l[:4] == "--- ": break
589 if l[:4] == "--- ": break
587 text += l
590 text += l
588
591
589 # parse values that exist when importing the result of an hg export
592 # parse values that exist when importing the result of an hg export
590 hgpatch = user = snippet = None
593 hgpatch = user = snippet = None
591 ui.debug('text:\n')
594 ui.debug('text:\n')
592 for t in text.splitlines():
595 for t in text.splitlines():
593 ui.debug(t,'\n')
596 ui.debug(t,'\n')
594 if t == '# HG changeset patch' or hgpatch == True:
597 if t == '# HG changeset patch' or hgpatch == True:
595 hgpatch = True
598 hgpatch = True
596 if t[:7] == "# User ":
599 if t[:7] == "# User ":
597 user = t[7:]
600 user = t[7:]
598 ui.debug('User: %s\n' % user)
601 ui.debug('User: %s\n' % user)
599 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
602 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
600 if snippet: text = snippet + '\n' + text
603 if snippet: text = snippet + '\n' + text
601 ui.debug('text:\n%s\n' % text)
604 ui.debug('text:\n%s\n' % text)
602
605
603 # make sure text isn't empty
606 # make sure text isn't empty
604 if not text: text = "imported patch %s\n" % patch
607 if not text: text = "imported patch %s\n" % patch
605
608
606 f = os.popen("patch -p%d < %s" % (strip, pf))
609 f = os.popen("patch -p%d < %s" % (strip, pf))
607 files = []
610 files = []
608 for l in f.read().splitlines():
611 for l in f.read().splitlines():
609 l.rstrip('\r\n');
612 l.rstrip('\r\n');
610 ui.status("%s\n" % l)
613 ui.status("%s\n" % l)
611 if l[:14] == 'patching file ':
614 if l[:14] == 'patching file ':
612 pf = l[14:]
615 pf = l[14:]
613 if pf not in files:
616 if pf not in files:
614 files.append(pf)
617 files.append(pf)
615 patcherr = f.close()
618 patcherr = f.close()
616 if patcherr:
619 if patcherr:
617 sys.stderr.write("patch failed")
620 sys.stderr.write("patch failed")
618 sys.exit(1)
621 sys.exit(1)
619
622
620 if len(files) > 0:
623 if len(files) > 0:
621 addremove(ui, repo, *files)
624 addremove(ui, repo, *files)
622 repo.commit(files, text, user)
625 repo.commit(files, text, user)
623
626
624 def init(ui, source=None):
627 def init(ui, source=None):
625 """create a new repository in the current directory"""
628 """create a new repository in the current directory"""
626
629
627 if source:
630 if source:
628 ui.warn("no longer supported: use \"hg clone\" instead\n")
631 ui.warn("no longer supported: use \"hg clone\" instead\n")
629 sys.exit(1)
632 sys.exit(1)
630 repo = hg.repository(ui, ".", create=1)
633 repo = hg.repository(ui, ".", create=1)
631
634
632 def log(ui, repo, f=None, **opts):
635 def log(ui, repo, f=None, **opts):
633 """show the revision history of the repository or a single file"""
636 """show the revision history of the repository or a single file"""
634 if f:
637 if f:
635 filelog = repo.file(relpath(repo, [f])[0])
638 filelog = repo.file(relpath(repo, [f])[0])
636 log = filelog
639 log = filelog
637 lookup = filelog.lookup
640 lookup = filelog.lookup
638 else:
641 else:
639 filelog = None
642 filelog = None
640 log = repo.changelog
643 log = repo.changelog
641 lookup = repo.lookup
644 lookup = repo.lookup
642 revlist = []
645 revlist = []
643 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
646 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
644 while revs:
647 while revs:
645 if len(revs) == 1:
648 if len(revs) == 1:
646 revlist.append(revs.pop(0))
649 revlist.append(revs.pop(0))
647 else:
650 else:
648 a = revs.pop(0)
651 a = revs.pop(0)
649 b = revs.pop(0)
652 b = revs.pop(0)
650 off = a > b and -1 or 1
653 off = a > b and -1 or 1
651 revlist.extend(range(a, b + off, off))
654 revlist.extend(range(a, b + off, off))
652
655
653 for i in revlist or range(log.count() - 1, -1, -1):
656 for i in revlist or range(log.count() - 1, -1, -1):
654 show_changeset(ui, repo, filelog=filelog, rev=i)
657 show_changeset(ui, repo, filelog=filelog, rev=i)
655
658
656 def manifest(ui, repo, rev = []):
659 def manifest(ui, repo, rev = []):
657 """output the latest or given revision of the project manifest"""
660 """output the latest or given revision of the project manifest"""
658 n = repo.manifest.tip()
661 n = repo.manifest.tip()
659 if rev:
662 if rev:
660 n = repo.manifest.lookup(rev)
663 n = repo.manifest.lookup(rev)
661 m = repo.manifest.read(n)
664 m = repo.manifest.read(n)
662 mf = repo.manifest.readflags(n)
665 mf = repo.manifest.readflags(n)
663 files = m.keys()
666 files = m.keys()
664 files.sort()
667 files.sort()
665
668
666 for f in files:
669 for f in files:
667 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
670 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
668
671
669 def parents(ui, repo, node = None):
672 def parents(ui, repo, node = None):
670 '''show the parents of the current working dir'''
673 '''show the parents of the current working dir'''
671 if node:
674 if node:
672 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
675 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
673 else:
676 else:
674 p = repo.dirstate.parents()
677 p = repo.dirstate.parents()
675
678
676 for n in p:
679 for n in p:
677 if n != hg.nullid:
680 if n != hg.nullid:
678 show_changeset(ui, repo, changenode=n)
681 show_changeset(ui, repo, changenode=n)
679
682
680 def pull(ui, repo, source="default", **opts):
683 def pull(ui, repo, source="default", **opts):
681 """pull changes from the specified source"""
684 """pull changes from the specified source"""
682 source = ui.expandpath(source)
685 source = ui.expandpath(source)
683
686
684 ui.status('pulling from %s\n' % (source))
687 ui.status('pulling from %s\n' % (source))
685
688
686 other = hg.repository(ui, source)
689 other = hg.repository(ui, source)
687 fetch = repo.findincoming(other)
690 fetch = repo.findincoming(other)
688 if not fetch:
691 if not fetch:
689 ui.status("no changes found\n")
692 ui.status("no changes found\n")
690 return
693 return
691
694
692 cg = other.changegroup(fetch)
695 cg = other.changegroup(fetch)
693 r = repo.addchangegroup(cg)
696 r = repo.addchangegroup(cg)
694 if cg and not r:
697 if cg and not r:
695 if opts['update']:
698 if opts['update']:
696 return update(ui, repo)
699 return update(ui, repo)
697 else:
700 else:
698 ui.status("(run 'hg update' to get a working copy)\n")
701 ui.status("(run 'hg update' to get a working copy)\n")
699
702
700 return r
703 return r
701
704
702 def push(ui, repo, dest="default-push"):
705 def push(ui, repo, dest="default-push"):
703 """push changes to the specified destination"""
706 """push changes to the specified destination"""
704 dest = ui.expandpath(dest)
707 dest = ui.expandpath(dest)
705
708
706 if not dest.startswith("ssh://"):
709 if not dest.startswith("ssh://"):
707 ui.warn("abort: can only push to ssh:// destinations currently\n")
710 ui.warn("abort: can only push to ssh:// destinations currently\n")
708 return 1
711 return 1
709
712
710 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
713 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
711 if not m:
714 if not m:
712 ui.warn("abort: couldn't parse destination %s\n" % dest)
715 ui.warn("abort: couldn't parse destination %s\n" % dest)
713 return 1
716 return 1
714
717
715 user, host, port, path = map(m.group, (2, 3, 5, 7))
718 user, host, port, path = map(m.group, (2, 3, 5, 7))
716 uhost = user and ("%s@%s" % (user, host)) or host
719 uhost = user and ("%s@%s" % (user, host)) or host
717 port = port and (" -p %s") % port or ""
720 port = port and (" -p %s") % port or ""
718 path = path or ""
721 path = path or ""
719
722
720 sport = random.randrange(30000, 60000)
723 sport = random.randrange(30000, 60000)
721 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
724 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
722 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
725 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
723
726
724 child = os.fork()
727 child = os.fork()
725 if not child:
728 if not child:
726 sys.stdout = file("/dev/null", "w")
729 sys.stdout = file("/dev/null", "w")
727 sys.stderr = sys.stdout
730 sys.stderr = sys.stdout
728 hgweb.server(repo.root, "pull", "", "localhost", sport)
731 hgweb.server(repo.root, "pull", "", "localhost", sport)
729 else:
732 else:
730 ui.status("connecting to %s\n" % host)
733 ui.status("connecting to %s\n" % host)
731 r = os.system(cmd)
734 r = os.system(cmd)
732 os.kill(child, signal.SIGTERM)
735 os.kill(child, signal.SIGTERM)
733 return r
736 return r
734
737
735 def rawcommit(ui, repo, *flist, **rc):
738 def rawcommit(ui, repo, *flist, **rc):
736 "raw commit interface"
739 "raw commit interface"
737
740
738 text = rc['text']
741 text = rc['text']
739 if not text and rc['logfile']:
742 if not text and rc['logfile']:
740 try: text = open(rc['logfile']).read()
743 try: text = open(rc['logfile']).read()
741 except IOError: pass
744 except IOError: pass
742 if not text and not rc['logfile']:
745 if not text and not rc['logfile']:
743 ui.warn("abort: missing commit text\n")
746 ui.warn("abort: missing commit text\n")
744 return 1
747 return 1
745
748
746 files = relpath(repo, list(flist))
749 files = relpath(repo, list(flist))
747 if rc['files']:
750 if rc['files']:
748 files += open(rc['files']).read().splitlines()
751 files += open(rc['files']).read().splitlines()
749
752
750 rc['parent'] = map(repo.lookup, rc['parent'])
753 rc['parent'] = map(repo.lookup, rc['parent'])
751
754
752 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
755 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
753
756
754 def recover(ui, repo):
757 def recover(ui, repo):
755 """roll back an interrupted transaction"""
758 """roll back an interrupted transaction"""
756 repo.recover()
759 repo.recover()
757
760
758 def remove(ui, repo, file, *files):
761 def remove(ui, repo, file, *files):
759 """remove the specified files on the next commit"""
762 """remove the specified files on the next commit"""
760 repo.remove(relpath(repo, (file,) + files))
763 repo.remove(relpath(repo, (file,) + files))
761
764
762 def revert(ui, repo, *names, **opts):
765 def revert(ui, repo, *names, **opts):
763 """revert modified files or dirs back to their unmodified states"""
766 """revert modified files or dirs back to their unmodified states"""
764 node = opts['rev'] and repo.lookup(opts['rev']) or \
767 node = opts['rev'] and repo.lookup(opts['rev']) or \
765 repo.dirstate.parents()[0]
768 repo.dirstate.parents()[0]
766 root = os.path.realpath(repo.root)
769 root = os.path.realpath(repo.root)
767
770
768 def trimpath(p):
771 def trimpath(p):
769 p = os.path.realpath(p)
772 p = os.path.realpath(p)
770 if p.startswith(root):
773 if p.startswith(root):
771 rest = p[len(root):]
774 rest = p[len(root):]
772 if not rest:
775 if not rest:
773 return rest
776 return rest
774 if p.startswith(os.sep):
777 if p.startswith(os.sep):
775 return rest[1:]
778 return rest[1:]
776 return p
779 return p
777
780
778 relnames = map(trimpath, names or [os.getcwd()])
781 relnames = map(trimpath, names or [os.getcwd()])
779 chosen = {}
782 chosen = {}
780
783
781 def choose(name):
784 def choose(name):
782 def body(name):
785 def body(name):
783 for r in relnames:
786 for r in relnames:
784 if not name.startswith(r): continue
787 if not name.startswith(r): continue
785 rest = name[len(r):]
788 rest = name[len(r):]
786 if not rest: return r, True
789 if not rest: return r, True
787 depth = rest.count(os.sep)
790 depth = rest.count(os.sep)
788 if not r:
791 if not r:
789 if depth == 0 or not opts['nonrecursive']: return r, True
792 if depth == 0 or not opts['nonrecursive']: return r, True
790 elif rest[0] == os.sep:
793 elif rest[0] == os.sep:
791 if depth == 1 or not opts['nonrecursive']: return r, True
794 if depth == 1 or not opts['nonrecursive']: return r, True
792 return None, False
795 return None, False
793 relname, ret = body(name)
796 relname, ret = body(name)
794 if ret:
797 if ret:
795 chosen[relname] = 1
798 chosen[relname] = 1
796 return ret
799 return ret
797
800
798 r = repo.update(node, False, True, choose, False)
801 r = repo.update(node, False, True, choose, False)
799 for n in relnames:
802 for n in relnames:
800 if n not in chosen:
803 if n not in chosen:
801 ui.warn('error: no matches for %s\n' % n)
804 ui.warn('error: no matches for %s\n' % n)
802 r = 1
805 r = 1
803 sys.stdout.flush()
806 sys.stdout.flush()
804 return r
807 return r
805
808
806 def root(ui, repo):
809 def root(ui, repo):
807 """print the root (top) of the current working dir"""
810 """print the root (top) of the current working dir"""
808 ui.write(repo.root + "\n")
811 ui.write(repo.root + "\n")
809
812
810 def serve(ui, repo, **opts):
813 def serve(ui, repo, **opts):
811 """export the repository via HTTP"""
814 """export the repository via HTTP"""
812 def openlog(opt, default):
815 def openlog(opt, default):
813 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
816 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
814 else: return default
817 else: return default
815 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
818 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
816 opts["address"], opts["port"],
819 opts["address"], opts["port"],
817 openlog('accesslog', sys.stdout),
820 openlog('accesslog', sys.stdout),
818 openlog('errorlog', sys.stderr))
821 openlog('errorlog', sys.stderr))
819 if ui.verbose:
822 if ui.verbose:
820 addr, port = httpd.socket.getsockname()
823 addr, port = httpd.socket.getsockname()
821 if addr == '0.0.0.0':
824 if addr == '0.0.0.0':
822 addr = socket.gethostname()
825 addr = socket.gethostname()
823 else:
826 else:
824 try:
827 try:
825 addr = socket.gethostbyaddr(addr)[0]
828 addr = socket.gethostbyaddr(addr)[0]
826 except: pass
829 except: pass
827 if port != 80:
830 if port != 80:
828 ui.status('listening at http://%s:%d/\n' % (addr, port))
831 ui.status('listening at http://%s:%d/\n' % (addr, port))
829 else:
832 else:
830 ui.status('listening at http://%s/\n' % addr)
833 ui.status('listening at http://%s/\n' % addr)
831 httpd.serve_forever()
834 httpd.serve_forever()
832
835
833 def status(ui, repo):
836 def status(ui, repo):
834 '''show changed files in the working directory
837 '''show changed files in the working directory
835
838
836 C = changed
839 C = changed
837 A = added
840 A = added
838 R = removed
841 R = removed
839 ? = not tracked'''
842 ? = not tracked'''
840
843
841 (c, a, d, u) = repo.changes(None, None)
844 (c, a, d, u) = repo.changes(None, None)
842 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
845 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
843
846
844 for f in c: ui.write("C ", f, "\n")
847 for f in c: ui.write("C ", f, "\n")
845 for f in a: ui.write("A ", f, "\n")
848 for f in a: ui.write("A ", f, "\n")
846 for f in d: ui.write("R ", f, "\n")
849 for f in d: ui.write("R ", f, "\n")
847 for f in u: ui.write("? ", f, "\n")
850 for f in u: ui.write("? ", f, "\n")
848
851
849 def tag(ui, repo, name, rev = None, **opts):
852 def tag(ui, repo, name, rev = None, **opts):
850 """add a tag for the current tip or a given revision"""
853 """add a tag for the current tip or a given revision"""
851
854
852 if name == "tip":
855 if name == "tip":
853 ui.warn("abort: 'tip' is a reserved name!\n")
856 ui.warn("abort: 'tip' is a reserved name!\n")
854 return -1
857 return -1
855 if rev:
858 if rev:
856 r = hg.hex(repo.lookup(rev))
859 r = hg.hex(repo.lookup(rev))
857 else:
860 else:
858 r = hg.hex(repo.changelog.tip())
861 r = hg.hex(repo.changelog.tip())
859
862
860 if name.find(revrangesep) >= 0:
863 if name.find(revrangesep) >= 0:
861 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
864 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
862 return -1
865 return -1
863
866
864 if opts['local']:
867 if opts['local']:
865 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
868 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
866 return
869 return
867
870
868 (c, a, d, u) = repo.changes(None, None)
871 (c, a, d, u) = repo.changes(None, None)
869 for x in (c, a, d, u):
872 for x in (c, a, d, u):
870 if ".hgtags" in x:
873 if ".hgtags" in x:
871 ui.warn("abort: working copy of .hgtags is changed!\n")
874 ui.warn("abort: working copy of .hgtags is changed!\n")
872 ui.status("(please commit .hgtags manually)\n")
875 ui.status("(please commit .hgtags manually)\n")
873 return -1
876 return -1
874
877
875 add = 0
878 add = 0
876 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
879 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
877 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
880 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
878 if add: repo.add([".hgtags"])
881 if add: repo.add([".hgtags"])
879
882
880 if not opts['text']:
883 if not opts['text']:
881 opts['text'] = "Added tag %s for changeset %s" % (name, r)
884 opts['text'] = "Added tag %s for changeset %s" % (name, r)
882
885
883 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
886 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
884
887
885 def tags(ui, repo):
888 def tags(ui, repo):
886 """list repository tags"""
889 """list repository tags"""
887
890
888 l = repo.tagslist()
891 l = repo.tagslist()
889 l.reverse()
892 l.reverse()
890 for t, n in l:
893 for t, n in l:
891 try:
894 try:
892 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
895 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
893 except KeyError:
896 except KeyError:
894 r = " ?:?"
897 r = " ?:?"
895 ui.write("%-30s %s\n" % (t, r))
898 ui.write("%-30s %s\n" % (t, r))
896
899
897 def tip(ui, repo):
900 def tip(ui, repo):
898 """show the tip revision"""
901 """show the tip revision"""
899 n = repo.changelog.tip()
902 n = repo.changelog.tip()
900 show_changeset(ui, repo, changenode=n)
903 show_changeset(ui, repo, changenode=n)
901
904
902 def undo(ui, repo):
905 def undo(ui, repo):
903 """undo the last commit or pull
906 """undo the last commit or pull
904
907
905 Roll back the last pull or commit transaction on the
908 Roll back the last pull or commit transaction on the
906 repository, restoring the project to its earlier state.
909 repository, restoring the project to its earlier state.
907
910
908 This command should be used with care. There is only one level of
911 This command should be used with care. There is only one level of
909 undo and there is no redo.
912 undo and there is no redo.
910
913
911 This command is not intended for use on public repositories. Once
914 This command is not intended for use on public repositories. Once
912 a change is visible for pull by other users, undoing it locally is
915 a change is visible for pull by other users, undoing it locally is
913 ineffective.
916 ineffective.
914 """
917 """
915 repo.undo()
918 repo.undo()
916
919
917 def update(ui, repo, node=None, merge=False, clean=False):
920 def update(ui, repo, node=None, merge=False, clean=False):
918 '''update or merge working directory
921 '''update or merge working directory
919
922
920 If there are no outstanding changes in the working directory and
923 If there are no outstanding changes in the working directory and
921 there is a linear relationship between the current version and the
924 there is a linear relationship between the current version and the
922 requested version, the result is the requested version.
925 requested version, the result is the requested version.
923
926
924 Otherwise the result is a merge between the contents of the
927 Otherwise the result is a merge between the contents of the
925 current working directory and the requested version. Files that
928 current working directory and the requested version. Files that
926 changed between either parent are marked as changed for the next
929 changed between either parent are marked as changed for the next
927 commit and a commit must be performed before any further updates
930 commit and a commit must be performed before any further updates
928 are allowed.
931 are allowed.
929 '''
932 '''
930 node = node and repo.lookup(node) or repo.changelog.tip()
933 node = node and repo.lookup(node) or repo.changelog.tip()
931 return repo.update(node, allow=merge, force=clean)
934 return repo.update(node, allow=merge, force=clean)
932
935
933 def verify(ui, repo):
936 def verify(ui, repo):
934 """verify the integrity of the repository"""
937 """verify the integrity of the repository"""
935 return repo.verify()
938 return repo.verify()
936
939
937 # Command options and aliases are listed here, alphabetically
940 # Command options and aliases are listed here, alphabetically
938
941
939 table = {
942 table = {
940 "^add": (add, [], "hg add [files]"),
943 "^add": (add, [], "hg add [files]"),
941 "addremove": (addremove, [], "hg addremove [files]"),
944 "addremove": (addremove, [], "hg addremove [files]"),
942 "^annotate": (annotate,
945 "^annotate": (annotate,
943 [('r', 'revision', '', 'revision'),
946 [('r', 'revision', '', 'revision'),
944 ('u', 'user', None, 'show user'),
947 ('u', 'user', None, 'show user'),
945 ('n', 'number', None, 'show revision number'),
948 ('n', 'number', None, 'show revision number'),
946 ('c', 'changeset', None, 'show changeset')],
949 ('c', 'changeset', None, 'show changeset')],
947 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
950 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
948 "cat": (cat, [], 'hg cat <file> [rev]'),
951 "cat": (cat, [], 'hg cat <file> [rev]'),
949 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
952 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
950 'hg clone [options] <source> [dest]'),
953 'hg clone [options] <source> [dest]'),
951 "^commit|ci": (commit,
954 "^commit|ci": (commit,
952 [('t', 'text', "", 'commit text'),
955 [('t', 'text', "", 'commit text'),
953 ('A', 'addremove', None, 'run add/remove during commit'),
956 ('A', 'addremove', None, 'run add/remove during commit'),
954 ('l', 'logfile', "", 'commit text file'),
957 ('l', 'logfile', "", 'commit text file'),
955 ('d', 'date', "", 'date code'),
958 ('d', 'date', "", 'date code'),
956 ('u', 'user', "", 'user')],
959 ('u', 'user', "", 'user')],
957 'hg commit [files]'),
960 'hg commit [files]'),
958 "copy": (copy, [], 'hg copy <source> <dest>'),
961 "copy": (copy, [], 'hg copy <source> <dest>'),
959 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
962 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
960 "debugstate": (debugstate, [], 'debugstate'),
963 "debugstate": (debugstate, [], 'debugstate'),
961 "debugindex": (debugindex, [], 'debugindex <file>'),
964 "debugindex": (debugindex, [], 'debugindex <file>'),
962 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
965 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
963 "^diff": (diff, [('r', 'rev', [], 'revision')],
966 "^diff": (diff, [('r', 'rev', [], 'revision')],
964 'hg diff [-r A] [-r B] [files]'),
967 'hg diff [-r A] [-r B] [files]'),
965 "^export": (export, [('o', 'output', "", 'output to file')],
968 "^export": (export, [('o', 'output', "", 'output to file')],
966 "hg export [-o file] <changeset> ..."),
969 "hg export [-o file] <changeset> ..."),
967 "forget": (forget, [], "hg forget [files]"),
970 "forget": (forget, [], "hg forget [files]"),
968 "heads": (heads, [], 'hg heads'),
971 "heads": (heads, [], 'hg heads'),
969 "help": (help, [], 'hg help [command]'),
972 "help": (help, [], 'hg help [command]'),
970 "identify|id": (identify, [], 'hg identify'),
973 "identify|id": (identify, [], 'hg identify'),
971 "import|patch": (import_,
974 "import|patch": (import_,
972 [('p', 'strip', 1, 'path strip'),
975 [('p', 'strip', 1, 'path strip'),
973 ('b', 'base', "", 'base path')],
976 ('b', 'base', "", 'base path')],
974 "hg import [options] <patches>"),
977 "hg import [options] <patches>"),
975 "^init": (init, [], 'hg init'),
978 "^init": (init, [], 'hg init'),
976 "^log|history": (log,
979 "^log|history": (log,
977 [('r', 'rev', [], 'revision')],
980 [('r', 'rev', [], 'revision')],
978 'hg log [-r A] [-r B] [file]'),
981 'hg log [-r A] [-r B] [file]'),
979 "manifest": (manifest, [], 'hg manifest [rev]'),
982 "manifest": (manifest, [], 'hg manifest [rev]'),
980 "parents": (parents, [], 'hg parents [node]'),
983 "parents": (parents, [], 'hg parents [node]'),
981 "^pull": (pull,
984 "^pull": (pull,
982 [('u', 'update', None, 'update working directory')],
985 [('u', 'update', None, 'update working directory')],
983 'hg pull [options] [source]'),
986 'hg pull [options] [source]'),
984 "^push": (push, [], 'hg push <destination>'),
987 "^push": (push, [], 'hg push <destination>'),
985 "rawcommit": (rawcommit,
988 "rawcommit": (rawcommit,
986 [('p', 'parent', [], 'parent'),
989 [('p', 'parent', [], 'parent'),
987 ('d', 'date', "", 'date code'),
990 ('d', 'date', "", 'date code'),
988 ('u', 'user', "", 'user'),
991 ('u', 'user', "", 'user'),
989 ('F', 'files', "", 'file list'),
992 ('F', 'files', "", 'file list'),
990 ('t', 'text', "", 'commit text'),
993 ('t', 'text', "", 'commit text'),
991 ('l', 'logfile', "", 'commit text file')],
994 ('l', 'logfile', "", 'commit text file')],
992 'hg rawcommit [options] [files]'),
995 'hg rawcommit [options] [files]'),
993 "recover": (recover, [], "hg recover"),
996 "recover": (recover, [], "hg recover"),
994 "^remove|rm": (remove, [], "hg remove [files]"),
997 "^remove|rm": (remove, [], "hg remove [files]"),
995 "^revert": (revert,
998 "^revert": (revert,
996 [("n", "nonrecursive", None, "don't recurse into subdirs"),
999 [("n", "nonrecursive", None, "don't recurse into subdirs"),
997 ("r", "rev", "", "revision")],
1000 ("r", "rev", "", "revision")],
998 "hg revert [files|dirs]"),
1001 "hg revert [files|dirs]"),
999 "root": (root, [], "hg root"),
1002 "root": (root, [], "hg root"),
1000 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1003 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1001 ('E', 'errorlog', '', 'error log file'),
1004 ('E', 'errorlog', '', 'error log file'),
1002 ('p', 'port', 8000, 'listen port'),
1005 ('p', 'port', 8000, 'listen port'),
1003 ('a', 'address', '', 'interface address'),
1006 ('a', 'address', '', 'interface address'),
1004 ('n', 'name', os.getcwd(), 'repository name'),
1007 ('n', 'name', os.getcwd(), 'repository name'),
1005 ('t', 'templates', "", 'template map')],
1008 ('t', 'templates', "", 'template map')],
1006 "hg serve [options]"),
1009 "hg serve [options]"),
1007 "^status": (status, [], 'hg status'),
1010 "^status": (status, [], 'hg status'),
1008 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1011 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1009 ('t', 'text', "", 'commit text'),
1012 ('t', 'text', "", 'commit text'),
1010 ('d', 'date', "", 'date code'),
1013 ('d', 'date', "", 'date code'),
1011 ('u', 'user', "", 'user')],
1014 ('u', 'user', "", 'user')],
1012 'hg tag [options] <name> [rev]'),
1015 'hg tag [options] <name> [rev]'),
1013 "tags": (tags, [], 'hg tags'),
1016 "tags": (tags, [], 'hg tags'),
1014 "tip": (tip, [], 'hg tip'),
1017 "tip": (tip, [], 'hg tip'),
1015 "undo": (undo, [], 'hg undo'),
1018 "undo": (undo, [], 'hg undo'),
1016 "^update|up|checkout|co":
1019 "^update|up|checkout|co":
1017 (update,
1020 (update,
1018 [('m', 'merge', None, 'allow merging of conflicts'),
1021 [('m', 'merge', None, 'allow merging of conflicts'),
1019 ('C', 'clean', None, 'overwrite locally modified files')],
1022 ('C', 'clean', None, 'overwrite locally modified files')],
1020 'hg update [options] [node]'),
1023 'hg update [options] [node]'),
1021 "verify": (verify, [], 'hg verify'),
1024 "verify": (verify, [], 'hg verify'),
1022 "version": (show_version, [], 'hg version'),
1025 "version": (show_version, [], 'hg version'),
1023 }
1026 }
1024
1027
1025 globalopts = [('v', 'verbose', None, 'verbose'),
1028 globalopts = [('v', 'verbose', None, 'verbose'),
1026 ('', 'debug', None, 'debug'),
1029 ('', 'debug', None, 'debug'),
1027 ('q', 'quiet', None, 'quiet'),
1030 ('q', 'quiet', None, 'quiet'),
1028 ('', 'profile', None, 'profile'),
1031 ('', 'profile', None, 'profile'),
1029 ('R', 'repository', "", 'repository root directory'),
1032 ('R', 'repository', "", 'repository root directory'),
1030 ('', 'traceback', None, 'print traceback on exception'),
1033 ('', 'traceback', None, 'print traceback on exception'),
1031 ('y', 'noninteractive', None, 'run non-interactively'),
1034 ('y', 'noninteractive', None, 'run non-interactively'),
1032 ('', 'version', None, 'output version information and exit'),
1035 ('', 'version', None, 'output version information and exit'),
1033 ]
1036 ]
1034
1037
1035 norepo = "clone init version help debugindex debugindexdot"
1038 norepo = "clone init version help debugindex debugindexdot"
1036
1039
1037 def find(cmd):
1040 def find(cmd):
1038 for e in table.keys():
1041 for e in table.keys():
1039 if re.match("(%s)$" % e, cmd):
1042 if re.match("(%s)$" % e, cmd):
1040 return table[e]
1043 return table[e]
1041
1044
1042 raise UnknownCommand(cmd)
1045 raise UnknownCommand(cmd)
1043
1046
1044 class SignalInterrupt(Exception): pass
1047 class SignalInterrupt(Exception): pass
1045
1048
1046 def catchterm(*args):
1049 def catchterm(*args):
1047 raise SignalInterrupt
1050 raise SignalInterrupt
1048
1051
1049 def run():
1052 def run():
1050 sys.exit(dispatch(sys.argv[1:]))
1053 sys.exit(dispatch(sys.argv[1:]))
1051
1054
1052 class ParseError(Exception): pass
1055 class ParseError(Exception): pass
1053
1056
1054 def parse(args):
1057 def parse(args):
1055 options = {}
1058 options = {}
1056 cmdoptions = {}
1059 cmdoptions = {}
1057
1060
1058 try:
1061 try:
1059 args = fancyopts.fancyopts(args, globalopts, options)
1062 args = fancyopts.fancyopts(args, globalopts, options)
1060 except fancyopts.getopt.GetoptError, inst:
1063 except fancyopts.getopt.GetoptError, inst:
1061 raise ParseError(cmd, inst)
1064 raise ParseError(cmd, inst)
1062
1065
1063 if options["version"]:
1066 if options["version"]:
1064 return ("version", show_version, [], options, cmdoptions)
1067 return ("version", show_version, [], options, cmdoptions)
1065 elif not args:
1068 elif not args:
1066 return ("help", help, [], options, cmdoptions)
1069 return ("help", help, [], options, cmdoptions)
1067 else:
1070 else:
1068 cmd, args = args[0], args[1:]
1071 cmd, args = args[0], args[1:]
1069
1072
1070 i = find(cmd)
1073 i = find(cmd)
1071
1074
1072 # combine global options into local
1075 # combine global options into local
1073 c = list(i[1])
1076 c = list(i[1])
1074 l = len(c)
1077 l = len(c)
1075 for o in globalopts:
1078 for o in globalopts:
1076 c.append((o[0], o[1], options[o[1]], o[3]))
1079 c.append((o[0], o[1], options[o[1]], o[3]))
1077
1080
1078 try:
1081 try:
1079 args = fancyopts.fancyopts(args, c, cmdoptions)
1082 args = fancyopts.fancyopts(args, c, cmdoptions)
1080 except fancyopts.getopt.GetoptError, inst:
1083 except fancyopts.getopt.GetoptError, inst:
1081 raise ParseError(cmd, inst)
1084 raise ParseError(cmd, inst)
1082
1085
1083 # separate global options back out
1086 # separate global options back out
1084 for o in globalopts:
1087 for o in globalopts:
1085 n = o[1]
1088 n = o[1]
1086 options[n] = cmdoptions[n]
1089 options[n] = cmdoptions[n]
1087 del cmdoptions[n]
1090 del cmdoptions[n]
1088
1091
1089 return (cmd, i[0], args, options, cmdoptions)
1092 return (cmd, i[0], args, options, cmdoptions)
1090
1093
1091 def dispatch(args):
1094 def dispatch(args):
1092 signal.signal(signal.SIGTERM, catchterm)
1095 signal.signal(signal.SIGTERM, catchterm)
1093
1096
1094 try:
1097 try:
1095 cmd, func, args, options, cmdoptions = parse(args)
1098 cmd, func, args, options, cmdoptions = parse(args)
1096 except ParseError, inst:
1099 except ParseError, inst:
1097 u = ui.ui()
1100 u = ui.ui()
1098 if inst.args[0]:
1101 if inst.args[0]:
1099 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1102 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1100 help(u, inst.args[0])
1103 help(u, inst.args[0])
1101 else:
1104 else:
1102 u.warn("hg: %s\n" % inst.args[1])
1105 u.warn("hg: %s\n" % inst.args[1])
1103 help(u)
1106 help(u)
1104 sys.exit(-1)
1107 sys.exit(-1)
1105 except UnknownCommand, inst:
1108 except UnknownCommand, inst:
1106 u = ui.ui()
1109 u = ui.ui()
1107 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1110 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1108 help(u)
1111 help(u)
1109 sys.exit(1)
1112 sys.exit(1)
1110
1113
1111 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1114 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1112 not options["noninteractive"])
1115 not options["noninteractive"])
1113
1116
1114 try:
1117 try:
1115 try:
1118 try:
1116 if cmd not in norepo.split():
1119 if cmd not in norepo.split():
1117 path = options["repository"] or ""
1120 path = options["repository"] or ""
1118 repo = hg.repository(ui=u, path=path)
1121 repo = hg.repository(ui=u, path=path)
1119 d = lambda: func(u, repo, *args, **cmdoptions)
1122 d = lambda: func(u, repo, *args, **cmdoptions)
1120 else:
1123 else:
1121 d = lambda: func(u, *args, **cmdoptions)
1124 d = lambda: func(u, *args, **cmdoptions)
1122
1125
1123 if options['profile']:
1126 if options['profile']:
1124 import hotshot, hotshot.stats
1127 import hotshot, hotshot.stats
1125 prof = hotshot.Profile("hg.prof")
1128 prof = hotshot.Profile("hg.prof")
1126 r = prof.runcall(d)
1129 r = prof.runcall(d)
1127 prof.close()
1130 prof.close()
1128 stats = hotshot.stats.load("hg.prof")
1131 stats = hotshot.stats.load("hg.prof")
1129 stats.strip_dirs()
1132 stats.strip_dirs()
1130 stats.sort_stats('time', 'calls')
1133 stats.sort_stats('time', 'calls')
1131 stats.print_stats(40)
1134 stats.print_stats(40)
1132 return r
1135 return r
1133 else:
1136 else:
1134 return d()
1137 return d()
1135 except:
1138 except:
1136 if options['traceback']:
1139 if options['traceback']:
1137 traceback.print_exc()
1140 traceback.print_exc()
1138 raise
1141 raise
1139 except util.CommandError, inst:
1142 except util.CommandError, inst:
1140 u.warn("abort: %s\n" % inst.args)
1143 u.warn("abort: %s\n" % inst.args)
1141 except hg.RepoError, inst:
1144 except hg.RepoError, inst:
1142 u.warn("abort: ", inst, "!\n")
1145 u.warn("abort: ", inst, "!\n")
1143 except SignalInterrupt:
1146 except SignalInterrupt:
1144 u.warn("killed!\n")
1147 u.warn("killed!\n")
1145 except KeyboardInterrupt:
1148 except KeyboardInterrupt:
1146 u.warn("interrupted!\n")
1149 u.warn("interrupted!\n")
1147 except IOError, inst:
1150 except IOError, inst:
1148 if hasattr(inst, "code"):
1151 if hasattr(inst, "code"):
1149 u.warn("abort: %s\n" % inst)
1152 u.warn("abort: %s\n" % inst)
1150 elif hasattr(inst, "reason"):
1153 elif hasattr(inst, "reason"):
1151 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1154 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1152 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1155 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1153 u.warn("broken pipe\n")
1156 u.warn("broken pipe\n")
1154 else:
1157 else:
1155 raise
1158 raise
1156 except OSError, inst:
1159 except OSError, inst:
1157 if hasattr(inst, "filename"):
1160 if hasattr(inst, "filename"):
1158 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1161 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1159 else:
1162 else:
1160 u.warn("abort: %s\n" % inst.strerror)
1163 u.warn("abort: %s\n" % inst.strerror)
1161 except TypeError, inst:
1164 except TypeError, inst:
1162 # was this an argument error?
1165 # was this an argument error?
1163 tb = traceback.extract_tb(sys.exc_info()[2])
1166 tb = traceback.extract_tb(sys.exc_info()[2])
1164 if len(tb) > 2: # no
1167 if len(tb) > 2: # no
1165 raise
1168 raise
1166 u.debug(inst, "\n")
1169 u.debug(inst, "\n")
1167 u.warn("%s: invalid arguments\n" % cmd)
1170 u.warn("%s: invalid arguments\n" % cmd)
1168 help(u, cmd)
1171 help(u, cmd)
1169
1172
1170 sys.exit(-1)
1173 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now