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