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