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