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