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