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