##// END OF EJS Templates
typo fix in command help text...
TK Soh -
r913:46581ad4 default
parent child Browse files
Show More
@@ -1,1541 +1,1541 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from demandload import demandload
8 from demandload import demandload
9 demandload(globals(), "os re sys signal shutil")
9 demandload(globals(), "os re sys signal shutil")
10 demandload(globals(), "fancyopts ui hg util")
10 demandload(globals(), "fancyopts ui hg util")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
11 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
12 demandload(globals(), "errno socket version struct 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 n = r.lookup(rev)
459 else:
459 else:
460 n = r.tip()
460 n = r.tip()
461 fp = make_file(repo, r, opts['output'], node=n)
461 fp = make_file(repo, r, opts['output'], node=n)
462 fp.write(r.read(n))
462 fp.write(r.read(n))
463
463
464 def clone(ui, source, dest=None, **opts):
464 def clone(ui, source, dest=None, **opts):
465 """make a copy of an existing repository"""
465 """make a copy of an existing repository"""
466 if dest is None:
466 if dest is None:
467 dest = os.path.basename(os.path.normpath(source))
467 dest = os.path.basename(os.path.normpath(source))
468
468
469 if os.path.exists(dest):
469 if os.path.exists(dest):
470 ui.warn("abort: destination '%s' already exists\n" % dest)
470 ui.warn("abort: destination '%s' already exists\n" % dest)
471 return 1
471 return 1
472
472
473 dest = os.path.realpath(dest)
473 dest = os.path.realpath(dest)
474
474
475 class Dircleanup:
475 class Dircleanup:
476 def __init__(self, dir_):
476 def __init__(self, dir_):
477 self.rmtree = shutil.rmtree
477 self.rmtree = shutil.rmtree
478 self.dir_ = dir_
478 self.dir_ = dir_
479 os.mkdir(dir_)
479 os.mkdir(dir_)
480 def close(self):
480 def close(self):
481 self.dir_ = None
481 self.dir_ = None
482 def __del__(self):
482 def __del__(self):
483 if self.dir_:
483 if self.dir_:
484 self.rmtree(self.dir_, True)
484 self.rmtree(self.dir_, True)
485
485
486 d = Dircleanup(dest)
486 d = Dircleanup(dest)
487 abspath = source
487 abspath = source
488 source = ui.expandpath(source)
488 source = ui.expandpath(source)
489 other = hg.repository(ui, source)
489 other = hg.repository(ui, source)
490
490
491 if other.dev() != -1:
491 if other.dev() != -1:
492 abspath = os.path.abspath(source)
492 abspath = os.path.abspath(source)
493 copyfile = (os.stat(dest).st_dev == other.dev()
493 copyfile = (os.stat(dest).st_dev == other.dev()
494 and getattr(os, 'link', None) or shutil.copy2)
494 and getattr(os, 'link', None) or shutil.copy2)
495 if copyfile is not shutil.copy2:
495 if copyfile is not shutil.copy2:
496 ui.note("cloning by hardlink\n")
496 ui.note("cloning by hardlink\n")
497 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
497 util.copytree(os.path.join(source, ".hg"), os.path.join(dest, ".hg"),
498 copyfile)
498 copyfile)
499 try:
499 try:
500 os.unlink(os.path.join(dest, ".hg", "dirstate"))
500 os.unlink(os.path.join(dest, ".hg", "dirstate"))
501 except OSError:
501 except OSError:
502 pass
502 pass
503
503
504 repo = hg.repository(ui, dest)
504 repo = hg.repository(ui, dest)
505
505
506 else:
506 else:
507 repo = hg.repository(ui, dest, create=1)
507 repo = hg.repository(ui, dest, create=1)
508 repo.pull(other)
508 repo.pull(other)
509
509
510 f = repo.opener("hgrc", "w")
510 f = repo.opener("hgrc", "w")
511 f.write("[paths]\n")
511 f.write("[paths]\n")
512 f.write("default = %s\n" % abspath)
512 f.write("default = %s\n" % abspath)
513
513
514 if not opts['noupdate']:
514 if not opts['noupdate']:
515 update(ui, repo)
515 update(ui, repo)
516
516
517 d.close()
517 d.close()
518
518
519 def commit(ui, repo, *pats, **opts):
519 def commit(ui, repo, *pats, **opts):
520 """commit the specified files or all outstanding changes"""
520 """commit the specified files or all outstanding changes"""
521 if opts['text']:
521 if opts['text']:
522 ui.warn("Warning: -t and --text is deprecated,"
522 ui.warn("Warning: -t and --text is deprecated,"
523 " please use -m or --message instead.\n")
523 " please use -m or --message instead.\n")
524 message = opts['message'] or opts['text']
524 message = opts['message'] or opts['text']
525 logfile = opts['logfile']
525 logfile = opts['logfile']
526 if not message and logfile:
526 if not message and logfile:
527 try:
527 try:
528 if logfile == '-':
528 if logfile == '-':
529 message = sys.stdin.read()
529 message = sys.stdin.read()
530 else:
530 else:
531 message = open(logfile).read()
531 message = open(logfile).read()
532 except IOError, why:
532 except IOError, why:
533 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
533 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
534
534
535 if opts['addremove']:
535 if opts['addremove']:
536 addremove(ui, repo, *pats, **opts)
536 addremove(ui, repo, *pats, **opts)
537 cwd = repo.getcwd()
537 cwd = repo.getcwd()
538 if not pats and cwd:
538 if not pats and cwd:
539 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
539 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
540 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
540 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
541 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
541 fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
542 if pats:
542 if pats:
543 c, a, d, u = repo.changes(files = fns, match = match)
543 c, a, d, u = repo.changes(files = fns, match = match)
544 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
544 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
545 else:
545 else:
546 files = []
546 files = []
547 repo.commit(files, message, opts['user'], opts['date'], match)
547 repo.commit(files, message, opts['user'], opts['date'], match)
548
548
549 def copy(ui, repo, source, dest):
549 def copy(ui, repo, source, dest):
550 """mark a file as copied or renamed for the next commit"""
550 """mark a file as copied or renamed for the next commit"""
551 return repo.copy(*relpath(repo, (source, dest)))
551 return repo.copy(*relpath(repo, (source, dest)))
552
552
553 def debugcheckstate(ui, repo):
553 def debugcheckstate(ui, repo):
554 """validate the correctness of the current dirstate"""
554 """validate the correctness of the current dirstate"""
555 parent1, parent2 = repo.dirstate.parents()
555 parent1, parent2 = repo.dirstate.parents()
556 repo.dirstate.read()
556 repo.dirstate.read()
557 dc = repo.dirstate.map
557 dc = repo.dirstate.map
558 keys = dc.keys()
558 keys = dc.keys()
559 keys.sort()
559 keys.sort()
560 m1n = repo.changelog.read(parent1)[0]
560 m1n = repo.changelog.read(parent1)[0]
561 m2n = repo.changelog.read(parent2)[0]
561 m2n = repo.changelog.read(parent2)[0]
562 m1 = repo.manifest.read(m1n)
562 m1 = repo.manifest.read(m1n)
563 m2 = repo.manifest.read(m2n)
563 m2 = repo.manifest.read(m2n)
564 errors = 0
564 errors = 0
565 for f in dc:
565 for f in dc:
566 state = repo.dirstate.state(f)
566 state = repo.dirstate.state(f)
567 if state in "nr" and f not in m1:
567 if state in "nr" and f not in m1:
568 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
568 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
569 errors += 1
569 errors += 1
570 if state in "a" and f in m1:
570 if state in "a" and f in m1:
571 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
571 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
572 errors += 1
572 errors += 1
573 if state in "m" and f not in m1 and f not in m2:
573 if state in "m" and f not in m1 and f not in m2:
574 ui.warn("%s in state %s, but not in either manifest\n" %
574 ui.warn("%s in state %s, but not in either manifest\n" %
575 (f, state))
575 (f, state))
576 errors += 1
576 errors += 1
577 for f in m1:
577 for f in m1:
578 state = repo.dirstate.state(f)
578 state = repo.dirstate.state(f)
579 if state not in "nrm":
579 if state not in "nrm":
580 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
580 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
581 errors += 1
581 errors += 1
582 if errors:
582 if errors:
583 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
583 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
584
584
585 def debugstate(ui, repo):
585 def debugstate(ui, repo):
586 """show the contents of the current dirstate"""
586 """show the contents of the current dirstate"""
587 repo.dirstate.read()
587 repo.dirstate.read()
588 dc = repo.dirstate.map
588 dc = repo.dirstate.map
589 keys = dc.keys()
589 keys = dc.keys()
590 keys.sort()
590 keys.sort()
591 for file_ in keys:
591 for file_ in keys:
592 ui.write("%c %3o %10d %s %s\n"
592 ui.write("%c %3o %10d %s %s\n"
593 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
593 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
594 time.strftime("%x %X",
594 time.strftime("%x %X",
595 time.localtime(dc[file_][3])), file_))
595 time.localtime(dc[file_][3])), file_))
596
596
597 def debugindex(ui, file_):
597 def debugindex(ui, file_):
598 """dump the contents of an index file"""
598 """dump the contents of an index file"""
599 r = hg.revlog(hg.opener(""), file_, "")
599 r = hg.revlog(hg.opener(""), file_, "")
600 ui.write(" rev offset length base linkrev" +
600 ui.write(" rev offset length base linkrev" +
601 " p1 p2 nodeid\n")
601 " p1 p2 nodeid\n")
602 for i in range(r.count()):
602 for i in range(r.count()):
603 e = r.index[i]
603 e = r.index[i]
604 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
604 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
605 i, e[0], e[1], e[2], e[3],
605 i, e[0], e[1], e[2], e[3],
606 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
606 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
607
607
608 def debugindexdot(ui, file_):
608 def debugindexdot(ui, file_):
609 """dump an index DAG as a .dot file"""
609 """dump an index DAG as a .dot file"""
610 r = hg.revlog(hg.opener(""), file_, "")
610 r = hg.revlog(hg.opener(""), file_, "")
611 ui.write("digraph G {\n")
611 ui.write("digraph G {\n")
612 for i in range(r.count()):
612 for i in range(r.count()):
613 e = r.index[i]
613 e = r.index[i]
614 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
614 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
615 if e[5] != hg.nullid:
615 if e[5] != hg.nullid:
616 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
616 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
617 ui.write("}\n")
617 ui.write("}\n")
618
618
619 def debugwalk(ui, repo, *pats, **opts):
619 def debugwalk(ui, repo, *pats, **opts):
620 items = list(walk(repo, pats, opts))
620 items = list(walk(repo, pats, opts))
621 if not items: return
621 if not items: return
622 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
622 fmt = '%%s %%-%ds %%s' % max([len(abs) for (src, abs, rel) in items])
623 for i in items: print fmt % i
623 for i in items: print fmt % i
624
624
625 def diff(ui, repo, *pats, **opts):
625 def diff(ui, repo, *pats, **opts):
626 """diff working directory (or selected files)"""
626 """diff working directory (or selected files)"""
627 revs = []
627 revs = []
628 if opts['rev']:
628 if opts['rev']:
629 revs = map(lambda x: repo.lookup(x), opts['rev'])
629 revs = map(lambda x: repo.lookup(x), opts['rev'])
630
630
631 if len(revs) > 2:
631 if len(revs) > 2:
632 raise util.Abort("too many revisions to diff")
632 raise util.Abort("too many revisions to diff")
633
633
634 files = []
634 files = []
635 match = util.always
635 match = util.always
636 if pats:
636 if pats:
637 roots, match, results = makewalk(repo, pats, opts)
637 roots, match, results = makewalk(repo, pats, opts)
638 for src, abs, rel in results:
638 for src, abs, rel in results:
639 files.append(abs)
639 files.append(abs)
640 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
640 dodiff(sys.stdout, ui, repo, files, *revs, **{'match': match})
641
641
642 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
642 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
643 node = repo.lookup(changeset)
643 node = repo.lookup(changeset)
644 prev, other = repo.changelog.parents(node)
644 prev, other = repo.changelog.parents(node)
645 change = repo.changelog.read(node)
645 change = repo.changelog.read(node)
646
646
647 fp = make_file(repo, repo.changelog, opts['output'],
647 fp = make_file(repo, repo.changelog, opts['output'],
648 node=node, total=total, seqno=seqno,
648 node=node, total=total, seqno=seqno,
649 revwidth=revwidth)
649 revwidth=revwidth)
650 if fp != sys.stdout:
650 if fp != sys.stdout:
651 ui.note("%s\n" % fp.name)
651 ui.note("%s\n" % fp.name)
652
652
653 fp.write("# HG changeset patch\n")
653 fp.write("# HG changeset patch\n")
654 fp.write("# User %s\n" % change[1])
654 fp.write("# User %s\n" % change[1])
655 fp.write("# Node ID %s\n" % hg.hex(node))
655 fp.write("# Node ID %s\n" % hg.hex(node))
656 fp.write("# Parent %s\n" % hg.hex(prev))
656 fp.write("# Parent %s\n" % hg.hex(prev))
657 if other != hg.nullid:
657 if other != hg.nullid:
658 fp.write("# Parent %s\n" % hg.hex(other))
658 fp.write("# Parent %s\n" % hg.hex(other))
659 fp.write(change[4].rstrip())
659 fp.write(change[4].rstrip())
660 fp.write("\n\n")
660 fp.write("\n\n")
661
661
662 dodiff(fp, ui, repo, None, prev, node)
662 dodiff(fp, ui, repo, None, prev, node)
663 if fp != sys.stdout: fp.close()
663 if fp != sys.stdout: fp.close()
664
664
665 def export(ui, repo, *changesets, **opts):
665 def export(ui, repo, *changesets, **opts):
666 """dump the header and diffs for one or more changesets"""
666 """dump the header and diffs for one or more changesets"""
667 if not changesets:
667 if not changesets:
668 raise util.Abort("export requires at least one changeset")
668 raise util.Abort("export requires at least one changeset")
669 seqno = 0
669 seqno = 0
670 revs = list(revrange(ui, repo, changesets))
670 revs = list(revrange(ui, repo, changesets))
671 total = len(revs)
671 total = len(revs)
672 revwidth = max(len(revs[0]), len(revs[-1]))
672 revwidth = max(len(revs[0]), len(revs[-1]))
673 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
673 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
674 for cset in revs:
674 for cset in revs:
675 seqno += 1
675 seqno += 1
676 doexport(ui, repo, cset, seqno, total, revwidth, opts)
676 doexport(ui, repo, cset, seqno, total, revwidth, opts)
677
677
678 def forget(ui, repo, *pats, **opts):
678 def forget(ui, repo, *pats, **opts):
679 """don't add the specified files on the next commit"""
679 """don't add the specified files on the next commit"""
680 q = dict(zip(pats, pats))
680 q = dict(zip(pats, pats))
681 forget = []
681 forget = []
682 for src, abs, rel in walk(repo, pats, opts):
682 for src, abs, rel in walk(repo, pats, opts):
683 if repo.dirstate.state(abs) == 'a':
683 if repo.dirstate.state(abs) == 'a':
684 forget.append(abs)
684 forget.append(abs)
685 if rel not in q: ui.status('forgetting ', rel, '\n')
685 if rel not in q: ui.status('forgetting ', rel, '\n')
686 repo.forget(forget)
686 repo.forget(forget)
687
687
688 def heads(ui, repo, **opts):
688 def heads(ui, repo, **opts):
689 """show current repository heads"""
689 """show current repository heads"""
690 heads = repo.changelog.heads()
690 heads = repo.changelog.heads()
691 br = None
691 br = None
692 if opts['branches']:
692 if opts['branches']:
693 br = repo.branchlookup(heads)
693 br = repo.branchlookup(heads)
694 for n in repo.changelog.heads():
694 for n in repo.changelog.heads():
695 show_changeset(ui, repo, changenode=n, brinfo=br)
695 show_changeset(ui, repo, changenode=n, brinfo=br)
696
696
697 def identify(ui, repo):
697 def identify(ui, repo):
698 """print information about the working copy"""
698 """print information about the working copy"""
699 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
699 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
700 if not parents:
700 if not parents:
701 ui.write("unknown\n")
701 ui.write("unknown\n")
702 return
702 return
703
703
704 hexfunc = ui.verbose and hg.hex or hg.short
704 hexfunc = ui.verbose and hg.hex or hg.short
705 (c, a, d, u) = repo.changes()
705 (c, a, d, u) = repo.changes()
706 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
706 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
707 (c or a or d) and "+" or "")]
707 (c or a or d) and "+" or "")]
708
708
709 if not ui.quiet:
709 if not ui.quiet:
710 # multiple tags for a single parent separated by '/'
710 # multiple tags for a single parent separated by '/'
711 parenttags = ['/'.join(tags)
711 parenttags = ['/'.join(tags)
712 for tags in map(repo.nodetags, parents) if tags]
712 for tags in map(repo.nodetags, parents) if tags]
713 # tags for multiple parents separated by ' + '
713 # tags for multiple parents separated by ' + '
714 if parenttags:
714 if parenttags:
715 output.append(' + '.join(parenttags))
715 output.append(' + '.join(parenttags))
716
716
717 ui.write("%s\n" % ' '.join(output))
717 ui.write("%s\n" % ' '.join(output))
718
718
719 def import_(ui, repo, patch1, *patches, **opts):
719 def import_(ui, repo, patch1, *patches, **opts):
720 """import an ordered set of patches"""
720 """import an ordered set of patches"""
721 patches = (patch1,) + patches
721 patches = (patch1,) + patches
722
722
723 d = opts["base"]
723 d = opts["base"]
724 strip = opts["strip"]
724 strip = opts["strip"]
725
725
726 for patch in patches:
726 for patch in patches:
727 ui.status("applying %s\n" % patch)
727 ui.status("applying %s\n" % patch)
728 pf = os.path.join(d, patch)
728 pf = os.path.join(d, patch)
729
729
730 message = []
730 message = []
731 user = None
731 user = None
732 hgpatch = False
732 hgpatch = False
733 for line in file(pf):
733 for line in file(pf):
734 line = line.rstrip()
734 line = line.rstrip()
735 if line.startswith("--- ") or line.startswith("diff -r"):
735 if line.startswith("--- ") or line.startswith("diff -r"):
736 break
736 break
737 elif hgpatch:
737 elif hgpatch:
738 # parse values when importing the result of an hg export
738 # parse values when importing the result of an hg export
739 if line.startswith("# User "):
739 if line.startswith("# User "):
740 user = line[7:]
740 user = line[7:]
741 ui.debug('User: %s\n' % user)
741 ui.debug('User: %s\n' % user)
742 elif not line.startswith("# ") and line:
742 elif not line.startswith("# ") and line:
743 message.append(line)
743 message.append(line)
744 hgpatch = False
744 hgpatch = False
745 elif line == '# HG changeset patch':
745 elif line == '# HG changeset patch':
746 hgpatch = True
746 hgpatch = True
747 message = [] # We may have collected garbage
747 message = [] # We may have collected garbage
748 else:
748 else:
749 message.append(line)
749 message.append(line)
750
750
751 # make sure message isn't empty
751 # make sure message isn't empty
752 if not message:
752 if not message:
753 message = "imported patch %s\n" % patch
753 message = "imported patch %s\n" % patch
754 else:
754 else:
755 message = "%s\n" % '\n'.join(message)
755 message = "%s\n" % '\n'.join(message)
756 ui.debug('message:\n%s\n' % message)
756 ui.debug('message:\n%s\n' % message)
757
757
758 f = os.popen("patch -p%d < '%s'" % (strip, pf))
758 f = os.popen("patch -p%d < '%s'" % (strip, pf))
759 files = []
759 files = []
760 for l in f.read().splitlines():
760 for l in f.read().splitlines():
761 l.rstrip('\r\n');
761 l.rstrip('\r\n');
762 ui.status("%s\n" % l)
762 ui.status("%s\n" % l)
763 if l.startswith('patching file '):
763 if l.startswith('patching file '):
764 pf = l[14:]
764 pf = l[14:]
765 if pf not in files:
765 if pf not in files:
766 files.append(pf)
766 files.append(pf)
767 patcherr = f.close()
767 patcherr = f.close()
768 if patcherr:
768 if patcherr:
769 raise util.Abort("patch failed")
769 raise util.Abort("patch failed")
770
770
771 if len(files) > 0:
771 if len(files) > 0:
772 addremove(ui, repo, *files)
772 addremove(ui, repo, *files)
773 repo.commit(files, message, user)
773 repo.commit(files, message, user)
774
774
775 def init(ui, dest="."):
775 def init(ui, dest="."):
776 """create a new repository in the given directory"""
776 """create a new repository in the given directory"""
777 if not os.path.exists(dest):
777 if not os.path.exists(dest):
778 os.mkdir(dest)
778 os.mkdir(dest)
779 hg.repository(ui, dest, create=1)
779 hg.repository(ui, dest, create=1)
780
780
781 def locate(ui, repo, *pats, **opts):
781 def locate(ui, repo, *pats, **opts):
782 """locate files matching specific patterns"""
782 """locate files matching specific patterns"""
783 end = '\n'
783 end = '\n'
784 if opts['print0']: end = '\0'
784 if opts['print0']: end = '\0'
785
785
786 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
786 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
787 if repo.dirstate.state(abs) == '?': continue
787 if repo.dirstate.state(abs) == '?': continue
788 if opts['fullpath']:
788 if opts['fullpath']:
789 ui.write(os.path.join(repo.root, abs), end)
789 ui.write(os.path.join(repo.root, abs), end)
790 else:
790 else:
791 ui.write(rel, end)
791 ui.write(rel, end)
792
792
793 def log(ui, repo, f=None, **opts):
793 def log(ui, repo, f=None, **opts):
794 """show the revision history of the repository or a single file"""
794 """show the revision history of the repository or a single file"""
795 if f:
795 if f:
796 files = relpath(repo, [f])
796 files = relpath(repo, [f])
797 filelog = repo.file(files[0])
797 filelog = repo.file(files[0])
798 log = filelog
798 log = filelog
799 lookup = filelog.lookup
799 lookup = filelog.lookup
800 else:
800 else:
801 files = None
801 files = None
802 filelog = None
802 filelog = None
803 log = repo.changelog
803 log = repo.changelog
804 lookup = repo.lookup
804 lookup = repo.lookup
805 revlist = []
805 revlist = []
806 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
806 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
807 while revs:
807 while revs:
808 if len(revs) == 1:
808 if len(revs) == 1:
809 revlist.append(revs.pop(0))
809 revlist.append(revs.pop(0))
810 else:
810 else:
811 a = revs.pop(0)
811 a = revs.pop(0)
812 b = revs.pop(0)
812 b = revs.pop(0)
813 off = a > b and -1 or 1
813 off = a > b and -1 or 1
814 revlist.extend(range(a, b + off, off))
814 revlist.extend(range(a, b + off, off))
815
815
816 for i in revlist or range(log.count() - 1, -1, -1):
816 for i in revlist or range(log.count() - 1, -1, -1):
817 show_changeset(ui, repo, filelog=filelog, rev=i)
817 show_changeset(ui, repo, filelog=filelog, rev=i)
818 if opts['patch']:
818 if opts['patch']:
819 if filelog:
819 if filelog:
820 filenode = filelog.node(i)
820 filenode = filelog.node(i)
821 i = filelog.linkrev(filenode)
821 i = filelog.linkrev(filenode)
822 changenode = repo.changelog.node(i)
822 changenode = repo.changelog.node(i)
823 prev, other = repo.changelog.parents(changenode)
823 prev, other = repo.changelog.parents(changenode)
824 dodiff(sys.stdout, ui, repo, files, prev, changenode)
824 dodiff(sys.stdout, ui, repo, files, prev, changenode)
825 ui.write("\n\n")
825 ui.write("\n\n")
826
826
827 def manifest(ui, repo, rev=None):
827 def manifest(ui, repo, rev=None):
828 """output the latest or given revision of the project manifest"""
828 """output the latest or given revision of the project manifest"""
829 if rev:
829 if rev:
830 try:
830 try:
831 # assume all revision numbers are for changesets
831 # assume all revision numbers are for changesets
832 n = repo.lookup(rev)
832 n = repo.lookup(rev)
833 change = repo.changelog.read(n)
833 change = repo.changelog.read(n)
834 n = change[0]
834 n = change[0]
835 except hg.RepoError:
835 except hg.RepoError:
836 n = repo.manifest.lookup(rev)
836 n = repo.manifest.lookup(rev)
837 else:
837 else:
838 n = repo.manifest.tip()
838 n = repo.manifest.tip()
839 m = repo.manifest.read(n)
839 m = repo.manifest.read(n)
840 mf = repo.manifest.readflags(n)
840 mf = repo.manifest.readflags(n)
841 files = m.keys()
841 files = m.keys()
842 files.sort()
842 files.sort()
843
843
844 for f in files:
844 for f in files:
845 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
845 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
846
846
847 def parents(ui, repo, rev=None):
847 def parents(ui, repo, rev=None):
848 """show the parents of the working dir or revision"""
848 """show the parents of the working dir or revision"""
849 if rev:
849 if rev:
850 p = repo.changelog.parents(repo.lookup(rev))
850 p = repo.changelog.parents(repo.lookup(rev))
851 else:
851 else:
852 p = repo.dirstate.parents()
852 p = repo.dirstate.parents()
853
853
854 for n in p:
854 for n in p:
855 if n != hg.nullid:
855 if n != hg.nullid:
856 show_changeset(ui, repo, changenode=n)
856 show_changeset(ui, repo, changenode=n)
857
857
858 def paths(ui, repo, search = None):
858 def paths(ui, repo, search = None):
859 """show path or list of available paths"""
859 """show path or list of available paths"""
860 if search:
860 if search:
861 for name, path in ui.configitems("paths"):
861 for name, path in ui.configitems("paths"):
862 if name == search:
862 if name == search:
863 ui.write("%s\n" % path)
863 ui.write("%s\n" % path)
864 return
864 return
865 ui.warn("not found!\n")
865 ui.warn("not found!\n")
866 return 1
866 return 1
867 else:
867 else:
868 for name, path in ui.configitems("paths"):
868 for name, path in ui.configitems("paths"):
869 ui.write("%s = %s\n" % (name, path))
869 ui.write("%s = %s\n" % (name, path))
870
870
871 def pull(ui, repo, source="default", **opts):
871 def pull(ui, repo, source="default", **opts):
872 """pull changes from the specified source"""
872 """pull changes from the specified source"""
873 source = ui.expandpath(source)
873 source = ui.expandpath(source)
874 ui.status('pulling from %s\n' % (source))
874 ui.status('pulling from %s\n' % (source))
875
875
876 other = hg.repository(ui, source)
876 other = hg.repository(ui, source)
877 r = repo.pull(other)
877 r = repo.pull(other)
878 if not r:
878 if not r:
879 if opts['update']:
879 if opts['update']:
880 return update(ui, repo)
880 return update(ui, repo)
881 else:
881 else:
882 ui.status("(run 'hg update' to get a working copy)\n")
882 ui.status("(run 'hg update' to get a working copy)\n")
883
883
884 return r
884 return r
885
885
886 def push(ui, repo, dest="default-push", force=False):
886 def push(ui, repo, dest="default-push", force=False):
887 """push changes to the specified destination"""
887 """push changes to the specified destination"""
888 dest = ui.expandpath(dest)
888 dest = ui.expandpath(dest)
889 ui.status('pushing to %s\n' % (dest))
889 ui.status('pushing to %s\n' % (dest))
890
890
891 other = hg.repository(ui, dest)
891 other = hg.repository(ui, dest)
892 r = repo.push(other, force)
892 r = repo.push(other, force)
893 return r
893 return r
894
894
895 def rawcommit(ui, repo, *flist, **rc):
895 def rawcommit(ui, repo, *flist, **rc):
896 "raw commit interface"
896 "raw commit interface"
897 if rc['text']:
897 if rc['text']:
898 ui.warn("Warning: -t and --text is deprecated,"
898 ui.warn("Warning: -t and --text is deprecated,"
899 " please use -m or --message instead.\n")
899 " please use -m or --message instead.\n")
900 message = rc['message'] or rc['text']
900 message = rc['message'] or rc['text']
901 if not message and rc['logfile']:
901 if not message and rc['logfile']:
902 try:
902 try:
903 message = open(rc['logfile']).read()
903 message = open(rc['logfile']).read()
904 except IOError:
904 except IOError:
905 pass
905 pass
906 if not message and not rc['logfile']:
906 if not message and not rc['logfile']:
907 ui.warn("abort: missing commit message\n")
907 ui.warn("abort: missing commit message\n")
908 return 1
908 return 1
909
909
910 files = relpath(repo, list(flist))
910 files = relpath(repo, list(flist))
911 if rc['files']:
911 if rc['files']:
912 files += open(rc['files']).read().splitlines()
912 files += open(rc['files']).read().splitlines()
913
913
914 rc['parent'] = map(repo.lookup, rc['parent'])
914 rc['parent'] = map(repo.lookup, rc['parent'])
915
915
916 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
916 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
917
917
918 def recover(ui, repo):
918 def recover(ui, repo):
919 """roll back an interrupted transaction"""
919 """roll back an interrupted transaction"""
920 repo.recover()
920 repo.recover()
921
921
922 def remove(ui, repo, file1, *files):
922 def remove(ui, repo, file1, *files):
923 """remove the specified files on the next commit"""
923 """remove the specified files on the next commit"""
924 repo.remove(relpath(repo, (file1,) + files))
924 repo.remove(relpath(repo, (file1,) + files))
925
925
926 def revert(ui, repo, *names, **opts):
926 def revert(ui, repo, *names, **opts):
927 """revert modified files or dirs back to their unmodified states"""
927 """revert modified files or dirs back to their unmodified states"""
928 node = opts['rev'] and repo.lookup(opts['rev']) or \
928 node = opts['rev'] and repo.lookup(opts['rev']) or \
929 repo.dirstate.parents()[0]
929 repo.dirstate.parents()[0]
930 root = os.path.realpath(repo.root)
930 root = os.path.realpath(repo.root)
931
931
932 def trimpath(p):
932 def trimpath(p):
933 p = os.path.realpath(p)
933 p = os.path.realpath(p)
934 if p.startswith(root):
934 if p.startswith(root):
935 rest = p[len(root):]
935 rest = p[len(root):]
936 if not rest:
936 if not rest:
937 return rest
937 return rest
938 if p.startswith(os.sep):
938 if p.startswith(os.sep):
939 return rest[1:]
939 return rest[1:]
940 return p
940 return p
941
941
942 relnames = map(trimpath, names or [os.getcwd()])
942 relnames = map(trimpath, names or [os.getcwd()])
943 chosen = {}
943 chosen = {}
944
944
945 def choose(name):
945 def choose(name):
946 def body(name):
946 def body(name):
947 for r in relnames:
947 for r in relnames:
948 if not name.startswith(r):
948 if not name.startswith(r):
949 continue
949 continue
950 rest = name[len(r):]
950 rest = name[len(r):]
951 if not rest:
951 if not rest:
952 return r, True
952 return r, True
953 depth = rest.count(os.sep)
953 depth = rest.count(os.sep)
954 if not r:
954 if not r:
955 if depth == 0 or not opts['nonrecursive']:
955 if depth == 0 or not opts['nonrecursive']:
956 return r, True
956 return r, True
957 elif rest[0] == os.sep:
957 elif rest[0] == os.sep:
958 if depth == 1 or not opts['nonrecursive']:
958 if depth == 1 or not opts['nonrecursive']:
959 return r, True
959 return r, True
960 return None, False
960 return None, False
961 relname, ret = body(name)
961 relname, ret = body(name)
962 if ret:
962 if ret:
963 chosen[relname] = 1
963 chosen[relname] = 1
964 return ret
964 return ret
965
965
966 r = repo.update(node, False, True, choose, False)
966 r = repo.update(node, False, True, choose, False)
967 for n in relnames:
967 for n in relnames:
968 if n not in chosen:
968 if n not in chosen:
969 ui.warn('error: no matches for %s\n' % n)
969 ui.warn('error: no matches for %s\n' % n)
970 r = 1
970 r = 1
971 sys.stdout.flush()
971 sys.stdout.flush()
972 return r
972 return r
973
973
974 def root(ui, repo):
974 def root(ui, repo):
975 """print the root (top) of the current working dir"""
975 """print the root (top) of the current working dir"""
976 ui.write(repo.root + "\n")
976 ui.write(repo.root + "\n")
977
977
978 def serve(ui, repo, **opts):
978 def serve(ui, repo, **opts):
979 """export the repository via HTTP"""
979 """export the repository via HTTP"""
980
980
981 if opts["stdio"]:
981 if opts["stdio"]:
982 fin, fout = sys.stdin, sys.stdout
982 fin, fout = sys.stdin, sys.stdout
983 sys.stdout = sys.stderr
983 sys.stdout = sys.stderr
984
984
985 def getarg():
985 def getarg():
986 argline = fin.readline()[:-1]
986 argline = fin.readline()[:-1]
987 arg, l = argline.split()
987 arg, l = argline.split()
988 val = fin.read(int(l))
988 val = fin.read(int(l))
989 return arg, val
989 return arg, val
990 def respond(v):
990 def respond(v):
991 fout.write("%d\n" % len(v))
991 fout.write("%d\n" % len(v))
992 fout.write(v)
992 fout.write(v)
993 fout.flush()
993 fout.flush()
994
994
995 lock = None
995 lock = None
996
996
997 while 1:
997 while 1:
998 cmd = fin.readline()[:-1]
998 cmd = fin.readline()[:-1]
999 if cmd == '':
999 if cmd == '':
1000 return
1000 return
1001 if cmd == "heads":
1001 if cmd == "heads":
1002 h = repo.heads()
1002 h = repo.heads()
1003 respond(" ".join(map(hg.hex, h)) + "\n")
1003 respond(" ".join(map(hg.hex, h)) + "\n")
1004 if cmd == "lock":
1004 if cmd == "lock":
1005 lock = repo.lock()
1005 lock = repo.lock()
1006 respond("")
1006 respond("")
1007 if cmd == "unlock":
1007 if cmd == "unlock":
1008 if lock:
1008 if lock:
1009 lock.release()
1009 lock.release()
1010 lock = None
1010 lock = None
1011 respond("")
1011 respond("")
1012 elif cmd == "branches":
1012 elif cmd == "branches":
1013 arg, nodes = getarg()
1013 arg, nodes = getarg()
1014 nodes = map(hg.bin, nodes.split(" "))
1014 nodes = map(hg.bin, nodes.split(" "))
1015 r = []
1015 r = []
1016 for b in repo.branches(nodes):
1016 for b in repo.branches(nodes):
1017 r.append(" ".join(map(hg.hex, b)) + "\n")
1017 r.append(" ".join(map(hg.hex, b)) + "\n")
1018 respond("".join(r))
1018 respond("".join(r))
1019 elif cmd == "between":
1019 elif cmd == "between":
1020 arg, pairs = getarg()
1020 arg, pairs = getarg()
1021 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1021 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1022 r = []
1022 r = []
1023 for b in repo.between(pairs):
1023 for b in repo.between(pairs):
1024 r.append(" ".join(map(hg.hex, b)) + "\n")
1024 r.append(" ".join(map(hg.hex, b)) + "\n")
1025 respond("".join(r))
1025 respond("".join(r))
1026 elif cmd == "changegroup":
1026 elif cmd == "changegroup":
1027 nodes = []
1027 nodes = []
1028 arg, roots = getarg()
1028 arg, roots = getarg()
1029 nodes = map(hg.bin, roots.split(" "))
1029 nodes = map(hg.bin, roots.split(" "))
1030
1030
1031 cg = repo.changegroup(nodes)
1031 cg = repo.changegroup(nodes)
1032 while 1:
1032 while 1:
1033 d = cg.read(4096)
1033 d = cg.read(4096)
1034 if not d:
1034 if not d:
1035 break
1035 break
1036 fout.write(d)
1036 fout.write(d)
1037
1037
1038 fout.flush()
1038 fout.flush()
1039
1039
1040 elif cmd == "addchangegroup":
1040 elif cmd == "addchangegroup":
1041 if not lock:
1041 if not lock:
1042 respond("not locked")
1042 respond("not locked")
1043 continue
1043 continue
1044 respond("")
1044 respond("")
1045
1045
1046 r = repo.addchangegroup(fin)
1046 r = repo.addchangegroup(fin)
1047 respond("")
1047 respond("")
1048
1048
1049 def openlog(opt, default):
1049 def openlog(opt, default):
1050 if opts[opt] and opts[opt] != '-':
1050 if opts[opt] and opts[opt] != '-':
1051 return open(opts[opt], 'w')
1051 return open(opts[opt], 'w')
1052 else:
1052 else:
1053 return default
1053 return default
1054
1054
1055 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1055 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1056 opts["address"], opts["port"], opts["ipv6"],
1056 opts["address"], opts["port"], opts["ipv6"],
1057 openlog('accesslog', sys.stdout),
1057 openlog('accesslog', sys.stdout),
1058 openlog('errorlog', sys.stderr))
1058 openlog('errorlog', sys.stderr))
1059 if ui.verbose:
1059 if ui.verbose:
1060 addr, port = httpd.socket.getsockname()
1060 addr, port = httpd.socket.getsockname()
1061 if addr == '0.0.0.0':
1061 if addr == '0.0.0.0':
1062 addr = socket.gethostname()
1062 addr = socket.gethostname()
1063 else:
1063 else:
1064 try:
1064 try:
1065 addr = socket.gethostbyaddr(addr)[0]
1065 addr = socket.gethostbyaddr(addr)[0]
1066 except socket.error:
1066 except socket.error:
1067 pass
1067 pass
1068 if port != 80:
1068 if port != 80:
1069 ui.status('listening at http://%s:%d/\n' % (addr, port))
1069 ui.status('listening at http://%s:%d/\n' % (addr, port))
1070 else:
1070 else:
1071 ui.status('listening at http://%s/\n' % addr)
1071 ui.status('listening at http://%s/\n' % addr)
1072 httpd.serve_forever()
1072 httpd.serve_forever()
1073
1073
1074 def status(ui, repo, *pats, **opts):
1074 def status(ui, repo, *pats, **opts):
1075 '''show changed files in the working directory
1075 '''show changed files in the working directory
1076
1076
1077 M = modified
1077 M = modified
1078 A = added
1078 A = added
1079 R = removed
1079 R = removed
1080 ? = not tracked
1080 ? = not tracked
1081 '''
1081 '''
1082
1082
1083 cwd = repo.getcwd()
1083 cwd = repo.getcwd()
1084 files, matchfn = matchpats(repo, cwd, pats, opts)
1084 files, matchfn = matchpats(repo, cwd, pats, opts)
1085 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1085 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1086 for n in repo.changes(files=files, match=matchfn)]
1086 for n in repo.changes(files=files, match=matchfn)]
1087
1087
1088 changetypes = [('modified', 'M', c),
1088 changetypes = [('modified', 'M', c),
1089 ('added', 'A', a),
1089 ('added', 'A', a),
1090 ('removed', 'R', d),
1090 ('removed', 'R', d),
1091 ('unknown', '?', u)]
1091 ('unknown', '?', u)]
1092
1092
1093 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1093 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1094 or changetypes):
1094 or changetypes):
1095 for f in changes:
1095 for f in changes:
1096 ui.write("%s %s\n" % (char, f))
1096 ui.write("%s %s\n" % (char, f))
1097
1097
1098 def tag(ui, repo, name, rev=None, **opts):
1098 def tag(ui, repo, name, rev=None, **opts):
1099 """add a tag for the current tip or a given revision"""
1099 """add a tag for the current tip or a given revision"""
1100 if opts['text']:
1100 if opts['text']:
1101 ui.warn("Warning: -t and --text is deprecated,"
1101 ui.warn("Warning: -t and --text is deprecated,"
1102 " please use -m or --message instead.\n")
1102 " please use -m or --message instead.\n")
1103 if name == "tip":
1103 if name == "tip":
1104 ui.warn("abort: 'tip' is a reserved name!\n")
1104 ui.warn("abort: 'tip' is a reserved name!\n")
1105 return -1
1105 return -1
1106 if rev:
1106 if rev:
1107 r = hg.hex(repo.lookup(rev))
1107 r = hg.hex(repo.lookup(rev))
1108 else:
1108 else:
1109 r = hg.hex(repo.changelog.tip())
1109 r = hg.hex(repo.changelog.tip())
1110
1110
1111 if name.find(revrangesep) >= 0:
1111 if name.find(revrangesep) >= 0:
1112 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1112 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1113 return -1
1113 return -1
1114
1114
1115 if opts['local']:
1115 if opts['local']:
1116 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1116 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1117 return
1117 return
1118
1118
1119 (c, a, d, u) = repo.changes()
1119 (c, a, d, u) = repo.changes()
1120 for x in (c, a, d, u):
1120 for x in (c, a, d, u):
1121 if ".hgtags" in x:
1121 if ".hgtags" in x:
1122 ui.warn("abort: working copy of .hgtags is changed!\n")
1122 ui.warn("abort: working copy of .hgtags is changed!\n")
1123 ui.status("(please commit .hgtags manually)\n")
1123 ui.status("(please commit .hgtags manually)\n")
1124 return -1
1124 return -1
1125
1125
1126 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1126 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1127 if repo.dirstate.state(".hgtags") == '?':
1127 if repo.dirstate.state(".hgtags") == '?':
1128 repo.add([".hgtags"])
1128 repo.add([".hgtags"])
1129
1129
1130 message = (opts['message'] or opts['text'] or
1130 message = (opts['message'] or opts['text'] or
1131 "Added tag %s for changeset %s" % (name, r))
1131 "Added tag %s for changeset %s" % (name, r))
1132 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1132 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1133
1133
1134 def tags(ui, repo):
1134 def tags(ui, repo):
1135 """list repository tags"""
1135 """list repository tags"""
1136
1136
1137 l = repo.tagslist()
1137 l = repo.tagslist()
1138 l.reverse()
1138 l.reverse()
1139 for t, n in l:
1139 for t, n in l:
1140 try:
1140 try:
1141 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1141 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1142 except KeyError:
1142 except KeyError:
1143 r = " ?:?"
1143 r = " ?:?"
1144 ui.write("%-30s %s\n" % (t, r))
1144 ui.write("%-30s %s\n" % (t, r))
1145
1145
1146 def tip(ui, repo):
1146 def tip(ui, repo):
1147 """show the tip revision"""
1147 """show the tip revision"""
1148 n = repo.changelog.tip()
1148 n = repo.changelog.tip()
1149 show_changeset(ui, repo, changenode=n)
1149 show_changeset(ui, repo, changenode=n)
1150
1150
1151 def undo(ui, repo):
1151 def undo(ui, repo):
1152 """undo the last commit or pull
1152 """undo the last commit or pull
1153
1153
1154 Roll back the last pull or commit transaction on the
1154 Roll back the last pull or commit transaction on the
1155 repository, restoring the project to its earlier state.
1155 repository, restoring the project to its earlier state.
1156
1156
1157 This command should be used with care. There is only one level of
1157 This command should be used with care. There is only one level of
1158 undo and there is no redo.
1158 undo and there is no redo.
1159
1159
1160 This command is not intended for use on public repositories. Once
1160 This command is not intended for use on public repositories. Once
1161 a change is visible for pull by other users, undoing it locally is
1161 a change is visible for pull by other users, undoing it locally is
1162 ineffective.
1162 ineffective.
1163 """
1163 """
1164 repo.undo()
1164 repo.undo()
1165
1165
1166 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1166 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1167 '''update or merge working directory
1167 '''update or merge working directory
1168
1168
1169 If there are no outstanding changes in the working directory and
1169 If there are no outstanding changes in the working directory and
1170 there is a linear relationship between the current version and the
1170 there is a linear relationship between the current version and the
1171 requested version, the result is the requested version.
1171 requested version, the result is the requested version.
1172
1172
1173 Otherwise the result is a merge between the contents of the
1173 Otherwise the result is a merge between the contents of the
1174 current working directory and the requested version. Files that
1174 current working directory and the requested version. Files that
1175 changed between either parent are marked as changed for the next
1175 changed between either parent are marked as changed for the next
1176 commit and a commit must be performed before any further updates
1176 commit and a commit must be performed before any further updates
1177 are allowed.
1177 are allowed.
1178 '''
1178 '''
1179 if branch:
1179 if branch:
1180 br = repo.branchlookup(branch=branch)
1180 br = repo.branchlookup(branch=branch)
1181 found = []
1181 found = []
1182 for x in br:
1182 for x in br:
1183 if branch in br[x]:
1183 if branch in br[x]:
1184 found.append(x)
1184 found.append(x)
1185 if len(found) > 1:
1185 if len(found) > 1:
1186 ui.warn("Found multiple heads for %s\n" % branch)
1186 ui.warn("Found multiple heads for %s\n" % branch)
1187 for x in found:
1187 for x in found:
1188 show_changeset(ui, repo, changenode=x, brinfo=br)
1188 show_changeset(ui, repo, changenode=x, brinfo=br)
1189 return 1
1189 return 1
1190 if len(found) == 1:
1190 if len(found) == 1:
1191 node = found[0]
1191 node = found[0]
1192 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1192 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1193 else:
1193 else:
1194 ui.warn("branch %s not found\n" % (branch))
1194 ui.warn("branch %s not found\n" % (branch))
1195 return 1
1195 return 1
1196 else:
1196 else:
1197 node = node and repo.lookup(node) or repo.changelog.tip()
1197 node = node and repo.lookup(node) or repo.changelog.tip()
1198 return repo.update(node, allow=merge, force=clean)
1198 return repo.update(node, allow=merge, force=clean)
1199
1199
1200 def verify(ui, repo):
1200 def verify(ui, repo):
1201 """verify the integrity of the repository"""
1201 """verify the integrity of the repository"""
1202 return repo.verify()
1202 return repo.verify()
1203
1203
1204 # Command options and aliases are listed here, alphabetically
1204 # Command options and aliases are listed here, alphabetically
1205
1205
1206 table = {
1206 table = {
1207 "^add":
1207 "^add":
1208 (add,
1208 (add,
1209 [('I', 'include', [], 'include path in search'),
1209 [('I', 'include', [], 'include path in search'),
1210 ('X', 'exclude', [], 'exclude path from search')],
1210 ('X', 'exclude', [], 'exclude path from search')],
1211 "hg add [FILE]..."),
1211 "hg add [OPTION]... [FILE]..."),
1212 "addremove":
1212 "addremove":
1213 (addremove,
1213 (addremove,
1214 [('I', 'include', [], 'include path in search'),
1214 [('I', 'include', [], 'include path in search'),
1215 ('X', 'exclude', [], 'exclude path from search')],
1215 ('X', 'exclude', [], 'exclude path from search')],
1216 "hg addremove [OPTION]... [FILE]..."),
1216 "hg addremove [OPTION]... [FILE]..."),
1217 "^annotate":
1217 "^annotate":
1218 (annotate,
1218 (annotate,
1219 [('r', 'rev', '', 'revision'),
1219 [('r', 'rev', '', 'revision'),
1220 ('u', 'user', None, 'show user'),
1220 ('u', 'user', None, 'show user'),
1221 ('n', 'number', None, 'show revision number'),
1221 ('n', 'number', None, 'show revision number'),
1222 ('c', 'changeset', None, 'show changeset'),
1222 ('c', 'changeset', None, 'show changeset'),
1223 ('I', 'include', [], 'include path in search'),
1223 ('I', 'include', [], 'include path in search'),
1224 ('X', 'exclude', [], 'exclude path from search')],
1224 ('X', 'exclude', [], 'exclude path from search')],
1225 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1225 'hg annotate [OPTION]... FILE...'),
1226 "cat":
1226 "cat":
1227 (cat,
1227 (cat,
1228 [('o', 'output', "", 'output to file')],
1228 [('o', 'output', "", 'output to file')],
1229 'hg cat [-o OUTFILE] FILE [REV]'),
1229 'hg cat [-o OUTFILE] FILE [REV]'),
1230 "^clone":
1230 "^clone":
1231 (clone,
1231 (clone,
1232 [('U', 'noupdate', None, 'skip update after cloning')],
1232 [('U', 'noupdate', None, 'skip update after cloning')],
1233 'hg clone [-U] SOURCE [DEST]'),
1233 'hg clone [-U] SOURCE [DEST]'),
1234 "^commit|ci":
1234 "^commit|ci":
1235 (commit,
1235 (commit,
1236 [('A', 'addremove', None, 'run add/remove during commit'),
1236 [('A', 'addremove', None, 'run add/remove during commit'),
1237 ('I', 'include', [], 'include path in search'),
1237 ('I', 'include', [], 'include path in search'),
1238 ('X', 'exclude', [], 'exclude path from search'),
1238 ('X', 'exclude', [], 'exclude path from search'),
1239 ('m', 'message', "", 'commit message'),
1239 ('m', 'message', "", 'commit message'),
1240 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1240 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1241 ('l', 'logfile', "", 'commit message file'),
1241 ('l', 'logfile', "", 'commit message file'),
1242 ('d', 'date', "", 'date code'),
1242 ('d', 'date', "", 'date code'),
1243 ('u', 'user', "", 'user')],
1243 ('u', 'user', "", 'user')],
1244 'hg commit [OPTION]... [FILE]...'),
1244 'hg commit [OPTION]... [FILE]...'),
1245 "copy": (copy, [], 'hg copy SOURCE DEST'),
1245 "copy": (copy, [], 'hg copy SOURCE DEST'),
1246 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1246 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1247 "debugstate": (debugstate, [], 'debugstate'),
1247 "debugstate": (debugstate, [], 'debugstate'),
1248 "debugindex": (debugindex, [], 'debugindex FILE'),
1248 "debugindex": (debugindex, [], 'debugindex FILE'),
1249 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1249 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1250 "debugwalk":
1250 "debugwalk":
1251 (debugwalk,
1251 (debugwalk,
1252 [('I', 'include', [], 'include path in search'),
1252 [('I', 'include', [], 'include path in search'),
1253 ('X', 'exclude', [], 'exclude path from search')],
1253 ('X', 'exclude', [], 'exclude path from search')],
1254 'debugwalk [OPTIONS]... [FILE]...'),
1254 'debugwalk [OPTION]... [FILE]...'),
1255 "^diff":
1255 "^diff":
1256 (diff,
1256 (diff,
1257 [('r', 'rev', [], 'revision'),
1257 [('r', 'rev', [], 'revision'),
1258 ('I', 'include', [], 'include path in search'),
1258 ('I', 'include', [], 'include path in search'),
1259 ('X', 'exclude', [], 'exclude path from search')],
1259 ('X', 'exclude', [], 'exclude path from search')],
1260 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1260 'hg diff [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1261 "^export":
1261 "^export":
1262 (export,
1262 (export,
1263 [('o', 'output', "", 'output to file')],
1263 [('o', 'output', "", 'output to file')],
1264 "hg export [-o OUTFILE] REV..."),
1264 "hg export [-o OUTFILE] REV..."),
1265 "forget":
1265 "forget":
1266 (forget,
1266 (forget,
1267 [('I', 'include', [], 'include path in search'),
1267 [('I', 'include', [], 'include path in search'),
1268 ('X', 'exclude', [], 'exclude path from search')],
1268 ('X', 'exclude', [], 'exclude path from search')],
1269 "hg forget FILE..."),
1269 "hg forget [OPTION]... FILE..."),
1270 "heads":
1270 "heads":
1271 (heads,
1271 (heads,
1272 [('b', 'branches', None, 'find branch info')],
1272 [('b', 'branches', None, 'find branch info')],
1273 'hg [-b] heads'),
1273 'hg [-b] heads'),
1274 "help": (help_, [], 'hg help [COMMAND]'),
1274 "help": (help_, [], 'hg help [COMMAND]'),
1275 "identify|id": (identify, [], 'hg identify'),
1275 "identify|id": (identify, [], 'hg identify'),
1276 "import|patch":
1276 "import|patch":
1277 (import_,
1277 (import_,
1278 [('p', 'strip', 1, 'path strip'),
1278 [('p', 'strip', 1, 'path strip'),
1279 ('b', 'base', "", 'base path')],
1279 ('b', 'base', "", 'base path')],
1280 "hg import [-p NUM] [-b BASE] PATCH..."),
1280 "hg import [-p NUM] [-b BASE] PATCH..."),
1281 "^init": (init, [], 'hg init [DEST]'),
1281 "^init": (init, [], 'hg init [DEST]'),
1282 "locate":
1282 "locate":
1283 (locate,
1283 (locate,
1284 [('r', 'rev', '', 'revision'),
1284 [('r', 'rev', '', 'revision'),
1285 ('0', 'print0', None, 'end records with NUL'),
1285 ('0', 'print0', None, 'end records with NUL'),
1286 ('f', 'fullpath', None, 'print complete paths'),
1286 ('f', 'fullpath', None, 'print complete paths'),
1287 ('I', 'include', [], 'include path in search'),
1287 ('I', 'include', [], 'include path in search'),
1288 ('X', 'exclude', [], 'exclude path from search')],
1288 ('X', 'exclude', [], 'exclude path from search')],
1289 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1289 'hg locate [OPTION]... [PATTERN]...'),
1290 "^log|history":
1290 "^log|history":
1291 (log,
1291 (log,
1292 [('r', 'rev', [], 'revision'),
1292 [('r', 'rev', [], 'revision'),
1293 ('p', 'patch', None, 'show patch')],
1293 ('p', 'patch', None, 'show patch')],
1294 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1294 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1295 "manifest": (manifest, [], 'hg manifest [REV]'),
1295 "manifest": (manifest, [], 'hg manifest [REV]'),
1296 "parents": (parents, [], 'hg parents [REV]'),
1296 "parents": (parents, [], 'hg parents [REV]'),
1297 "paths": (paths, [], 'hg paths [name]'),
1297 "paths": (paths, [], 'hg paths [name]'),
1298 "^pull":
1298 "^pull":
1299 (pull,
1299 (pull,
1300 [('u', 'update', None, 'update working directory')],
1300 [('u', 'update', None, 'update working directory')],
1301 'hg pull [-u] [SOURCE]'),
1301 'hg pull [-u] [SOURCE]'),
1302 "^push":
1302 "^push":
1303 (push,
1303 (push,
1304 [('f', 'force', None, 'force push')],
1304 [('f', 'force', None, 'force push')],
1305 'hg push [DEST]'),
1305 'hg push [-f] [DEST]'),
1306 "rawcommit":
1306 "rawcommit":
1307 (rawcommit,
1307 (rawcommit,
1308 [('p', 'parent', [], 'parent'),
1308 [('p', 'parent', [], 'parent'),
1309 ('d', 'date', "", 'date code'),
1309 ('d', 'date', "", 'date code'),
1310 ('u', 'user', "", 'user'),
1310 ('u', 'user', "", 'user'),
1311 ('F', 'files', "", 'file list'),
1311 ('F', 'files', "", 'file list'),
1312 ('m', 'message', "", 'commit message'),
1312 ('m', 'message', "", 'commit message'),
1313 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1313 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1314 ('l', 'logfile', "", 'commit message file')],
1314 ('l', 'logfile', "", 'commit message file')],
1315 'hg rawcommit [OPTION]... [FILE]...'),
1315 'hg rawcommit [OPTION]... [FILE]...'),
1316 "recover": (recover, [], "hg recover"),
1316 "recover": (recover, [], "hg recover"),
1317 "^remove|rm": (remove, [], "hg remove FILE..."),
1317 "^remove|rm": (remove, [], "hg remove FILE..."),
1318 "^revert":
1318 "^revert":
1319 (revert,
1319 (revert,
1320 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1320 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1321 ("r", "rev", "", "revision")],
1321 ("r", "rev", "", "revision")],
1322 "hg revert [-n] [-r REV] [NAME]..."),
1322 "hg revert [-n] [-r REV] [NAME]..."),
1323 "root": (root, [], "hg root"),
1323 "root": (root, [], "hg root"),
1324 "^serve":
1324 "^serve":
1325 (serve,
1325 (serve,
1326 [('A', 'accesslog', '', 'access log file'),
1326 [('A', 'accesslog', '', 'access log file'),
1327 ('E', 'errorlog', '', 'error log file'),
1327 ('E', 'errorlog', '', 'error log file'),
1328 ('p', 'port', 8000, 'listen port'),
1328 ('p', 'port', 8000, 'listen port'),
1329 ('a', 'address', '', 'interface address'),
1329 ('a', 'address', '', 'interface address'),
1330 ('n', 'name', os.getcwd(), 'repository name'),
1330 ('n', 'name', os.getcwd(), 'repository name'),
1331 ('', 'stdio', None, 'for remote clients'),
1331 ('', 'stdio', None, 'for remote clients'),
1332 ('t', 'templates', "", 'template map'),
1332 ('t', 'templates', "", 'template map'),
1333 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1333 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1334 "hg serve [OPTION]..."),
1334 "hg serve [OPTION]..."),
1335 "^status":
1335 "^status":
1336 (status,
1336 (status,
1337 [('m', 'modified', None, 'show only modified files'),
1337 [('m', 'modified', None, 'show only modified files'),
1338 ('a', 'added', None, 'show only added files'),
1338 ('a', 'added', None, 'show only added files'),
1339 ('r', 'removed', None, 'show only removed files'),
1339 ('r', 'removed', None, 'show only removed files'),
1340 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1340 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1341 ('I', 'include', [], 'include path in search'),
1341 ('I', 'include', [], 'include path in search'),
1342 ('X', 'exclude', [], 'exclude path from search')],
1342 ('X', 'exclude', [], 'exclude path from search')],
1343 "hg status [FILE]..."),
1343 "hg status [OPTION]... [FILE]..."),
1344 "tag":
1344 "tag":
1345 (tag,
1345 (tag,
1346 [('l', 'local', None, 'make the tag local'),
1346 [('l', 'local', None, 'make the tag local'),
1347 ('m', 'message', "", 'commit message'),
1347 ('m', 'message', "", 'commit message'),
1348 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1348 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1349 ('d', 'date', "", 'date code'),
1349 ('d', 'date', "", 'date code'),
1350 ('u', 'user', "", 'user')],
1350 ('u', 'user', "", 'user')],
1351 'hg tag [OPTION]... NAME [REV]'),
1351 'hg tag [OPTION]... NAME [REV]'),
1352 "tags": (tags, [], 'hg tags'),
1352 "tags": (tags, [], 'hg tags'),
1353 "tip": (tip, [], 'hg tip'),
1353 "tip": (tip, [], 'hg tip'),
1354 "undo": (undo, [], 'hg undo'),
1354 "undo": (undo, [], 'hg undo'),
1355 "^update|up|checkout|co":
1355 "^update|up|checkout|co":
1356 (update,
1356 (update,
1357 [('b', 'branch', "", 'checkout the head of a specific branch'),
1357 [('b', 'branch', "", 'checkout the head of a specific branch'),
1358 ('m', 'merge', None, 'allow merging of conflicts'),
1358 ('m', 'merge', None, 'allow merging of conflicts'),
1359 ('C', 'clean', None, 'overwrite locally modified files')],
1359 ('C', 'clean', None, 'overwrite locally modified files')],
1360 'hg update [-b TAG] [-m] [-C] [REV]'),
1360 'hg update [-b TAG] [-m] [-C] [REV]'),
1361 "verify": (verify, [], 'hg verify'),
1361 "verify": (verify, [], 'hg verify'),
1362 "version": (show_version, [], 'hg version'),
1362 "version": (show_version, [], 'hg version'),
1363 }
1363 }
1364
1364
1365 globalopts = [('v', 'verbose', None, 'verbose mode'),
1365 globalopts = [('v', 'verbose', None, 'verbose mode'),
1366 ('', 'debug', None, 'debug mode'),
1366 ('', 'debug', None, 'debug mode'),
1367 ('q', 'quiet', None, 'quiet mode'),
1367 ('q', 'quiet', None, 'quiet mode'),
1368 ('', 'profile', None, 'profile'),
1368 ('', 'profile', None, 'profile'),
1369 ('R', 'repository', "", 'repository root directory'),
1369 ('R', 'repository', "", 'repository root directory'),
1370 ('', 'traceback', None, 'print traceback on exception'),
1370 ('', 'traceback', None, 'print traceback on exception'),
1371 ('y', 'noninteractive', None, 'run non-interactively'),
1371 ('y', 'noninteractive', None, 'run non-interactively'),
1372 ('', 'version', None, 'output version information and exit'),
1372 ('', 'version', None, 'output version information and exit'),
1373 ('', 'time', None, 'time how long the command takes'),
1373 ('', 'time', None, 'time how long the command takes'),
1374 ]
1374 ]
1375
1375
1376 norepo = "clone init version help debugindex debugindexdot"
1376 norepo = "clone init version help debugindex debugindexdot"
1377
1377
1378 def find(cmd):
1378 def find(cmd):
1379 for e in table.keys():
1379 for e in table.keys():
1380 if re.match("(%s)$" % e, cmd):
1380 if re.match("(%s)$" % e, cmd):
1381 return e, table[e]
1381 return e, table[e]
1382
1382
1383 raise UnknownCommand(cmd)
1383 raise UnknownCommand(cmd)
1384
1384
1385 class SignalInterrupt(Exception):
1385 class SignalInterrupt(Exception):
1386 """Exception raised on SIGTERM and SIGHUP."""
1386 """Exception raised on SIGTERM and SIGHUP."""
1387
1387
1388 def catchterm(*args):
1388 def catchterm(*args):
1389 raise SignalInterrupt
1389 raise SignalInterrupt
1390
1390
1391 def run():
1391 def run():
1392 sys.exit(dispatch(sys.argv[1:]))
1392 sys.exit(dispatch(sys.argv[1:]))
1393
1393
1394 class ParseError(Exception):
1394 class ParseError(Exception):
1395 """Exception raised on errors in parsing the command line."""
1395 """Exception raised on errors in parsing the command line."""
1396
1396
1397 def parse(args):
1397 def parse(args):
1398 options = {}
1398 options = {}
1399 cmdoptions = {}
1399 cmdoptions = {}
1400
1400
1401 try:
1401 try:
1402 args = fancyopts.fancyopts(args, globalopts, options)
1402 args = fancyopts.fancyopts(args, globalopts, options)
1403 except fancyopts.getopt.GetoptError, inst:
1403 except fancyopts.getopt.GetoptError, inst:
1404 raise ParseError(None, inst)
1404 raise ParseError(None, inst)
1405
1405
1406 if options["version"]:
1406 if options["version"]:
1407 return ("version", show_version, [], options, cmdoptions)
1407 return ("version", show_version, [], options, cmdoptions)
1408 elif not args:
1408 elif not args:
1409 return ("help", help_, ["shortlist"], options, cmdoptions)
1409 return ("help", help_, ["shortlist"], options, cmdoptions)
1410 else:
1410 else:
1411 cmd, args = args[0], args[1:]
1411 cmd, args = args[0], args[1:]
1412
1412
1413 i = find(cmd)[1]
1413 i = find(cmd)[1]
1414
1414
1415 # combine global options into local
1415 # combine global options into local
1416 c = list(i[1])
1416 c = list(i[1])
1417 for o in globalopts:
1417 for o in globalopts:
1418 c.append((o[0], o[1], options[o[1]], o[3]))
1418 c.append((o[0], o[1], options[o[1]], o[3]))
1419
1419
1420 try:
1420 try:
1421 args = fancyopts.fancyopts(args, c, cmdoptions)
1421 args = fancyopts.fancyopts(args, c, cmdoptions)
1422 except fancyopts.getopt.GetoptError, inst:
1422 except fancyopts.getopt.GetoptError, inst:
1423 raise ParseError(cmd, inst)
1423 raise ParseError(cmd, inst)
1424
1424
1425 # separate global options back out
1425 # separate global options back out
1426 for o in globalopts:
1426 for o in globalopts:
1427 n = o[1]
1427 n = o[1]
1428 options[n] = cmdoptions[n]
1428 options[n] = cmdoptions[n]
1429 del cmdoptions[n]
1429 del cmdoptions[n]
1430
1430
1431 return (cmd, i[0], args, options, cmdoptions)
1431 return (cmd, i[0], args, options, cmdoptions)
1432
1432
1433 def dispatch(args):
1433 def dispatch(args):
1434 signal.signal(signal.SIGTERM, catchterm)
1434 signal.signal(signal.SIGTERM, catchterm)
1435 try:
1435 try:
1436 signal.signal(signal.SIGHUP, catchterm)
1436 signal.signal(signal.SIGHUP, catchterm)
1437 except AttributeError:
1437 except AttributeError:
1438 pass
1438 pass
1439
1439
1440 try:
1440 try:
1441 cmd, func, args, options, cmdoptions = parse(args)
1441 cmd, func, args, options, cmdoptions = parse(args)
1442 except ParseError, inst:
1442 except ParseError, inst:
1443 u = ui.ui()
1443 u = ui.ui()
1444 if inst.args[0]:
1444 if inst.args[0]:
1445 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1445 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1446 help_(u, inst.args[0])
1446 help_(u, inst.args[0])
1447 else:
1447 else:
1448 u.warn("hg: %s\n" % inst.args[1])
1448 u.warn("hg: %s\n" % inst.args[1])
1449 help_(u, 'shortlist')
1449 help_(u, 'shortlist')
1450 sys.exit(-1)
1450 sys.exit(-1)
1451 except UnknownCommand, inst:
1451 except UnknownCommand, inst:
1452 u = ui.ui()
1452 u = ui.ui()
1453 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1453 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1454 help_(u, 'shortlist')
1454 help_(u, 'shortlist')
1455 sys.exit(1)
1455 sys.exit(1)
1456
1456
1457 if options["time"]:
1457 if options["time"]:
1458 def get_times():
1458 def get_times():
1459 t = os.times()
1459 t = os.times()
1460 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1460 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1461 t = (t[0], t[1], t[2], t[3], time.clock())
1461 t = (t[0], t[1], t[2], t[3], time.clock())
1462 return t
1462 return t
1463 s = get_times()
1463 s = get_times()
1464 def print_time():
1464 def print_time():
1465 t = get_times()
1465 t = get_times()
1466 u = ui.ui()
1466 u = ui.ui()
1467 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1467 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1468 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1468 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1469 atexit.register(print_time)
1469 atexit.register(print_time)
1470
1470
1471 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1471 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1472 not options["noninteractive"])
1472 not options["noninteractive"])
1473
1473
1474 try:
1474 try:
1475 try:
1475 try:
1476 if cmd not in norepo.split():
1476 if cmd not in norepo.split():
1477 path = options["repository"] or ""
1477 path = options["repository"] or ""
1478 repo = hg.repository(ui=u, path=path)
1478 repo = hg.repository(ui=u, path=path)
1479 d = lambda: func(u, repo, *args, **cmdoptions)
1479 d = lambda: func(u, repo, *args, **cmdoptions)
1480 else:
1480 else:
1481 d = lambda: func(u, *args, **cmdoptions)
1481 d = lambda: func(u, *args, **cmdoptions)
1482
1482
1483 if options['profile']:
1483 if options['profile']:
1484 import hotshot, hotshot.stats
1484 import hotshot, hotshot.stats
1485 prof = hotshot.Profile("hg.prof")
1485 prof = hotshot.Profile("hg.prof")
1486 r = prof.runcall(d)
1486 r = prof.runcall(d)
1487 prof.close()
1487 prof.close()
1488 stats = hotshot.stats.load("hg.prof")
1488 stats = hotshot.stats.load("hg.prof")
1489 stats.strip_dirs()
1489 stats.strip_dirs()
1490 stats.sort_stats('time', 'calls')
1490 stats.sort_stats('time', 'calls')
1491 stats.print_stats(40)
1491 stats.print_stats(40)
1492 return r
1492 return r
1493 else:
1493 else:
1494 return d()
1494 return d()
1495 except:
1495 except:
1496 if options['traceback']:
1496 if options['traceback']:
1497 traceback.print_exc()
1497 traceback.print_exc()
1498 raise
1498 raise
1499 except hg.RepoError, inst:
1499 except hg.RepoError, inst:
1500 u.warn("abort: ", inst, "!\n")
1500 u.warn("abort: ", inst, "!\n")
1501 except SignalInterrupt:
1501 except SignalInterrupt:
1502 u.warn("killed!\n")
1502 u.warn("killed!\n")
1503 except KeyboardInterrupt:
1503 except KeyboardInterrupt:
1504 try:
1504 try:
1505 u.warn("interrupted!\n")
1505 u.warn("interrupted!\n")
1506 except IOError, inst:
1506 except IOError, inst:
1507 if inst.errno == errno.EPIPE:
1507 if inst.errno == errno.EPIPE:
1508 if u.debugflag:
1508 if u.debugflag:
1509 u.warn("\nbroken pipe\n")
1509 u.warn("\nbroken pipe\n")
1510 else:
1510 else:
1511 raise
1511 raise
1512 except IOError, inst:
1512 except IOError, inst:
1513 if hasattr(inst, "code"):
1513 if hasattr(inst, "code"):
1514 u.warn("abort: %s\n" % inst)
1514 u.warn("abort: %s\n" % inst)
1515 elif hasattr(inst, "reason"):
1515 elif hasattr(inst, "reason"):
1516 u.warn("abort: error: %s\n" % inst.reason[1])
1516 u.warn("abort: error: %s\n" % inst.reason[1])
1517 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1517 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1518 if u.debugflag: u.warn("broken pipe\n")
1518 if u.debugflag: u.warn("broken pipe\n")
1519 else:
1519 else:
1520 raise
1520 raise
1521 except OSError, inst:
1521 except OSError, inst:
1522 if hasattr(inst, "filename"):
1522 if hasattr(inst, "filename"):
1523 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1523 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1524 else:
1524 else:
1525 u.warn("abort: %s\n" % inst.strerror)
1525 u.warn("abort: %s\n" % inst.strerror)
1526 except util.Abort, inst:
1526 except util.Abort, inst:
1527 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1527 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1528 sys.exit(1)
1528 sys.exit(1)
1529 except TypeError, inst:
1529 except TypeError, inst:
1530 # was this an argument error?
1530 # was this an argument error?
1531 tb = traceback.extract_tb(sys.exc_info()[2])
1531 tb = traceback.extract_tb(sys.exc_info()[2])
1532 if len(tb) > 2: # no
1532 if len(tb) > 2: # no
1533 raise
1533 raise
1534 u.debug(inst, "\n")
1534 u.debug(inst, "\n")
1535 u.warn("%s: invalid arguments\n" % cmd)
1535 u.warn("%s: invalid arguments\n" % cmd)
1536 help_(u, cmd)
1536 help_(u, cmd)
1537 except UnknownCommand, inst:
1537 except UnknownCommand, inst:
1538 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1538 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1539 help_(u, 'shortlist')
1539 help_(u, 'shortlist')
1540
1540
1541 sys.exit(-1)
1541 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now