##// END OF EJS Templates
Output file of 'export' is opened as binary (other OS)...
thananck@yahoo.com -
r615:ad2999fa default
parent child Browse files
Show More
@@ -1,1185 +1,1185 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 from demandload import *
8 from demandload import *
9 demandload(globals(), "os re sys signal")
9 demandload(globals(), "os re sys signal")
10 demandload(globals(), "fancyopts ui hg util")
10 demandload(globals(), "fancyopts ui hg util")
11 demandload(globals(), "hgweb mdiff random signal time traceback")
11 demandload(globals(), "hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version")
12 demandload(globals(), "errno socket version")
13
13
14 class UnknownCommand(Exception): pass
14 class UnknownCommand(Exception): pass
15
15
16 def filterfiles(filters, files):
16 def filterfiles(filters, files):
17 l = [ x for x in files if x in filters ]
17 l = [ x for x in files if x in filters ]
18
18
19 for t in filters:
19 for t in filters:
20 if t and t[-1] != "/": t += "/"
20 if t and t[-1] != "/": t += "/"
21 l += [ x for x in files if x.startswith(t) ]
21 l += [ x for x in files if x.startswith(t) ]
22 return l
22 return l
23
23
24 def relfilter(repo, files):
24 def relfilter(repo, files):
25 if os.getcwd() != repo.root:
25 if os.getcwd() != repo.root:
26 p = os.getcwd()[len(repo.root) + 1: ]
26 p = os.getcwd()[len(repo.root) + 1: ]
27 return filterfiles([util.pconvert(p)], files)
27 return filterfiles([util.pconvert(p)], files)
28 return files
28 return files
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 if os.getcwd() != repo.root:
31 if os.getcwd() != repo.root:
32 p = os.getcwd()[len(repo.root) + 1: ]
32 p = os.getcwd()[len(repo.root) + 1: ]
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
33 return [ util.pconvert(os.path.normpath(os.path.join(p, x)))
34 for x in args ]
34 for x in args ]
35 return args
35 return args
36
36
37 revrangesep = ':'
37 revrangesep = ':'
38
38
39 def revrange(ui, repo, revs = [], revlog = None):
39 def revrange(ui, repo, revs = [], revlog = None):
40 if revlog is None:
40 if revlog is None:
41 revlog = repo.changelog
41 revlog = repo.changelog
42 revcount = revlog.count()
42 revcount = revlog.count()
43 def fix(val, defval):
43 def fix(val, defval):
44 if not val: return defval
44 if not val: return defval
45 try:
45 try:
46 num = int(val)
46 num = int(val)
47 if str(num) != val: raise ValueError
47 if str(num) != val: raise ValueError
48 if num < 0: num += revcount
48 if num < 0: num += revcount
49 if not (0 <= num < revcount):
49 if not (0 <= num < revcount):
50 raise ValueError
50 raise ValueError
51 except ValueError:
51 except ValueError:
52 try:
52 try:
53 num = repo.changelog.rev(repo.lookup(val))
53 num = repo.changelog.rev(repo.lookup(val))
54 except KeyError:
54 except KeyError:
55 try:
55 try:
56 num = revlog.rev(revlog.lookup(val))
56 num = revlog.rev(revlog.lookup(val))
57 except KeyError:
57 except KeyError:
58 ui.warn('abort: invalid revision identifier %s\n' % val)
58 ui.warn('abort: invalid revision identifier %s\n' % val)
59 sys.exit(1)
59 sys.exit(1)
60 return num
60 return num
61 for spec in revs:
61 for spec in revs:
62 if spec.find(revrangesep) >= 0:
62 if spec.find(revrangesep) >= 0:
63 start, end = spec.split(revrangesep, 1)
63 start, end = spec.split(revrangesep, 1)
64 start = fix(start, 0)
64 start = fix(start, 0)
65 end = fix(end, revcount - 1)
65 end = fix(end, revcount - 1)
66 if end > start:
66 if end > start:
67 end += 1
67 end += 1
68 step = 1
68 step = 1
69 else:
69 else:
70 end -= 1
70 end -= 1
71 step = -1
71 step = -1
72 for rev in xrange(start, end, step):
72 for rev in xrange(start, end, step):
73 yield str(rev)
73 yield str(rev)
74 else:
74 else:
75 yield spec
75 yield spec
76
76
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
77 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
78 def date(c):
78 def date(c):
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
79 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
80
80
81 (c, a, d, u) = repo.changes(node1, node2, files)
81 (c, a, d, u) = repo.changes(node1, node2, files)
82 if files:
82 if files:
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
83 c, a, d = map(lambda x: filterfiles(files, x), (c, a, d))
84
84
85 if not c and not a and not d:
85 if not c and not a and not d:
86 return
86 return
87
87
88 if node2:
88 if node2:
89 change = repo.changelog.read(node2)
89 change = repo.changelog.read(node2)
90 mmap2 = repo.manifest.read(change[0])
90 mmap2 = repo.manifest.read(change[0])
91 def read(f): return repo.file(f).read(mmap2[f])
91 def read(f): return repo.file(f).read(mmap2[f])
92 date2 = date(change)
92 date2 = date(change)
93 else:
93 else:
94 date2 = time.asctime()
94 date2 = time.asctime()
95 if not node1:
95 if not node1:
96 node1 = repo.dirstate.parents()[0]
96 node1 = repo.dirstate.parents()[0]
97 def read(f): return repo.wfile(f).read()
97 def read(f): return repo.wfile(f).read()
98
98
99 if ui.quiet:
99 if ui.quiet:
100 r = None
100 r = None
101 else:
101 else:
102 hexfunc = ui.verbose and hg.hex or hg.short
102 hexfunc = ui.verbose and hg.hex or hg.short
103 r = [hexfunc(node) for node in [node1, node2] if node]
103 r = [hexfunc(node) for node in [node1, node2] if node]
104
104
105 change = repo.changelog.read(node1)
105 change = repo.changelog.read(node1)
106 mmap = repo.manifest.read(change[0])
106 mmap = repo.manifest.read(change[0])
107 date1 = date(change)
107 date1 = date(change)
108
108
109 for f in c:
109 for f in c:
110 to = None
110 to = None
111 if f in mmap:
111 if f in mmap:
112 to = repo.file(f).read(mmap[f])
112 to = repo.file(f).read(mmap[f])
113 tn = read(f)
113 tn = read(f)
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
114 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
115 for f in a:
115 for f in a:
116 to = None
116 to = None
117 tn = read(f)
117 tn = read(f)
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
118 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
119 for f in d:
119 for f in d:
120 to = repo.file(f).read(mmap[f])
120 to = repo.file(f).read(mmap[f])
121 tn = None
121 tn = None
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
122 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
123
123
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
124 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
125 """show a single changeset or file revision"""
125 """show a single changeset or file revision"""
126 changelog = repo.changelog
126 changelog = repo.changelog
127 if filelog:
127 if filelog:
128 log = filelog
128 log = filelog
129 filerev = rev
129 filerev = rev
130 node = filenode = filelog.node(filerev)
130 node = filenode = filelog.node(filerev)
131 changerev = filelog.linkrev(filenode)
131 changerev = filelog.linkrev(filenode)
132 changenode = changenode or changelog.node(changerev)
132 changenode = changenode or changelog.node(changerev)
133 else:
133 else:
134 log = changelog
134 log = changelog
135 changerev = rev
135 changerev = rev
136 if changenode is None:
136 if changenode is None:
137 changenode = changelog.node(changerev)
137 changenode = changelog.node(changerev)
138 elif not changerev:
138 elif not changerev:
139 rev = changerev = changelog.rev(changenode)
139 rev = changerev = changelog.rev(changenode)
140 node = changenode
140 node = changenode
141
141
142 if ui.quiet:
142 if ui.quiet:
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
143 ui.write("%d:%s\n" % (rev, hg.hex(node)))
144 return
144 return
145
145
146 changes = changelog.read(changenode)
146 changes = changelog.read(changenode)
147
147
148 parents = [(log.rev(parent), hg.hex(parent))
148 parents = [(log.rev(parent), hg.hex(parent))
149 for parent in log.parents(node)
149 for parent in log.parents(node)
150 if ui.debugflag or parent != hg.nullid]
150 if ui.debugflag or parent != hg.nullid]
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
151 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
152 parents = []
152 parents = []
153
153
154 if filelog:
154 if filelog:
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
155 ui.write("revision: %d:%s\n" % (filerev, hg.hex(filenode)))
156 for parent in parents:
156 for parent in parents:
157 ui.write("parent: %d:%s\n" % parent)
157 ui.write("parent: %d:%s\n" % parent)
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
158 ui.status("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
159 else:
159 else:
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
160 ui.write("changeset: %d:%s\n" % (changerev, hg.hex(changenode)))
161 for tag in repo.nodetags(changenode):
161 for tag in repo.nodetags(changenode):
162 ui.status("tag: %s\n" % tag)
162 ui.status("tag: %s\n" % tag)
163 for parent in parents:
163 for parent in parents:
164 ui.write("parent: %d:%s\n" % parent)
164 ui.write("parent: %d:%s\n" % parent)
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
165 ui.note("manifest: %d:%s\n" % (repo.manifest.rev(changes[0]),
166 hg.hex(changes[0])))
166 hg.hex(changes[0])))
167 ui.status("user: %s\n" % changes[1])
167 ui.status("user: %s\n" % changes[1])
168 ui.status("date: %s\n" % time.asctime(
168 ui.status("date: %s\n" % time.asctime(
169 time.localtime(float(changes[2].split(' ')[0]))))
169 time.localtime(float(changes[2].split(' ')[0]))))
170 if ui.debugflag:
170 if ui.debugflag:
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
171 files = repo.changes(changelog.parents(changenode)[0], changenode)
172 for key, value in zip(["files:", "files+:", "files-:"], files):
172 for key, value in zip(["files:", "files+:", "files-:"], files):
173 if value:
173 if value:
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
174 ui.note("%-12s %s\n" % (key, " ".join(value)))
175 else:
175 else:
176 ui.note("files: %s\n" % " ".join(changes[3]))
176 ui.note("files: %s\n" % " ".join(changes[3]))
177 description = changes[4].strip()
177 description = changes[4].strip()
178 if description:
178 if description:
179 if ui.verbose:
179 if ui.verbose:
180 ui.status("description:\n")
180 ui.status("description:\n")
181 ui.status(description)
181 ui.status(description)
182 ui.status("\n\n")
182 ui.status("\n\n")
183 else:
183 else:
184 ui.status("summary: %s\n" % description.splitlines()[0])
184 ui.status("summary: %s\n" % description.splitlines()[0])
185 ui.status("\n")
185 ui.status("\n")
186
186
187 def show_version(ui):
187 def show_version(ui):
188 """output version and copyright information"""
188 """output version and copyright information"""
189 ui.write("Mercurial version %s\n" % version.get_version())
189 ui.write("Mercurial version %s\n" % version.get_version())
190 ui.status(
190 ui.status(
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
191 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
192 "This is free software; see the source for copying conditions. "
192 "This is free software; see the source for copying conditions. "
193 "There is NO\nwarranty; "
193 "There is NO\nwarranty; "
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
194 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
195 )
195 )
196
196
197 def help(ui, cmd=None):
197 def help(ui, cmd=None):
198 '''show help for a given command or all commands'''
198 '''show help for a given command or all commands'''
199 if cmd:
199 if cmd:
200 try:
200 try:
201 i = find(cmd)
201 i = find(cmd)
202 ui.write("%s\n\n" % i[2])
202 ui.write("%s\n\n" % i[2])
203
203
204 if i[1]:
204 if i[1]:
205 for s, l, d, c in i[1]:
205 for s, l, d, c in i[1]:
206 opt=' '
206 opt=' '
207 if s: opt = opt + '-' + s + ' '
207 if s: opt = opt + '-' + s + ' '
208 if l: opt = opt + '--' + l + ' '
208 if l: opt = opt + '--' + l + ' '
209 if d: opt = opt + '(' + str(d) + ')'
209 if d: opt = opt + '(' + str(d) + ')'
210 ui.write(opt, "\n")
210 ui.write(opt, "\n")
211 if c: ui.write(' %s\n' % c)
211 if c: ui.write(' %s\n' % c)
212 ui.write("\n")
212 ui.write("\n")
213
213
214 ui.write(i[0].__doc__, "\n")
214 ui.write(i[0].__doc__, "\n")
215 except UnknownCommand:
215 except UnknownCommand:
216 ui.warn("hg: unknown command %s\n" % cmd)
216 ui.warn("hg: unknown command %s\n" % cmd)
217 sys.exit(0)
217 sys.exit(0)
218 else:
218 else:
219 if ui.verbose:
219 if ui.verbose:
220 show_version(ui)
220 show_version(ui)
221 ui.write('\n')
221 ui.write('\n')
222 if ui.verbose:
222 if ui.verbose:
223 ui.write('hg commands:\n\n')
223 ui.write('hg commands:\n\n')
224 else:
224 else:
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
225 ui.write('basic hg commands (use "hg help -v" for more):\n\n')
226
226
227 h = {}
227 h = {}
228 for c, e in table.items():
228 for c, e in table.items():
229 f = c.split("|")[0]
229 f = c.split("|")[0]
230 if not ui.verbose and not f.startswith("^"):
230 if not ui.verbose and not f.startswith("^"):
231 continue
231 continue
232 if not ui.debugflag and f.startswith("debug"):
232 if not ui.debugflag and f.startswith("debug"):
233 continue
233 continue
234 f = f.lstrip("^")
234 f = f.lstrip("^")
235 d = ""
235 d = ""
236 if e[0].__doc__:
236 if e[0].__doc__:
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
237 d = e[0].__doc__.splitlines(0)[0].rstrip()
238 h[f] = d
238 h[f] = d
239
239
240 fns = h.keys()
240 fns = h.keys()
241 fns.sort()
241 fns.sort()
242 m = max(map(len, fns))
242 m = max(map(len, fns))
243 for f in fns:
243 for f in fns:
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
244 ui.write(' %-*s %s\n' % (m, f, h[f]))
245
245
246 # Commands start here, listed alphabetically
246 # Commands start here, listed alphabetically
247
247
248 def add(ui, repo, file, *files):
248 def add(ui, repo, file, *files):
249 '''add the specified files on the next commit'''
249 '''add the specified files on the next commit'''
250 repo.add(relpath(repo, (file,) + files))
250 repo.add(relpath(repo, (file,) + files))
251
251
252 def addremove(ui, repo, *files):
252 def addremove(ui, repo, *files):
253 """add all new files, delete all missing files"""
253 """add all new files, delete all missing files"""
254 if files:
254 if files:
255 files = relpath(repo, files)
255 files = relpath(repo, files)
256 d = []
256 d = []
257 u = []
257 u = []
258 for f in files:
258 for f in files:
259 p = repo.wjoin(f)
259 p = repo.wjoin(f)
260 s = repo.dirstate.state(f)
260 s = repo.dirstate.state(f)
261 isfile = os.path.isfile(p)
261 isfile = os.path.isfile(p)
262 if s != 'r' and not isfile:
262 if s != 'r' and not isfile:
263 d.append(f)
263 d.append(f)
264 elif s not in 'nmai' and isfile:
264 elif s not in 'nmai' and isfile:
265 u.append(f)
265 u.append(f)
266 else:
266 else:
267 (c, a, d, u) = repo.changes(None, None)
267 (c, a, d, u) = repo.changes(None, None)
268 repo.add(u)
268 repo.add(u)
269 repo.remove(d)
269 repo.remove(d)
270
270
271 def annotate(u, repo, file, *files, **ops):
271 def annotate(u, repo, file, *files, **ops):
272 """show changeset information per file line"""
272 """show changeset information per file line"""
273 def getnode(rev):
273 def getnode(rev):
274 return hg.short(repo.changelog.node(rev))
274 return hg.short(repo.changelog.node(rev))
275
275
276 def getname(rev):
276 def getname(rev):
277 try:
277 try:
278 return bcache[rev]
278 return bcache[rev]
279 except KeyError:
279 except KeyError:
280 cl = repo.changelog.read(repo.changelog.node(rev))
280 cl = repo.changelog.read(repo.changelog.node(rev))
281 name = cl[1]
281 name = cl[1]
282 f = name.find('@')
282 f = name.find('@')
283 if f >= 0:
283 if f >= 0:
284 name = name[:f]
284 name = name[:f]
285 f = name.find('<')
285 f = name.find('<')
286 if f >= 0:
286 if f >= 0:
287 name = name[f+1:]
287 name = name[f+1:]
288 bcache[rev] = name
288 bcache[rev] = name
289 return name
289 return name
290
290
291 bcache = {}
291 bcache = {}
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
292 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
293 if not ops['user'] and not ops['changeset']:
293 if not ops['user'] and not ops['changeset']:
294 ops['number'] = 1
294 ops['number'] = 1
295
295
296 node = repo.dirstate.parents()[0]
296 node = repo.dirstate.parents()[0]
297 if ops['revision']:
297 if ops['revision']:
298 node = repo.changelog.lookup(ops['revision'])
298 node = repo.changelog.lookup(ops['revision'])
299 change = repo.changelog.read(node)
299 change = repo.changelog.read(node)
300 mmap = repo.manifest.read(change[0])
300 mmap = repo.manifest.read(change[0])
301 for f in relpath(repo, (file,) + files):
301 for f in relpath(repo, (file,) + files):
302 lines = repo.file(f).annotate(mmap[f])
302 lines = repo.file(f).annotate(mmap[f])
303 pieces = []
303 pieces = []
304
304
305 for o, f in opmap:
305 for o, f in opmap:
306 if ops[o]:
306 if ops[o]:
307 l = [ f(n) for n,t in lines ]
307 l = [ f(n) for n,t in lines ]
308 m = max(map(len, l))
308 m = max(map(len, l))
309 pieces.append([ "%*s" % (m, x) for x in l])
309 pieces.append([ "%*s" % (m, x) for x in l])
310
310
311 for p,l in zip(zip(*pieces), lines):
311 for p,l in zip(zip(*pieces), lines):
312 u.write(" ".join(p) + ": " + l[1])
312 u.write(" ".join(p) + ": " + l[1])
313
313
314 def cat(ui, repo, file, rev = []):
314 def cat(ui, repo, file, rev = []):
315 """output the latest or given revision of a file"""
315 """output the latest or given revision of a file"""
316 r = repo.file(relpath(repo, [file])[0])
316 r = repo.file(relpath(repo, [file])[0])
317 n = r.tip()
317 n = r.tip()
318 if rev: n = r.lookup(rev)
318 if rev: n = r.lookup(rev)
319 sys.stdout.write(r.read(n))
319 sys.stdout.write(r.read(n))
320
320
321 def clone(ui, source, dest = None, **opts):
321 def clone(ui, source, dest = None, **opts):
322 """make a copy of an existing repository"""
322 """make a copy of an existing repository"""
323 source = ui.expandpath(source)
323 source = ui.expandpath(source)
324
324
325 if dest is None:
325 if dest is None:
326 dest = os.path.basename(os.path.normpath(source))
326 dest = os.path.basename(os.path.normpath(source))
327
327
328 if os.path.exists(dest):
328 if os.path.exists(dest):
329 ui.warn("abort: destination '%s' already exists\n" % dest)
329 ui.warn("abort: destination '%s' already exists\n" % dest)
330 return 1
330 return 1
331
331
332 class dircleanup:
332 class dircleanup:
333 def __init__(self, dir):
333 def __init__(self, dir):
334 self.dir = dir
334 self.dir = dir
335 os.mkdir(dir)
335 os.mkdir(dir)
336 def close(self):
336 def close(self):
337 self.dir = None
337 self.dir = None
338 def __del__(self):
338 def __del__(self):
339 if self.dir:
339 if self.dir:
340 import shutil
340 import shutil
341 shutil.rmtree(self.dir, True)
341 shutil.rmtree(self.dir, True)
342
342
343 d = dircleanup(dest)
343 d = dircleanup(dest)
344
344
345 link = 0
345 link = 0
346 abspath = source
346 abspath = source
347 if not (source.startswith("http://") or
347 if not (source.startswith("http://") or
348 source.startswith("hg://") or
348 source.startswith("hg://") or
349 source.startswith("old-http://")):
349 source.startswith("old-http://")):
350 abspath = os.path.abspath(source)
350 abspath = os.path.abspath(source)
351 d1 = os.stat(dest).st_dev
351 d1 = os.stat(dest).st_dev
352 d2 = os.stat(source).st_dev
352 d2 = os.stat(source).st_dev
353 if d1 == d2: link = 1
353 if d1 == d2: link = 1
354
354
355 if link:
355 if link:
356 ui.note("copying by hardlink\n")
356 ui.note("copying by hardlink\n")
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
357 util.system("cp -al '%s'/.hg '%s'/.hg" % (source, dest))
358 try:
358 try:
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
359 os.remove(os.path.join(dest, ".hg", "dirstate"))
360 except: pass
360 except: pass
361
361
362 repo = hg.repository(ui, dest)
362 repo = hg.repository(ui, dest)
363
363
364 else:
364 else:
365 repo = hg.repository(ui, dest, create=1)
365 repo = hg.repository(ui, dest, create=1)
366 other = hg.repository(ui, source)
366 other = hg.repository(ui, source)
367 fetch = repo.findincoming(other)
367 fetch = repo.findincoming(other)
368 if fetch:
368 if fetch:
369 cg = other.changegroup(fetch)
369 cg = other.changegroup(fetch)
370 repo.addchangegroup(cg)
370 repo.addchangegroup(cg)
371
371
372 f = repo.opener("hgrc", "w")
372 f = repo.opener("hgrc", "w")
373 f.write("[paths]\n")
373 f.write("[paths]\n")
374 f.write("default = %s\n" % abspath)
374 f.write("default = %s\n" % abspath)
375
375
376 if not opts['noupdate']:
376 if not opts['noupdate']:
377 update(ui, repo)
377 update(ui, repo)
378
378
379 d.close()
379 d.close()
380
380
381 def commit(ui, repo, *files, **opts):
381 def commit(ui, repo, *files, **opts):
382 """commit the specified files or all outstanding changes"""
382 """commit the specified files or all outstanding changes"""
383 text = opts['text']
383 text = opts['text']
384 if not text and opts['logfile']:
384 if not text and opts['logfile']:
385 try: text = open(opts['logfile']).read()
385 try: text = open(opts['logfile']).read()
386 except IOError: pass
386 except IOError: pass
387
387
388 if opts['addremove']:
388 if opts['addremove']:
389 addremove(ui, repo, *files)
389 addremove(ui, repo, *files)
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
390 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
391
391
392 def copy(ui, repo, source, dest):
392 def copy(ui, repo, source, dest):
393 """mark a file as copied or renamed for the next commit"""
393 """mark a file as copied or renamed for the next commit"""
394 return repo.copy(*relpath(repo, (source, dest)))
394 return repo.copy(*relpath(repo, (source, dest)))
395
395
396 def debugcheckstate(ui, repo):
396 def debugcheckstate(ui, repo):
397 """validate the correctness of the current dirstate"""
397 """validate the correctness of the current dirstate"""
398 parent1, parent2 = repo.dirstate.parents()
398 parent1, parent2 = repo.dirstate.parents()
399 repo.dirstate.read()
399 repo.dirstate.read()
400 dc = repo.dirstate.map
400 dc = repo.dirstate.map
401 keys = dc.keys()
401 keys = dc.keys()
402 keys.sort()
402 keys.sort()
403 m1n = repo.changelog.read(parent1)[0]
403 m1n = repo.changelog.read(parent1)[0]
404 m2n = repo.changelog.read(parent2)[0]
404 m2n = repo.changelog.read(parent2)[0]
405 m1 = repo.manifest.read(m1n)
405 m1 = repo.manifest.read(m1n)
406 m2 = repo.manifest.read(m2n)
406 m2 = repo.manifest.read(m2n)
407 errors = 0
407 errors = 0
408 for f in dc:
408 for f in dc:
409 state = repo.dirstate.state(f)
409 state = repo.dirstate.state(f)
410 if state in "nr" and f not in m1:
410 if state in "nr" and f not in m1:
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
411 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
412 errors += 1
412 errors += 1
413 if state in "a" and f in m1:
413 if state in "a" and f in m1:
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
414 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
415 errors += 1
415 errors += 1
416 if state in "m" and f not in m1 and f not in m2:
416 if state in "m" and f not in m1 and f not in m2:
417 ui.warn("%s in state %s, but not in either manifest\n" %
417 ui.warn("%s in state %s, but not in either manifest\n" %
418 (f, state))
418 (f, state))
419 errors += 1
419 errors += 1
420 for f in m1:
420 for f in m1:
421 state = repo.dirstate.state(f)
421 state = repo.dirstate.state(f)
422 if state not in "nrm":
422 if state not in "nrm":
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
423 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
424 errors += 1
424 errors += 1
425 if errors:
425 if errors:
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
426 ui.warn(".hg/dirstate inconsistent with current parent's manifest\n")
427 sys.exit(1)
427 sys.exit(1)
428
428
429 def debugstate(ui, repo):
429 def debugstate(ui, repo):
430 """show the contents of the current dirstate"""
430 """show the contents of the current dirstate"""
431 repo.dirstate.read()
431 repo.dirstate.read()
432 dc = repo.dirstate.map
432 dc = repo.dirstate.map
433 keys = dc.keys()
433 keys = dc.keys()
434 keys.sort()
434 keys.sort()
435 for file in keys:
435 for file in keys:
436 ui.write("%c %s\n" % (dc[file][0], file))
436 ui.write("%c %s\n" % (dc[file][0], file))
437
437
438 def debugindex(ui, file):
438 def debugindex(ui, file):
439 """dump the contents of an index file"""
439 """dump the contents of an index file"""
440 r = hg.revlog(hg.opener(""), file, "")
440 r = hg.revlog(hg.opener(""), file, "")
441 ui.write(" rev offset length base linkrev" +
441 ui.write(" rev offset length base linkrev" +
442 " p1 p2 nodeid\n")
442 " p1 p2 nodeid\n")
443 for i in range(r.count()):
443 for i in range(r.count()):
444 e = r.index[i]
444 e = r.index[i]
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
445 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
446 i, e[0], e[1], e[2], e[3],
446 i, e[0], e[1], e[2], e[3],
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
447 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
448
448
449 def debugindexdot(ui, file):
449 def debugindexdot(ui, file):
450 """dump an index DAG as a .dot file"""
450 """dump an index DAG as a .dot file"""
451 r = hg.revlog(hg.opener(""), file, "")
451 r = hg.revlog(hg.opener(""), file, "")
452 ui.write("digraph G {\n")
452 ui.write("digraph G {\n")
453 for i in range(r.count()):
453 for i in range(r.count()):
454 e = r.index[i]
454 e = r.index[i]
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
455 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
456 if e[5] != hg.nullid:
456 if e[5] != hg.nullid:
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
457 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
458 ui.write("}\n")
458 ui.write("}\n")
459
459
460 def diff(ui, repo, *files, **opts):
460 def diff(ui, repo, *files, **opts):
461 """diff working directory (or selected files)"""
461 """diff working directory (or selected files)"""
462 revs = []
462 revs = []
463 if opts['rev']:
463 if opts['rev']:
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
464 revs = map(lambda x: repo.lookup(x), opts['rev'])
465
465
466 if len(revs) > 2:
466 if len(revs) > 2:
467 ui.warn("too many revisions to diff\n")
467 ui.warn("too many revisions to diff\n")
468 sys.exit(1)
468 sys.exit(1)
469
469
470 if files:
470 if files:
471 files = relpath(repo, files)
471 files = relpath(repo, files)
472 else:
472 else:
473 files = relpath(repo, [""])
473 files = relpath(repo, [""])
474
474
475 dodiff(sys.stdout, ui, repo, files, *revs)
475 dodiff(sys.stdout, ui, repo, files, *revs)
476
476
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
477 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
478 node = repo.lookup(changeset)
478 node = repo.lookup(changeset)
479 prev, other = repo.changelog.parents(node)
479 prev, other = repo.changelog.parents(node)
480 change = repo.changelog.read(node)
480 change = repo.changelog.read(node)
481
481
482 def expand(name):
482 def expand(name):
483 expansions = {
483 expansions = {
484 '%': lambda: '%',
484 '%': lambda: '%',
485 'H': lambda: hg.hex(node),
485 'H': lambda: hg.hex(node),
486 'N': lambda: str(total),
486 'N': lambda: str(total),
487 'R': lambda: str(repo.changelog.rev(node)),
487 'R': lambda: str(repo.changelog.rev(node)),
488 'b': lambda: os.path.basename(repo.root),
488 'b': lambda: os.path.basename(repo.root),
489 'h': lambda: hg.short(node),
489 'h': lambda: hg.short(node),
490 'n': lambda: str(seqno).zfill(len(str(total))),
490 'n': lambda: str(seqno).zfill(len(str(total))),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
491 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
492 }
492 }
493 newname = []
493 newname = []
494 namelen = len(name)
494 namelen = len(name)
495 i = 0
495 i = 0
496 while i < namelen:
496 while i < namelen:
497 c = name[i]
497 c = name[i]
498 if c == '%':
498 if c == '%':
499 i += 1
499 i += 1
500 c = name[i]
500 c = name[i]
501 c = expansions[c]()
501 c = expansions[c]()
502 newname.append(c)
502 newname.append(c)
503 i += 1
503 i += 1
504 return ''.join(newname)
504 return ''.join(newname)
505
505
506 if opts['output'] and opts['output'] != '-':
506 if opts['output'] and opts['output'] != '-':
507 try:
507 try:
508 fp = open(expand(opts['output']), 'w')
508 fp = open(expand(opts['output']), 'wb')
509 except KeyError, inst:
509 except KeyError, inst:
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
510 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
511 inst.args[0])
511 inst.args[0])
512 sys.exit(1)
512 sys.exit(1)
513 else:
513 else:
514 fp = sys.stdout
514 fp = sys.stdout
515
515
516 fp.write("# HG changeset patch\n")
516 fp.write("# HG changeset patch\n")
517 fp.write("# User %s\n" % change[1])
517 fp.write("# User %s\n" % change[1])
518 fp.write("# Node ID %s\n" % hg.hex(node))
518 fp.write("# Node ID %s\n" % hg.hex(node))
519 fp.write("# Parent %s\n" % hg.hex(prev))
519 fp.write("# Parent %s\n" % hg.hex(prev))
520 if other != hg.nullid:
520 if other != hg.nullid:
521 fp.write("# Parent %s\n" % hg.hex(other))
521 fp.write("# Parent %s\n" % hg.hex(other))
522 fp.write(change[4].rstrip())
522 fp.write(change[4].rstrip())
523 fp.write("\n\n")
523 fp.write("\n\n")
524
524
525 dodiff(fp, ui, repo, None, prev, node)
525 dodiff(fp, ui, repo, None, prev, node)
526
526
527 def export(ui, repo, *changesets, **opts):
527 def export(ui, repo, *changesets, **opts):
528 """dump the header and diffs for one or more changesets"""
528 """dump the header and diffs for one or more changesets"""
529 if not changesets:
529 if not changesets:
530 ui.warn("error: export requires at least one changeset\n")
530 ui.warn("error: export requires at least one changeset\n")
531 sys.exit(1)
531 sys.exit(1)
532 seqno = 0
532 seqno = 0
533 revs = list(revrange(ui, repo, changesets))
533 revs = list(revrange(ui, repo, changesets))
534 total = len(revs)
534 total = len(revs)
535 revwidth = max(len(revs[0]), len(revs[-1]))
535 revwidth = max(len(revs[0]), len(revs[-1]))
536 for cset in revs:
536 for cset in revs:
537 seqno += 1
537 seqno += 1
538 doexport(ui, repo, cset, seqno, total, revwidth, opts)
538 doexport(ui, repo, cset, seqno, total, revwidth, opts)
539
539
540 def forget(ui, repo, file, *files):
540 def forget(ui, repo, file, *files):
541 """don't add the specified files on the next commit"""
541 """don't add the specified files on the next commit"""
542 repo.forget(relpath(repo, (file,) + files))
542 repo.forget(relpath(repo, (file,) + files))
543
543
544 def heads(ui, repo):
544 def heads(ui, repo):
545 """show current repository heads"""
545 """show current repository heads"""
546 for n in repo.changelog.heads():
546 for n in repo.changelog.heads():
547 show_changeset(ui, repo, changenode=n)
547 show_changeset(ui, repo, changenode=n)
548
548
549 def identify(ui, repo):
549 def identify(ui, repo):
550 """print information about the working copy"""
550 """print information about the working copy"""
551 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
551 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
552 if not parents:
552 if not parents:
553 ui.write("unknown\n")
553 ui.write("unknown\n")
554 return
554 return
555
555
556 hexfunc = ui.verbose and hg.hex or hg.short
556 hexfunc = ui.verbose and hg.hex or hg.short
557 (c, a, d, u) = repo.changes(None, None)
557 (c, a, d, u) = repo.changes(None, None)
558 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
558 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
559 (c or a or d) and "+" or "")]
559 (c or a or d) and "+" or "")]
560
560
561 if not ui.quiet:
561 if not ui.quiet:
562 # multiple tags for a single parent separated by '/'
562 # multiple tags for a single parent separated by '/'
563 parenttags = ['/'.join(tags)
563 parenttags = ['/'.join(tags)
564 for tags in map(repo.nodetags, parents) if tags]
564 for tags in map(repo.nodetags, parents) if tags]
565 # tags for multiple parents separated by ' + '
565 # tags for multiple parents separated by ' + '
566 output.append(' + '.join(parenttags))
566 output.append(' + '.join(parenttags))
567
567
568 ui.write("%s\n" % ' '.join(output))
568 ui.write("%s\n" % ' '.join(output))
569
569
570 def import_(ui, repo, patch1, *patches, **opts):
570 def import_(ui, repo, patch1, *patches, **opts):
571 """import an ordered set of patches"""
571 """import an ordered set of patches"""
572 try:
572 try:
573 import psyco
573 import psyco
574 psyco.full()
574 psyco.full()
575 except:
575 except:
576 pass
576 pass
577
577
578 patches = (patch1,) + patches
578 patches = (patch1,) + patches
579
579
580 d = opts["base"]
580 d = opts["base"]
581 strip = opts["strip"]
581 strip = opts["strip"]
582
582
583 for patch in patches:
583 for patch in patches:
584 ui.status("applying %s\n" % patch)
584 ui.status("applying %s\n" % patch)
585 pf = os.path.join(d, patch)
585 pf = os.path.join(d, patch)
586
586
587 text = ""
587 text = ""
588 for l in file(pf):
588 for l in file(pf):
589 if l.startswith("--- ") or l.startswith("diff -r"): break
589 if l.startswith("--- ") or l.startswith("diff -r"): break
590 text += l
590 text += l
591
591
592 # parse values that exist when importing the result of an hg export
592 # parse values that exist when importing the result of an hg export
593 hgpatch = user = snippet = None
593 hgpatch = user = snippet = None
594 ui.debug('text:\n')
594 ui.debug('text:\n')
595 for t in text.splitlines():
595 for t in text.splitlines():
596 ui.debug(t,'\n')
596 ui.debug(t,'\n')
597 if t == '# HG changeset patch' or hgpatch == True:
597 if t == '# HG changeset patch' or hgpatch == True:
598 hgpatch = True
598 hgpatch = True
599 if t[:7] == "# User ":
599 if t[:7] == "# User ":
600 user = t[7:]
600 user = t[7:]
601 ui.debug('User: %s\n' % user)
601 ui.debug('User: %s\n' % user)
602 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
602 if t[:2] <> "# " and t.strip() and not snippet: snippet = t
603 if snippet: text = snippet + '\n' + text
603 if snippet: text = snippet + '\n' + text
604 ui.debug('text:\n%s\n' % text)
604 ui.debug('text:\n%s\n' % text)
605
605
606 # make sure text isn't empty
606 # make sure text isn't empty
607 if not text: text = "imported patch %s\n" % patch
607 if not text: text = "imported patch %s\n" % patch
608
608
609 f = os.popen("patch -p%d < %s" % (strip, pf))
609 f = os.popen("patch -p%d < %s" % (strip, pf))
610 files = []
610 files = []
611 for l in f.read().splitlines():
611 for l in f.read().splitlines():
612 l.rstrip('\r\n');
612 l.rstrip('\r\n');
613 ui.status("%s\n" % l)
613 ui.status("%s\n" % l)
614 if l[:14] == 'patching file ':
614 if l[:14] == 'patching file ':
615 pf = l[14:]
615 pf = l[14:]
616 if pf not in files:
616 if pf not in files:
617 files.append(pf)
617 files.append(pf)
618 patcherr = f.close()
618 patcherr = f.close()
619 if patcherr:
619 if patcherr:
620 sys.stderr.write("patch failed")
620 sys.stderr.write("patch failed")
621 sys.exit(1)
621 sys.exit(1)
622
622
623 if len(files) > 0:
623 if len(files) > 0:
624 addremove(ui, repo, *files)
624 addremove(ui, repo, *files)
625 repo.commit(files, text, user)
625 repo.commit(files, text, user)
626
626
627 def init(ui, source=None):
627 def init(ui, source=None):
628 """create a new repository in the current directory"""
628 """create a new repository in the current directory"""
629
629
630 if source:
630 if source:
631 ui.warn("no longer supported: use \"hg clone\" instead\n")
631 ui.warn("no longer supported: use \"hg clone\" instead\n")
632 sys.exit(1)
632 sys.exit(1)
633 repo = hg.repository(ui, ".", create=1)
633 repo = hg.repository(ui, ".", create=1)
634
634
635 def log(ui, repo, f=None, **opts):
635 def log(ui, repo, f=None, **opts):
636 """show the revision history of the repository or a single file"""
636 """show the revision history of the repository or a single file"""
637 if f:
637 if f:
638 files = relpath(repo, [f])
638 files = relpath(repo, [f])
639 filelog = repo.file(files[0])
639 filelog = repo.file(files[0])
640 log = filelog
640 log = filelog
641 lookup = filelog.lookup
641 lookup = filelog.lookup
642 else:
642 else:
643 files = None
643 files = None
644 filelog = None
644 filelog = None
645 log = repo.changelog
645 log = repo.changelog
646 lookup = repo.lookup
646 lookup = repo.lookup
647 revlist = []
647 revlist = []
648 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
648 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
649 while revs:
649 while revs:
650 if len(revs) == 1:
650 if len(revs) == 1:
651 revlist.append(revs.pop(0))
651 revlist.append(revs.pop(0))
652 else:
652 else:
653 a = revs.pop(0)
653 a = revs.pop(0)
654 b = revs.pop(0)
654 b = revs.pop(0)
655 off = a > b and -1 or 1
655 off = a > b and -1 or 1
656 revlist.extend(range(a, b + off, off))
656 revlist.extend(range(a, b + off, off))
657
657
658 for i in revlist or range(log.count() - 1, -1, -1):
658 for i in revlist or range(log.count() - 1, -1, -1):
659 show_changeset(ui, repo, filelog=filelog, rev=i)
659 show_changeset(ui, repo, filelog=filelog, rev=i)
660 if opts['patch']:
660 if opts['patch']:
661 if filelog:
661 if filelog:
662 filenode = filelog.node(i)
662 filenode = filelog.node(i)
663 i = filelog.linkrev(filenode)
663 i = filelog.linkrev(filenode)
664 changenode = repo.changelog.node(i)
664 changenode = repo.changelog.node(i)
665 prev, other = repo.changelog.parents(changenode)
665 prev, other = repo.changelog.parents(changenode)
666 dodiff(sys.stdout, ui, repo, files, prev, changenode)
666 dodiff(sys.stdout, ui, repo, files, prev, changenode)
667 ui.write("\n")
667 ui.write("\n")
668 ui.write("\n")
668 ui.write("\n")
669
669
670 def manifest(ui, repo, rev = []):
670 def manifest(ui, repo, rev = []):
671 """output the latest or given revision of the project manifest"""
671 """output the latest or given revision of the project manifest"""
672 n = repo.manifest.tip()
672 n = repo.manifest.tip()
673 if rev:
673 if rev:
674 n = repo.manifest.lookup(rev)
674 n = repo.manifest.lookup(rev)
675 m = repo.manifest.read(n)
675 m = repo.manifest.read(n)
676 mf = repo.manifest.readflags(n)
676 mf = repo.manifest.readflags(n)
677 files = m.keys()
677 files = m.keys()
678 files.sort()
678 files.sort()
679
679
680 for f in files:
680 for f in files:
681 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
681 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
682
682
683 def parents(ui, repo, node = None):
683 def parents(ui, repo, node = None):
684 '''show the parents of the current working dir'''
684 '''show the parents of the current working dir'''
685 if node:
685 if node:
686 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
686 p = repo.changelog.parents(repo.lookup(hg.bin(node)))
687 else:
687 else:
688 p = repo.dirstate.parents()
688 p = repo.dirstate.parents()
689
689
690 for n in p:
690 for n in p:
691 if n != hg.nullid:
691 if n != hg.nullid:
692 show_changeset(ui, repo, changenode=n)
692 show_changeset(ui, repo, changenode=n)
693
693
694 def pull(ui, repo, source="default", **opts):
694 def pull(ui, repo, source="default", **opts):
695 """pull changes from the specified source"""
695 """pull changes from the specified source"""
696 source = ui.expandpath(source)
696 source = ui.expandpath(source)
697
697
698 ui.status('pulling from %s\n' % (source))
698 ui.status('pulling from %s\n' % (source))
699
699
700 other = hg.repository(ui, source)
700 other = hg.repository(ui, source)
701 fetch = repo.findincoming(other)
701 fetch = repo.findincoming(other)
702 if not fetch:
702 if not fetch:
703 ui.status("no changes found\n")
703 ui.status("no changes found\n")
704 return
704 return
705
705
706 cg = other.changegroup(fetch)
706 cg = other.changegroup(fetch)
707 r = repo.addchangegroup(cg)
707 r = repo.addchangegroup(cg)
708 if cg and not r:
708 if cg and not r:
709 if opts['update']:
709 if opts['update']:
710 return update(ui, repo)
710 return update(ui, repo)
711 else:
711 else:
712 ui.status("(run 'hg update' to get a working copy)\n")
712 ui.status("(run 'hg update' to get a working copy)\n")
713
713
714 return r
714 return r
715
715
716 def push(ui, repo, dest="default-push"):
716 def push(ui, repo, dest="default-push"):
717 """push changes to the specified destination"""
717 """push changes to the specified destination"""
718 dest = ui.expandpath(dest)
718 dest = ui.expandpath(dest)
719
719
720 if not dest.startswith("ssh://"):
720 if not dest.startswith("ssh://"):
721 ui.warn("abort: can only push to ssh:// destinations currently\n")
721 ui.warn("abort: can only push to ssh:// destinations currently\n")
722 return 1
722 return 1
723
723
724 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
724 m = re.match(r'ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?', dest)
725 if not m:
725 if not m:
726 ui.warn("abort: couldn't parse destination %s\n" % dest)
726 ui.warn("abort: couldn't parse destination %s\n" % dest)
727 return 1
727 return 1
728
728
729 user, host, port, path = map(m.group, (2, 3, 5, 7))
729 user, host, port, path = map(m.group, (2, 3, 5, 7))
730 uhost = user and ("%s@%s" % (user, host)) or host
730 uhost = user and ("%s@%s" % (user, host)) or host
731 port = port and (" -p %s") % port or ""
731 port = port and (" -p %s") % port or ""
732 path = path or ""
732 path = path or ""
733
733
734 sport = random.randrange(30000, 60000)
734 sport = random.randrange(30000, 60000)
735 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
735 cmd = "ssh %s%s -R %d:localhost:%d 'cd %s; hg pull http://localhost:%d/'"
736 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
736 cmd = cmd % (uhost, port, sport+1, sport, path, sport+1)
737
737
738 child = os.fork()
738 child = os.fork()
739 if not child:
739 if not child:
740 sys.stdout = file("/dev/null", "w")
740 sys.stdout = file("/dev/null", "w")
741 sys.stderr = sys.stdout
741 sys.stderr = sys.stdout
742 hgweb.server(repo.root, "pull", "", "localhost", sport)
742 hgweb.server(repo.root, "pull", "", "localhost", sport)
743 else:
743 else:
744 ui.status("connecting to %s\n" % host)
744 ui.status("connecting to %s\n" % host)
745 r = os.system(cmd)
745 r = os.system(cmd)
746 os.kill(child, signal.SIGTERM)
746 os.kill(child, signal.SIGTERM)
747 return r
747 return r
748
748
749 def rawcommit(ui, repo, *flist, **rc):
749 def rawcommit(ui, repo, *flist, **rc):
750 "raw commit interface"
750 "raw commit interface"
751
751
752 text = rc['text']
752 text = rc['text']
753 if not text and rc['logfile']:
753 if not text and rc['logfile']:
754 try: text = open(rc['logfile']).read()
754 try: text = open(rc['logfile']).read()
755 except IOError: pass
755 except IOError: pass
756 if not text and not rc['logfile']:
756 if not text and not rc['logfile']:
757 ui.warn("abort: missing commit text\n")
757 ui.warn("abort: missing commit text\n")
758 return 1
758 return 1
759
759
760 files = relpath(repo, list(flist))
760 files = relpath(repo, list(flist))
761 if rc['files']:
761 if rc['files']:
762 files += open(rc['files']).read().splitlines()
762 files += open(rc['files']).read().splitlines()
763
763
764 rc['parent'] = map(repo.lookup, rc['parent'])
764 rc['parent'] = map(repo.lookup, rc['parent'])
765
765
766 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
766 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
767
767
768 def recover(ui, repo):
768 def recover(ui, repo):
769 """roll back an interrupted transaction"""
769 """roll back an interrupted transaction"""
770 repo.recover()
770 repo.recover()
771
771
772 def remove(ui, repo, file, *files):
772 def remove(ui, repo, file, *files):
773 """remove the specified files on the next commit"""
773 """remove the specified files on the next commit"""
774 repo.remove(relpath(repo, (file,) + files))
774 repo.remove(relpath(repo, (file,) + files))
775
775
776 def revert(ui, repo, *names, **opts):
776 def revert(ui, repo, *names, **opts):
777 """revert modified files or dirs back to their unmodified states"""
777 """revert modified files or dirs back to their unmodified states"""
778 node = opts['rev'] and repo.lookup(opts['rev']) or \
778 node = opts['rev'] and repo.lookup(opts['rev']) or \
779 repo.dirstate.parents()[0]
779 repo.dirstate.parents()[0]
780 root = os.path.realpath(repo.root)
780 root = os.path.realpath(repo.root)
781
781
782 def trimpath(p):
782 def trimpath(p):
783 p = os.path.realpath(p)
783 p = os.path.realpath(p)
784 if p.startswith(root):
784 if p.startswith(root):
785 rest = p[len(root):]
785 rest = p[len(root):]
786 if not rest:
786 if not rest:
787 return rest
787 return rest
788 if p.startswith(os.sep):
788 if p.startswith(os.sep):
789 return rest[1:]
789 return rest[1:]
790 return p
790 return p
791
791
792 relnames = map(trimpath, names or [os.getcwd()])
792 relnames = map(trimpath, names or [os.getcwd()])
793 chosen = {}
793 chosen = {}
794
794
795 def choose(name):
795 def choose(name):
796 def body(name):
796 def body(name):
797 for r in relnames:
797 for r in relnames:
798 if not name.startswith(r): continue
798 if not name.startswith(r): continue
799 rest = name[len(r):]
799 rest = name[len(r):]
800 if not rest: return r, True
800 if not rest: return r, True
801 depth = rest.count(os.sep)
801 depth = rest.count(os.sep)
802 if not r:
802 if not r:
803 if depth == 0 or not opts['nonrecursive']: return r, True
803 if depth == 0 or not opts['nonrecursive']: return r, True
804 elif rest[0] == os.sep:
804 elif rest[0] == os.sep:
805 if depth == 1 or not opts['nonrecursive']: return r, True
805 if depth == 1 or not opts['nonrecursive']: return r, True
806 return None, False
806 return None, False
807 relname, ret = body(name)
807 relname, ret = body(name)
808 if ret:
808 if ret:
809 chosen[relname] = 1
809 chosen[relname] = 1
810 return ret
810 return ret
811
811
812 r = repo.update(node, False, True, choose, False)
812 r = repo.update(node, False, True, choose, False)
813 for n in relnames:
813 for n in relnames:
814 if n not in chosen:
814 if n not in chosen:
815 ui.warn('error: no matches for %s\n' % n)
815 ui.warn('error: no matches for %s\n' % n)
816 r = 1
816 r = 1
817 sys.stdout.flush()
817 sys.stdout.flush()
818 return r
818 return r
819
819
820 def root(ui, repo):
820 def root(ui, repo):
821 """print the root (top) of the current working dir"""
821 """print the root (top) of the current working dir"""
822 ui.write(repo.root + "\n")
822 ui.write(repo.root + "\n")
823
823
824 def serve(ui, repo, **opts):
824 def serve(ui, repo, **opts):
825 """export the repository via HTTP"""
825 """export the repository via HTTP"""
826 def openlog(opt, default):
826 def openlog(opt, default):
827 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
827 if opts[opt] and opts[opt] != '-': return open(opts[opt], 'w')
828 else: return default
828 else: return default
829 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
829 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
830 opts["address"], opts["port"],
830 opts["address"], opts["port"],
831 openlog('accesslog', sys.stdout),
831 openlog('accesslog', sys.stdout),
832 openlog('errorlog', sys.stderr))
832 openlog('errorlog', sys.stderr))
833 if ui.verbose:
833 if ui.verbose:
834 addr, port = httpd.socket.getsockname()
834 addr, port = httpd.socket.getsockname()
835 if addr == '0.0.0.0':
835 if addr == '0.0.0.0':
836 addr = socket.gethostname()
836 addr = socket.gethostname()
837 else:
837 else:
838 try:
838 try:
839 addr = socket.gethostbyaddr(addr)[0]
839 addr = socket.gethostbyaddr(addr)[0]
840 except: pass
840 except: pass
841 if port != 80:
841 if port != 80:
842 ui.status('listening at http://%s:%d/\n' % (addr, port))
842 ui.status('listening at http://%s:%d/\n' % (addr, port))
843 else:
843 else:
844 ui.status('listening at http://%s/\n' % addr)
844 ui.status('listening at http://%s/\n' % addr)
845 httpd.serve_forever()
845 httpd.serve_forever()
846
846
847 def status(ui, repo):
847 def status(ui, repo):
848 '''show changed files in the working directory
848 '''show changed files in the working directory
849
849
850 C = changed
850 C = changed
851 A = added
851 A = added
852 R = removed
852 R = removed
853 ? = not tracked'''
853 ? = not tracked'''
854
854
855 (c, a, d, u) = repo.changes(None, None)
855 (c, a, d, u) = repo.changes(None, None)
856 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
856 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
857
857
858 for f in c: ui.write("C ", f, "\n")
858 for f in c: ui.write("C ", f, "\n")
859 for f in a: ui.write("A ", f, "\n")
859 for f in a: ui.write("A ", f, "\n")
860 for f in d: ui.write("R ", f, "\n")
860 for f in d: ui.write("R ", f, "\n")
861 for f in u: ui.write("? ", f, "\n")
861 for f in u: ui.write("? ", f, "\n")
862
862
863 def tag(ui, repo, name, rev = None, **opts):
863 def tag(ui, repo, name, rev = None, **opts):
864 """add a tag for the current tip or a given revision"""
864 """add a tag for the current tip or a given revision"""
865
865
866 if name == "tip":
866 if name == "tip":
867 ui.warn("abort: 'tip' is a reserved name!\n")
867 ui.warn("abort: 'tip' is a reserved name!\n")
868 return -1
868 return -1
869 if rev:
869 if rev:
870 r = hg.hex(repo.lookup(rev))
870 r = hg.hex(repo.lookup(rev))
871 else:
871 else:
872 r = hg.hex(repo.changelog.tip())
872 r = hg.hex(repo.changelog.tip())
873
873
874 if name.find(revrangesep) >= 0:
874 if name.find(revrangesep) >= 0:
875 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
875 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
876 return -1
876 return -1
877
877
878 if opts['local']:
878 if opts['local']:
879 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
879 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
880 return
880 return
881
881
882 (c, a, d, u) = repo.changes(None, None)
882 (c, a, d, u) = repo.changes(None, None)
883 for x in (c, a, d, u):
883 for x in (c, a, d, u):
884 if ".hgtags" in x:
884 if ".hgtags" in x:
885 ui.warn("abort: working copy of .hgtags is changed!\n")
885 ui.warn("abort: working copy of .hgtags is changed!\n")
886 ui.status("(please commit .hgtags manually)\n")
886 ui.status("(please commit .hgtags manually)\n")
887 return -1
887 return -1
888
888
889 add = 0
889 add = 0
890 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
890 if not os.path.exists(repo.wjoin(".hgtags")): add = 1
891 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
891 repo.wfile(".hgtags", "a").write("%s %s\n" % (r, name))
892 if add: repo.add([".hgtags"])
892 if add: repo.add([".hgtags"])
893
893
894 if not opts['text']:
894 if not opts['text']:
895 opts['text'] = "Added tag %s for changeset %s" % (name, r)
895 opts['text'] = "Added tag %s for changeset %s" % (name, r)
896
896
897 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
897 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
898
898
899 def tags(ui, repo):
899 def tags(ui, repo):
900 """list repository tags"""
900 """list repository tags"""
901
901
902 l = repo.tagslist()
902 l = repo.tagslist()
903 l.reverse()
903 l.reverse()
904 for t, n in l:
904 for t, n in l:
905 try:
905 try:
906 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
906 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
907 except KeyError:
907 except KeyError:
908 r = " ?:?"
908 r = " ?:?"
909 ui.write("%-30s %s\n" % (t, r))
909 ui.write("%-30s %s\n" % (t, r))
910
910
911 def tip(ui, repo):
911 def tip(ui, repo):
912 """show the tip revision"""
912 """show the tip revision"""
913 n = repo.changelog.tip()
913 n = repo.changelog.tip()
914 show_changeset(ui, repo, changenode=n)
914 show_changeset(ui, repo, changenode=n)
915
915
916 def undo(ui, repo):
916 def undo(ui, repo):
917 """undo the last commit or pull
917 """undo the last commit or pull
918
918
919 Roll back the last pull or commit transaction on the
919 Roll back the last pull or commit transaction on the
920 repository, restoring the project to its earlier state.
920 repository, restoring the project to its earlier state.
921
921
922 This command should be used with care. There is only one level of
922 This command should be used with care. There is only one level of
923 undo and there is no redo.
923 undo and there is no redo.
924
924
925 This command is not intended for use on public repositories. Once
925 This command is not intended for use on public repositories. Once
926 a change is visible for pull by other users, undoing it locally is
926 a change is visible for pull by other users, undoing it locally is
927 ineffective.
927 ineffective.
928 """
928 """
929 repo.undo()
929 repo.undo()
930
930
931 def update(ui, repo, node=None, merge=False, clean=False):
931 def update(ui, repo, node=None, merge=False, clean=False):
932 '''update or merge working directory
932 '''update or merge working directory
933
933
934 If there are no outstanding changes in the working directory and
934 If there are no outstanding changes in the working directory and
935 there is a linear relationship between the current version and the
935 there is a linear relationship between the current version and the
936 requested version, the result is the requested version.
936 requested version, the result is the requested version.
937
937
938 Otherwise the result is a merge between the contents of the
938 Otherwise the result is a merge between the contents of the
939 current working directory and the requested version. Files that
939 current working directory and the requested version. Files that
940 changed between either parent are marked as changed for the next
940 changed between either parent are marked as changed for the next
941 commit and a commit must be performed before any further updates
941 commit and a commit must be performed before any further updates
942 are allowed.
942 are allowed.
943 '''
943 '''
944 node = node and repo.lookup(node) or repo.changelog.tip()
944 node = node and repo.lookup(node) or repo.changelog.tip()
945 return repo.update(node, allow=merge, force=clean)
945 return repo.update(node, allow=merge, force=clean)
946
946
947 def verify(ui, repo):
947 def verify(ui, repo):
948 """verify the integrity of the repository"""
948 """verify the integrity of the repository"""
949 return repo.verify()
949 return repo.verify()
950
950
951 # Command options and aliases are listed here, alphabetically
951 # Command options and aliases are listed here, alphabetically
952
952
953 table = {
953 table = {
954 "^add": (add, [], "hg add [files]"),
954 "^add": (add, [], "hg add [files]"),
955 "addremove": (addremove, [], "hg addremove [files]"),
955 "addremove": (addremove, [], "hg addremove [files]"),
956 "^annotate": (annotate,
956 "^annotate": (annotate,
957 [('r', 'revision', '', 'revision'),
957 [('r', 'revision', '', 'revision'),
958 ('u', 'user', None, 'show user'),
958 ('u', 'user', None, 'show user'),
959 ('n', 'number', None, 'show revision number'),
959 ('n', 'number', None, 'show revision number'),
960 ('c', 'changeset', None, 'show changeset')],
960 ('c', 'changeset', None, 'show changeset')],
961 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
961 'hg annotate [-u] [-c] [-n] [-r id] [files]'),
962 "cat": (cat, [], 'hg cat <file> [rev]'),
962 "cat": (cat, [], 'hg cat <file> [rev]'),
963 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
963 "^clone": (clone, [('U', 'noupdate', None, 'skip update after cloning')],
964 'hg clone [options] <source> [dest]'),
964 'hg clone [options] <source> [dest]'),
965 "^commit|ci": (commit,
965 "^commit|ci": (commit,
966 [('t', 'text', "", 'commit text'),
966 [('t', 'text', "", 'commit text'),
967 ('A', 'addremove', None, 'run add/remove during commit'),
967 ('A', 'addremove', None, 'run add/remove during commit'),
968 ('l', 'logfile', "", 'commit text file'),
968 ('l', 'logfile', "", 'commit text file'),
969 ('d', 'date', "", 'date code'),
969 ('d', 'date', "", 'date code'),
970 ('u', 'user', "", 'user')],
970 ('u', 'user', "", 'user')],
971 'hg commit [files]'),
971 'hg commit [files]'),
972 "copy": (copy, [], 'hg copy <source> <dest>'),
972 "copy": (copy, [], 'hg copy <source> <dest>'),
973 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
973 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
974 "debugstate": (debugstate, [], 'debugstate'),
974 "debugstate": (debugstate, [], 'debugstate'),
975 "debugindex": (debugindex, [], 'debugindex <file>'),
975 "debugindex": (debugindex, [], 'debugindex <file>'),
976 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
976 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
977 "^diff": (diff, [('r', 'rev', [], 'revision')],
977 "^diff": (diff, [('r', 'rev', [], 'revision')],
978 'hg diff [-r A] [-r B] [files]'),
978 'hg diff [-r A] [-r B] [files]'),
979 "^export": (export, [('o', 'output', "", 'output to file')],
979 "^export": (export, [('o', 'output', "", 'output to file')],
980 "hg export [-o file] <changeset> ..."),
980 "hg export [-o file] <changeset> ..."),
981 "forget": (forget, [], "hg forget [files]"),
981 "forget": (forget, [], "hg forget [files]"),
982 "heads": (heads, [], 'hg heads'),
982 "heads": (heads, [], 'hg heads'),
983 "help": (help, [], 'hg help [command]'),
983 "help": (help, [], 'hg help [command]'),
984 "identify|id": (identify, [], 'hg identify'),
984 "identify|id": (identify, [], 'hg identify'),
985 "import|patch": (import_,
985 "import|patch": (import_,
986 [('p', 'strip', 1, 'path strip'),
986 [('p', 'strip', 1, 'path strip'),
987 ('b', 'base', "", 'base path')],
987 ('b', 'base', "", 'base path')],
988 "hg import [options] <patches>"),
988 "hg import [options] <patches>"),
989 "^init": (init, [], 'hg init'),
989 "^init": (init, [], 'hg init'),
990 "^log|history": (log,
990 "^log|history": (log,
991 [('r', 'rev', [], 'revision'),
991 [('r', 'rev', [], 'revision'),
992 ('p', 'patch', None, 'show patch')],
992 ('p', 'patch', None, 'show patch')],
993 'hg log [-r A] [-r B] [-p] [file]'),
993 'hg log [-r A] [-r B] [-p] [file]'),
994 "manifest": (manifest, [], 'hg manifest [rev]'),
994 "manifest": (manifest, [], 'hg manifest [rev]'),
995 "parents": (parents, [], 'hg parents [node]'),
995 "parents": (parents, [], 'hg parents [node]'),
996 "^pull": (pull,
996 "^pull": (pull,
997 [('u', 'update', None, 'update working directory')],
997 [('u', 'update', None, 'update working directory')],
998 'hg pull [options] [source]'),
998 'hg pull [options] [source]'),
999 "^push": (push, [], 'hg push <destination>'),
999 "^push": (push, [], 'hg push <destination>'),
1000 "rawcommit": (rawcommit,
1000 "rawcommit": (rawcommit,
1001 [('p', 'parent', [], 'parent'),
1001 [('p', 'parent', [], 'parent'),
1002 ('d', 'date', "", 'date code'),
1002 ('d', 'date', "", 'date code'),
1003 ('u', 'user', "", 'user'),
1003 ('u', 'user', "", 'user'),
1004 ('F', 'files', "", 'file list'),
1004 ('F', 'files', "", 'file list'),
1005 ('t', 'text', "", 'commit text'),
1005 ('t', 'text', "", 'commit text'),
1006 ('l', 'logfile', "", 'commit text file')],
1006 ('l', 'logfile', "", 'commit text file')],
1007 'hg rawcommit [options] [files]'),
1007 'hg rawcommit [options] [files]'),
1008 "recover": (recover, [], "hg recover"),
1008 "recover": (recover, [], "hg recover"),
1009 "^remove|rm": (remove, [], "hg remove [files]"),
1009 "^remove|rm": (remove, [], "hg remove [files]"),
1010 "^revert": (revert,
1010 "^revert": (revert,
1011 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1011 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1012 ("r", "rev", "", "revision")],
1012 ("r", "rev", "", "revision")],
1013 "hg revert [files|dirs]"),
1013 "hg revert [files|dirs]"),
1014 "root": (root, [], "hg root"),
1014 "root": (root, [], "hg root"),
1015 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1015 "^serve": (serve, [('A', 'accesslog', '', 'access log file'),
1016 ('E', 'errorlog', '', 'error log file'),
1016 ('E', 'errorlog', '', 'error log file'),
1017 ('p', 'port', 8000, 'listen port'),
1017 ('p', 'port', 8000, 'listen port'),
1018 ('a', 'address', '', 'interface address'),
1018 ('a', 'address', '', 'interface address'),
1019 ('n', 'name', os.getcwd(), 'repository name'),
1019 ('n', 'name', os.getcwd(), 'repository name'),
1020 ('t', 'templates', "", 'template map')],
1020 ('t', 'templates', "", 'template map')],
1021 "hg serve [options]"),
1021 "hg serve [options]"),
1022 "^status": (status, [], 'hg status'),
1022 "^status": (status, [], 'hg status'),
1023 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1023 "tag": (tag, [('l', 'local', None, 'make the tag local'),
1024 ('t', 'text', "", 'commit text'),
1024 ('t', 'text', "", 'commit text'),
1025 ('d', 'date', "", 'date code'),
1025 ('d', 'date', "", 'date code'),
1026 ('u', 'user', "", 'user')],
1026 ('u', 'user', "", 'user')],
1027 'hg tag [options] <name> [rev]'),
1027 'hg tag [options] <name> [rev]'),
1028 "tags": (tags, [], 'hg tags'),
1028 "tags": (tags, [], 'hg tags'),
1029 "tip": (tip, [], 'hg tip'),
1029 "tip": (tip, [], 'hg tip'),
1030 "undo": (undo, [], 'hg undo'),
1030 "undo": (undo, [], 'hg undo'),
1031 "^update|up|checkout|co":
1031 "^update|up|checkout|co":
1032 (update,
1032 (update,
1033 [('m', 'merge', None, 'allow merging of conflicts'),
1033 [('m', 'merge', None, 'allow merging of conflicts'),
1034 ('C', 'clean', None, 'overwrite locally modified files')],
1034 ('C', 'clean', None, 'overwrite locally modified files')],
1035 'hg update [options] [node]'),
1035 'hg update [options] [node]'),
1036 "verify": (verify, [], 'hg verify'),
1036 "verify": (verify, [], 'hg verify'),
1037 "version": (show_version, [], 'hg version'),
1037 "version": (show_version, [], 'hg version'),
1038 }
1038 }
1039
1039
1040 globalopts = [('v', 'verbose', None, 'verbose'),
1040 globalopts = [('v', 'verbose', None, 'verbose'),
1041 ('', 'debug', None, 'debug'),
1041 ('', 'debug', None, 'debug'),
1042 ('q', 'quiet', None, 'quiet'),
1042 ('q', 'quiet', None, 'quiet'),
1043 ('', 'profile', None, 'profile'),
1043 ('', 'profile', None, 'profile'),
1044 ('R', 'repository', "", 'repository root directory'),
1044 ('R', 'repository', "", 'repository root directory'),
1045 ('', 'traceback', None, 'print traceback on exception'),
1045 ('', 'traceback', None, 'print traceback on exception'),
1046 ('y', 'noninteractive', None, 'run non-interactively'),
1046 ('y', 'noninteractive', None, 'run non-interactively'),
1047 ('', 'version', None, 'output version information and exit'),
1047 ('', 'version', None, 'output version information and exit'),
1048 ]
1048 ]
1049
1049
1050 norepo = "clone init version help debugindex debugindexdot"
1050 norepo = "clone init version help debugindex debugindexdot"
1051
1051
1052 def find(cmd):
1052 def find(cmd):
1053 for e in table.keys():
1053 for e in table.keys():
1054 if re.match("(%s)$" % e, cmd):
1054 if re.match("(%s)$" % e, cmd):
1055 return table[e]
1055 return table[e]
1056
1056
1057 raise UnknownCommand(cmd)
1057 raise UnknownCommand(cmd)
1058
1058
1059 class SignalInterrupt(Exception): pass
1059 class SignalInterrupt(Exception): pass
1060
1060
1061 def catchterm(*args):
1061 def catchterm(*args):
1062 raise SignalInterrupt
1062 raise SignalInterrupt
1063
1063
1064 def run():
1064 def run():
1065 sys.exit(dispatch(sys.argv[1:]))
1065 sys.exit(dispatch(sys.argv[1:]))
1066
1066
1067 class ParseError(Exception): pass
1067 class ParseError(Exception): pass
1068
1068
1069 def parse(args):
1069 def parse(args):
1070 options = {}
1070 options = {}
1071 cmdoptions = {}
1071 cmdoptions = {}
1072
1072
1073 try:
1073 try:
1074 args = fancyopts.fancyopts(args, globalopts, options)
1074 args = fancyopts.fancyopts(args, globalopts, options)
1075 except fancyopts.getopt.GetoptError, inst:
1075 except fancyopts.getopt.GetoptError, inst:
1076 raise ParseError(cmd, inst)
1076 raise ParseError(cmd, inst)
1077
1077
1078 if options["version"]:
1078 if options["version"]:
1079 return ("version", show_version, [], options, cmdoptions)
1079 return ("version", show_version, [], options, cmdoptions)
1080 elif not args:
1080 elif not args:
1081 return ("help", help, [], options, cmdoptions)
1081 return ("help", help, [], options, cmdoptions)
1082 else:
1082 else:
1083 cmd, args = args[0], args[1:]
1083 cmd, args = args[0], args[1:]
1084
1084
1085 i = find(cmd)
1085 i = find(cmd)
1086
1086
1087 # combine global options into local
1087 # combine global options into local
1088 c = list(i[1])
1088 c = list(i[1])
1089 l = len(c)
1089 l = len(c)
1090 for o in globalopts:
1090 for o in globalopts:
1091 c.append((o[0], o[1], options[o[1]], o[3]))
1091 c.append((o[0], o[1], options[o[1]], o[3]))
1092
1092
1093 try:
1093 try:
1094 args = fancyopts.fancyopts(args, c, cmdoptions)
1094 args = fancyopts.fancyopts(args, c, cmdoptions)
1095 except fancyopts.getopt.GetoptError, inst:
1095 except fancyopts.getopt.GetoptError, inst:
1096 raise ParseError(cmd, inst)
1096 raise ParseError(cmd, inst)
1097
1097
1098 # separate global options back out
1098 # separate global options back out
1099 for o in globalopts:
1099 for o in globalopts:
1100 n = o[1]
1100 n = o[1]
1101 options[n] = cmdoptions[n]
1101 options[n] = cmdoptions[n]
1102 del cmdoptions[n]
1102 del cmdoptions[n]
1103
1103
1104 return (cmd, i[0], args, options, cmdoptions)
1104 return (cmd, i[0], args, options, cmdoptions)
1105
1105
1106 def dispatch(args):
1106 def dispatch(args):
1107 signal.signal(signal.SIGTERM, catchterm)
1107 signal.signal(signal.SIGTERM, catchterm)
1108
1108
1109 try:
1109 try:
1110 cmd, func, args, options, cmdoptions = parse(args)
1110 cmd, func, args, options, cmdoptions = parse(args)
1111 except ParseError, inst:
1111 except ParseError, inst:
1112 u = ui.ui()
1112 u = ui.ui()
1113 if inst.args[0]:
1113 if inst.args[0]:
1114 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1114 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1115 help(u, inst.args[0])
1115 help(u, inst.args[0])
1116 else:
1116 else:
1117 u.warn("hg: %s\n" % inst.args[1])
1117 u.warn("hg: %s\n" % inst.args[1])
1118 help(u)
1118 help(u)
1119 sys.exit(-1)
1119 sys.exit(-1)
1120 except UnknownCommand, inst:
1120 except UnknownCommand, inst:
1121 u = ui.ui()
1121 u = ui.ui()
1122 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1122 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1123 help(u)
1123 help(u)
1124 sys.exit(1)
1124 sys.exit(1)
1125
1125
1126 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1126 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1127 not options["noninteractive"])
1127 not options["noninteractive"])
1128
1128
1129 try:
1129 try:
1130 try:
1130 try:
1131 if cmd not in norepo.split():
1131 if cmd not in norepo.split():
1132 path = options["repository"] or ""
1132 path = options["repository"] or ""
1133 repo = hg.repository(ui=u, path=path)
1133 repo = hg.repository(ui=u, path=path)
1134 d = lambda: func(u, repo, *args, **cmdoptions)
1134 d = lambda: func(u, repo, *args, **cmdoptions)
1135 else:
1135 else:
1136 d = lambda: func(u, *args, **cmdoptions)
1136 d = lambda: func(u, *args, **cmdoptions)
1137
1137
1138 if options['profile']:
1138 if options['profile']:
1139 import hotshot, hotshot.stats
1139 import hotshot, hotshot.stats
1140 prof = hotshot.Profile("hg.prof")
1140 prof = hotshot.Profile("hg.prof")
1141 r = prof.runcall(d)
1141 r = prof.runcall(d)
1142 prof.close()
1142 prof.close()
1143 stats = hotshot.stats.load("hg.prof")
1143 stats = hotshot.stats.load("hg.prof")
1144 stats.strip_dirs()
1144 stats.strip_dirs()
1145 stats.sort_stats('time', 'calls')
1145 stats.sort_stats('time', 'calls')
1146 stats.print_stats(40)
1146 stats.print_stats(40)
1147 return r
1147 return r
1148 else:
1148 else:
1149 return d()
1149 return d()
1150 except:
1150 except:
1151 if options['traceback']:
1151 if options['traceback']:
1152 traceback.print_exc()
1152 traceback.print_exc()
1153 raise
1153 raise
1154 except util.CommandError, inst:
1154 except util.CommandError, inst:
1155 u.warn("abort: %s\n" % inst.args)
1155 u.warn("abort: %s\n" % inst.args)
1156 except hg.RepoError, inst:
1156 except hg.RepoError, inst:
1157 u.warn("abort: ", inst, "!\n")
1157 u.warn("abort: ", inst, "!\n")
1158 except SignalInterrupt:
1158 except SignalInterrupt:
1159 u.warn("killed!\n")
1159 u.warn("killed!\n")
1160 except KeyboardInterrupt:
1160 except KeyboardInterrupt:
1161 u.warn("interrupted!\n")
1161 u.warn("interrupted!\n")
1162 except IOError, inst:
1162 except IOError, inst:
1163 if hasattr(inst, "code"):
1163 if hasattr(inst, "code"):
1164 u.warn("abort: %s\n" % inst)
1164 u.warn("abort: %s\n" % inst)
1165 elif hasattr(inst, "reason"):
1165 elif hasattr(inst, "reason"):
1166 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1166 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1167 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1167 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1168 u.warn("broken pipe\n")
1168 u.warn("broken pipe\n")
1169 else:
1169 else:
1170 raise
1170 raise
1171 except OSError, inst:
1171 except OSError, inst:
1172 if hasattr(inst, "filename"):
1172 if hasattr(inst, "filename"):
1173 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1173 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1174 else:
1174 else:
1175 u.warn("abort: %s\n" % inst.strerror)
1175 u.warn("abort: %s\n" % inst.strerror)
1176 except TypeError, inst:
1176 except TypeError, inst:
1177 # was this an argument error?
1177 # was this an argument error?
1178 tb = traceback.extract_tb(sys.exc_info()[2])
1178 tb = traceback.extract_tb(sys.exc_info()[2])
1179 if len(tb) > 2: # no
1179 if len(tb) > 2: # no
1180 raise
1180 raise
1181 u.debug(inst, "\n")
1181 u.debug(inst, "\n")
1182 u.warn("%s: invalid arguments\n" % cmd)
1182 u.warn("%s: invalid arguments\n" % cmd)
1183 help(u, cmd)
1183 help(u, cmd)
1184
1184
1185 sys.exit(-1)
1185 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now