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