##// END OF EJS Templates
Show filenames for hg export in verbose mode on a separate lines....
Thomas Arendsen Hein -
r755:87e2b094 default
parent child Browse files
Show More
@@ -1,1358 +1,1359 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 text = opts['text']
463 text = opts['text']
464 logfile = opts['logfile']
464 logfile = opts['logfile']
465 if not text and logfile:
465 if not text and logfile:
466 try:
466 try:
467 text = open(logfile).read()
467 text = open(logfile).read()
468 except IOError, why:
468 except IOError, why:
469 ui.warn("Can't read commit text %s: %s\n" % (logfile, why))
469 ui.warn("Can't read commit text %s: %s\n" % (logfile, why))
470
470
471 if opts['addremove']:
471 if opts['addremove']:
472 addremove(ui, repo, *files)
472 addremove(ui, repo, *files)
473 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
473 repo.commit(relpath(repo, files), text, opts['user'], opts['date'])
474
474
475 def copy(ui, repo, source, dest):
475 def copy(ui, repo, source, dest):
476 """mark a file as copied or renamed for the next commit"""
476 """mark a file as copied or renamed for the next commit"""
477 return repo.copy(*relpath(repo, (source, dest)))
477 return repo.copy(*relpath(repo, (source, dest)))
478
478
479 def debugcheckstate(ui, repo):
479 def debugcheckstate(ui, repo):
480 """validate the correctness of the current dirstate"""
480 """validate the correctness of the current dirstate"""
481 parent1, parent2 = repo.dirstate.parents()
481 parent1, parent2 = repo.dirstate.parents()
482 repo.dirstate.read()
482 repo.dirstate.read()
483 dc = repo.dirstate.map
483 dc = repo.dirstate.map
484 keys = dc.keys()
484 keys = dc.keys()
485 keys.sort()
485 keys.sort()
486 m1n = repo.changelog.read(parent1)[0]
486 m1n = repo.changelog.read(parent1)[0]
487 m2n = repo.changelog.read(parent2)[0]
487 m2n = repo.changelog.read(parent2)[0]
488 m1 = repo.manifest.read(m1n)
488 m1 = repo.manifest.read(m1n)
489 m2 = repo.manifest.read(m2n)
489 m2 = repo.manifest.read(m2n)
490 errors = 0
490 errors = 0
491 for f in dc:
491 for f in dc:
492 state = repo.dirstate.state(f)
492 state = repo.dirstate.state(f)
493 if state in "nr" and f not in m1:
493 if state in "nr" and f not in m1:
494 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
494 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
495 errors += 1
495 errors += 1
496 if state in "a" and f in m1:
496 if state in "a" and f in m1:
497 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
497 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
498 errors += 1
498 errors += 1
499 if state in "m" and f not in m1 and f not in m2:
499 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" %
500 ui.warn("%s in state %s, but not in either manifest\n" %
501 (f, state))
501 (f, state))
502 errors += 1
502 errors += 1
503 for f in m1:
503 for f in m1:
504 state = repo.dirstate.state(f)
504 state = repo.dirstate.state(f)
505 if state not in "nrm":
505 if state not in "nrm":
506 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
506 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
507 errors += 1
507 errors += 1
508 if errors:
508 if errors:
509 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
509 raise Abort(".hg/dirstate inconsistent with current parent's manifest")
510
510
511 def debugstate(ui, repo):
511 def debugstate(ui, repo):
512 """show the contents of the current dirstate"""
512 """show the contents of the current dirstate"""
513 repo.dirstate.read()
513 repo.dirstate.read()
514 dc = repo.dirstate.map
514 dc = repo.dirstate.map
515 keys = dc.keys()
515 keys = dc.keys()
516 keys.sort()
516 keys.sort()
517 for file_ in keys:
517 for file_ in keys:
518 ui.write("%c %s\n" % (dc[file_][0], file_))
518 ui.write("%c %s\n" % (dc[file_][0], file_))
519
519
520 def debugindex(ui, file_):
520 def debugindex(ui, file_):
521 """dump the contents of an index file"""
521 """dump the contents of an index file"""
522 r = hg.revlog(hg.opener(""), file_, "")
522 r = hg.revlog(hg.opener(""), file_, "")
523 ui.write(" rev offset length base linkrev" +
523 ui.write(" rev offset length base linkrev" +
524 " p1 p2 nodeid\n")
524 " p1 p2 nodeid\n")
525 for i in range(r.count()):
525 for i in range(r.count()):
526 e = r.index[i]
526 e = r.index[i]
527 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
527 ui.write("% 6d % 9d % 7d % 6d % 7d %s.. %s.. %s..\n" % (
528 i, e[0], e[1], e[2], e[3],
528 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])))
529 hg.hex(e[4][:5]), hg.hex(e[5][:5]), hg.hex(e[6][:5])))
530
530
531 def debugindexdot(ui, file_):
531 def debugindexdot(ui, file_):
532 """dump an index DAG as a .dot file"""
532 """dump an index DAG as a .dot file"""
533 r = hg.revlog(hg.opener(""), file_, "")
533 r = hg.revlog(hg.opener(""), file_, "")
534 ui.write("digraph G {\n")
534 ui.write("digraph G {\n")
535 for i in range(r.count()):
535 for i in range(r.count()):
536 e = r.index[i]
536 e = r.index[i]
537 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
537 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
538 if e[5] != hg.nullid:
538 if e[5] != hg.nullid:
539 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
539 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
540 ui.write("}\n")
540 ui.write("}\n")
541
541
542 def diff(ui, repo, *pats, **opts):
542 def diff(ui, repo, *pats, **opts):
543 """diff working directory (or selected files)"""
543 """diff working directory (or selected files)"""
544 revs = []
544 revs = []
545 if opts['rev']:
545 if opts['rev']:
546 revs = map(lambda x: repo.lookup(x), opts['rev'])
546 revs = map(lambda x: repo.lookup(x), opts['rev'])
547
547
548 if len(revs) > 2:
548 if len(revs) > 2:
549 raise Abort("too many revisions to diff")
549 raise Abort("too many revisions to diff")
550
550
551 files = []
551 files = []
552 for src, abs, rel in walk(repo, pats, opts):
552 for src, abs, rel in walk(repo, pats, opts):
553 files.append(abs)
553 files.append(abs)
554 dodiff(sys.stdout, ui, repo, files, *revs)
554 dodiff(sys.stdout, ui, repo, files, *revs)
555
555
556 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
556 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
557 node = repo.lookup(changeset)
557 node = repo.lookup(changeset)
558 prev, other = repo.changelog.parents(node)
558 prev, other = repo.changelog.parents(node)
559 change = repo.changelog.read(node)
559 change = repo.changelog.read(node)
560
560
561 fp = make_file(repo, repo.changelog, opts['output'],
561 fp = make_file(repo, repo.changelog, opts['output'],
562 node=node, total=total, seqno=seqno,
562 node=node, total=total, seqno=seqno,
563 revwidth=revwidth)
563 revwidth=revwidth)
564 if fp != sys.stdout:
564 if fp != sys.stdout:
565 ui.note("Exporting patch to '%s'.\n" % fp.name)
565 ui.note("%s\n" % fp.name)
566
566
567 fp.write("# HG changeset patch\n")
567 fp.write("# HG changeset patch\n")
568 fp.write("# User %s\n" % change[1])
568 fp.write("# User %s\n" % change[1])
569 fp.write("# Node ID %s\n" % hg.hex(node))
569 fp.write("# Node ID %s\n" % hg.hex(node))
570 fp.write("# Parent %s\n" % hg.hex(prev))
570 fp.write("# Parent %s\n" % hg.hex(prev))
571 if other != hg.nullid:
571 if other != hg.nullid:
572 fp.write("# Parent %s\n" % hg.hex(other))
572 fp.write("# Parent %s\n" % hg.hex(other))
573 fp.write(change[4].rstrip())
573 fp.write(change[4].rstrip())
574 fp.write("\n\n")
574 fp.write("\n\n")
575
575
576 dodiff(fp, ui, repo, None, prev, node)
576 dodiff(fp, ui, repo, None, prev, node)
577 if fp != sys.stdout: fp.close()
577 if fp != sys.stdout: fp.close()
578
578
579 def export(ui, repo, *changesets, **opts):
579 def export(ui, repo, *changesets, **opts):
580 """dump the header and diffs for one or more changesets"""
580 """dump the header and diffs for one or more changesets"""
581 if not changesets:
581 if not changesets:
582 raise Abort("export requires at least one changeset")
582 raise Abort("export requires at least one changeset")
583 seqno = 0
583 seqno = 0
584 revs = list(revrange(ui, repo, changesets))
584 revs = list(revrange(ui, repo, changesets))
585 total = len(revs)
585 total = len(revs)
586 revwidth = max(len(revs[0]), len(revs[-1]))
586 revwidth = max(len(revs[0]), len(revs[-1]))
587 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
587 for cset in revs:
588 for cset in revs:
588 seqno += 1
589 seqno += 1
589 doexport(ui, repo, cset, seqno, total, revwidth, opts)
590 doexport(ui, repo, cset, seqno, total, revwidth, opts)
590
591
591 def forget(ui, repo, file1, *files):
592 def forget(ui, repo, file1, *files):
592 """don't add the specified files on the next commit"""
593 """don't add the specified files on the next commit"""
593 repo.forget(relpath(repo, (file1,) + files))
594 repo.forget(relpath(repo, (file1,) + files))
594
595
595 def heads(ui, repo):
596 def heads(ui, repo):
596 """show current repository heads"""
597 """show current repository heads"""
597 for n in repo.changelog.heads():
598 for n in repo.changelog.heads():
598 show_changeset(ui, repo, changenode=n)
599 show_changeset(ui, repo, changenode=n)
599
600
600 def identify(ui, repo):
601 def identify(ui, repo):
601 """print information about the working copy"""
602 """print information about the working copy"""
602 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
603 parents = [p for p in repo.dirstate.parents() if p != hg.nullid]
603 if not parents:
604 if not parents:
604 ui.write("unknown\n")
605 ui.write("unknown\n")
605 return
606 return
606
607
607 hexfunc = ui.verbose and hg.hex or hg.short
608 hexfunc = ui.verbose and hg.hex or hg.short
608 (c, a, d, u) = repo.changes()
609 (c, a, d, u) = repo.changes()
609 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
610 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
610 (c or a or d) and "+" or "")]
611 (c or a or d) and "+" or "")]
611
612
612 if not ui.quiet:
613 if not ui.quiet:
613 # multiple tags for a single parent separated by '/'
614 # multiple tags for a single parent separated by '/'
614 parenttags = ['/'.join(tags)
615 parenttags = ['/'.join(tags)
615 for tags in map(repo.nodetags, parents) if tags]
616 for tags in map(repo.nodetags, parents) if tags]
616 # tags for multiple parents separated by ' + '
617 # tags for multiple parents separated by ' + '
617 output.append(' + '.join(parenttags))
618 output.append(' + '.join(parenttags))
618
619
619 ui.write("%s\n" % ' '.join(output))
620 ui.write("%s\n" % ' '.join(output))
620
621
621 def import_(ui, repo, patch1, *patches, **opts):
622 def import_(ui, repo, patch1, *patches, **opts):
622 """import an ordered set of patches"""
623 """import an ordered set of patches"""
623 try:
624 try:
624 import psyco
625 import psyco
625 psyco.full()
626 psyco.full()
626 except ImportError:
627 except ImportError:
627 pass
628 pass
628
629
629 patches = (patch1,) + patches
630 patches = (patch1,) + patches
630
631
631 d = opts["base"]
632 d = opts["base"]
632 strip = opts["strip"]
633 strip = opts["strip"]
633
634
634 for patch in patches:
635 for patch in patches:
635 ui.status("applying %s\n" % patch)
636 ui.status("applying %s\n" % patch)
636 pf = os.path.join(d, patch)
637 pf = os.path.join(d, patch)
637
638
638 text = []
639 text = []
639 user = None
640 user = None
640 hgpatch = False
641 hgpatch = False
641 for line in file(pf):
642 for line in file(pf):
642 line = line.rstrip()
643 line = line.rstrip()
643 if line.startswith("--- ") or line.startswith("diff -r"):
644 if line.startswith("--- ") or line.startswith("diff -r"):
644 break
645 break
645 elif hgpatch:
646 elif hgpatch:
646 # parse values when importing the result of an hg export
647 # parse values when importing the result of an hg export
647 if line.startswith("# User "):
648 if line.startswith("# User "):
648 user = line[7:]
649 user = line[7:]
649 ui.debug('User: %s\n' % user)
650 ui.debug('User: %s\n' % user)
650 elif not line.startswith("# ") and line:
651 elif not line.startswith("# ") and line:
651 text.append(line)
652 text.append(line)
652 hgpatch = False
653 hgpatch = False
653 elif line == '# HG changeset patch':
654 elif line == '# HG changeset patch':
654 hgpatch = True
655 hgpatch = True
655 else:
656 else:
656 text.append(line)
657 text.append(line)
657
658
658 # make sure text isn't empty
659 # make sure text isn't empty
659 if not text:
660 if not text:
660 text = "imported patch %s\n" % patch
661 text = "imported patch %s\n" % patch
661 else:
662 else:
662 text = "%s\n" % '\n'.join(text)
663 text = "%s\n" % '\n'.join(text)
663 ui.debug('text:\n%s\n' % text)
664 ui.debug('text:\n%s\n' % text)
664
665
665 f = os.popen("patch -p%d < %s" % (strip, pf))
666 f = os.popen("patch -p%d < %s" % (strip, pf))
666 files = []
667 files = []
667 for l in f.read().splitlines():
668 for l in f.read().splitlines():
668 l.rstrip('\r\n');
669 l.rstrip('\r\n');
669 ui.status("%s\n" % l)
670 ui.status("%s\n" % l)
670 if l.startswith('patching file '):
671 if l.startswith('patching file '):
671 pf = l[14:]
672 pf = l[14:]
672 if pf not in files:
673 if pf not in files:
673 files.append(pf)
674 files.append(pf)
674 patcherr = f.close()
675 patcherr = f.close()
675 if patcherr:
676 if patcherr:
676 raise Abort("patch failed")
677 raise Abort("patch failed")
677
678
678 if len(files) > 0:
679 if len(files) > 0:
679 addremove(ui, repo, *files)
680 addremove(ui, repo, *files)
680 repo.commit(files, text, user)
681 repo.commit(files, text, user)
681
682
682 def init(ui, source=None):
683 def init(ui, source=None):
683 """create a new repository in the current directory"""
684 """create a new repository in the current directory"""
684
685
685 if source:
686 if source:
686 raise Abort("no longer supported: use \"hg clone\" instead")
687 raise Abort("no longer supported: use \"hg clone\" instead")
687 hg.repository(ui, ".", create=1)
688 hg.repository(ui, ".", create=1)
688
689
689 def locate(ui, repo, *pats, **opts):
690 def locate(ui, repo, *pats, **opts):
690 """locate files matching specific patterns"""
691 """locate files matching specific patterns"""
691 end = '\n'
692 end = '\n'
692 if opts['print0']: end = '\0'
693 if opts['print0']: end = '\0'
693
694
694 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
695 for src, abs, rel in walk(repo, pats, opts, '(?:.*/|)'):
695 if repo.dirstate.state(abs) == '?': continue
696 if repo.dirstate.state(abs) == '?': continue
696 if opts['fullpath']:
697 if opts['fullpath']:
697 ui.write(os.path.join(repo.root, abs), end)
698 ui.write(os.path.join(repo.root, abs), end)
698 else:
699 else:
699 ui.write(rel, end)
700 ui.write(rel, end)
700
701
701 def log(ui, repo, f=None, **opts):
702 def log(ui, repo, f=None, **opts):
702 """show the revision history of the repository or a single file"""
703 """show the revision history of the repository or a single file"""
703 if f:
704 if f:
704 files = relpath(repo, [f])
705 files = relpath(repo, [f])
705 filelog = repo.file(files[0])
706 filelog = repo.file(files[0])
706 log = filelog
707 log = filelog
707 lookup = filelog.lookup
708 lookup = filelog.lookup
708 else:
709 else:
709 files = None
710 files = None
710 filelog = None
711 filelog = None
711 log = repo.changelog
712 log = repo.changelog
712 lookup = repo.lookup
713 lookup = repo.lookup
713 revlist = []
714 revlist = []
714 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
715 revs = [log.rev(lookup(rev)) for rev in opts['rev']]
715 while revs:
716 while revs:
716 if len(revs) == 1:
717 if len(revs) == 1:
717 revlist.append(revs.pop(0))
718 revlist.append(revs.pop(0))
718 else:
719 else:
719 a = revs.pop(0)
720 a = revs.pop(0)
720 b = revs.pop(0)
721 b = revs.pop(0)
721 off = a > b and -1 or 1
722 off = a > b and -1 or 1
722 revlist.extend(range(a, b + off, off))
723 revlist.extend(range(a, b + off, off))
723
724
724 for i in revlist or range(log.count() - 1, -1, -1):
725 for i in revlist or range(log.count() - 1, -1, -1):
725 show_changeset(ui, repo, filelog=filelog, rev=i)
726 show_changeset(ui, repo, filelog=filelog, rev=i)
726 if opts['patch']:
727 if opts['patch']:
727 if filelog:
728 if filelog:
728 filenode = filelog.node(i)
729 filenode = filelog.node(i)
729 i = filelog.linkrev(filenode)
730 i = filelog.linkrev(filenode)
730 changenode = repo.changelog.node(i)
731 changenode = repo.changelog.node(i)
731 prev, other = repo.changelog.parents(changenode)
732 prev, other = repo.changelog.parents(changenode)
732 dodiff(sys.stdout, ui, repo, files, prev, changenode)
733 dodiff(sys.stdout, ui, repo, files, prev, changenode)
733 ui.write("\n\n")
734 ui.write("\n\n")
734
735
735 def manifest(ui, repo, rev=None):
736 def manifest(ui, repo, rev=None):
736 """output the latest or given revision of the project manifest"""
737 """output the latest or given revision of the project manifest"""
737 if rev:
738 if rev:
738 try:
739 try:
739 # assume all revision numbers are for changesets
740 # assume all revision numbers are for changesets
740 n = repo.lookup(rev)
741 n = repo.lookup(rev)
741 change = repo.changelog.read(n)
742 change = repo.changelog.read(n)
742 n = change[0]
743 n = change[0]
743 except hg.RepoError:
744 except hg.RepoError:
744 n = repo.manifest.lookup(rev)
745 n = repo.manifest.lookup(rev)
745 else:
746 else:
746 n = repo.manifest.tip()
747 n = repo.manifest.tip()
747 m = repo.manifest.read(n)
748 m = repo.manifest.read(n)
748 mf = repo.manifest.readflags(n)
749 mf = repo.manifest.readflags(n)
749 files = m.keys()
750 files = m.keys()
750 files.sort()
751 files.sort()
751
752
752 for f in files:
753 for f in files:
753 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
754 ui.write("%40s %3s %s\n" % (hg.hex(m[f]), mf[f] and "755" or "644", f))
754
755
755 def parents(ui, repo, rev=None):
756 def parents(ui, repo, rev=None):
756 """show the parents of the working dir or revision"""
757 """show the parents of the working dir or revision"""
757 if rev:
758 if rev:
758 p = repo.changelog.parents(repo.lookup(rev))
759 p = repo.changelog.parents(repo.lookup(rev))
759 else:
760 else:
760 p = repo.dirstate.parents()
761 p = repo.dirstate.parents()
761
762
762 for n in p:
763 for n in p:
763 if n != hg.nullid:
764 if n != hg.nullid:
764 show_changeset(ui, repo, changenode=n)
765 show_changeset(ui, repo, changenode=n)
765
766
766 def pull(ui, repo, source="default", **opts):
767 def pull(ui, repo, source="default", **opts):
767 """pull changes from the specified source"""
768 """pull changes from the specified source"""
768 source = ui.expandpath(source)
769 source = ui.expandpath(source)
769 ui.status('pulling from %s\n' % (source))
770 ui.status('pulling from %s\n' % (source))
770
771
771 other = hg.repository(ui, source)
772 other = hg.repository(ui, source)
772 r = repo.pull(other)
773 r = repo.pull(other)
773 if not r:
774 if not r:
774 if opts['update']:
775 if opts['update']:
775 return update(ui, repo)
776 return update(ui, repo)
776 else:
777 else:
777 ui.status("(run 'hg update' to get a working copy)\n")
778 ui.status("(run 'hg update' to get a working copy)\n")
778
779
779 return r
780 return r
780
781
781 def push(ui, repo, dest="default-push"):
782 def push(ui, repo, dest="default-push"):
782 """push changes to the specified destination"""
783 """push changes to the specified destination"""
783 dest = ui.expandpath(dest)
784 dest = ui.expandpath(dest)
784 ui.status('pushing to %s\n' % (dest))
785 ui.status('pushing to %s\n' % (dest))
785
786
786 other = hg.repository(ui, dest)
787 other = hg.repository(ui, dest)
787 r = repo.push(other)
788 r = repo.push(other)
788 return r
789 return r
789
790
790 def rawcommit(ui, repo, *flist, **rc):
791 def rawcommit(ui, repo, *flist, **rc):
791 "raw commit interface"
792 "raw commit interface"
792
793
793 text = rc['text']
794 text = rc['text']
794 if not text and rc['logfile']:
795 if not text and rc['logfile']:
795 try:
796 try:
796 text = open(rc['logfile']).read()
797 text = open(rc['logfile']).read()
797 except IOError:
798 except IOError:
798 pass
799 pass
799 if not text and not rc['logfile']:
800 if not text and not rc['logfile']:
800 ui.warn("abort: missing commit text\n")
801 ui.warn("abort: missing commit text\n")
801 return 1
802 return 1
802
803
803 files = relpath(repo, list(flist))
804 files = relpath(repo, list(flist))
804 if rc['files']:
805 if rc['files']:
805 files += open(rc['files']).read().splitlines()
806 files += open(rc['files']).read().splitlines()
806
807
807 rc['parent'] = map(repo.lookup, rc['parent'])
808 rc['parent'] = map(repo.lookup, rc['parent'])
808
809
809 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
810 repo.rawcommit(files, text, rc['user'], rc['date'], *rc['parent'])
810
811
811 def recover(ui, repo):
812 def recover(ui, repo):
812 """roll back an interrupted transaction"""
813 """roll back an interrupted transaction"""
813 repo.recover()
814 repo.recover()
814
815
815 def remove(ui, repo, file1, *files):
816 def remove(ui, repo, file1, *files):
816 """remove the specified files on the next commit"""
817 """remove the specified files on the next commit"""
817 repo.remove(relpath(repo, (file1,) + files))
818 repo.remove(relpath(repo, (file1,) + files))
818
819
819 def revert(ui, repo, *names, **opts):
820 def revert(ui, repo, *names, **opts):
820 """revert modified files or dirs back to their unmodified states"""
821 """revert modified files or dirs back to their unmodified states"""
821 node = opts['rev'] and repo.lookup(opts['rev']) or \
822 node = opts['rev'] and repo.lookup(opts['rev']) or \
822 repo.dirstate.parents()[0]
823 repo.dirstate.parents()[0]
823 root = os.path.realpath(repo.root)
824 root = os.path.realpath(repo.root)
824
825
825 def trimpath(p):
826 def trimpath(p):
826 p = os.path.realpath(p)
827 p = os.path.realpath(p)
827 if p.startswith(root):
828 if p.startswith(root):
828 rest = p[len(root):]
829 rest = p[len(root):]
829 if not rest:
830 if not rest:
830 return rest
831 return rest
831 if p.startswith(os.sep):
832 if p.startswith(os.sep):
832 return rest[1:]
833 return rest[1:]
833 return p
834 return p
834
835
835 relnames = map(trimpath, names or [os.getcwd()])
836 relnames = map(trimpath, names or [os.getcwd()])
836 chosen = {}
837 chosen = {}
837
838
838 def choose(name):
839 def choose(name):
839 def body(name):
840 def body(name):
840 for r in relnames:
841 for r in relnames:
841 if not name.startswith(r):
842 if not name.startswith(r):
842 continue
843 continue
843 rest = name[len(r):]
844 rest = name[len(r):]
844 if not rest:
845 if not rest:
845 return r, True
846 return r, True
846 depth = rest.count(os.sep)
847 depth = rest.count(os.sep)
847 if not r:
848 if not r:
848 if depth == 0 or not opts['nonrecursive']:
849 if depth == 0 or not opts['nonrecursive']:
849 return r, True
850 return r, True
850 elif rest[0] == os.sep:
851 elif rest[0] == os.sep:
851 if depth == 1 or not opts['nonrecursive']:
852 if depth == 1 or not opts['nonrecursive']:
852 return r, True
853 return r, True
853 return None, False
854 return None, False
854 relname, ret = body(name)
855 relname, ret = body(name)
855 if ret:
856 if ret:
856 chosen[relname] = 1
857 chosen[relname] = 1
857 return ret
858 return ret
858
859
859 r = repo.update(node, False, True, choose, False)
860 r = repo.update(node, False, True, choose, False)
860 for n in relnames:
861 for n in relnames:
861 if n not in chosen:
862 if n not in chosen:
862 ui.warn('error: no matches for %s\n' % n)
863 ui.warn('error: no matches for %s\n' % n)
863 r = 1
864 r = 1
864 sys.stdout.flush()
865 sys.stdout.flush()
865 return r
866 return r
866
867
867 def root(ui, repo):
868 def root(ui, repo):
868 """print the root (top) of the current working dir"""
869 """print the root (top) of the current working dir"""
869 ui.write(repo.root + "\n")
870 ui.write(repo.root + "\n")
870
871
871 def serve(ui, repo, **opts):
872 def serve(ui, repo, **opts):
872 """export the repository via HTTP"""
873 """export the repository via HTTP"""
873
874
874 if opts["stdio"]:
875 if opts["stdio"]:
875 fin, fout = sys.stdin, sys.stdout
876 fin, fout = sys.stdin, sys.stdout
876 sys.stdout = sys.stderr
877 sys.stdout = sys.stderr
877
878
878 def getarg():
879 def getarg():
879 argline = fin.readline()[:-1]
880 argline = fin.readline()[:-1]
880 arg, l = argline.split()
881 arg, l = argline.split()
881 val = fin.read(int(l))
882 val = fin.read(int(l))
882 return arg, val
883 return arg, val
883 def respond(v):
884 def respond(v):
884 fout.write("%d\n" % len(v))
885 fout.write("%d\n" % len(v))
885 fout.write(v)
886 fout.write(v)
886 fout.flush()
887 fout.flush()
887
888
888 lock = None
889 lock = None
889
890
890 while 1:
891 while 1:
891 cmd = fin.readline()[:-1]
892 cmd = fin.readline()[:-1]
892 if cmd == '':
893 if cmd == '':
893 return
894 return
894 if cmd == "heads":
895 if cmd == "heads":
895 h = repo.heads()
896 h = repo.heads()
896 respond(" ".join(map(hg.hex, h)) + "\n")
897 respond(" ".join(map(hg.hex, h)) + "\n")
897 if cmd == "lock":
898 if cmd == "lock":
898 lock = repo.lock()
899 lock = repo.lock()
899 respond("")
900 respond("")
900 if cmd == "unlock":
901 if cmd == "unlock":
901 if lock:
902 if lock:
902 lock.release()
903 lock.release()
903 lock = None
904 lock = None
904 respond("")
905 respond("")
905 elif cmd == "branches":
906 elif cmd == "branches":
906 arg, nodes = getarg()
907 arg, nodes = getarg()
907 nodes = map(hg.bin, nodes.split(" "))
908 nodes = map(hg.bin, nodes.split(" "))
908 r = []
909 r = []
909 for b in repo.branches(nodes):
910 for b in repo.branches(nodes):
910 r.append(" ".join(map(hg.hex, b)) + "\n")
911 r.append(" ".join(map(hg.hex, b)) + "\n")
911 respond("".join(r))
912 respond("".join(r))
912 elif cmd == "between":
913 elif cmd == "between":
913 arg, pairs = getarg()
914 arg, pairs = getarg()
914 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
915 pairs = [map(hg.bin, p.split("-")) for p in pairs.split(" ")]
915 r = []
916 r = []
916 for b in repo.between(pairs):
917 for b in repo.between(pairs):
917 r.append(" ".join(map(hg.hex, b)) + "\n")
918 r.append(" ".join(map(hg.hex, b)) + "\n")
918 respond("".join(r))
919 respond("".join(r))
919 elif cmd == "changegroup":
920 elif cmd == "changegroup":
920 nodes = []
921 nodes = []
921 arg, roots = getarg()
922 arg, roots = getarg()
922 nodes = map(hg.bin, roots.split(" "))
923 nodes = map(hg.bin, roots.split(" "))
923
924
924 cg = repo.changegroup(nodes)
925 cg = repo.changegroup(nodes)
925 while 1:
926 while 1:
926 d = cg.read(4096)
927 d = cg.read(4096)
927 if not d:
928 if not d:
928 break
929 break
929 fout.write(d)
930 fout.write(d)
930
931
931 fout.flush()
932 fout.flush()
932
933
933 elif cmd == "addchangegroup":
934 elif cmd == "addchangegroup":
934 if not lock:
935 if not lock:
935 respond("not locked")
936 respond("not locked")
936 continue
937 continue
937 respond("")
938 respond("")
938
939
939 r = repo.addchangegroup(fin)
940 r = repo.addchangegroup(fin)
940 respond("")
941 respond("")
941
942
942 def openlog(opt, default):
943 def openlog(opt, default):
943 if opts[opt] and opts[opt] != '-':
944 if opts[opt] and opts[opt] != '-':
944 return open(opts[opt], 'w')
945 return open(opts[opt], 'w')
945 else:
946 else:
946 return default
947 return default
947
948
948 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
949 httpd = hgweb.create_server(repo.root, opts["name"], opts["templates"],
949 opts["address"], opts["port"],
950 opts["address"], opts["port"],
950 openlog('accesslog', sys.stdout),
951 openlog('accesslog', sys.stdout),
951 openlog('errorlog', sys.stderr))
952 openlog('errorlog', sys.stderr))
952 if ui.verbose:
953 if ui.verbose:
953 addr, port = httpd.socket.getsockname()
954 addr, port = httpd.socket.getsockname()
954 if addr == '0.0.0.0':
955 if addr == '0.0.0.0':
955 addr = socket.gethostname()
956 addr = socket.gethostname()
956 else:
957 else:
957 try:
958 try:
958 addr = socket.gethostbyaddr(addr)[0]
959 addr = socket.gethostbyaddr(addr)[0]
959 except socket.error:
960 except socket.error:
960 pass
961 pass
961 if port != 80:
962 if port != 80:
962 ui.status('listening at http://%s:%d/\n' % (addr, port))
963 ui.status('listening at http://%s:%d/\n' % (addr, port))
963 else:
964 else:
964 ui.status('listening at http://%s/\n' % addr)
965 ui.status('listening at http://%s/\n' % addr)
965 httpd.serve_forever()
966 httpd.serve_forever()
966
967
967 def status(ui, repo, *pats, **opts):
968 def status(ui, repo, *pats, **opts):
968 '''show changed files in the working directory
969 '''show changed files in the working directory
969
970
970 M = modified
971 M = modified
971 A = added
972 A = added
972 R = removed
973 R = removed
973 ? = not tracked'''
974 ? = not tracked'''
974
975
975 (c, a, d, u) = repo.changes(match = matchpats(repo.getcwd(), pats, opts))
976 (c, a, d, u) = repo.changes(match = matchpats(repo.getcwd(), pats, opts))
976 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
977 (c, a, d, u) = map(lambda x: relfilter(repo, x), (c, a, d, u))
977
978
978 for f in c:
979 for f in c:
979 ui.write("M ", f, "\n")
980 ui.write("M ", f, "\n")
980 for f in a:
981 for f in a:
981 ui.write("A ", f, "\n")
982 ui.write("A ", f, "\n")
982 for f in d:
983 for f in d:
983 ui.write("R ", f, "\n")
984 ui.write("R ", f, "\n")
984 for f in u:
985 for f in u:
985 ui.write("? ", f, "\n")
986 ui.write("? ", f, "\n")
986
987
987 def tag(ui, repo, name, rev=None, **opts):
988 def tag(ui, repo, name, rev=None, **opts):
988 """add a tag for the current tip or a given revision"""
989 """add a tag for the current tip or a given revision"""
989
990
990 if name == "tip":
991 if name == "tip":
991 ui.warn("abort: 'tip' is a reserved name!\n")
992 ui.warn("abort: 'tip' is a reserved name!\n")
992 return -1
993 return -1
993 if rev:
994 if rev:
994 r = hg.hex(repo.lookup(rev))
995 r = hg.hex(repo.lookup(rev))
995 else:
996 else:
996 r = hg.hex(repo.changelog.tip())
997 r = hg.hex(repo.changelog.tip())
997
998
998 if name.find(revrangesep) >= 0:
999 if name.find(revrangesep) >= 0:
999 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1000 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1000 return -1
1001 return -1
1001
1002
1002 if opts['local']:
1003 if opts['local']:
1003 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1004 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1004 return
1005 return
1005
1006
1006 (c, a, d, u) = repo.changes()
1007 (c, a, d, u) = repo.changes()
1007 for x in (c, a, d, u):
1008 for x in (c, a, d, u):
1008 if ".hgtags" in x:
1009 if ".hgtags" in x:
1009 ui.warn("abort: working copy of .hgtags is changed!\n")
1010 ui.warn("abort: working copy of .hgtags is changed!\n")
1010 ui.status("(please commit .hgtags manually)\n")
1011 ui.status("(please commit .hgtags manually)\n")
1011 return -1
1012 return -1
1012
1013
1013 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1014 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1014 if repo.dirstate.state(".hgtags") == '?':
1015 if repo.dirstate.state(".hgtags") == '?':
1015 repo.add([".hgtags"])
1016 repo.add([".hgtags"])
1016
1017
1017 if not opts['text']:
1018 if not opts['text']:
1018 opts['text'] = "Added tag %s for changeset %s" % (name, r)
1019 opts['text'] = "Added tag %s for changeset %s" % (name, r)
1019
1020
1020 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
1021 repo.commit([".hgtags"], opts['text'], opts['user'], opts['date'])
1021
1022
1022 def tags(ui, repo):
1023 def tags(ui, repo):
1023 """list repository tags"""
1024 """list repository tags"""
1024
1025
1025 l = repo.tagslist()
1026 l = repo.tagslist()
1026 l.reverse()
1027 l.reverse()
1027 for t, n in l:
1028 for t, n in l:
1028 try:
1029 try:
1029 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1030 r = "%5d:%s" % (repo.changelog.rev(n), hg.hex(n))
1030 except KeyError:
1031 except KeyError:
1031 r = " ?:?"
1032 r = " ?:?"
1032 ui.write("%-30s %s\n" % (t, r))
1033 ui.write("%-30s %s\n" % (t, r))
1033
1034
1034 def tip(ui, repo):
1035 def tip(ui, repo):
1035 """show the tip revision"""
1036 """show the tip revision"""
1036 n = repo.changelog.tip()
1037 n = repo.changelog.tip()
1037 show_changeset(ui, repo, changenode=n)
1038 show_changeset(ui, repo, changenode=n)
1038
1039
1039 def undo(ui, repo):
1040 def undo(ui, repo):
1040 """undo the last commit or pull
1041 """undo the last commit or pull
1041
1042
1042 Roll back the last pull or commit transaction on the
1043 Roll back the last pull or commit transaction on the
1043 repository, restoring the project to its earlier state.
1044 repository, restoring the project to its earlier state.
1044
1045
1045 This command should be used with care. There is only one level of
1046 This command should be used with care. There is only one level of
1046 undo and there is no redo.
1047 undo and there is no redo.
1047
1048
1048 This command is not intended for use on public repositories. Once
1049 This command is not intended for use on public repositories. Once
1049 a change is visible for pull by other users, undoing it locally is
1050 a change is visible for pull by other users, undoing it locally is
1050 ineffective.
1051 ineffective.
1051 """
1052 """
1052 repo.undo()
1053 repo.undo()
1053
1054
1054 def update(ui, repo, node=None, merge=False, clean=False):
1055 def update(ui, repo, node=None, merge=False, clean=False):
1055 '''update or merge working directory
1056 '''update or merge working directory
1056
1057
1057 If there are no outstanding changes in the working directory and
1058 If there are no outstanding changes in the working directory and
1058 there is a linear relationship between the current version and the
1059 there is a linear relationship between the current version and the
1059 requested version, the result is the requested version.
1060 requested version, the result is the requested version.
1060
1061
1061 Otherwise the result is a merge between the contents of the
1062 Otherwise the result is a merge between the contents of the
1062 current working directory and the requested version. Files that
1063 current working directory and the requested version. Files that
1063 changed between either parent are marked as changed for the next
1064 changed between either parent are marked as changed for the next
1064 commit and a commit must be performed before any further updates
1065 commit and a commit must be performed before any further updates
1065 are allowed.
1066 are allowed.
1066 '''
1067 '''
1067 node = node and repo.lookup(node) or repo.changelog.tip()
1068 node = node and repo.lookup(node) or repo.changelog.tip()
1068 return repo.update(node, allow=merge, force=clean)
1069 return repo.update(node, allow=merge, force=clean)
1069
1070
1070 def verify(ui, repo):
1071 def verify(ui, repo):
1071 """verify the integrity of the repository"""
1072 """verify the integrity of the repository"""
1072 return repo.verify()
1073 return repo.verify()
1073
1074
1074 # Command options and aliases are listed here, alphabetically
1075 # Command options and aliases are listed here, alphabetically
1075
1076
1076 table = {
1077 table = {
1077 "^add": (add,
1078 "^add": (add,
1078 [('I', 'include', [], 'include path in search'),
1079 [('I', 'include', [], 'include path in search'),
1079 ('X', 'exclude', [], 'exclude path from search')],
1080 ('X', 'exclude', [], 'exclude path from search')],
1080 "hg add [OPTIONS] [FILES]"),
1081 "hg add [OPTIONS] [FILES]"),
1081 "addremove": (addremove, [], "hg addremove [FILES]"),
1082 "addremove": (addremove, [], "hg addremove [FILES]"),
1082 "^annotate":
1083 "^annotate":
1083 (annotate,
1084 (annotate,
1084 [('I', 'include', [], 'include path in search'),
1085 [('I', 'include', [], 'include path in search'),
1085 ('X', 'exclude', [], 'exclude path from search'),
1086 ('X', 'exclude', [], 'exclude path from search'),
1086 ('r', 'rev', '', 'revision'),
1087 ('r', 'rev', '', 'revision'),
1087 ('u', 'user', None, 'show user'),
1088 ('u', 'user', None, 'show user'),
1088 ('n', 'number', None, 'show revision number'),
1089 ('n', 'number', None, 'show revision number'),
1089 ('c', 'changeset', None, 'show changeset')],
1090 ('c', 'changeset', None, 'show changeset')],
1090 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1091 'hg annotate [-r REV] [-u] [-n] [-c] FILE...'),
1091 "cat":
1092 "cat":
1092 (cat,
1093 (cat,
1093 [('o', 'output', "", 'output to file')],
1094 [('o', 'output', "", 'output to file')],
1094 'hg cat [-o OUTFILE] FILE [REV]'),
1095 'hg cat [-o OUTFILE] FILE [REV]'),
1095 "^clone":
1096 "^clone":
1096 (clone,
1097 (clone,
1097 [('U', 'noupdate', None, 'skip update after cloning')],
1098 [('U', 'noupdate', None, 'skip update after cloning')],
1098 'hg clone [-U] SOURCE [DEST]'),
1099 'hg clone [-U] SOURCE [DEST]'),
1099 "^commit|ci":
1100 "^commit|ci":
1100 (commit,
1101 (commit,
1101 [('A', 'addremove', None, 'run add/remove during commit'),
1102 [('A', 'addremove', None, 'run add/remove during commit'),
1102 ('m', 'text', "", 'commit message'),
1103 ('m', 'text', "", 'commit message'),
1103 ('t', 'text', "", 'commit message (deprecated)'),
1104 ('t', 'text', "", 'commit message (deprecated)'),
1104 ('l', 'logfile', "", 'commit text file'),
1105 ('l', 'logfile', "", 'commit text file'),
1105 ('d', 'date', "", 'date code'),
1106 ('d', 'date', "", 'date code'),
1106 ('u', 'user', "", 'user')],
1107 ('u', 'user', "", 'user')],
1107 'hg commit [OPTION]... [FILE]...'),
1108 'hg commit [OPTION]... [FILE]...'),
1108 "copy": (copy, [], 'hg copy SOURCE DEST'),
1109 "copy": (copy, [], 'hg copy SOURCE DEST'),
1109 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1110 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1110 "debugstate": (debugstate, [], 'debugstate'),
1111 "debugstate": (debugstate, [], 'debugstate'),
1111 "debugindex": (debugindex, [], 'debugindex FILE'),
1112 "debugindex": (debugindex, [], 'debugindex FILE'),
1112 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1113 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1113 "^diff":
1114 "^diff":
1114 (diff,
1115 (diff,
1115 [('I', 'include', [], 'include path in search'),
1116 [('I', 'include', [], 'include path in search'),
1116 ('X', 'exclude', [], 'exclude path from search'),
1117 ('X', 'exclude', [], 'exclude path from search'),
1117 ('r', 'rev', [], 'revision')],
1118 ('r', 'rev', [], 'revision')],
1118 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1119 'hg diff [-r REV1 [-r REV2]] [FILE]...'),
1119 "^export":
1120 "^export":
1120 (export,
1121 (export,
1121 [('o', 'output', "", 'output to file')],
1122 [('o', 'output', "", 'output to file')],
1122 "hg export [-o OUTFILE] REV..."),
1123 "hg export [-o OUTFILE] REV..."),
1123 "forget": (forget, [], "hg forget FILE..."),
1124 "forget": (forget, [], "hg forget FILE..."),
1124 "heads": (heads, [], 'hg heads'),
1125 "heads": (heads, [], 'hg heads'),
1125 "help": (help_, [], 'hg help [COMMAND]'),
1126 "help": (help_, [], 'hg help [COMMAND]'),
1126 "identify|id": (identify, [], 'hg identify'),
1127 "identify|id": (identify, [], 'hg identify'),
1127 "import|patch":
1128 "import|patch":
1128 (import_,
1129 (import_,
1129 [('p', 'strip', 1, 'path strip'),
1130 [('p', 'strip', 1, 'path strip'),
1130 ('b', 'base', "", 'base path')],
1131 ('b', 'base', "", 'base path')],
1131 "hg import [-p NUM] [-b BASE] PATCH..."),
1132 "hg import [-p NUM] [-b BASE] PATCH..."),
1132 "^init": (init, [], 'hg init'),
1133 "^init": (init, [], 'hg init'),
1133 "locate":
1134 "locate":
1134 (locate,
1135 (locate,
1135 [('0', 'print0', None, 'end records with NUL'),
1136 [('0', 'print0', None, 'end records with NUL'),
1136 ('f', 'fullpath', None, 'print complete paths'),
1137 ('f', 'fullpath', None, 'print complete paths'),
1137 ('I', 'include', [], 'include path in search'),
1138 ('I', 'include', [], 'include path in search'),
1138 ('r', 'rev', '', 'revision'),
1139 ('r', 'rev', '', 'revision'),
1139 ('X', 'exclude', [], 'exclude path from search')],
1140 ('X', 'exclude', [], 'exclude path from search')],
1140 'hg locate [OPTION]... [PATTERN]...'),
1141 'hg locate [OPTION]... [PATTERN]...'),
1141 "^log|history":
1142 "^log|history":
1142 (log,
1143 (log,
1143 [('r', 'rev', [], 'revision'),
1144 [('r', 'rev', [], 'revision'),
1144 ('p', 'patch', None, 'show patch')],
1145 ('p', 'patch', None, 'show patch')],
1145 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1146 'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
1146 "manifest": (manifest, [], 'hg manifest [REV]'),
1147 "manifest": (manifest, [], 'hg manifest [REV]'),
1147 "parents": (parents, [], 'hg parents [REV]'),
1148 "parents": (parents, [], 'hg parents [REV]'),
1148 "^pull":
1149 "^pull":
1149 (pull,
1150 (pull,
1150 [('u', 'update', None, 'update working directory')],
1151 [('u', 'update', None, 'update working directory')],
1151 'hg pull [-u] [SOURCE]'),
1152 'hg pull [-u] [SOURCE]'),
1152 "^push": (push, [], 'hg push [DEST]'),
1153 "^push": (push, [], 'hg push [DEST]'),
1153 "rawcommit":
1154 "rawcommit":
1154 (rawcommit,
1155 (rawcommit,
1155 [('p', 'parent', [], 'parent'),
1156 [('p', 'parent', [], 'parent'),
1156 ('d', 'date', "", 'date code'),
1157 ('d', 'date', "", 'date code'),
1157 ('u', 'user', "", 'user'),
1158 ('u', 'user', "", 'user'),
1158 ('F', 'files', "", 'file list'),
1159 ('F', 'files', "", 'file list'),
1159 ('m', 'text', "", 'commit message'),
1160 ('m', 'text', "", 'commit message'),
1160 ('t', 'text', "", 'commit message (deprecated)'),
1161 ('t', 'text', "", 'commit message (deprecated)'),
1161 ('l', 'logfile', "", 'commit text file')],
1162 ('l', 'logfile', "", 'commit text file')],
1162 'hg rawcommit [OPTION]... [FILE]...'),
1163 'hg rawcommit [OPTION]... [FILE]...'),
1163 "recover": (recover, [], "hg recover"),
1164 "recover": (recover, [], "hg recover"),
1164 "^remove|rm": (remove, [], "hg remove FILE..."),
1165 "^remove|rm": (remove, [], "hg remove FILE..."),
1165 "^revert":
1166 "^revert":
1166 (revert,
1167 (revert,
1167 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1168 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1168 ("r", "rev", "", "revision")],
1169 ("r", "rev", "", "revision")],
1169 "hg revert [-n] [-r REV] NAME..."),
1170 "hg revert [-n] [-r REV] NAME..."),
1170 "root": (root, [], "hg root"),
1171 "root": (root, [], "hg root"),
1171 "^serve":
1172 "^serve":
1172 (serve,
1173 (serve,
1173 [('A', 'accesslog', '', 'access log file'),
1174 [('A', 'accesslog', '', 'access log file'),
1174 ('E', 'errorlog', '', 'error log file'),
1175 ('E', 'errorlog', '', 'error log file'),
1175 ('p', 'port', 8000, 'listen port'),
1176 ('p', 'port', 8000, 'listen port'),
1176 ('a', 'address', '', 'interface address'),
1177 ('a', 'address', '', 'interface address'),
1177 ('n', 'name', os.getcwd(), 'repository name'),
1178 ('n', 'name', os.getcwd(), 'repository name'),
1178 ('', 'stdio', None, 'for remote clients'),
1179 ('', 'stdio', None, 'for remote clients'),
1179 ('t', 'templates', "", 'template map')],
1180 ('t', 'templates', "", 'template map')],
1180 "hg serve [OPTION]..."),
1181 "hg serve [OPTION]..."),
1181 "^status": (status,
1182 "^status": (status,
1182 [('I', 'include', [], 'include path in search'),
1183 [('I', 'include', [], 'include path in search'),
1183 ('X', 'exclude', [], 'exclude path from search')],
1184 ('X', 'exclude', [], 'exclude path from search')],
1184 'hg status [OPTION]... [FILE]...'),
1185 'hg status [OPTION]... [FILE]...'),
1185 "tag":
1186 "tag":
1186 (tag,
1187 (tag,
1187 [('l', 'local', None, 'make the tag local'),
1188 [('l', 'local', None, 'make the tag local'),
1188 ('m', 'text', "", 'commit message'),
1189 ('m', 'text', "", 'commit message'),
1189 ('t', 'text', "", 'commit message (deprecated)'),
1190 ('t', 'text', "", 'commit message (deprecated)'),
1190 ('d', 'date', "", 'date code'),
1191 ('d', 'date', "", 'date code'),
1191 ('u', 'user', "", 'user')],
1192 ('u', 'user', "", 'user')],
1192 'hg tag [OPTION]... NAME [REV]'),
1193 'hg tag [OPTION]... NAME [REV]'),
1193 "tags": (tags, [], 'hg tags'),
1194 "tags": (tags, [], 'hg tags'),
1194 "tip": (tip, [], 'hg tip'),
1195 "tip": (tip, [], 'hg tip'),
1195 "undo": (undo, [], 'hg undo'),
1196 "undo": (undo, [], 'hg undo'),
1196 "^update|up|checkout|co":
1197 "^update|up|checkout|co":
1197 (update,
1198 (update,
1198 [('m', 'merge', None, 'allow merging of conflicts'),
1199 [('m', 'merge', None, 'allow merging of conflicts'),
1199 ('C', 'clean', None, 'overwrite locally modified files')],
1200 ('C', 'clean', None, 'overwrite locally modified files')],
1200 'hg update [-m] [-C] [REV]'),
1201 'hg update [-m] [-C] [REV]'),
1201 "verify": (verify, [], 'hg verify'),
1202 "verify": (verify, [], 'hg verify'),
1202 "version": (show_version, [], 'hg version'),
1203 "version": (show_version, [], 'hg version'),
1203 }
1204 }
1204
1205
1205 globalopts = [('v', 'verbose', None, 'verbose'),
1206 globalopts = [('v', 'verbose', None, 'verbose'),
1206 ('', 'debug', None, 'debug'),
1207 ('', 'debug', None, 'debug'),
1207 ('q', 'quiet', None, 'quiet'),
1208 ('q', 'quiet', None, 'quiet'),
1208 ('', 'profile', None, 'profile'),
1209 ('', 'profile', None, 'profile'),
1209 ('R', 'repository', "", 'repository root directory'),
1210 ('R', 'repository', "", 'repository root directory'),
1210 ('', 'traceback', None, 'print traceback on exception'),
1211 ('', 'traceback', None, 'print traceback on exception'),
1211 ('y', 'noninteractive', None, 'run non-interactively'),
1212 ('y', 'noninteractive', None, 'run non-interactively'),
1212 ('', 'version', None, 'output version information and exit'),
1213 ('', 'version', None, 'output version information and exit'),
1213 ]
1214 ]
1214
1215
1215 norepo = "clone init version help debugindex debugindexdot"
1216 norepo = "clone init version help debugindex debugindexdot"
1216
1217
1217 def find(cmd):
1218 def find(cmd):
1218 for e in table.keys():
1219 for e in table.keys():
1219 if re.match("(%s)$" % e, cmd):
1220 if re.match("(%s)$" % e, cmd):
1220 return table[e]
1221 return table[e]
1221
1222
1222 raise UnknownCommand(cmd)
1223 raise UnknownCommand(cmd)
1223
1224
1224 class SignalInterrupt(Exception):
1225 class SignalInterrupt(Exception):
1225 """Exception raised on SIGTERM and SIGHUP."""
1226 """Exception raised on SIGTERM and SIGHUP."""
1226
1227
1227 def catchterm(*args):
1228 def catchterm(*args):
1228 raise SignalInterrupt
1229 raise SignalInterrupt
1229
1230
1230 def run():
1231 def run():
1231 sys.exit(dispatch(sys.argv[1:]))
1232 sys.exit(dispatch(sys.argv[1:]))
1232
1233
1233 class ParseError(Exception):
1234 class ParseError(Exception):
1234 """Exception raised on errors in parsing the command line."""
1235 """Exception raised on errors in parsing the command line."""
1235
1236
1236 def parse(args):
1237 def parse(args):
1237 options = {}
1238 options = {}
1238 cmdoptions = {}
1239 cmdoptions = {}
1239
1240
1240 try:
1241 try:
1241 args = fancyopts.fancyopts(args, globalopts, options)
1242 args = fancyopts.fancyopts(args, globalopts, options)
1242 except fancyopts.getopt.GetoptError, inst:
1243 except fancyopts.getopt.GetoptError, inst:
1243 raise ParseError(None, inst)
1244 raise ParseError(None, inst)
1244
1245
1245 if options["version"]:
1246 if options["version"]:
1246 return ("version", show_version, [], options, cmdoptions)
1247 return ("version", show_version, [], options, cmdoptions)
1247 elif not args:
1248 elif not args:
1248 return ("help", help_, [], options, cmdoptions)
1249 return ("help", help_, [], options, cmdoptions)
1249 else:
1250 else:
1250 cmd, args = args[0], args[1:]
1251 cmd, args = args[0], args[1:]
1251
1252
1252 i = find(cmd)
1253 i = find(cmd)
1253
1254
1254 # combine global options into local
1255 # combine global options into local
1255 c = list(i[1])
1256 c = list(i[1])
1256 for o in globalopts:
1257 for o in globalopts:
1257 c.append((o[0], o[1], options[o[1]], o[3]))
1258 c.append((o[0], o[1], options[o[1]], o[3]))
1258
1259
1259 try:
1260 try:
1260 args = fancyopts.fancyopts(args, c, cmdoptions)
1261 args = fancyopts.fancyopts(args, c, cmdoptions)
1261 except fancyopts.getopt.GetoptError, inst:
1262 except fancyopts.getopt.GetoptError, inst:
1262 raise ParseError(cmd, inst)
1263 raise ParseError(cmd, inst)
1263
1264
1264 # separate global options back out
1265 # separate global options back out
1265 for o in globalopts:
1266 for o in globalopts:
1266 n = o[1]
1267 n = o[1]
1267 options[n] = cmdoptions[n]
1268 options[n] = cmdoptions[n]
1268 del cmdoptions[n]
1269 del cmdoptions[n]
1269
1270
1270 return (cmd, i[0], args, options, cmdoptions)
1271 return (cmd, i[0], args, options, cmdoptions)
1271
1272
1272 def dispatch(args):
1273 def dispatch(args):
1273 signal.signal(signal.SIGTERM, catchterm)
1274 signal.signal(signal.SIGTERM, catchterm)
1274 try:
1275 try:
1275 signal.signal(signal.SIGHUP, catchterm)
1276 signal.signal(signal.SIGHUP, catchterm)
1276 except AttributeError:
1277 except AttributeError:
1277 pass
1278 pass
1278
1279
1279 try:
1280 try:
1280 cmd, func, args, options, cmdoptions = parse(args)
1281 cmd, func, args, options, cmdoptions = parse(args)
1281 except ParseError, inst:
1282 except ParseError, inst:
1282 u = ui.ui()
1283 u = ui.ui()
1283 if inst.args[0]:
1284 if inst.args[0]:
1284 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1285 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1285 help_(u, inst.args[0])
1286 help_(u, inst.args[0])
1286 else:
1287 else:
1287 u.warn("hg: %s\n" % inst.args[1])
1288 u.warn("hg: %s\n" % inst.args[1])
1288 help_(u)
1289 help_(u)
1289 sys.exit(-1)
1290 sys.exit(-1)
1290 except UnknownCommand, inst:
1291 except UnknownCommand, inst:
1291 u = ui.ui()
1292 u = ui.ui()
1292 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1293 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1293 help_(u)
1294 help_(u)
1294 sys.exit(1)
1295 sys.exit(1)
1295
1296
1296 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1297 u = ui.ui(options["verbose"], options["debug"], options["quiet"],
1297 not options["noninteractive"])
1298 not options["noninteractive"])
1298
1299
1299 try:
1300 try:
1300 try:
1301 try:
1301 if cmd not in norepo.split():
1302 if cmd not in norepo.split():
1302 path = options["repository"] or ""
1303 path = options["repository"] or ""
1303 repo = hg.repository(ui=u, path=path)
1304 repo = hg.repository(ui=u, path=path)
1304 d = lambda: func(u, repo, *args, **cmdoptions)
1305 d = lambda: func(u, repo, *args, **cmdoptions)
1305 else:
1306 else:
1306 d = lambda: func(u, *args, **cmdoptions)
1307 d = lambda: func(u, *args, **cmdoptions)
1307
1308
1308 if options['profile']:
1309 if options['profile']:
1309 import hotshot, hotshot.stats
1310 import hotshot, hotshot.stats
1310 prof = hotshot.Profile("hg.prof")
1311 prof = hotshot.Profile("hg.prof")
1311 r = prof.runcall(d)
1312 r = prof.runcall(d)
1312 prof.close()
1313 prof.close()
1313 stats = hotshot.stats.load("hg.prof")
1314 stats = hotshot.stats.load("hg.prof")
1314 stats.strip_dirs()
1315 stats.strip_dirs()
1315 stats.sort_stats('time', 'calls')
1316 stats.sort_stats('time', 'calls')
1316 stats.print_stats(40)
1317 stats.print_stats(40)
1317 return r
1318 return r
1318 else:
1319 else:
1319 return d()
1320 return d()
1320 except:
1321 except:
1321 if options['traceback']:
1322 if options['traceback']:
1322 traceback.print_exc()
1323 traceback.print_exc()
1323 raise
1324 raise
1324 except util.CommandError, inst:
1325 except util.CommandError, inst:
1325 u.warn("abort: %s\n" % inst.args)
1326 u.warn("abort: %s\n" % inst.args)
1326 except hg.RepoError, inst:
1327 except hg.RepoError, inst:
1327 u.warn("abort: ", inst, "!\n")
1328 u.warn("abort: ", inst, "!\n")
1328 except SignalInterrupt:
1329 except SignalInterrupt:
1329 u.warn("killed!\n")
1330 u.warn("killed!\n")
1330 except KeyboardInterrupt:
1331 except KeyboardInterrupt:
1331 u.warn("interrupted!\n")
1332 u.warn("interrupted!\n")
1332 except IOError, inst:
1333 except IOError, inst:
1333 if hasattr(inst, "code"):
1334 if hasattr(inst, "code"):
1334 u.warn("abort: %s\n" % inst)
1335 u.warn("abort: %s\n" % inst)
1335 elif hasattr(inst, "reason"):
1336 elif hasattr(inst, "reason"):
1336 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1337 u.warn("abort: error %d: %s\n" % (inst.reason[0], inst.reason[1]))
1337 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1338 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1338 if u.debugflag: u.warn("broken pipe\n")
1339 if u.debugflag: u.warn("broken pipe\n")
1339 else:
1340 else:
1340 raise
1341 raise
1341 except OSError, inst:
1342 except OSError, inst:
1342 if hasattr(inst, "filename"):
1343 if hasattr(inst, "filename"):
1343 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1344 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1344 else:
1345 else:
1345 u.warn("abort: %s\n" % inst.strerror)
1346 u.warn("abort: %s\n" % inst.strerror)
1346 except Abort, inst:
1347 except Abort, inst:
1347 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1348 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1348 sys.exit(1)
1349 sys.exit(1)
1349 except TypeError, inst:
1350 except TypeError, inst:
1350 # was this an argument error?
1351 # was this an argument error?
1351 tb = traceback.extract_tb(sys.exc_info()[2])
1352 tb = traceback.extract_tb(sys.exc_info()[2])
1352 if len(tb) > 2: # no
1353 if len(tb) > 2: # no
1353 raise
1354 raise
1354 u.debug(inst, "\n")
1355 u.debug(inst, "\n")
1355 u.warn("%s: invalid arguments\n" % cmd)
1356 u.warn("%s: invalid arguments\n" % cmd)
1356 help_(u, cmd)
1357 help_(u, cmd)
1357
1358
1358 sys.exit(-1)
1359 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now