##// END OF EJS Templates
Update synopsis for 'hg update', too.
Thomas Arendsen Hein -
r906:c711930c default
parent child Browse files
Show More
@@ -1,1542 +1,1542 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, source=None):
775 def init(ui, source=None):
776 """create a new repository in the current directory"""
776 """create a new repository in the current directory"""
777
777
778 if source:
778 if source:
779 raise util.Abort("no longer supported: use \"hg clone\" instead")
779 raise util.Abort("no longer supported: use \"hg clone\" instead")
780 hg.repository(ui, ".", create=1)
780 hg.repository(ui, ".", create=1)
781
781
782 def locate(ui, repo, *pats, **opts):
782 def locate(ui, repo, *pats, **opts):
783 """locate files matching specific patterns"""
783 """locate files matching specific patterns"""
784 end = '\n'
784 end = '\n'
785 if opts['print0']: end = '\0'
785 if opts['print0']: end = '\0'
786
786
787 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
787 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
788 if repo.dirstate.state(abs) == '?': continue
788 if repo.dirstate.state(abs) == '?': continue
789 if opts['fullpath']:
789 if opts['fullpath']:
790 ui.write(os.path.join(repo.root, abs), end)
790 ui.write(os.path.join(repo.root, abs), end)
791 else:
791 else:
792 ui.write(rel, end)
792 ui.write(rel, end)
793
793
794 def log(ui, repo, f=None, **opts):
794 def log(ui, repo, f=None, **opts):
795 """show the revision history of the repository or a single file"""
795 """show the revision history of the repository or a single file"""
796 if f:
796 if f:
797 files = relpath(repo, [f])
797 files = relpath(repo, [f])
798 filelog = repo.file(files[0])
798 filelog = repo.file(files[0])
799 log = filelog
799 log = filelog
800 lookup = filelog.lookup
800 lookup = filelog.lookup
801 else:
801 else:
802 files = None
802 files = None
803 filelog = None
803 filelog = None
804 log = repo.changelog
804 log = repo.changelog
805 lookup = repo.lookup
805 lookup = repo.lookup
806 revlist = []
806 revlist = []
807 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
807 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
808 while revs:
808 while revs:
809 if len(revs) == 1:
809 if len(revs) == 1:
810 revlist.append(revs.pop(0))
810 revlist.append(revs.pop(0))
811 else:
811 else:
812 a = revs.pop(0)
812 a = revs.pop(0)
813 b = revs.pop(0)
813 b = revs.pop(0)
814 off = a > b and -1 or 1
814 off = a > b and -1 or 1
815 revlist.extend(range(a, b + off, off))
815 revlist.extend(range(a, b + off, off))
816
816
817 for i in revlist or range(log.count() - 1, -1, -1):
817 for i in revlist or range(log.count() - 1, -1, -1):
818 show_changeset(ui, repo, filelog=filelog, rev=i)
818 show_changeset(ui, repo, filelog=filelog, rev=i)
819 if opts['patch']:
819 if opts['patch']:
820 if filelog:
820 if filelog:
821 filenode = filelog.node(i)
821 filenode = filelog.node(i)
822 i = filelog.linkrev(filenode)
822 i = filelog.linkrev(filenode)
823 changenode = repo.changelog.node(i)
823 changenode = repo.changelog.node(i)
824 prev, other = repo.changelog.parents(changenode)
824 prev, other = repo.changelog.parents(changenode)
825 dodiff(sys.stdout, ui, repo, files, prev, changenode)
825 dodiff(sys.stdout, ui, repo, files, prev, changenode)
826 ui.write("\n\n")
826 ui.write("\n\n")
827
827
828 def manifest(ui, repo, rev=None):
828 def manifest(ui, repo, rev=None):
829 """output the latest or given revision of the project manifest"""
829 """output the latest or given revision of the project manifest"""
830 if rev:
830 if rev:
831 try:
831 try:
832 # assume all revision numbers are for changesets
832 # assume all revision numbers are for changesets
833 n = repo.lookup(rev)
833 n = repo.lookup(rev)
834 change = repo.changelog.read(n)
834 change = repo.changelog.read(n)
835 n = change[0]
835 n = change[0]
836 except hg.RepoError:
836 except hg.RepoError:
837 n = repo.manifest.lookup(rev)
837 n = repo.manifest.lookup(rev)
838 else:
838 else:
839 n = repo.manifest.tip()
839 n = repo.manifest.tip()
840 m = repo.manifest.read(n)
840 m = repo.manifest.read(n)
841 mf = repo.manifest.readflags(n)
841 mf = repo.manifest.readflags(n)
842 files = m.keys()
842 files = m.keys()
843 files.sort()
843 files.sort()
844
844
845 for f in files:
845 for f in files:
846 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
846 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
847
847
848 def parents(ui, repo, rev=None):
848 def parents(ui, repo, rev=None):
849 """show the parents of the working dir or revision"""
849 """show the parents of the working dir or revision"""
850 if rev:
850 if rev:
851 p = repo.changelog.parents(repo.lookup(rev))
851 p = repo.changelog.parents(repo.lookup(rev))
852 else:
852 else:
853 p = repo.dirstate.parents()
853 p = repo.dirstate.parents()
854
854
855 for n in p:
855 for n in p:
856 if n != hg.nullid:
856 if n != hg.nullid:
857 show_changeset(ui, repo, changenode=n)
857 show_changeset(ui, repo, changenode=n)
858
858
859 def paths(ui, repo, search = None):
859 def paths(ui, repo, search = None):
860 """show path or list of available paths"""
860 """show path or list of available paths"""
861 if search:
861 if search:
862 for name, path in ui.configitems("paths"):
862 for name, path in ui.configitems("paths"):
863 if name == search:
863 if name == search:
864 ui.write("%s\n" % path)
864 ui.write("%s\n" % path)
865 return
865 return
866 ui.warn("not found!\n")
866 ui.warn("not found!\n")
867 return 1
867 return 1
868 else:
868 else:
869 for name, path in ui.configitems("paths"):
869 for name, path in ui.configitems("paths"):
870 ui.write("%s = %s\n" % (name, path))
870 ui.write("%s = %s\n" % (name, path))
871
871
872 def pull(ui, repo, source="default", **opts):
872 def pull(ui, repo, source="default", **opts):
873 """pull changes from the specified source"""
873 """pull changes from the specified source"""
874 source = ui.expandpath(source)
874 source = ui.expandpath(source)
875 ui.status('pulling from %s\n' % (source))
875 ui.status('pulling from %s\n' % (source))
876
876
877 other = hg.repository(ui, source)
877 other = hg.repository(ui, source)
878 r = repo.pull(other)
878 r = repo.pull(other)
879 if not r:
879 if not r:
880 if opts['update']:
880 if opts['update']:
881 return update(ui, repo)
881 return update(ui, repo)
882 else:
882 else:
883 ui.status("(run 'hg update' to get a working copy)\n")
883 ui.status("(run 'hg update' to get a working copy)\n")
884
884
885 return r
885 return r
886
886
887 def push(ui, repo, dest="default-push", force=False):
887 def push(ui, repo, dest="default-push", force=False):
888 """push changes to the specified destination"""
888 """push changes to the specified destination"""
889 dest = ui.expandpath(dest)
889 dest = ui.expandpath(dest)
890 ui.status('pushing to %s\n' % (dest))
890 ui.status('pushing to %s\n' % (dest))
891
891
892 other = hg.repository(ui, dest)
892 other = hg.repository(ui, dest)
893 r = repo.push(other, force)
893 r = repo.push(other, force)
894 return r
894 return r
895
895
896 def rawcommit(ui, repo, *flist, **rc):
896 def rawcommit(ui, repo, *flist, **rc):
897 "raw commit interface"
897 "raw commit interface"
898 if rc['text']:
898 if rc['text']:
899 ui.warn("Warning: -t and --text is deprecated,"
899 ui.warn("Warning: -t and --text is deprecated,"
900 " please use -m or --message instead.\n")
900 " please use -m or --message instead.\n")
901 message = rc['message'] or rc['text']
901 message = rc['message'] or rc['text']
902 if not message and rc['logfile']:
902 if not message and rc['logfile']:
903 try:
903 try:
904 message = open(rc['logfile']).read()
904 message = open(rc['logfile']).read()
905 except IOError:
905 except IOError:
906 pass
906 pass
907 if not message and not rc['logfile']:
907 if not message and not rc['logfile']:
908 ui.warn("abort: missing commit message\n")
908 ui.warn("abort: missing commit message\n")
909 return 1
909 return 1
910
910
911 files = relpath(repo, list(flist))
911 files = relpath(repo, list(flist))
912 if rc['files']:
912 if rc['files']:
913 files += open(rc['files']).read().splitlines()
913 files += open(rc['files']).read().splitlines()
914
914
915 rc['parent'] = map(repo.lookup, rc['parent'])
915 rc['parent'] = map(repo.lookup, rc['parent'])
916
916
917 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
917 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
918
918
919 def recover(ui, repo):
919 def recover(ui, repo):
920 """roll back an interrupted transaction"""
920 """roll back an interrupted transaction"""
921 repo.recover()
921 repo.recover()
922
922
923 def remove(ui, repo, file1, *files):
923 def remove(ui, repo, file1, *files):
924 """remove the specified files on the next commit"""
924 """remove the specified files on the next commit"""
925 repo.remove(relpath(repo, (file1,) + files))
925 repo.remove(relpath(repo, (file1,) + files))
926
926
927 def revert(ui, repo, *names, **opts):
927 def revert(ui, repo, *names, **opts):
928 """revert modified files or dirs back to their unmodified states"""
928 """revert modified files or dirs back to their unmodified states"""
929 node = opts['rev'] and repo.lookup(opts['rev']) or \
929 node = opts['rev'] and repo.lookup(opts['rev']) or \
930 repo.dirstate.parents()[0]
930 repo.dirstate.parents()[0]
931 root = os.path.realpath(repo.root)
931 root = os.path.realpath(repo.root)
932
932
933 def trimpath(p):
933 def trimpath(p):
934 p = os.path.realpath(p)
934 p = os.path.realpath(p)
935 if p.startswith(root):
935 if p.startswith(root):
936 rest = p[len(root):]
936 rest = p[len(root):]
937 if not rest:
937 if not rest:
938 return rest
938 return rest
939 if p.startswith(os.sep):
939 if p.startswith(os.sep):
940 return rest[1:]
940 return rest[1:]
941 return p
941 return p
942
942
943 relnames = map(trimpath, names or [os.getcwd()])
943 relnames = map(trimpath, names or [os.getcwd()])
944 chosen = {}
944 chosen = {}
945
945
946 def choose(name):
946 def choose(name):
947 def body(name):
947 def body(name):
948 for r in relnames:
948 for r in relnames:
949 if not name.startswith(r):
949 if not name.startswith(r):
950 continue
950 continue
951 rest = name[len(r):]
951 rest = name[len(r):]
952 if not rest:
952 if not rest:
953 return r, True
953 return r, True
954 depth = rest.count(os.sep)
954 depth = rest.count(os.sep)
955 if not r:
955 if not r:
956 if depth == 0 or not opts['nonrecursive']:
956 if depth == 0 or not opts['nonrecursive']:
957 return r, True
957 return r, True
958 elif rest[0] == os.sep:
958 elif rest[0] == os.sep:
959 if depth == 1 or not opts['nonrecursive']:
959 if depth == 1 or not opts['nonrecursive']:
960 return r, True
960 return r, True
961 return None, False
961 return None, False
962 relname, ret = body(name)
962 relname, ret = body(name)
963 if ret:
963 if ret:
964 chosen[relname] = 1
964 chosen[relname] = 1
965 return ret
965 return ret
966
966
967 r = repo.update(node, False, True, choose, False)
967 r = repo.update(node, False, True, choose, False)
968 for n in relnames:
968 for n in relnames:
969 if n not in chosen:
969 if n not in chosen:
970 ui.warn('error: no matches for %s\n' % n)
970 ui.warn('error: no matches for %s\n' % n)
971 r = 1
971 r = 1
972 sys.stdout.flush()
972 sys.stdout.flush()
973 return r
973 return r
974
974
975 def root(ui, repo):
975 def root(ui, repo):
976 """print the root (top) of the current working dir"""
976 """print the root (top) of the current working dir"""
977 ui.write(repo.root + "\n")
977 ui.write(repo.root + "\n")
978
978
979 def serve(ui, repo, **opts):
979 def serve(ui, repo, **opts):
980 """export the repository via HTTP"""
980 """export the repository via HTTP"""
981
981
982 if opts["stdio"]:
982 if opts["stdio"]:
983 fin, fout = sys.stdin, sys.stdout
983 fin, fout = sys.stdin, sys.stdout
984 sys.stdout = sys.stderr
984 sys.stdout = sys.stderr
985
985
986 def getarg():
986 def getarg():
987 argline = fin.readline()[:-1]
987 argline = fin.readline()[:-1]
988 arg, l = argline.split()
988 arg, l = argline.split()
989 val = fin.read(int(l))
989 val = fin.read(int(l))
990 return arg, val
990 return arg, val
991 def respond(v):
991 def respond(v):
992 fout.write("%d\n" % len(v))
992 fout.write("%d\n" % len(v))
993 fout.write(v)
993 fout.write(v)
994 fout.flush()
994 fout.flush()
995
995
996 lock = None
996 lock = None
997
997
998 while 1:
998 while 1:
999 cmd = fin.readline()[:-1]
999 cmd = fin.readline()[:-1]
1000 if cmd == '':
1000 if cmd == '':
1001 return
1001 return
1002 if cmd == "heads":
1002 if cmd == "heads":
1003 h = repo.heads()
1003 h = repo.heads()
1004 respond(" ".join(map(hg.hex, h)) + "\n")
1004 respond(" ".join(map(hg.hex, h)) + "\n")
1005 if cmd == "lock":
1005 if cmd == "lock":
1006 lock = repo.lock()
1006 lock = repo.lock()
1007 respond("")
1007 respond("")
1008 if cmd == "unlock":
1008 if cmd == "unlock":
1009 if lock:
1009 if lock:
1010 lock.release()
1010 lock.release()
1011 lock = None
1011 lock = None
1012 respond("")
1012 respond("")
1013 elif cmd == "branches":
1013 elif cmd == "branches":
1014 arg, nodes = getarg()
1014 arg, nodes = getarg()
1015 nodes = map(hg.bin, nodes.split(" "))
1015 nodes = map(hg.bin, nodes.split(" "))
1016 r = []
1016 r = []
1017 for b in repo.branches(nodes):
1017 for b in repo.branches(nodes):
1018 r.append(" ".join(map(hg.hex, b)) + "\n")
1018 r.append(" ".join(map(hg.hex, b)) + "\n")
1019 respond("".join(r))
1019 respond("".join(r))
1020 elif cmd == "between":
1020 elif cmd == "between":
1021 arg, pairs = getarg()
1021 arg, pairs = getarg()
1022 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1022 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
1023 r = []
1023 r = []
1024 for b in repo.between(pairs):
1024 for b in repo.between(pairs):
1025 r.append(" ".join(map(hg.hex, b)) + "\n")
1025 r.append(" ".join(map(hg.hex, b)) + "\n")
1026 respond("".join(r))
1026 respond("".join(r))
1027 elif cmd == "changegroup":
1027 elif cmd == "changegroup":
1028 nodes = []
1028 nodes = []
1029 arg, roots = getarg()
1029 arg, roots = getarg()
1030 nodes = map(hg.bin, roots.split(" "))
1030 nodes = map(hg.bin, roots.split(" "))
1031
1031
1032 cg = repo.changegroup(nodes)
1032 cg = repo.changegroup(nodes)
1033 while 1:
1033 while 1:
1034 d = cg.read(4096)
1034 d = cg.read(4096)
1035 if not d:
1035 if not d:
1036 break
1036 break
1037 fout.write(d)
1037 fout.write(d)
1038
1038
1039 fout.flush()
1039 fout.flush()
1040
1040
1041 elif cmd == "addchangegroup":
1041 elif cmd == "addchangegroup":
1042 if not lock:
1042 if not lock:
1043 respond("not locked")
1043 respond("not locked")
1044 continue
1044 continue
1045 respond("")
1045 respond("")
1046
1046
1047 r = repo.addchangegroup(fin)
1047 r = repo.addchangegroup(fin)
1048 respond("")
1048 respond("")
1049
1049
1050 def openlog(opt, default):
1050 def openlog(opt, default):
1051 if opts[opt] and opts[opt] != '-':
1051 if opts[opt] and opts[opt] != '-':
1052 return open(opts[opt], 'w')
1052 return open(opts[opt], 'w')
1053 else:
1053 else:
1054 return default
1054 return default
1055
1055
1056 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1056 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
1057 opts["address"], opts["port"], opts["ipv6"],
1057 opts["address"], opts["port"], opts["ipv6"],
1058 openlog('accesslog', sys.stdout),
1058 openlog('accesslog', sys.stdout),
1059 openlog('errorlog', sys.stderr))
1059 openlog('errorlog', sys.stderr))
1060 if ui.verbose:
1060 if ui.verbose:
1061 addr, port = httpd.socket.getsockname()
1061 addr, port = httpd.socket.getsockname()
1062 if addr == '0.0.0.0':
1062 if addr == '0.0.0.0':
1063 addr = socket.gethostname()
1063 addr = socket.gethostname()
1064 else:
1064 else:
1065 try:
1065 try:
1066 addr = socket.gethostbyaddr(addr)[0]
1066 addr = socket.gethostbyaddr(addr)[0]
1067 except socket.error:
1067 except socket.error:
1068 pass
1068 pass
1069 if port != 80:
1069 if port != 80:
1070 ui.status('listening at http://%s:%d/\n' % (addr, port))
1070 ui.status('listening at http://%s:%d/\n' % (addr, port))
1071 else:
1071 else:
1072 ui.status('listening at http://%s/\n' % addr)
1072 ui.status('listening at http://%s/\n' % addr)
1073 httpd.serve_forever()
1073 httpd.serve_forever()
1074
1074
1075 def status(ui, repo, *pats, **opts):
1075 def status(ui, repo, *pats, **opts):
1076 '''show changed files in the working directory
1076 '''show changed files in the working directory
1077
1077
1078 M = modified
1078 M = modified
1079 A = added
1079 A = added
1080 R = removed
1080 R = removed
1081 ? = not tracked
1081 ? = not tracked
1082 '''
1082 '''
1083
1083
1084 cwd = repo.getcwd()
1084 cwd = repo.getcwd()
1085 files, matchfn = matchpats(repo, cwd, pats, opts)
1085 files, matchfn = matchpats(repo, cwd, pats, opts)
1086 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1086 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1087 for n in repo.changes(files=files, match=matchfn)]
1087 for n in repo.changes(files=files, match=matchfn)]
1088
1088
1089 changetypes = [('modified', 'M', c),
1089 changetypes = [('modified', 'M', c),
1090 ('added', 'A', a),
1090 ('added', 'A', a),
1091 ('removed', 'R', d),
1091 ('removed', 'R', d),
1092 ('unknown', '?', u)]
1092 ('unknown', '?', u)]
1093
1093
1094 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1094 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1095 or changetypes):
1095 or changetypes):
1096 for f in changes:
1096 for f in changes:
1097 ui.write("%s %s\n" % (char, f))
1097 ui.write("%s %s\n" % (char, f))
1098
1098
1099 def tag(ui, repo, name, rev=None, **opts):
1099 def tag(ui, repo, name, rev=None, **opts):
1100 """add a tag for the current tip or a given revision"""
1100 """add a tag for the current tip or a given revision"""
1101 if opts['text']:
1101 if opts['text']:
1102 ui.warn("Warning: -t and --text is deprecated,"
1102 ui.warn("Warning: -t and --text is deprecated,"
1103 " please use -m or --message instead.\n")
1103 " please use -m or --message instead.\n")
1104 if name == "tip":
1104 if name == "tip":
1105 ui.warn("abort: 'tip' is a reserved name!\n")
1105 ui.warn("abort: 'tip' is a reserved name!\n")
1106 return -1
1106 return -1
1107 if rev:
1107 if rev:
1108 r = hg.hex(repo.lookup(rev))
1108 r = hg.hex(repo.lookup(rev))
1109 else:
1109 else:
1110 r = hg.hex(repo.changelog.tip())
1110 r = hg.hex(repo.changelog.tip())
1111
1111
1112 if name.find(revrangesep) >= 0:
1112 if name.find(revrangesep) >= 0:
1113 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1113 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1114 return -1
1114 return -1
1115
1115
1116 if opts['local']:
1116 if opts['local']:
1117 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1117 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1118 return
1118 return
1119
1119
1120 (c, a, d, u) = repo.changes()
1120 (c, a, d, u) = repo.changes()
1121 for x in (c, a, d, u):
1121 for x in (c, a, d, u):
1122 if ".hgtags" in x:
1122 if ".hgtags" in x:
1123 ui.warn("abort: working copy of .hgtags is changed!\n")
1123 ui.warn("abort: working copy of .hgtags is changed!\n")
1124 ui.status("(please commit .hgtags manually)\n")
1124 ui.status("(please commit .hgtags manually)\n")
1125 return -1
1125 return -1
1126
1126
1127 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1127 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1128 if repo.dirstate.state(".hgtags") == '?':
1128 if repo.dirstate.state(".hgtags") == '?':
1129 repo.add([".hgtags"])
1129 repo.add([".hgtags"])
1130
1130
1131 message = (opts['message'] or opts['text'] or
1131 message = (opts['message'] or opts['text'] or
1132 "Added tag %s for changeset %s" % (name, r))
1132 "Added tag %s for changeset %s" % (name, r))
1133 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1133 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1134
1134
1135 def tags(ui, repo):
1135 def tags(ui, repo):
1136 """list repository tags"""
1136 """list repository tags"""
1137
1137
1138 l = repo.tagslist()
1138 l = repo.tagslist()
1139 l.reverse()
1139 l.reverse()
1140 for t, n in l:
1140 for t, n in l:
1141 try:
1141 try:
1142 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1142 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1143 except KeyError:
1143 except KeyError:
1144 r = " ?:?"
1144 r = " ?:?"
1145 ui.write("%-30s %s\n" % (t, r))
1145 ui.write("%-30s %s\n" % (t, r))
1146
1146
1147 def tip(ui, repo):
1147 def tip(ui, repo):
1148 """show the tip revision"""
1148 """show the tip revision"""
1149 n = repo.changelog.tip()
1149 n = repo.changelog.tip()
1150 show_changeset(ui, repo, changenode=n)
1150 show_changeset(ui, repo, changenode=n)
1151
1151
1152 def undo(ui, repo):
1152 def undo(ui, repo):
1153 """undo the last commit or pull
1153 """undo the last commit or pull
1154
1154
1155 Roll back the last pull or commit transaction on the
1155 Roll back the last pull or commit transaction on the
1156 repository, restoring the project to its earlier state.
1156 repository, restoring the project to its earlier state.
1157
1157
1158 This command should be used with care. There is only one level of
1158 This command should be used with care. There is only one level of
1159 undo and there is no redo.
1159 undo and there is no redo.
1160
1160
1161 This command is not intended for use on public repositories. Once
1161 This command is not intended for use on public repositories. Once
1162 a change is visible for pull by other users, undoing it locally is
1162 a change is visible for pull by other users, undoing it locally is
1163 ineffective.
1163 ineffective.
1164 """
1164 """
1165 repo.undo()
1165 repo.undo()
1166
1166
1167 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1167 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1168 '''update or merge working directory
1168 '''update or merge working directory
1169
1169
1170 If there are no outstanding changes in the working directory and
1170 If there are no outstanding changes in the working directory and
1171 there is a linear relationship between the current version and the
1171 there is a linear relationship between the current version and the
1172 requested version, the result is the requested version.
1172 requested version, the result is the requested version.
1173
1173
1174 Otherwise the result is a merge between the contents of the
1174 Otherwise the result is a merge between the contents of the
1175 current working directory and the requested version. Files that
1175 current working directory and the requested version. Files that
1176 changed between either parent are marked as changed for the next
1176 changed between either parent are marked as changed for the next
1177 commit and a commit must be performed before any further updates
1177 commit and a commit must be performed before any further updates
1178 are allowed.
1178 are allowed.
1179 '''
1179 '''
1180 if branch:
1180 if branch:
1181 br = repo.branchlookup(branch=branch)
1181 br = repo.branchlookup(branch=branch)
1182 found = []
1182 found = []
1183 for x in br:
1183 for x in br:
1184 if branch in br[x]:
1184 if branch in br[x]:
1185 found.append(x)
1185 found.append(x)
1186 if len(found) > 1:
1186 if len(found) > 1:
1187 ui.warn("Found multiple heads for %s\n" % branch)
1187 ui.warn("Found multiple heads for %s\n" % branch)
1188 for x in found:
1188 for x in found:
1189 show_changeset(ui, repo, changenode=x, brinfo=br)
1189 show_changeset(ui, repo, changenode=x, brinfo=br)
1190 return 1
1190 return 1
1191 if len(found) == 1:
1191 if len(found) == 1:
1192 node = found[0]
1192 node = found[0]
1193 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1193 ui.warn("Using head %s for branch %s\n" % (hg.short(node), branch))
1194 else:
1194 else:
1195 ui.warn("branch %s not found\n" % (branch))
1195 ui.warn("branch %s not found\n" % (branch))
1196 return 1
1196 return 1
1197 else:
1197 else:
1198 node = node and repo.lookup(node) or repo.changelog.tip()
1198 node = node and repo.lookup(node) or repo.changelog.tip()
1199 return repo.update(node, allow=merge, force=clean)
1199 return repo.update(node, allow=merge, force=clean)
1200
1200
1201 def verify(ui, repo):
1201 def verify(ui, repo):
1202 """verify the integrity of the repository"""
1202 """verify the integrity of the repository"""
1203 return repo.verify()
1203 return repo.verify()
1204
1204
1205 # Command options and aliases are listed here, alphabetically
1205 # Command options and aliases are listed here, alphabetically
1206
1206
1207 table = {
1207 table = {
1208 "^add":
1208 "^add":
1209 (add,
1209 (add,
1210 [('I', 'include', [], 'include path in search'),
1210 [('I', 'include', [], 'include path in search'),
1211 ('X', 'exclude', [], 'exclude path from search')],
1211 ('X', 'exclude', [], 'exclude path from search')],
1212 "hg add [FILE]..."),
1212 "hg add [FILE]..."),
1213 "addremove":
1213 "addremove":
1214 (addremove,
1214 (addremove,
1215 [('I', 'include', [], 'include path in search'),
1215 [('I', 'include', [], 'include path in search'),
1216 ('X', 'exclude', [], 'exclude path from search')],
1216 ('X', 'exclude', [], 'exclude path from search')],
1217 "hg addremove [OPTION]... [FILE]..."),
1217 "hg addremove [OPTION]... [FILE]..."),
1218 "^annotate":
1218 "^annotate":
1219 (annotate,
1219 (annotate,
1220 [('r', 'rev', '', 'revision'),
1220 [('r', 'rev', '', 'revision'),
1221 ('u', 'user', None, 'show user'),
1221 ('u', 'user', None, 'show user'),
1222 ('n', 'number', None, 'show revision number'),
1222 ('n', 'number', None, 'show revision number'),
1223 ('c', 'changeset', None, 'show changeset'),
1223 ('c', 'changeset', None, 'show changeset'),
1224 ('I', 'include', [], 'include path in search'),
1224 ('I', 'include', [], 'include path in search'),
1225 ('X', 'exclude', [], 'exclude path from search')],
1225 ('X', 'exclude', [], 'exclude path from search')],
1226 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1226 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1227 "cat":
1227 "cat":
1228 (cat,
1228 (cat,
1229 [('o', 'output', "", 'output to file')],
1229 [('o', 'output', "", 'output to file')],
1230 'hg cat [-o OUTFILE] FILE [REV]'),
1230 'hg cat [-o OUTFILE] FILE [REV]'),
1231 "^clone":
1231 "^clone":
1232 (clone,
1232 (clone,
1233 [('U', 'noupdate', None, 'skip update after cloning')],
1233 [('U', 'noupdate', None, 'skip update after cloning')],
1234 'hg clone [-U] SOURCE [DEST]'),
1234 'hg clone [-U] SOURCE [DEST]'),
1235 "^commit|ci":
1235 "^commit|ci":
1236 (commit,
1236 (commit,
1237 [('A', 'addremove', None, 'run add/remove during commit'),
1237 [('A', 'addremove', None, 'run add/remove during commit'),
1238 ('I', 'include', [], 'include path in search'),
1238 ('I', 'include', [], 'include path in search'),
1239 ('X', 'exclude', [], 'exclude path from search'),
1239 ('X', 'exclude', [], 'exclude path from search'),
1240 ('m', 'message', "", 'commit message'),
1240 ('m', 'message', "", 'commit message'),
1241 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1241 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1242 ('l', 'logfile', "", 'commit message file'),
1242 ('l', 'logfile', "", 'commit message file'),
1243 ('d', 'date', "", 'date code'),
1243 ('d', 'date', "", 'date code'),
1244 ('u', 'user', "", 'user')],
1244 ('u', 'user', "", 'user')],
1245 'hg commit [OPTION]... [FILE]...'),
1245 'hg commit [OPTION]... [FILE]...'),
1246 "copy": (copy, [], 'hg copy SOURCE DEST'),
1246 "copy": (copy, [], 'hg copy SOURCE DEST'),
1247 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1247 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1248 "debugstate": (debugstate, [], 'debugstate'),
1248 "debugstate": (debugstate, [], 'debugstate'),
1249 "debugindex": (debugindex, [], 'debugindex FILE'),
1249 "debugindex": (debugindex, [], 'debugindex FILE'),
1250 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1250 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1251 "debugwalk":
1251 "debugwalk":
1252 (debugwalk,
1252 (debugwalk,
1253 [('I', 'include', [], 'include path in search'),
1253 [('I', 'include', [], 'include path in search'),
1254 ('X', 'exclude', [], 'exclude path from search')],
1254 ('X', 'exclude', [], 'exclude path from search')],
1255 'debugwalk [OPTIONS]... [FILE]...'),
1255 'debugwalk [OPTIONS]... [FILE]...'),
1256 "^diff":
1256 "^diff":
1257 (diff,
1257 (diff,
1258 [('r', 'rev', [], 'revision'),
1258 [('r', 'rev', [], 'revision'),
1259 ('I', 'include', [], 'include path in search'),
1259 ('I', 'include', [], 'include path in search'),
1260 ('X', 'exclude', [], 'exclude path from search')],
1260 ('X', 'exclude', [], 'exclude path from search')],
1261 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1261 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1262 "^export":
1262 "^export":
1263 (export,
1263 (export,
1264 [('o', 'output', "", 'output to file')],
1264 [('o', 'output', "", 'output to file')],
1265 "hg export [-o OUTFILE] REV..."),
1265 "hg export [-o OUTFILE] REV..."),
1266 "forget":
1266 "forget":
1267 (forget,
1267 (forget,
1268 [('I', 'include', [], 'include path in search'),
1268 [('I', 'include', [], 'include path in search'),
1269 ('X', 'exclude', [], 'exclude path from search')],
1269 ('X', 'exclude', [], 'exclude path from search')],
1270 "hg forget FILE..."),
1270 "hg forget FILE..."),
1271 "heads":
1271 "heads":
1272 (heads,
1272 (heads,
1273 [('b', 'branches', None, 'find branch info')],
1273 [('b', 'branches', None, 'find branch info')],
1274 'hg [-b] heads'),
1274 'hg [-b] heads'),
1275 "help": (help_, [], 'hg help [COMMAND]'),
1275 "help": (help_, [], 'hg help [COMMAND]'),
1276 "identify|id": (identify, [], 'hg identify'),
1276 "identify|id": (identify, [], 'hg identify'),
1277 "import|patch":
1277 "import|patch":
1278 (import_,
1278 (import_,
1279 [('p', 'strip', 1, 'path strip'),
1279 [('p', 'strip', 1, 'path strip'),
1280 ('b', 'base', "", 'base path')],
1280 ('b', 'base', "", 'base path')],
1281 "hg import [-p NUM] [-b BASE] PATCH..."),
1281 "hg import [-p NUM] [-b BASE] PATCH..."),
1282 "^init": (init, [], 'hg init'),
1282 "^init": (init, [], 'hg init'),
1283 "locate":
1283 "locate":
1284 (locate,
1284 (locate,
1285 [('r', 'rev', '', 'revision'),
1285 [('r', 'rev', '', 'revision'),
1286 ('0', 'print0', None, 'end records with NUL'),
1286 ('0', 'print0', None, 'end records with NUL'),
1287 ('f', 'fullpath', None, 'print complete paths'),
1287 ('f', 'fullpath', None, 'print complete paths'),
1288 ('I', 'include', [], 'include path in search'),
1288 ('I', 'include', [], 'include path in search'),
1289 ('X', 'exclude', [], 'exclude path from search')],
1289 ('X', 'exclude', [], 'exclude path from search')],
1290 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1290 'hg locate [-r REV] [-f] [-0] [PATTERN]...'),
1291 "^log|history":
1291 "^log|history":
1292 (log,
1292 (log,
1293 [('r', 'rev', [], 'revision'),
1293 [('r', 'rev', [], 'revision'),
1294 ('p', 'patch', None, 'show patch')],
1294 ('p', 'patch', None, 'show patch')],
1295 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1295 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1296 "manifest": (manifest, [], 'hg manifest [REV]'),
1296 "manifest": (manifest, [], 'hg manifest [REV]'),
1297 "parents": (parents, [], 'hg parents [REV]'),
1297 "parents": (parents, [], 'hg parents [REV]'),
1298 "paths": (paths, [], 'hg paths [name]'),
1298 "paths": (paths, [], 'hg paths [name]'),
1299 "^pull":
1299 "^pull":
1300 (pull,
1300 (pull,
1301 [('u', 'update', None, 'update working directory')],
1301 [('u', 'update', None, 'update working directory')],
1302 'hg pull [-u] [SOURCE]'),
1302 'hg pull [-u] [SOURCE]'),
1303 "^push":
1303 "^push":
1304 (push,
1304 (push,
1305 [('f', 'force', None, 'force push')],
1305 [('f', 'force', None, 'force push')],
1306 'hg push [DEST]'),
1306 'hg push [DEST]'),
1307 "rawcommit":
1307 "rawcommit":
1308 (rawcommit,
1308 (rawcommit,
1309 [('p', 'parent', [], 'parent'),
1309 [('p', 'parent', [], 'parent'),
1310 ('d', 'date', "", 'date code'),
1310 ('d', 'date', "", 'date code'),
1311 ('u', 'user', "", 'user'),
1311 ('u', 'user', "", 'user'),
1312 ('F', 'files', "", 'file list'),
1312 ('F', 'files', "", 'file list'),
1313 ('m', 'message', "", 'commit message'),
1313 ('m', 'message', "", 'commit message'),
1314 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1314 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1315 ('l', 'logfile', "", 'commit message file')],
1315 ('l', 'logfile', "", 'commit message file')],
1316 'hg rawcommit [OPTION]... [FILE]...'),
1316 'hg rawcommit [OPTION]... [FILE]...'),
1317 "recover": (recover, [], "hg recover"),
1317 "recover": (recover, [], "hg recover"),
1318 "^remove|rm": (remove, [], "hg remove FILE..."),
1318 "^remove|rm": (remove, [], "hg remove FILE..."),
1319 "^revert":
1319 "^revert":
1320 (revert,
1320 (revert,
1321 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1321 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1322 ("r", "rev", "", "revision")],
1322 ("r", "rev", "", "revision")],
1323 "hg revert [-n] [-r REV] [NAME]..."),
1323 "hg revert [-n] [-r REV] [NAME]..."),
1324 "root": (root, [], "hg root"),
1324 "root": (root, [], "hg root"),
1325 "^serve":
1325 "^serve":
1326 (serve,
1326 (serve,
1327 [('A', 'accesslog', '', 'access log file'),
1327 [('A', 'accesslog', '', 'access log file'),
1328 ('E', 'errorlog', '', 'error log file'),
1328 ('E', 'errorlog', '', 'error log file'),
1329 ('p', 'port', 8000, 'listen port'),
1329 ('p', 'port', 8000, 'listen port'),
1330 ('a', 'address', '', 'interface address'),
1330 ('a', 'address', '', 'interface address'),
1331 ('n', 'name', os.getcwd(), 'repository name'),
1331 ('n', 'name', os.getcwd(), 'repository name'),
1332 ('', 'stdio', None, 'for remote clients'),
1332 ('', 'stdio', None, 'for remote clients'),
1333 ('t', 'templates', "", 'template map'),
1333 ('t', 'templates', "", 'template map'),
1334 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1334 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1335 "hg serve [OPTION]..."),
1335 "hg serve [OPTION]..."),
1336 "^status":
1336 "^status":
1337 (status,
1337 (status,
1338 [('m', 'modified', None, 'show only modified files'),
1338 [('m', 'modified', None, 'show only modified files'),
1339 ('a', 'added', None, 'show only added files'),
1339 ('a', 'added', None, 'show only added files'),
1340 ('r', 'removed', None, 'show only removed files'),
1340 ('r', 'removed', None, 'show only removed files'),
1341 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1341 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1342 ('I', 'include', [], 'include path in search'),
1342 ('I', 'include', [], 'include path in search'),
1343 ('X', 'exclude', [], 'exclude path from search')],
1343 ('X', 'exclude', [], 'exclude path from search')],
1344 "hg status [FILE]..."),
1344 "hg status [FILE]..."),
1345 "tag":
1345 "tag":
1346 (tag,
1346 (tag,
1347 [('l', 'local', None, 'make the tag local'),
1347 [('l', 'local', None, 'make the tag local'),
1348 ('m', 'message', "", 'commit message'),
1348 ('m', 'message', "", 'commit message'),
1349 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1349 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1350 ('d', 'date', "", 'date code'),
1350 ('d', 'date', "", 'date code'),
1351 ('u', 'user', "", 'user')],
1351 ('u', 'user', "", 'user')],
1352 'hg tag [OPTION]... NAME [REV]'),
1352 'hg tag [OPTION]... NAME [REV]'),
1353 "tags": (tags, [], 'hg tags'),
1353 "tags": (tags, [], 'hg tags'),
1354 "tip": (tip, [], 'hg tip'),
1354 "tip": (tip, [], 'hg tip'),
1355 "undo": (undo, [], 'hg undo'),
1355 "undo": (undo, [], 'hg undo'),
1356 "^update|up|checkout|co":
1356 "^update|up|checkout|co":
1357 (update,
1357 (update,
1358 [('b', 'branch', "", 'checkout the head of a specific branch'),
1358 [('b', 'branch', "", 'checkout the head of a specific branch'),
1359 ('m', 'merge', None, 'allow merging of conflicts'),
1359 ('m', 'merge', None, 'allow merging of conflicts'),
1360 ('C', 'clean', None, 'overwrite locally modified files')],
1360 ('C', 'clean', None, 'overwrite locally modified files')],
1361 'hg update [-m] [-C] [REV]'),
1361 'hg update [-b TAG] [-m] [-C] [REV]'),
1362 "verify": (verify, [], 'hg verify'),
1362 "verify": (verify, [], 'hg verify'),
1363 "version": (show_version, [], 'hg version'),
1363 "version": (show_version, [], 'hg version'),
1364 }
1364 }
1365
1365
1366 globalopts = [('v', 'verbose', None, 'verbose mode'),
1366 globalopts = [('v', 'verbose', None, 'verbose mode'),
1367 ('', 'debug', None, 'debug mode'),
1367 ('', 'debug', None, 'debug mode'),
1368 ('q', 'quiet', None, 'quiet mode'),
1368 ('q', 'quiet', None, 'quiet mode'),
1369 ('', 'profile', None, 'profile'),
1369 ('', 'profile', None, 'profile'),
1370 ('R', 'repository', "", 'repository root directory'),
1370 ('R', 'repository', "", 'repository root directory'),
1371 ('', 'traceback', None, 'print traceback on exception'),
1371 ('', 'traceback', None, 'print traceback on exception'),
1372 ('y', 'noninteractive', None, 'run non-interactively'),
1372 ('y', 'noninteractive', None, 'run non-interactively'),
1373 ('', 'version', None, 'output version information and exit'),
1373 ('', 'version', None, 'output version information and exit'),
1374 ('', 'time', None, 'time how long the command takes'),
1374 ('', 'time', None, 'time how long the command takes'),
1375 ]
1375 ]
1376
1376
1377 norepo = "clone init version help debugindex debugindexdot"
1377 norepo = "clone init version help debugindex debugindexdot"
1378
1378
1379 def find(cmd):
1379 def find(cmd):
1380 for e in table.keys():
1380 for e in table.keys():
1381 if re.match("(%s)$" % e, cmd):
1381 if re.match("(%s)$" % e, cmd):
1382 return e, table[e]
1382 return e, table[e]
1383
1383
1384 raise UnknownCommand(cmd)
1384 raise UnknownCommand(cmd)
1385
1385
1386 class SignalInterrupt(Exception):
1386 class SignalInterrupt(Exception):
1387 """Exception raised on SIGTERM and SIGHUP."""
1387 """Exception raised on SIGTERM and SIGHUP."""
1388
1388
1389 def catchterm(*args):
1389 def catchterm(*args):
1390 raise SignalInterrupt
1390 raise SignalInterrupt
1391
1391
1392 def run():
1392 def run():
1393 sys.exit(dispatch(sys.argv[1:]))
1393 sys.exit(dispatch(sys.argv[1:]))
1394
1394
1395 class ParseError(Exception):
1395 class ParseError(Exception):
1396 """Exception raised on errors in parsing the command line."""
1396 """Exception raised on errors in parsing the command line."""
1397
1397
1398 def parse(args):
1398 def parse(args):
1399 options = {}
1399 options = {}
1400 cmdoptions = {}
1400 cmdoptions = {}
1401
1401
1402 try:
1402 try:
1403 args = fancyopts.fancyopts(args, globalopts, options)
1403 args = fancyopts.fancyopts(args, globalopts, options)
1404 except fancyopts.getopt.GetoptError, inst:
1404 except fancyopts.getopt.GetoptError, inst:
1405 raise ParseError(None, inst)
1405 raise ParseError(None, inst)
1406
1406
1407 if options["version"]:
1407 if options["version"]:
1408 return ("version", show_version, [], options, cmdoptions)
1408 return ("version", show_version, [], options, cmdoptions)
1409 elif not args:
1409 elif not args:
1410 return ("help", help_, ["shortlist"], options, cmdoptions)
1410 return ("help", help_, ["shortlist"], options, cmdoptions)
1411 else:
1411 else:
1412 cmd, args = args[0], args[1:]
1412 cmd, args = args[0], args[1:]
1413
1413
1414 i = find(cmd)[1]
1414 i = find(cmd)[1]
1415
1415
1416 # combine global options into local
1416 # combine global options into local
1417 c = list(i[1])
1417 c = list(i[1])
1418 for o in globalopts:
1418 for o in globalopts:
1419 c.append((o[0], o[1], options[o[1]], o[3]))
1419 c.append((o[0], o[1], options[o[1]], o[3]))
1420
1420
1421 try:
1421 try:
1422 args = fancyopts.fancyopts(args, c, cmdoptions)
1422 args = fancyopts.fancyopts(args, c, cmdoptions)
1423 except fancyopts.getopt.GetoptError, inst:
1423 except fancyopts.getopt.GetoptError, inst:
1424 raise ParseError(cmd, inst)
1424 raise ParseError(cmd, inst)
1425
1425
1426 # separate global options back out
1426 # separate global options back out
1427 for o in globalopts:
1427 for o in globalopts:
1428 n = o[1]
1428 n = o[1]
1429 options[n] = cmdoptions[n]
1429 options[n] = cmdoptions[n]
1430 del cmdoptions[n]
1430 del cmdoptions[n]
1431
1431
1432 return (cmd, i[0], args, options, cmdoptions)
1432 return (cmd, i[0], args, options, cmdoptions)
1433
1433
1434 def dispatch(args):
1434 def dispatch(args):
1435 signal.signal(signal.SIGTERM, catchterm)
1435 signal.signal(signal.SIGTERM, catchterm)
1436 try:
1436 try:
1437 signal.signal(signal.SIGHUP, catchterm)
1437 signal.signal(signal.SIGHUP, catchterm)
1438 except AttributeError:
1438 except AttributeError:
1439 pass
1439 pass
1440
1440
1441 try:
1441 try:
1442 cmd, func, args, options, cmdoptions = parse(args)
1442 cmd, func, args, options, cmdoptions = parse(args)
1443 except ParseError, inst:
1443 except ParseError, inst:
1444 u = ui.ui()
1444 u = ui.ui()
1445 if inst.args[0]:
1445 if inst.args[0]:
1446 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1446 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1447 help_(u, inst.args[0])
1447 help_(u, inst.args[0])
1448 else:
1448 else:
1449 u.warn("hg: %s\n" % inst.args[1])
1449 u.warn("hg: %s\n" % inst.args[1])
1450 help_(u, 'shortlist')
1450 help_(u, 'shortlist')
1451 sys.exit(-1)
1451 sys.exit(-1)
1452 except UnknownCommand, inst:
1452 except UnknownCommand, inst:
1453 u = ui.ui()
1453 u = ui.ui()
1454 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1454 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1455 help_(u, 'shortlist')
1455 help_(u, 'shortlist')
1456 sys.exit(1)
1456 sys.exit(1)
1457
1457
1458 if options["time"]:
1458 if options["time"]:
1459 def get_times():
1459 def get_times():
1460 t = os.times()
1460 t = os.times()
1461 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1461 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1462 t = (t[0], t[1], t[2], t[3], time.clock())
1462 t = (t[0], t[1], t[2], t[3], time.clock())
1463 return t
1463 return t
1464 s = get_times()
1464 s = get_times()
1465 def print_time():
1465 def print_time():
1466 t = get_times()
1466 t = get_times()
1467 u = ui.ui()
1467 u = ui.ui()
1468 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1468 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1469 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1469 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1470 atexit.register(print_time)
1470 atexit.register(print_time)
1471
1471
1472 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1472 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1473 not options["noninteractive"])
1473 not options["noninteractive"])
1474
1474
1475 try:
1475 try:
1476 try:
1476 try:
1477 if cmd not in norepo.split():
1477 if cmd not in norepo.split():
1478 path = options["repository"] or ""
1478 path = options["repository"] or ""
1479 repo = hg.repository(ui=u, path=path)
1479 repo = hg.repository(ui=u, path=path)
1480 d = lambda: func(u, repo, *args, **cmdoptions)
1480 d = lambda: func(u, repo, *args, **cmdoptions)
1481 else:
1481 else:
1482 d = lambda: func(u, *args, **cmdoptions)
1482 d = lambda: func(u, *args, **cmdoptions)
1483
1483
1484 if options['profile']:
1484 if options['profile']:
1485 import hotshot, hotshot.stats
1485 import hotshot, hotshot.stats
1486 prof = hotshot.Profile("hg.prof")
1486 prof = hotshot.Profile("hg.prof")
1487 r = prof.runcall(d)
1487 r = prof.runcall(d)
1488 prof.close()
1488 prof.close()
1489 stats = hotshot.stats.load("hg.prof")
1489 stats = hotshot.stats.load("hg.prof")
1490 stats.strip_dirs()
1490 stats.strip_dirs()
1491 stats.sort_stats('time', 'calls')
1491 stats.sort_stats('time', 'calls')
1492 stats.print_stats(40)
1492 stats.print_stats(40)
1493 return r
1493 return r
1494 else:
1494 else:
1495 return d()
1495 return d()
1496 except:
1496 except:
1497 if options['traceback']:
1497 if options['traceback']:
1498 traceback.print_exc()
1498 traceback.print_exc()
1499 raise
1499 raise
1500 except hg.RepoError, inst:
1500 except hg.RepoError, inst:
1501 u.warn("abort: ", inst, "!\n")
1501 u.warn("abort: ", inst, "!\n")
1502 except SignalInterrupt:
1502 except SignalInterrupt:
1503 u.warn("killed!\n")
1503 u.warn("killed!\n")
1504 except KeyboardInterrupt:
1504 except KeyboardInterrupt:
1505 try:
1505 try:
1506 u.warn("interrupted!\n")
1506 u.warn("interrupted!\n")
1507 except IOError, inst:
1507 except IOError, inst:
1508 if inst.errno == errno.EPIPE:
1508 if inst.errno == errno.EPIPE:
1509 if u.debugflag:
1509 if u.debugflag:
1510 u.warn("\nbroken pipe\n")
1510 u.warn("\nbroken pipe\n")
1511 else:
1511 else:
1512 raise
1512 raise
1513 except IOError, inst:
1513 except IOError, inst:
1514 if hasattr(inst, "code"):
1514 if hasattr(inst, "code"):
1515 u.warn("abort: %s\n" % inst)
1515 u.warn("abort: %s\n" % inst)
1516 elif hasattr(inst, "reason"):
1516 elif hasattr(inst, "reason"):
1517 u.warn("abort: error: %s\n" % inst.reason[1])
1517 u.warn("abort: error: %s\n" % inst.reason[1])
1518 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1518 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1519 if u.debugflag: u.warn("broken pipe\n")
1519 if u.debugflag: u.warn("broken pipe\n")
1520 else:
1520 else:
1521 raise
1521 raise
1522 except OSError, inst:
1522 except OSError, inst:
1523 if hasattr(inst, "filename"):
1523 if hasattr(inst, "filename"):
1524 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1524 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1525 else:
1525 else:
1526 u.warn("abort: %s\n" % inst.strerror)
1526 u.warn("abort: %s\n" % inst.strerror)
1527 except util.Abort, inst:
1527 except util.Abort, inst:
1528 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1528 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1529 sys.exit(1)
1529 sys.exit(1)
1530 except TypeError, inst:
1530 except TypeError, inst:
1531 # was this an argument error?
1531 # was this an argument error?
1532 tb = traceback.extract_tb(sys.exc_info()[2])
1532 tb = traceback.extract_tb(sys.exc_info()[2])
1533 if len(tb) > 2: # no
1533 if len(tb) > 2: # no
1534 raise
1534 raise
1535 u.debug(inst, "\n")
1535 u.debug(inst, "\n")
1536 u.warn("%s: invalid arguments\n" % cmd)
1536 u.warn("%s: invalid arguments\n" % cmd)
1537 help_(u, cmd)
1537 help_(u, cmd)
1538 except UnknownCommand, inst:
1538 except UnknownCommand, inst:
1539 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1539 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1540 help_(u, 'shortlist')
1540 help_(u, 'shortlist')
1541
1541
1542 sys.exit(-1)
1542 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now