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