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