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