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