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