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