##// END OF EJS Templates
hg clone: don't try to delete "."...
mpm@selenic.com -
r513:2ab152e4 default
parent child Browse files
Show More
@@ -1,897 +1,897 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 created = 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 cg = repo.getchangegroup(other)
304 cg = repo.getchangegroup(other)
305 repo.addchangegroup(cg)
305 repo.addchangegroup(cg)
306
306
307 f = repo.opener("hgrc", "w")
307 f = repo.opener("hgrc", "w")
308 f.write("[paths]\n")
308 f.write("[paths]\n")
309 f.write("default = %s\n" % source)
309 f.write("default = %s\n" % source)
310
310
311 if not opts['noupdate']:
311 if not opts['noupdate']:
312 update(ui, repo)
312 update(ui, repo)
313
313
314 success = True
314 success = True
315
315
316 finally:
316 finally:
317 if not success:
317 if created and not success:
318 import shutil
318 import shutil
319 shutil.rmtree(dest, True)
319 shutil.rmtree(dest, True)
320
320
321 def commit(ui, repo, *files, **opts):
321 def commit(ui, repo, *files, **opts):
322 """commit the specified files or all outstanding changes"""
322 """commit the specified files or all outstanding changes"""
323 text = opts['text']
323 text = opts['text']
324 if not text and opts['logfile']:
324 if not text and opts['logfile']:
325 try: text = open(opts['logfile']).read()
325 try: text = open(opts['logfile']).read()
326 except IOError: pass
326 except IOError: pass
327
327
328 if opts['addremove']:
328 if opts['addremove']:
329 addremove(ui, repo, *files)
329 addremove(ui, repo, *files)
330 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
330 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
331
331
332 def copy(ui, repo, source, dest):
332 def copy(ui, repo, source, dest):
333 """mark a file as copied or renamed for the next commit"""
333 """mark a file as copied or renamed for the next commit"""
334 return repo.copy(*relpath(repo, (source, dest)))
334 return repo.copy(*relpath(repo, (source, dest)))
335
335
336 def debugcheckdirstate(ui, repo):
336 def debugcheckdirstate(ui, repo):
337 parent1, parent2 = repo.dirstate.parents()
337 parent1, parent2 = repo.dirstate.parents()
338 dc = repo.dirstate.dup()
338 dc = repo.dirstate.dup()
339 keys = dc.keys()
339 keys = dc.keys()
340 keys.sort()
340 keys.sort()
341 m1n = repo.changelog.read(parent1)[0]
341 m1n = repo.changelog.read(parent1)[0]
342 m2n = repo.changelog.read(parent2)[0]
342 m2n = repo.changelog.read(parent2)[0]
343 m1 = repo.manifest.read(m1n)
343 m1 = repo.manifest.read(m1n)
344 m2 = repo.manifest.read(m2n)
344 m2 = repo.manifest.read(m2n)
345 errors = 0
345 errors = 0
346 for f in dc:
346 for f in dc:
347 state = repo.dirstate.state(f)
347 state = repo.dirstate.state(f)
348 if state in "nr" and f not in m1:
348 if state in "nr" and f not in m1:
349 print "%s in state %s, but not listed in manifest1" % (f, state)
349 print "%s in state %s, but not listed in manifest1" % (f, state)
350 errors += 1
350 errors += 1
351 if state in "a" and f in m1:
351 if state in "a" and f in m1:
352 print "%s in state %s, but also listed in manifest1" % (f, state)
352 print "%s in state %s, but also listed in manifest1" % (f, state)
353 errors += 1
353 errors += 1
354 if state in "m" and f not in m1 and f not in m2:
354 if state in "m" and f not in m1 and f not in m2:
355 print "%s in state %s, but not listed in either manifest" % (f, state)
355 print "%s in state %s, but not listed in either manifest" % (f, state)
356 errors += 1
356 errors += 1
357 for f in m1:
357 for f in m1:
358 state = repo.dirstate.state(f)
358 state = repo.dirstate.state(f)
359 if state not in "nrm":
359 if state not in "nrm":
360 print "%s in manifest1, but listed as state %s" % (f, state)
360 print "%s in manifest1, but listed as state %s" % (f, state)
361 errors += 1
361 errors += 1
362 if errors:
362 if errors:
363 print ".hg/dirstate inconsistent with current parent's manifest, aborting"
363 print ".hg/dirstate inconsistent with current parent's manifest, aborting"
364 sys.exit(1)
364 sys.exit(1)
365
365
366 def debugdumpdirstate(ui, repo):
366 def debugdumpdirstate(ui, repo):
367 dc = repo.dirstate.dup()
367 dc = repo.dirstate.dup()
368 keys = dc.keys()
368 keys = dc.keys()
369 keys.sort()
369 keys.sort()
370 for file in keys:
370 for file in keys:
371 print "%s => %c" % (file, dc[file][0])
371 print "%s => %c" % (file, dc[file][0])
372
372
373 def debugindex(ui, file):
373 def debugindex(ui, file):
374 r = hg.revlog(hg.opener(""), file, "")
374 r = hg.revlog(hg.opener(""), file, "")
375 print " rev offset length base linkrev"+\
375 print " rev offset length base linkrev"+\
376 " p1 p2 nodeid"
376 " p1 p2 nodeid"
377 for i in range(r.count()):
377 for i in range(r.count()):
378 e = r.index[i]
378 e = r.index[i]
379 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
379 print "% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s.." % (
380 i, e[0], e[1], e[2], e[3],
380 i, e[0], e[1], e[2], e[3],
381 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
381 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5]))
382
382
383 def debugindexdot(ui, file):
383 def debugindexdot(ui, file):
384 r = hg.revlog(hg.opener(""), file, "")
384 r = hg.revlog(hg.opener(""), file, "")
385 print "digraph G {"
385 print "digraph G {"
386 for i in range(r.count()):
386 for i in range(r.count()):
387 e = r.index[i]
387 e = r.index[i]
388 print "\t%d -> %d" % (r.rev(e[4]), i)
388 print "\t%d -> %d" % (r.rev(e[4]), i)
389 if e[5] != hg.nullid:
389 if e[5] != hg.nullid:
390 print "\t%d -> %d" % (r.rev(e[5]), i)
390 print "\t%d -> %d" % (r.rev(e[5]), i)
391 print "}"
391 print "}"
392
392
393 def diff(ui, repo, *files, **opts):
393 def diff(ui, repo, *files, **opts):
394 """diff working directory (or selected files)"""
394 """diff working directory (or selected files)"""
395 revs = []
395 revs = []
396 if opts['rev']:
396 if opts['rev']:
397 revs = map(lambda x: repo.lookup(x), opts['rev'])
397 revs = map(lambda x: repo.lookup(x), opts['rev'])
398
398
399 if len(revs) > 2:
399 if len(revs) > 2:
400 ui.warn("too many revisions to diff\n")
400 ui.warn("too many revisions to diff\n")
401 sys.exit(1)
401 sys.exit(1)
402
402
403 if files:
403 if files:
404 files = relpath(repo, files)
404 files = relpath(repo, files)
405 else:
405 else:
406 files = relpath(repo, [""])
406 files = relpath(repo, [""])
407
407
408 dodiff(ui, repo, os.getcwd(), files, *revs)
408 dodiff(ui, repo, os.getcwd(), files, *revs)
409
409
410 def export(ui, repo, changeset):
410 def export(ui, repo, changeset):
411 """dump the changeset header and diffs for a revision"""
411 """dump the changeset header and diffs for a revision"""
412 node = repo.lookup(changeset)
412 node = repo.lookup(changeset)
413 prev, other = repo.changelog.parents(node)
413 prev, other = repo.changelog.parents(node)
414 change = repo.changelog.read(node)
414 change = repo.changelog.read(node)
415 print "# HG changeset patch"
415 print "# HG changeset patch"
416 print "# User %s" % change[1]
416 print "# User %s" % change[1]
417 print "# Node ID %s" % hg.hex(node)
417 print "# Node ID %s" % hg.hex(node)
418 print "# Parent %s" % hg.hex(prev)
418 print "# Parent %s" % hg.hex(prev)
419 print
419 print
420 if other != hg.nullid:
420 if other != hg.nullid:
421 print "# Parent %s" % hg.hex(other)
421 print "# Parent %s" % hg.hex(other)
422 print change[4].rstrip()
422 print change[4].rstrip()
423 print
423 print
424
424
425 dodiff(ui, repo, "", None, prev, node)
425 dodiff(ui, repo, "", None, prev, node)
426
426
427 def forget(ui, repo, file, *files):
427 def forget(ui, repo, file, *files):
428 """don't add the specified files on the next commit"""
428 """don't add the specified files on the next commit"""
429 repo.forget(relpath(repo, (file,) + files))
429 repo.forget(relpath(repo, (file,) + files))
430
430
431 def heads(ui, repo):
431 def heads(ui, repo):
432 """show current repository heads"""
432 """show current repository heads"""
433 for n in repo.changelog.heads():
433 for n in repo.changelog.heads():
434 show_changeset(ui, repo, changenode=n)
434 show_changeset(ui, repo, changenode=n)
435
435
436 def identify(ui, repo):
436 def identify(ui, repo):
437 """print information about the working copy"""
437 """print information about the working copy"""
438 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
438 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
439 if not parents:
439 if not parents:
440 ui.write("unknown\n")
440 ui.write("unknown\n")
441 return
441 return
442
442
443 hexfunc = ui.verbose and hg.hex or hg.short
443 hexfunc = ui.verbose and hg.hex or hg.short
444 (c, a, d, u) = repo.diffdir(repo.root)
444 (c, a, d, u) = repo.diffdir(repo.root)
445 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
445 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
446 (c or a or d) and "+" or "")]
446 (c or a or d) and "+" or "")]
447
447
448 if not ui.quiet:
448 if not ui.quiet:
449 # multiple tags for a single parent separated by '/'
449 # multiple tags for a single parent separated by '/'
450 parenttags = ['/'.join(tags)
450 parenttags = ['/'.join(tags)
451 for tags in map(repo.nodetags, parents) if tags]
451 for tags in map(repo.nodetags, parents) if tags]
452 # tags for multiple parents separated by ' + '
452 # tags for multiple parents separated by ' + '
453 output.append(' + '.join(parenttags))
453 output.append(' + '.join(parenttags))
454
454
455 ui.write("%s\n" % ' '.join(output))
455 ui.write("%s\n" % ' '.join(output))
456
456
457 def import_(ui, repo, patch1, *patches, **opts):
457 def import_(ui, repo, patch1, *patches, **opts):
458 """import an ordered set of patches"""
458 """import an ordered set of patches"""
459 try:
459 try:
460 import psyco
460 import psyco
461 psyco.full()
461 psyco.full()
462 except:
462 except:
463 pass
463 pass
464
464
465 patches = (patch1,) + patches
465 patches = (patch1,) + patches
466
466
467 d = opts["base"]
467 d = opts["base"]
468 strip = opts["strip"]
468 strip = opts["strip"]
469
469
470 for patch in patches:
470 for patch in patches:
471 ui.status("applying %s\n" % patch)
471 ui.status("applying %s\n" % patch)
472 pf = os.path.join(d, patch)
472 pf = os.path.join(d, patch)
473
473
474 text = ""
474 text = ""
475 for l in file(pf):
475 for l in file(pf):
476 if l[:4] == "--- ": break
476 if l[:4] == "--- ": break
477 text += l
477 text += l
478
478
479 # make sure text isn't empty
479 # make sure text isn't empty
480 if not text: text = "imported patch %s\n" % patch
480 if not text: text = "imported patch %s\n" % patch
481
481
482 f = os.popen("patch -p%d < %s" % (strip, pf))
482 f = os.popen("patch -p%d < %s" % (strip, pf))
483 files = []
483 files = []
484 for l in f.read().splitlines():
484 for l in f.read().splitlines():
485 l.rstrip('\r\n');
485 l.rstrip('\r\n');
486 ui.status("%s\n" % l)
486 ui.status("%s\n" % l)
487 if l[:14] == 'patching file ':
487 if l[:14] == 'patching file ':
488 pf = l[14:]
488 pf = l[14:]
489 if pf not in files:
489 if pf not in files:
490 files.append(pf)
490 files.append(pf)
491 patcherr = f.close()
491 patcherr = f.close()
492 if patcherr:
492 if patcherr:
493 sys.stderr.write("patch failed")
493 sys.stderr.write("patch failed")
494 sys.exit(1)
494 sys.exit(1)
495
495
496 if len(files) > 0:
496 if len(files) > 0:
497 addremove(ui, repo, *files)
497 addremove(ui, repo, *files)
498 repo.commit(files, text)
498 repo.commit(files, text)
499
499
500 def init(ui, source=None):
500 def init(ui, source=None):
501 """create a new repository in the current directory"""
501 """create a new repository in the current directory"""
502
502
503 if source:
503 if source:
504 ui.warn("no longer supported: use \"hg clone\" instead\n")
504 ui.warn("no longer supported: use \"hg clone\" instead\n")
505 sys.exit(1)
505 sys.exit(1)
506 repo = hg.repository(ui, ".", create=1)
506 repo = hg.repository(ui, ".", create=1)
507
507
508 def log(ui, repo, f = None):
508 def log(ui, repo, f = None):
509 """show the revision history of the repository or a single file"""
509 """show the revision history of the repository or a single file"""
510 if f:
510 if f:
511 f = relpath(repo, [f])[0]
511 f = relpath(repo, [f])[0]
512 r = repo.file(f)
512 r = repo.file(f)
513 for i in range(r.count() - 1, -1, -1):
513 for i in range(r.count() - 1, -1, -1):
514 show_changeset(ui, repo, filelog=r, rev=i)
514 show_changeset(ui, repo, filelog=r, rev=i)
515 else:
515 else:
516 for i in range(repo.changelog.count() - 1, -1, -1):
516 for i in range(repo.changelog.count() - 1, -1, -1):
517 show_changeset(ui, repo, rev=i)
517 show_changeset(ui, repo, rev=i)
518
518
519 def manifest(ui, repo, rev = []):
519 def manifest(ui, repo, rev = []):
520 """output the latest or given revision of the project manifest"""
520 """output the latest or given revision of the project manifest"""
521 n = repo.manifest.tip()
521 n = repo.manifest.tip()
522 if rev:
522 if rev:
523 n = repo.manifest.lookup(rev)
523 n = repo.manifest.lookup(rev)
524 m = repo.manifest.read(n)
524 m = repo.manifest.read(n)
525 mf = repo.manifest.readflags(n)
525 mf = repo.manifest.readflags(n)
526 files = m.keys()
526 files = m.keys()
527 files.sort()
527 files.sort()
528
528
529 for f in files:
529 for f in files:
530 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
530 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
531
531
532 def parents(ui, repo, node = None):
532 def parents(ui, repo, node = None):
533 '''show the parents of the current working dir'''
533 '''show the parents of the current working dir'''
534 if node:
534 if node:
535 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
535 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
536 else:
536 else:
537 p = repo.dirstate.parents()
537 p = repo.dirstate.parents()
538
538
539 for n in p:
539 for n in p:
540 if n != hg.nullid:
540 if n != hg.nullid:
541 show_changeset(ui, repo, changenode=n)
541 show_changeset(ui, repo, changenode=n)
542
542
543 def pull(ui, repo, source="default", **opts):
543 def pull(ui, repo, source="default", **opts):
544 """pull changes from the specified source"""
544 """pull changes from the specified source"""
545 source = ui.expandpath(source)
545 source = ui.expandpath(source)
546
546
547 ui.status('pulling from %s\n' % (source))
547 ui.status('pulling from %s\n' % (source))
548
548
549 other = hg.repository(ui, source)
549 other = hg.repository(ui, source)
550 cg = repo.getchangegroup(other)
550 cg = repo.getchangegroup(other)
551 r = repo.addchangegroup(cg)
551 r = repo.addchangegroup(cg)
552 if cg and not r:
552 if cg and not r:
553 if opts['update']:
553 if opts['update']:
554 return update(ui, repo)
554 return update(ui, repo)
555 else:
555 else:
556 ui.status("(run 'hg update' to get a working copy)\n")
556 ui.status("(run 'hg update' to get a working copy)\n")
557
557
558 return r
558 return r
559
559
560 def push(ui, repo, dest="default-push"):
560 def push(ui, repo, dest="default-push"):
561 """push changes to the specified destination"""
561 """push changes to the specified destination"""
562 dest = ui.expandpath(dest)
562 dest = ui.expandpath(dest)
563
563
564 if not dest.startswith("ssh://"):
564 if not dest.startswith("ssh://"):
565 ui.warn("abort: can only push to ssh:// destinations currently\n")
565 ui.warn("abort: can only push to ssh:// destinations currently\n")
566 return 1
566 return 1
567
567
568 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
568 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
569 if not m:
569 if not m:
570 ui.warn("abort: couldn't parse destination %s\n" % dest)
570 ui.warn("abort: couldn't parse destination %s\n" % dest)
571 return 1
571 return 1
572
572
573 user, host, port, path = map(m.group, (2, 3, 5, 7))
573 user, host, port, path = map(m.group, (2, 3, 5, 7))
574 host = user and ("%s@%s" % (user, host)) or host
574 host = user and ("%s@%s" % (user, host)) or host
575 port = port and (" -p %s") % port or ""
575 port = port and (" -p %s") % port or ""
576 path = path or ""
576 path = path or ""
577
577
578 sport = random.randrange(30000, 60000)
578 sport = random.randrange(30000, 60000)
579 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
579 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
580 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
580 cmd = cmd % (host, port, sport+1, sport, path, sport+1)
581
581
582 child = os.fork()
582 child = os.fork()
583 if not child:
583 if not child:
584 sys.stdout = file("/dev/null", "w")
584 sys.stdout = file("/dev/null", "w")
585 sys.stderr = sys.stdout
585 sys.stderr = sys.stdout
586 hgweb.server(repo.root, "pull", "", "localhost", sport)
586 hgweb.server(repo.root, "pull", "", "localhost", sport)
587 else:
587 else:
588 r = os.system(cmd)
588 r = os.system(cmd)
589 os.kill(child, signal.SIGTERM)
589 os.kill(child, signal.SIGTERM)
590 return r
590 return r
591
591
592 def rawcommit(ui, repo, *flist, **rc):
592 def rawcommit(ui, repo, *flist, **rc):
593 "raw commit interface"
593 "raw commit interface"
594
594
595 text = rc['text']
595 text = rc['text']
596 if not text and rc['logfile']:
596 if not text and rc['logfile']:
597 try: text = open(rc['logfile']).read()
597 try: text = open(rc['logfile']).read()
598 except IOError: pass
598 except IOError: pass
599 if not text and not rc['logfile']:
599 if not text and not rc['logfile']:
600 print "missing commit text"
600 print "missing commit text"
601 return 1
601 return 1
602
602
603 files = relpath(repo, list(flist))
603 files = relpath(repo, list(flist))
604 if rc['files']:
604 if rc['files']:
605 files += open(rc['files']).read().splitlines()
605 files += open(rc['files']).read().splitlines()
606
606
607 rc['parent'] = map(repo.lookup, rc['parent'])
607 rc['parent'] = map(repo.lookup, rc['parent'])
608
608
609 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
609 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
610
610
611 def recover(ui, repo):
611 def recover(ui, repo):
612 """roll back an interrupted transaction"""
612 """roll back an interrupted transaction"""
613 repo.recover()
613 repo.recover()
614
614
615 def remove(ui, repo, file, *files):
615 def remove(ui, repo, file, *files):
616 """remove the specified files on the next commit"""
616 """remove the specified files on the next commit"""
617 repo.remove(relpath(repo, (file,) + files))
617 repo.remove(relpath(repo, (file,) + files))
618
618
619 def root(ui, repo):
619 def root(ui, repo):
620 """print the root (top) of the current working dir"""
620 """print the root (top) of the current working dir"""
621 ui.write(repo.root + "\n")
621 ui.write(repo.root + "\n")
622
622
623 def serve(ui, repo, **opts):
623 def serve(ui, repo, **opts):
624 """export the repository via HTTP"""
624 """export the repository via HTTP"""
625 hgweb.server(repo.root, opts["name"], opts["templates"],
625 hgweb.server(repo.root, opts["name"], opts["templates"],
626 opts["address"], opts["port"])
626 opts["address"], opts["port"])
627
627
628 def status(ui, repo):
628 def status(ui, repo):
629 '''show changed files in the working directory
629 '''show changed files in the working directory
630
630
631 C = changed
631 C = changed
632 A = added
632 A = added
633 R = removed
633 R = removed
634 ? = not tracked'''
634 ? = not tracked'''
635
635
636 (c, a, d, u) = repo.diffdir(os.getcwd())
636 (c, a, d, u) = repo.diffdir(os.getcwd())
637 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
637 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
638
638
639 for f in c: print "C", f
639 for f in c: print "C", f
640 for f in a: print "A", f
640 for f in a: print "A", f
641 for f in d: print "R", f
641 for f in d: print "R", f
642 for f in u: print "?", f
642 for f in u: print "?", f
643
643
644 def tag(ui, repo, name, rev = None, **opts):
644 def tag(ui, repo, name, rev = None, **opts):
645 """add a tag for the current tip or a given revision"""
645 """add a tag for the current tip or a given revision"""
646
646
647 if name == "tip":
647 if name == "tip":
648 ui.warn("abort: 'tip' is a reserved name!\n")
648 ui.warn("abort: 'tip' is a reserved name!\n")
649 return -1
649 return -1
650
650
651 (c, a, d, u) = repo.diffdir(repo.root)
651 (c, a, d, u) = repo.diffdir(repo.root)
652 for x in (c, a, d, u):
652 for x in (c, a, d, u):
653 if ".hgtags" in x:
653 if ".hgtags" in x:
654 ui.warn("abort: working copy of .hgtags is changed!\n")
654 ui.warn("abort: working copy of .hgtags is changed!\n")
655 ui.status("(please commit .hgtags manually)\n")
655 ui.status("(please commit .hgtags manually)\n")
656 return -1
656 return -1
657
657
658 if rev:
658 if rev:
659 r = hg.hex(repo.lookup(rev))
659 r = hg.hex(repo.lookup(rev))
660 else:
660 else:
661 r = hg.hex(repo.changelog.tip())
661 r = hg.hex(repo.changelog.tip())
662
662
663 add = 0
663 add = 0
664 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
664 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
665 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
665 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
666 if add: repo.add([".hgtags"])
666 if add: repo.add([".hgtags"])
667
667
668 if not opts['text']:
668 if not opts['text']:
669 opts['text'] = "Added tag %s for changeset %s" % (name, r)
669 opts['text'] = "Added tag %s for changeset %s" % (name, r)
670
670
671 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
671 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
672
672
673 def tags(ui, repo):
673 def tags(ui, repo):
674 """list repository tags"""
674 """list repository tags"""
675
675
676 l = repo.tagslist()
676 l = repo.tagslist()
677 l.reverse()
677 l.reverse()
678 for t, n in l:
678 for t, n in l:
679 try:
679 try:
680 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
680 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
681 except KeyError:
681 except KeyError:
682 r = " ?:?"
682 r = " ?:?"
683 ui.write("%-30s %s\n" % (t, r))
683 ui.write("%-30s %s\n" % (t, r))
684
684
685 def tip(ui, repo):
685 def tip(ui, repo):
686 """show the tip revision"""
686 """show the tip revision"""
687 n = repo.changelog.tip()
687 n = repo.changelog.tip()
688 show_changeset(ui, repo, changenode=n)
688 show_changeset(ui, repo, changenode=n)
689
689
690 def undo(ui, repo):
690 def undo(ui, repo):
691 """undo the last transaction"""
691 """undo the last transaction"""
692 repo.undo()
692 repo.undo()
693
693
694 def update(ui, repo, node=None, merge=False, clean=False):
694 def update(ui, repo, node=None, merge=False, clean=False):
695 '''update or merge working directory
695 '''update or merge working directory
696
696
697 If there are no outstanding changes in the working directory and
697 If there are no outstanding changes in the working directory and
698 there is a linear relationship between the current version and the
698 there is a linear relationship between the current version and the
699 requested version, the result is the requested version.
699 requested version, the result is the requested version.
700
700
701 Otherwise the result is a merge between the contents of the
701 Otherwise the result is a merge between the contents of the
702 current working directory and the requested version. Files that
702 current working directory and the requested version. Files that
703 changed between either parent are marked as changed for the next
703 changed between either parent are marked as changed for the next
704 commit and a commit must be performed before any further updates
704 commit and a commit must be performed before any further updates
705 are allowed.
705 are allowed.
706 '''
706 '''
707 node = node and repo.lookup(node) or repo.changelog.tip()
707 node = node and repo.lookup(node) or repo.changelog.tip()
708 return repo.update(node, allow=merge, force=clean)
708 return repo.update(node, allow=merge, force=clean)
709
709
710 def verify(ui, repo):
710 def verify(ui, repo):
711 """verify the integrity of the repository"""
711 """verify the integrity of the repository"""
712 return repo.verify()
712 return repo.verify()
713
713
714 # Command options and aliases are listed here, alphabetically
714 # Command options and aliases are listed here, alphabetically
715
715
716 table = {
716 table = {
717 "add": (add, [], "hg add [files]"),
717 "add": (add, [], "hg add [files]"),
718 "addremove": (addremove, [], "hg addremove [files]"),
718 "addremove": (addremove, [], "hg addremove [files]"),
719 "annotate": (annotate,
719 "annotate": (annotate,
720 [('r', 'revision', '', 'revision'),
720 [('r', 'revision', '', 'revision'),
721 ('u', 'user', None, 'show user'),
721 ('u', 'user', None, 'show user'),
722 ('n', 'number', None, 'show revision number'),
722 ('n', 'number', None, 'show revision number'),
723 ('c', 'changeset', None, 'show changeset')],
723 ('c', 'changeset', None, 'show changeset')],
724 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
724 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
725 "cat": (cat, [], 'hg cat <file> [rev]'),
725 "cat": (cat, [], 'hg cat <file> [rev]'),
726 "clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
726 "clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
727 'hg clone [options] <source> [dest]'),
727 'hg clone [options] <source> [dest]'),
728 "commit|ci": (commit,
728 "commit|ci": (commit,
729 [('t', 'text', "", 'commit text'),
729 [('t', 'text', "", 'commit text'),
730 ('A', 'addremove', None, 'run add/remove during commit'),
730 ('A', 'addremove', None, 'run add/remove during commit'),
731 ('l', 'logfile', "", 'commit text file'),
731 ('l', 'logfile', "", 'commit text file'),
732 ('d', 'date', "", 'data'),
732 ('d', 'date', "", 'data'),
733 ('u', 'user', "", 'user')],
733 ('u', 'user', "", 'user')],
734 'hg commit [files]'),
734 'hg commit [files]'),
735 "copy": (copy, [], 'hg copy <source> <dest>'),
735 "copy": (copy, [], 'hg copy <source> <dest>'),
736 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
736 "debugcheckdirstate": (debugcheckdirstate, [], 'debugcheckdirstate'),
737 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
737 "debugdumpdirstate": (debugdumpdirstate, [], 'debugdumpdirstate'),
738 "debugindex": (debugindex, [], 'debugindex <file>'),
738 "debugindex": (debugindex, [], 'debugindex <file>'),
739 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
739 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
740 "diff": (diff, [('r', 'rev', [], 'revision')],
740 "diff": (diff, [('r', 'rev', [], 'revision')],
741 'hg diff [-r A] [-r B] [files]'),
741 'hg diff [-r A] [-r B] [files]'),
742 "export": (export, [], "hg export <changeset>"),
742 "export": (export, [], "hg export <changeset>"),
743 "forget": (forget, [], "hg forget [files]"),
743 "forget": (forget, [], "hg forget [files]"),
744 "heads": (heads, [], 'hg heads'),
744 "heads": (heads, [], 'hg heads'),
745 "help": (help, [], 'hg help [command]'),
745 "help": (help, [], 'hg help [command]'),
746 "identify|id": (identify, [], 'hg identify'),
746 "identify|id": (identify, [], 'hg identify'),
747 "import|patch": (import_,
747 "import|patch": (import_,
748 [('p', 'strip', 1, 'path strip'),
748 [('p', 'strip', 1, 'path strip'),
749 ('b', 'base', "", 'base path')],
749 ('b', 'base', "", 'base path')],
750 "hg import [options] <patches>"),
750 "hg import [options] <patches>"),
751 "init": (init, [], 'hg init'),
751 "init": (init, [], 'hg init'),
752 "log|history": (log, [], 'hg log [file]'),
752 "log|history": (log, [], 'hg log [file]'),
753 "manifest": (manifest, [], 'hg manifest [rev]'),
753 "manifest": (manifest, [], 'hg manifest [rev]'),
754 "parents": (parents, [], 'hg parents [node]'),
754 "parents": (parents, [], 'hg parents [node]'),
755 "pull": (pull,
755 "pull": (pull,
756 [('u', 'update', None, 'update working directory')],
756 [('u', 'update', None, 'update working directory')],
757 'hg pull [options] [source]'),
757 'hg pull [options] [source]'),
758 "push": (push, [], 'hg push <destination>'),
758 "push": (push, [], 'hg push <destination>'),
759 "rawcommit": (rawcommit,
759 "rawcommit": (rawcommit,
760 [('p', 'parent', [], 'parent'),
760 [('p', 'parent', [], 'parent'),
761 ('d', 'date', "", 'data'),
761 ('d', 'date', "", 'data'),
762 ('u', 'user', "", 'user'),
762 ('u', 'user', "", 'user'),
763 ('F', 'files', "", 'file list'),
763 ('F', 'files', "", 'file list'),
764 ('t', 'text', "", 'commit text'),
764 ('t', 'text', "", 'commit text'),
765 ('l', 'logfile', "", 'commit text file')],
765 ('l', 'logfile', "", 'commit text file')],
766 'hg rawcommit [options] [files]'),
766 'hg rawcommit [options] [files]'),
767 "recover": (recover, [], "hg recover"),
767 "recover": (recover, [], "hg recover"),
768 "remove|rm": (remove, [], "hg remove [files]"),
768 "remove|rm": (remove, [], "hg remove [files]"),
769 "root": (root, [], "hg root"),
769 "root": (root, [], "hg root"),
770 "serve": (serve, [('p', 'port', 8000, 'listen port'),
770 "serve": (serve, [('p', 'port', 8000, 'listen port'),
771 ('a', 'address', '', 'interface address'),
771 ('a', 'address', '', 'interface address'),
772 ('n', 'name', os.getcwd(), 'repository name'),
772 ('n', 'name', os.getcwd(), 'repository name'),
773 ('t', 'templates', "", 'template map')],
773 ('t', 'templates', "", 'template map')],
774 "hg serve [options]"),
774 "hg serve [options]"),
775 "status": (status, [], 'hg status'),
775 "status": (status, [], 'hg status'),
776 "tag": (tag, [('t', 'text', "", 'commit text'),
776 "tag": (tag, [('t', 'text', "", 'commit text'),
777 ('d', 'date', "", 'date'),
777 ('d', 'date', "", 'date'),
778 ('u', 'user', "", 'user')],
778 ('u', 'user', "", 'user')],
779 'hg tag [options] <name> [rev]'),
779 'hg tag [options] <name> [rev]'),
780 "tags": (tags, [], 'hg tags'),
780 "tags": (tags, [], 'hg tags'),
781 "tip": (tip, [], 'hg tip'),
781 "tip": (tip, [], 'hg tip'),
782 "undo": (undo, [], 'hg undo'),
782 "undo": (undo, [], 'hg undo'),
783 "update|up|checkout|co":
783 "update|up|checkout|co":
784 (update,
784 (update,
785 [('m', 'merge', None, 'allow merging of conflicts'),
785 [('m', 'merge', None, 'allow merging of conflicts'),
786 ('C', 'clean', None, 'overwrite locally modified files')],
786 ('C', 'clean', None, 'overwrite locally modified files')],
787 'hg update [options] [node]'),
787 'hg update [options] [node]'),
788 "verify": (verify, [], 'hg verify'),
788 "verify": (verify, [], 'hg verify'),
789 "version": (show_version, [], 'hg version'),
789 "version": (show_version, [], 'hg version'),
790 }
790 }
791
791
792 norepo = "clone init version help debugindex debugindexdot"
792 norepo = "clone init version help debugindex debugindexdot"
793
793
794 def find(cmd):
794 def find(cmd):
795 for e in table.keys():
795 for e in table.keys():
796 if re.match("(%s)$" % e, cmd):
796 if re.match("(%s)$" % e, cmd):
797 return table[e]
797 return table[e]
798
798
799 raise UnknownCommand(cmd)
799 raise UnknownCommand(cmd)
800
800
801 class SignalInterrupt(Exception): pass
801 class SignalInterrupt(Exception): pass
802
802
803 def catchterm(*args):
803 def catchterm(*args):
804 raise SignalInterrupt
804 raise SignalInterrupt
805
805
806 def run():
806 def run():
807 sys.exit(dispatch(sys.argv[1:]))
807 sys.exit(dispatch(sys.argv[1:]))
808
808
809 def dispatch(args):
809 def dispatch(args):
810 options = {}
810 options = {}
811 opts = [('v', 'verbose', None, 'verbose'),
811 opts = [('v', 'verbose', None, 'verbose'),
812 ('d', 'debug', None, 'debug'),
812 ('d', 'debug', None, 'debug'),
813 ('q', 'quiet', None, 'quiet'),
813 ('q', 'quiet', None, 'quiet'),
814 ('p', 'profile', None, 'profile'),
814 ('p', 'profile', None, 'profile'),
815 ('y', 'noninteractive', None, 'run non-interactively'),
815 ('y', 'noninteractive', None, 'run non-interactively'),
816 ('', 'version', None, 'output version information and exit'),
816 ('', 'version', None, 'output version information and exit'),
817 ]
817 ]
818
818
819 args = fancyopts.fancyopts(args, opts, options,
819 args = fancyopts.fancyopts(args, opts, options,
820 'hg [options] <command> [options] [files]')
820 'hg [options] <command> [options] [files]')
821
821
822 if not args:
822 if not args:
823 cmd = "help"
823 cmd = "help"
824 else:
824 else:
825 cmd, args = args[0], args[1:]
825 cmd, args = args[0], args[1:]
826
826
827 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
827 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
828 not options["noninteractive"])
828 not options["noninteractive"])
829
829
830 if options["version"]:
830 if options["version"]:
831 show_version(u)
831 show_version(u)
832 sys.exit(0)
832 sys.exit(0)
833
833
834 try:
834 try:
835 i = find(cmd)
835 i = find(cmd)
836 except UnknownCommand:
836 except UnknownCommand:
837 u.warn("hg: unknown command '%s'\n" % cmd)
837 u.warn("hg: unknown command '%s'\n" % cmd)
838 help(u)
838 help(u)
839 sys.exit(1)
839 sys.exit(1)
840
840
841 signal.signal(signal.SIGTERM, catchterm)
841 signal.signal(signal.SIGTERM, catchterm)
842
842
843 cmdoptions = {}
843 cmdoptions = {}
844 try:
844 try:
845 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
845 args = fancyopts.fancyopts(args, i[1], cmdoptions, i[2])
846 except fancyopts.getopt.GetoptError, inst:
846 except fancyopts.getopt.GetoptError, inst:
847 u.warn("hg %s: %s\n" % (cmd, inst))
847 u.warn("hg %s: %s\n" % (cmd, inst))
848 help(u, cmd)
848 help(u, cmd)
849 sys.exit(-1)
849 sys.exit(-1)
850
850
851 try:
851 try:
852 if cmd not in norepo.split():
852 if cmd not in norepo.split():
853 repo = hg.repository(ui = u)
853 repo = hg.repository(ui = u)
854 d = lambda: i[0](u, repo, *args, **cmdoptions)
854 d = lambda: i[0](u, repo, *args, **cmdoptions)
855 else:
855 else:
856 d = lambda: i[0](u, *args, **cmdoptions)
856 d = lambda: i[0](u, *args, **cmdoptions)
857
857
858 if options['profile']:
858 if options['profile']:
859 import hotshot, hotshot.stats
859 import hotshot, hotshot.stats
860 prof = hotshot.Profile("hg.prof")
860 prof = hotshot.Profile("hg.prof")
861 r = prof.runcall(d)
861 r = prof.runcall(d)
862 prof.close()
862 prof.close()
863 stats = hotshot.stats.load("hg.prof")
863 stats = hotshot.stats.load("hg.prof")
864 stats.strip_dirs()
864 stats.strip_dirs()
865 stats.sort_stats('time', 'calls')
865 stats.sort_stats('time', 'calls')
866 stats.print_stats(40)
866 stats.print_stats(40)
867 return r
867 return r
868 else:
868 else:
869 return d()
869 return d()
870 except util.CommandError, inst:
870 except util.CommandError, inst:
871 u.warn("abort: %s\n" % inst.args)
871 u.warn("abort: %s\n" % inst.args)
872 except hg.RepoError, inst:
872 except hg.RepoError, inst:
873 u.warn("abort: ", inst, "!\n")
873 u.warn("abort: ", inst, "!\n")
874 except SignalInterrupt:
874 except SignalInterrupt:
875 u.warn("killed!\n")
875 u.warn("killed!\n")
876 except KeyboardInterrupt:
876 except KeyboardInterrupt:
877 u.warn("interrupted!\n")
877 u.warn("interrupted!\n")
878 except IOError, inst:
878 except IOError, inst:
879 if hasattr(inst, "code"):
879 if hasattr(inst, "code"):
880 u.warn("abort: %s\n" % inst)
880 u.warn("abort: %s\n" % inst)
881 elif hasattr(inst, "reason"):
881 elif hasattr(inst, "reason"):
882 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
882 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
883 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
883 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
884 u.warn("broken pipe\n")
884 u.warn("broken pipe\n")
885 else:
885 else:
886 raise
886 raise
887 except TypeError, inst:
887 except TypeError, inst:
888 # was this an argument error?
888 # was this an argument error?
889 tb = traceback.extract_tb(sys.exc_info()[2])
889 tb = traceback.extract_tb(sys.exc_info()[2])
890 if len(tb) > 2: # no
890 if len(tb) > 2: # no
891 raise
891 raise
892 u.debug(inst, "\n")
892 u.debug(inst, "\n")
893 u.warn("%s: invalid arguments\n" % i[0].__name__)
893 u.warn("%s: invalid arguments\n" % i[0].__name__)
894 help(u, cmd)
894 help(u, cmd)
895
895
896 sys.exit(-1)
896 sys.exit(-1)
897
897
General Comments 0
You need to be logged in to leave comments. Login now