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