##// END OF EJS Templates
Changed printing of copies in hg debugstate to: "copy: source -> dest"
Thomas Arendsen Hein -
r1126:624a3a4f default
parent child Browse files
Show More
@@ -1,1895 +1,1894 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 revlog")
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
584
585 for fn in "dirstate", "lock":
585 for fn in "dirstate", "lock":
586 try:
586 try:
587 os.unlink(os.path.join(dest, ".hg", fn))
587 os.unlink(os.path.join(dest, ".hg", fn))
588 except OSError:
588 except OSError:
589 pass
589 pass
590
590
591 repo = hg.repository(ui, dest)
591 repo = hg.repository(ui, dest)
592
592
593 else:
593 else:
594 repo = hg.repository(ui, dest, create=1)
594 repo = hg.repository(ui, dest, create=1)
595 repo.pull(other)
595 repo.pull(other)
596
596
597 f = repo.opener("hgrc", "w")
597 f = repo.opener("hgrc", "w")
598 f.write("[paths]\n")
598 f.write("[paths]\n")
599 f.write("default = %s\n" % abspath)
599 f.write("default = %s\n" % abspath)
600
600
601 if not opts['noupdate']:
601 if not opts['noupdate']:
602 update(ui, repo)
602 update(ui, repo)
603
603
604 d.close()
604 d.close()
605
605
606 def commit(ui, repo, *pats, **opts):
606 def commit(ui, repo, *pats, **opts):
607 """commit the specified files or all outstanding changes"""
607 """commit the specified files or all outstanding changes"""
608 if opts['text']:
608 if opts['text']:
609 ui.warn("Warning: -t and --text is deprecated,"
609 ui.warn("Warning: -t and --text is deprecated,"
610 " please use -m or --message instead.\n")
610 " please use -m or --message instead.\n")
611 message = opts['message'] or opts['text']
611 message = opts['message'] or opts['text']
612 logfile = opts['logfile']
612 logfile = opts['logfile']
613 if not message and logfile:
613 if not message and logfile:
614 try:
614 try:
615 if logfile == '-':
615 if logfile == '-':
616 message = sys.stdin.read()
616 message = sys.stdin.read()
617 else:
617 else:
618 message = open(logfile).read()
618 message = open(logfile).read()
619 except IOError, why:
619 except IOError, why:
620 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
620 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
621
621
622 if opts['addremove']:
622 if opts['addremove']:
623 addremove(ui, repo, *pats, **opts)
623 addremove(ui, repo, *pats, **opts)
624 cwd = repo.getcwd()
624 cwd = repo.getcwd()
625 if not pats and cwd:
625 if not pats and cwd:
626 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
626 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
627 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
627 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
628 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
628 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
629 pats, opts)
629 pats, opts)
630 if pats:
630 if pats:
631 c, a, d, u = repo.changes(files=fns, match=match)
631 c, a, d, u = repo.changes(files=fns, match=match)
632 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
632 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
633 else:
633 else:
634 files = []
634 files = []
635 repo.commit(files, message, opts['user'], opts['date'], match)
635 repo.commit(files, message, opts['user'], opts['date'], match)
636
636
637 def copy(ui, repo, source, dest):
637 def copy(ui, repo, source, dest):
638 """mark a file as copied or renamed for the next commit"""
638 """mark a file as copied or renamed for the next commit"""
639 return repo.copy(*relpath(repo, (source, dest)))
639 return repo.copy(*relpath(repo, (source, dest)))
640
640
641 def debugcheckstate(ui, repo):
641 def debugcheckstate(ui, repo):
642 """validate the correctness of the current dirstate"""
642 """validate the correctness of the current dirstate"""
643 parent1, parent2 = repo.dirstate.parents()
643 parent1, parent2 = repo.dirstate.parents()
644 repo.dirstate.read()
644 repo.dirstate.read()
645 dc = repo.dirstate.map
645 dc = repo.dirstate.map
646 keys = dc.keys()
646 keys = dc.keys()
647 keys.sort()
647 keys.sort()
648 m1n = repo.changelog.read(parent1)[0]
648 m1n = repo.changelog.read(parent1)[0]
649 m2n = repo.changelog.read(parent2)[0]
649 m2n = repo.changelog.read(parent2)[0]
650 m1 = repo.manifest.read(m1n)
650 m1 = repo.manifest.read(m1n)
651 m2 = repo.manifest.read(m2n)
651 m2 = repo.manifest.read(m2n)
652 errors = 0
652 errors = 0
653 for f in dc:
653 for f in dc:
654 state = repo.dirstate.state(f)
654 state = repo.dirstate.state(f)
655 if state in "nr" and f not in m1:
655 if state in "nr" and f not in m1:
656 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
656 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
657 errors += 1
657 errors += 1
658 if state in "a" and f in m1:
658 if state in "a" and f in m1:
659 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
659 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
660 errors += 1
660 errors += 1
661 if state in "m" and f not in m1 and f not in m2:
661 if state in "m" and f not in m1 and f not in m2:
662 ui.warn("%s in state %s, but not in either manifest\n" %
662 ui.warn("%s in state %s, but not in either manifest\n" %
663 (f, state))
663 (f, state))
664 errors += 1
664 errors += 1
665 for f in m1:
665 for f in m1:
666 state = repo.dirstate.state(f)
666 state = repo.dirstate.state(f)
667 if state not in "nrm":
667 if state not in "nrm":
668 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
668 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
669 errors += 1
669 errors += 1
670 if errors:
670 if errors:
671 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
671 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
672
672
673 def debugconfig(ui):
673 def debugconfig(ui):
674 """show combined config settings from all hgrc files"""
674 """show combined config settings from all hgrc files"""
675 try:
675 try:
676 repo = hg.repository(ui)
676 repo = hg.repository(ui)
677 except hg.RepoError:
677 except hg.RepoError:
678 pass
678 pass
679 for section, name, value in ui.walkconfig():
679 for section, name, value in ui.walkconfig():
680 ui.write('%s.%s=%s\n' % (section, name, value))
680 ui.write('%s.%s=%s\n' % (section, name, value))
681
681
682 def debugstate(ui, repo):
682 def debugstate(ui, repo):
683 """show the contents of the current dirstate"""
683 """show the contents of the current dirstate"""
684 repo.dirstate.read()
684 repo.dirstate.read()
685 dc = repo.dirstate.map
685 dc = repo.dirstate.map
686 keys = dc.keys()
686 keys = dc.keys()
687 keys.sort()
687 keys.sort()
688 for file_ in keys:
688 for file_ in keys:
689 ui.write("%c %3o %10d %s %s\n"
689 ui.write("%c %3o %10d %s %s\n"
690 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
690 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
691 time.strftime("%x %X",
691 time.strftime("%x %X",
692 time.localtime(dc[file_][3])), file_))
692 time.localtime(dc[file_][3])), file_))
693 ui.write("\n")
694 for f in repo.dirstate.copies:
693 for f in repo.dirstate.copies:
695 ui.write("%s -> %s\n" % (repo.dirstate.copies[f], f))
694 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
696
695
697 def debugdata(ui, file_, rev):
696 def debugdata(ui, file_, rev):
698 """dump the contents of an data file revision"""
697 """dump the contents of an data file revision"""
699 r = revlog.revlog(file, file_[:-2] + ".i", file_)
698 r = revlog.revlog(file, file_[:-2] + ".i", file_)
700 ui.write(r.revision(r.lookup(rev)))
699 ui.write(r.revision(r.lookup(rev)))
701
700
702 def debugindex(ui, file_):
701 def debugindex(ui, file_):
703 """dump the contents of an index file"""
702 """dump the contents of an index file"""
704 r = revlog.revlog(file, file_, "")
703 r = revlog.revlog(file, file_, "")
705 ui.write(" rev offset length base linkrev" +
704 ui.write(" rev offset length base linkrev" +
706 " nodeid p1 p2\n")
705 " nodeid p1 p2\n")
707 for i in range(r.count()):
706 for i in range(r.count()):
708 e = r.index[i]
707 e = r.index[i]
709 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
708 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
710 i, e[0], e[1], e[2], e[3],
709 i, e[0], e[1], e[2], e[3],
711 short(e[6]), short(e[4]), short(e[5])))
710 short(e[6]), short(e[4]), short(e[5])))
712
711
713 def debugindexdot(ui, file_):
712 def debugindexdot(ui, file_):
714 """dump an index DAG as a .dot file"""
713 """dump an index DAG as a .dot file"""
715 r = revlog.revlog(file, file_, "")
714 r = revlog.revlog(file, file_, "")
716 ui.write("digraph G {\n")
715 ui.write("digraph G {\n")
717 for i in range(r.count()):
716 for i in range(r.count()):
718 e = r.index[i]
717 e = r.index[i]
719 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
718 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
720 if e[5] != nullid:
719 if e[5] != nullid:
721 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
720 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
722 ui.write("}\n")
721 ui.write("}\n")
723
722
724 def debugrename(ui, repo, file, rev=None):
723 def debugrename(ui, repo, file, rev=None):
725 r = repo.file(relpath(repo, [file])[0])
724 r = repo.file(relpath(repo, [file])[0])
726 if rev:
725 if rev:
727 try:
726 try:
728 # assume all revision numbers are for changesets
727 # assume all revision numbers are for changesets
729 n = repo.lookup(rev)
728 n = repo.lookup(rev)
730 change = repo.changelog.read(n)
729 change = repo.changelog.read(n)
731 m = repo.manifest.read(change[0])
730 m = repo.manifest.read(change[0])
732 n = m[relpath(repo, [file])[0]]
731 n = m[relpath(repo, [file])[0]]
733 except hg.RepoError, KeyError:
732 except hg.RepoError, KeyError:
734 n = r.lookup(rev)
733 n = r.lookup(rev)
735 else:
734 else:
736 n = r.tip()
735 n = r.tip()
737 m = r.renamed(n)
736 m = r.renamed(n)
738 if m:
737 if m:
739 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
738 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
740 else:
739 else:
741 ui.write("not renamed\n")
740 ui.write("not renamed\n")
742
741
743 def debugwalk(ui, repo, *pats, **opts):
742 def debugwalk(ui, repo, *pats, **opts):
744 """show how files match on given patterns"""
743 """show how files match on given patterns"""
745 items = list(walk(repo, pats, opts))
744 items = list(walk(repo, pats, opts))
746 if not items:
745 if not items:
747 return
746 return
748 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
747 fmt = '%%s %%-%ds %%-%ds %%s\n' % (
749 max([len(abs) for (src, abs, rel, exact) in items]),
748 max([len(abs) for (src, abs, rel, exact) in items]),
750 max([len(rel) for (src, abs, rel, exact) in items]))
749 max([len(rel) for (src, abs, rel, exact) in items]))
751 for src, abs, rel, exact in items:
750 for src, abs, rel, exact in items:
752 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
751 ui.write(fmt % (src, abs, rel, exact and 'exact' or ''))
753
752
754 def diff(ui, repo, *pats, **opts):
753 def diff(ui, repo, *pats, **opts):
755 """diff working directory (or selected files)"""
754 """diff working directory (or selected files)"""
756 node1, node2 = None, None
755 node1, node2 = None, None
757 revs = [repo.lookup(x) for x in opts['rev']]
756 revs = [repo.lookup(x) for x in opts['rev']]
758
757
759 if len(revs) > 0:
758 if len(revs) > 0:
760 node1 = revs[0]
759 node1 = revs[0]
761 if len(revs) > 1:
760 if len(revs) > 1:
762 node2 = revs[1]
761 node2 = revs[1]
763 if len(revs) > 2:
762 if len(revs) > 2:
764 raise util.Abort("too many revisions to diff")
763 raise util.Abort("too many revisions to diff")
765
764
766 files = []
765 files = []
767 match = util.always
766 match = util.always
768 if pats:
767 if pats:
769 roots, match, results = makewalk(repo, pats, opts)
768 roots, match, results = makewalk(repo, pats, opts)
770 for src, abs, rel, exact in results:
769 for src, abs, rel, exact in results:
771 files.append(abs)
770 files.append(abs)
772
771
773 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
772 dodiff(sys.stdout, ui, repo, node1, node2, files, match=match,
774 text=opts['text'])
773 text=opts['text'])
775
774
776 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
775 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
777 node = repo.lookup(changeset)
776 node = repo.lookup(changeset)
778 prev, other = repo.changelog.parents(node)
777 prev, other = repo.changelog.parents(node)
779 change = repo.changelog.read(node)
778 change = repo.changelog.read(node)
780
779
781 fp = make_file(repo, repo.changelog, opts['output'],
780 fp = make_file(repo, repo.changelog, opts['output'],
782 node=node, total=total, seqno=seqno,
781 node=node, total=total, seqno=seqno,
783 revwidth=revwidth)
782 revwidth=revwidth)
784 if fp != sys.stdout:
783 if fp != sys.stdout:
785 ui.note("%s\n" % fp.name)
784 ui.note("%s\n" % fp.name)
786
785
787 fp.write("# HG changeset patch\n")
786 fp.write("# HG changeset patch\n")
788 fp.write("# User %s\n" % change[1])
787 fp.write("# User %s\n" % change[1])
789 fp.write("# Node ID %s\n" % hex(node))
788 fp.write("# Node ID %s\n" % hex(node))
790 fp.write("# Parent %s\n" % hex(prev))
789 fp.write("# Parent %s\n" % hex(prev))
791 if other != nullid:
790 if other != nullid:
792 fp.write("# Parent %s\n" % hex(other))
791 fp.write("# Parent %s\n" % hex(other))
793 fp.write(change[4].rstrip())
792 fp.write(change[4].rstrip())
794 fp.write("\n\n")
793 fp.write("\n\n")
795
794
796 dodiff(fp, ui, repo, prev, node, text=opts['text'])
795 dodiff(fp, ui, repo, prev, node, text=opts['text'])
797 if fp != sys.stdout:
796 if fp != sys.stdout:
798 fp.close()
797 fp.close()
799
798
800 def export(ui, repo, *changesets, **opts):
799 def export(ui, repo, *changesets, **opts):
801 """dump the header and diffs for one or more changesets"""
800 """dump the header and diffs for one or more changesets"""
802 if not changesets:
801 if not changesets:
803 raise util.Abort("export requires at least one changeset")
802 raise util.Abort("export requires at least one changeset")
804 seqno = 0
803 seqno = 0
805 revs = list(revrange(ui, repo, changesets))
804 revs = list(revrange(ui, repo, changesets))
806 total = len(revs)
805 total = len(revs)
807 revwidth = max(map(len, revs))
806 revwidth = max(map(len, revs))
808 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
807 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
809 for cset in revs:
808 for cset in revs:
810 seqno += 1
809 seqno += 1
811 doexport(ui, repo, cset, seqno, total, revwidth, opts)
810 doexport(ui, repo, cset, seqno, total, revwidth, opts)
812
811
813 def forget(ui, repo, *pats, **opts):
812 def forget(ui, repo, *pats, **opts):
814 """don't add the specified files on the next commit"""
813 """don't add the specified files on the next commit"""
815 forget = []
814 forget = []
816 for src, abs, rel, exact in walk(repo, pats, opts):
815 for src, abs, rel, exact in walk(repo, pats, opts):
817 if repo.dirstate.state(abs) == 'a':
816 if repo.dirstate.state(abs) == 'a':
818 forget.append(abs)
817 forget.append(abs)
819 if not exact:
818 if not exact:
820 ui.status('forgetting ', rel, '\n')
819 ui.status('forgetting ', rel, '\n')
821 repo.forget(forget)
820 repo.forget(forget)
822
821
823 def grep(ui, repo, pattern, *pats, **opts):
822 def grep(ui, repo, pattern, *pats, **opts):
824 """search for a pattern in specified files and revisions"""
823 """search for a pattern in specified files and revisions"""
825 reflags = 0
824 reflags = 0
826 if opts['ignore_case']:
825 if opts['ignore_case']:
827 reflags |= re.I
826 reflags |= re.I
828 regexp = re.compile(pattern, reflags)
827 regexp = re.compile(pattern, reflags)
829 sep, end = ':', '\n'
828 sep, end = ':', '\n'
830 if opts['print0']:
829 if opts['print0']:
831 sep = end = '\0'
830 sep = end = '\0'
832
831
833 fcache = {}
832 fcache = {}
834 def getfile(fn):
833 def getfile(fn):
835 if fn not in fcache:
834 if fn not in fcache:
836 fcache[fn] = repo.file(fn)
835 fcache[fn] = repo.file(fn)
837 return fcache[fn]
836 return fcache[fn]
838
837
839 def matchlines(body):
838 def matchlines(body):
840 begin = 0
839 begin = 0
841 linenum = 0
840 linenum = 0
842 while True:
841 while True:
843 match = regexp.search(body, begin)
842 match = regexp.search(body, begin)
844 if not match:
843 if not match:
845 break
844 break
846 mstart, mend = match.span()
845 mstart, mend = match.span()
847 linenum += body.count('\n', begin, mstart) + 1
846 linenum += body.count('\n', begin, mstart) + 1
848 lstart = body.rfind('\n', begin, mstart) + 1 or begin
847 lstart = body.rfind('\n', begin, mstart) + 1 or begin
849 lend = body.find('\n', mend)
848 lend = body.find('\n', mend)
850 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
849 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
851 begin = lend + 1
850 begin = lend + 1
852
851
853 class linestate:
852 class linestate:
854 def __init__(self, line, linenum, colstart, colend):
853 def __init__(self, line, linenum, colstart, colend):
855 self.line = line
854 self.line = line
856 self.linenum = linenum
855 self.linenum = linenum
857 self.colstart = colstart
856 self.colstart = colstart
858 self.colend = colend
857 self.colend = colend
859 def __eq__(self, other):
858 def __eq__(self, other):
860 return self.line == other.line
859 return self.line == other.line
861 def __hash__(self):
860 def __hash__(self):
862 return hash(self.line)
861 return hash(self.line)
863
862
864 matches = {}
863 matches = {}
865 def grepbody(fn, rev, body):
864 def grepbody(fn, rev, body):
866 matches[rev].setdefault(fn, {})
865 matches[rev].setdefault(fn, {})
867 m = matches[rev][fn]
866 m = matches[rev][fn]
868 for lnum, cstart, cend, line in matchlines(body):
867 for lnum, cstart, cend, line in matchlines(body):
869 s = linestate(line, lnum, cstart, cend)
868 s = linestate(line, lnum, cstart, cend)
870 m[s] = s
869 m[s] = s
871
870
872 prev = {}
871 prev = {}
873 def display(fn, rev, states, prevstates):
872 def display(fn, rev, states, prevstates):
874 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
873 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
875 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
874 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
876 for l in diff:
875 for l in diff:
877 if incrementing:
876 if incrementing:
878 change = ((l in prevstates) and '-') or '+'
877 change = ((l in prevstates) and '-') or '+'
879 r = rev
878 r = rev
880 else:
879 else:
881 change = ((l in states) and '-') or '+'
880 change = ((l in states) and '-') or '+'
882 r = prev[fn]
881 r = prev[fn]
883 ui.write('%s:%s:%s:%s%s\n' % (fn, r, l.linenum, change, l.line))
882 ui.write('%s:%s:%s:%s%s\n' % (fn, r, l.linenum, change, l.line))
884
883
885 fstate = {}
884 fstate = {}
886 for st, rev, fns in walkchangerevs(ui, repo, repo.getcwd(), pats, opts):
885 for st, rev, fns in walkchangerevs(ui, repo, repo.getcwd(), pats, opts):
887 if st == 'window':
886 if st == 'window':
888 incrementing = rev
887 incrementing = rev
889 matches.clear()
888 matches.clear()
890 elif st == 'add':
889 elif st == 'add':
891 change = repo.changelog.read(repo.lookup(str(rev)))
890 change = repo.changelog.read(repo.lookup(str(rev)))
892 mf = repo.manifest.read(change[0])
891 mf = repo.manifest.read(change[0])
893 matches[rev] = {}
892 matches[rev] = {}
894 for fn in fns:
893 for fn in fns:
895 fstate.setdefault(fn, {})
894 fstate.setdefault(fn, {})
896 try:
895 try:
897 grepbody(fn, rev, getfile(fn).read(mf[fn]))
896 grepbody(fn, rev, getfile(fn).read(mf[fn]))
898 except KeyError:
897 except KeyError:
899 pass
898 pass
900 elif st == 'iter':
899 elif st == 'iter':
901 states = matches[rev].items()
900 states = matches[rev].items()
902 states.sort()
901 states.sort()
903 for fn, m in states:
902 for fn, m in states:
904 if incrementing or fstate[fn]:
903 if incrementing or fstate[fn]:
905 display(fn, rev, m, fstate[fn])
904 display(fn, rev, m, fstate[fn])
906 fstate[fn] = m
905 fstate[fn] = m
907 prev[fn] = rev
906 prev[fn] = rev
908
907
909 if not incrementing:
908 if not incrementing:
910 fstate = fstate.items()
909 fstate = fstate.items()
911 fstate.sort()
910 fstate.sort()
912 for fn, state in fstate:
911 for fn, state in fstate:
913 display(fn, rev, {}, state)
912 display(fn, rev, {}, state)
914
913
915 def heads(ui, repo, **opts):
914 def heads(ui, repo, **opts):
916 """show current repository heads"""
915 """show current repository heads"""
917 heads = repo.changelog.heads()
916 heads = repo.changelog.heads()
918 br = None
917 br = None
919 if opts['branches']:
918 if opts['branches']:
920 br = repo.branchlookup(heads)
919 br = repo.branchlookup(heads)
921 for n in repo.changelog.heads():
920 for n in repo.changelog.heads():
922 show_changeset(ui, repo, changenode=n, brinfo=br)
921 show_changeset(ui, repo, changenode=n, brinfo=br)
923
922
924 def identify(ui, repo):
923 def identify(ui, repo):
925 """print information about the working copy"""
924 """print information about the working copy"""
926 parents = [p for p in repo.dirstate.parents() if p != nullid]
925 parents = [p for p in repo.dirstate.parents() if p != nullid]
927 if not parents:
926 if not parents:
928 ui.write("unknown\n")
927 ui.write("unknown\n")
929 return
928 return
930
929
931 hexfunc = ui.verbose and hex or short
930 hexfunc = ui.verbose and hex or short
932 (c, a, d, u) = repo.changes()
931 (c, a, d, u) = repo.changes()
933 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
932 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
934 (c or a or d) and "+" or "")]
933 (c or a or d) and "+" or "")]
935
934
936 if not ui.quiet:
935 if not ui.quiet:
937 # multiple tags for a single parent separated by '/'
936 # multiple tags for a single parent separated by '/'
938 parenttags = ['/'.join(tags)
937 parenttags = ['/'.join(tags)
939 for tags in map(repo.nodetags, parents) if tags]
938 for tags in map(repo.nodetags, parents) if tags]
940 # tags for multiple parents separated by ' + '
939 # tags for multiple parents separated by ' + '
941 if parenttags:
940 if parenttags:
942 output.append(' + '.join(parenttags))
941 output.append(' + '.join(parenttags))
943
942
944 ui.write("%s\n" % ' '.join(output))
943 ui.write("%s\n" % ' '.join(output))
945
944
946 def import_(ui, repo, patch1, *patches, **opts):
945 def import_(ui, repo, patch1, *patches, **opts):
947 """import an ordered set of patches"""
946 """import an ordered set of patches"""
948 patches = (patch1,) + patches
947 patches = (patch1,) + patches
949
948
950 if not opts['force']:
949 if not opts['force']:
951 (c, a, d, u) = repo.changes()
950 (c, a, d, u) = repo.changes()
952 if c or a or d:
951 if c or a or d:
953 ui.warn("abort: outstanding uncommitted changes!\n")
952 ui.warn("abort: outstanding uncommitted changes!\n")
954 return 1
953 return 1
955
954
956 d = opts["base"]
955 d = opts["base"]
957 strip = opts["strip"]
956 strip = opts["strip"]
958
957
959 for patch in patches:
958 for patch in patches:
960 ui.status("applying %s\n" % patch)
959 ui.status("applying %s\n" % patch)
961 pf = os.path.join(d, patch)
960 pf = os.path.join(d, patch)
962
961
963 message = []
962 message = []
964 user = None
963 user = None
965 hgpatch = False
964 hgpatch = False
966 for line in file(pf):
965 for line in file(pf):
967 line = line.rstrip()
966 line = line.rstrip()
968 if line.startswith("--- ") or line.startswith("diff -r"):
967 if line.startswith("--- ") or line.startswith("diff -r"):
969 break
968 break
970 elif hgpatch:
969 elif hgpatch:
971 # parse values when importing the result of an hg export
970 # parse values when importing the result of an hg export
972 if line.startswith("# User "):
971 if line.startswith("# User "):
973 user = line[7:]
972 user = line[7:]
974 ui.debug('User: %s\n' % user)
973 ui.debug('User: %s\n' % user)
975 elif not line.startswith("# ") and line:
974 elif not line.startswith("# ") and line:
976 message.append(line)
975 message.append(line)
977 hgpatch = False
976 hgpatch = False
978 elif line == '# HG changeset patch':
977 elif line == '# HG changeset patch':
979 hgpatch = True
978 hgpatch = True
980 message = [] # We may have collected garbage
979 message = [] # We may have collected garbage
981 else:
980 else:
982 message.append(line)
981 message.append(line)
983
982
984 # make sure message isn't empty
983 # make sure message isn't empty
985 if not message:
984 if not message:
986 message = "imported patch %s\n" % patch
985 message = "imported patch %s\n" % patch
987 else:
986 else:
988 message = "%s\n" % '\n'.join(message)
987 message = "%s\n" % '\n'.join(message)
989 ui.debug('message:\n%s\n' % message)
988 ui.debug('message:\n%s\n' % message)
990
989
991 f = os.popen("patch -p%d < '%s'" % (strip, pf))
990 f = os.popen("patch -p%d < '%s'" % (strip, pf))
992 files = []
991 files = []
993 for l in f.read().splitlines():
992 for l in f.read().splitlines():
994 l.rstrip('\r\n');
993 l.rstrip('\r\n');
995 ui.status("%s\n" % l)
994 ui.status("%s\n" % l)
996 if l.startswith('patching file '):
995 if l.startswith('patching file '):
997 pf = l[14:]
996 pf = l[14:]
998 if pf not in files:
997 if pf not in files:
999 files.append(pf)
998 files.append(pf)
1000 patcherr = f.close()
999 patcherr = f.close()
1001 if patcherr:
1000 if patcherr:
1002 raise util.Abort("patch failed")
1001 raise util.Abort("patch failed")
1003
1002
1004 if len(files) > 0:
1003 if len(files) > 0:
1005 addremove(ui, repo, *files)
1004 addremove(ui, repo, *files)
1006 repo.commit(files, message, user)
1005 repo.commit(files, message, user)
1007
1006
1008 def incoming(ui, repo, source="default"):
1007 def incoming(ui, repo, source="default"):
1009 """show new changesets found in source"""
1008 """show new changesets found in source"""
1010 source = ui.expandpath(source)
1009 source = ui.expandpath(source)
1011 other = hg.repository(ui, source)
1010 other = hg.repository(ui, source)
1012 if not other.local():
1011 if not other.local():
1013 ui.warn("abort: incoming doesn't work for remote"
1012 ui.warn("abort: incoming doesn't work for remote"
1014 + " repositories yet, sorry!\n")
1013 + " repositories yet, sorry!\n")
1015 return 1
1014 return 1
1016 o = repo.findincoming(other)
1015 o = repo.findincoming(other)
1017 if not o:
1016 if not o:
1018 return
1017 return
1019 o = other.newer(o)
1018 o = other.newer(o)
1020 o.reverse()
1019 o.reverse()
1021 for n in o:
1020 for n in o:
1022 show_changeset(ui, other, changenode=n)
1021 show_changeset(ui, other, changenode=n)
1023
1022
1024 def init(ui, dest="."):
1023 def init(ui, dest="."):
1025 """create a new repository in the given directory"""
1024 """create a new repository in the given directory"""
1026 if not os.path.exists(dest):
1025 if not os.path.exists(dest):
1027 os.mkdir(dest)
1026 os.mkdir(dest)
1028 hg.repository(ui, dest, create=1)
1027 hg.repository(ui, dest, create=1)
1029
1028
1030 def locate(ui, repo, *pats, **opts):
1029 def locate(ui, repo, *pats, **opts):
1031 """locate files matching specific patterns"""
1030 """locate files matching specific patterns"""
1032 end = opts['print0'] and '\0' or '\n'
1031 end = opts['print0'] and '\0' or '\n'
1033
1032
1034 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1033 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1035 if repo.dirstate.state(abs) == '?':
1034 if repo.dirstate.state(abs) == '?':
1036 continue
1035 continue
1037 if opts['fullpath']:
1036 if opts['fullpath']:
1038 ui.write(os.path.join(repo.root, abs), end)
1037 ui.write(os.path.join(repo.root, abs), end)
1039 else:
1038 else:
1040 ui.write(rel, end)
1039 ui.write(rel, end)
1041
1040
1042 def log(ui, repo, *pats, **opts):
1041 def log(ui, repo, *pats, **opts):
1043 """show revision history of entire repository or files"""
1042 """show revision history of entire repository or files"""
1044 class dui:
1043 class dui:
1045 # Implement and delegate some ui protocol. Save hunks of
1044 # Implement and delegate some ui protocol. Save hunks of
1046 # output for later display in the desired order.
1045 # output for later display in the desired order.
1047 def __init__(self, ui):
1046 def __init__(self, ui):
1048 self.ui = ui
1047 self.ui = ui
1049 self.hunk = {}
1048 self.hunk = {}
1050 def bump(self, rev):
1049 def bump(self, rev):
1051 self.rev = rev
1050 self.rev = rev
1052 self.hunk[rev] = []
1051 self.hunk[rev] = []
1053 def note(self, *args):
1052 def note(self, *args):
1054 if self.verbose:
1053 if self.verbose:
1055 self.write(*args)
1054 self.write(*args)
1056 def status(self, *args):
1055 def status(self, *args):
1057 if not self.quiet:
1056 if not self.quiet:
1058 self.write(*args)
1057 self.write(*args)
1059 def write(self, *args):
1058 def write(self, *args):
1060 self.hunk[self.rev].append(args)
1059 self.hunk[self.rev].append(args)
1061 def __getattr__(self, key):
1060 def __getattr__(self, key):
1062 return getattr(self.ui, key)
1061 return getattr(self.ui, key)
1063 cwd = repo.getcwd()
1062 cwd = repo.getcwd()
1064 if not pats and cwd:
1063 if not pats and cwd:
1065 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1064 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1066 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1065 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1067 for st, rev, fns in walkchangerevs(ui, repo, (pats and cwd) or '', pats,
1066 for st, rev, fns in walkchangerevs(ui, repo, (pats and cwd) or '', pats,
1068 opts):
1067 opts):
1069 if st == 'window':
1068 if st == 'window':
1070 du = dui(ui)
1069 du = dui(ui)
1071 elif st == 'add':
1070 elif st == 'add':
1072 du.bump(rev)
1071 du.bump(rev)
1073 show_changeset(du, repo, rev)
1072 show_changeset(du, repo, rev)
1074 if opts['patch']:
1073 if opts['patch']:
1075 changenode = repo.changelog.node(rev)
1074 changenode = repo.changelog.node(rev)
1076 prev, other = repo.changelog.parents(changenode)
1075 prev, other = repo.changelog.parents(changenode)
1077 dodiff(du, du, repo, prev, changenode, fns)
1076 dodiff(du, du, repo, prev, changenode, fns)
1078 du.write("\n\n")
1077 du.write("\n\n")
1079 elif st == 'iter':
1078 elif st == 'iter':
1080 for args in du.hunk[rev]:
1079 for args in du.hunk[rev]:
1081 ui.write(*args)
1080 ui.write(*args)
1082
1081
1083 def manifest(ui, repo, rev=None):
1082 def manifest(ui, repo, rev=None):
1084 """output the latest or given revision of the project manifest"""
1083 """output the latest or given revision of the project manifest"""
1085 if rev:
1084 if rev:
1086 try:
1085 try:
1087 # assume all revision numbers are for changesets
1086 # assume all revision numbers are for changesets
1088 n = repo.lookup(rev)
1087 n = repo.lookup(rev)
1089 change = repo.changelog.read(n)
1088 change = repo.changelog.read(n)
1090 n = change[0]
1089 n = change[0]
1091 except hg.RepoError:
1090 except hg.RepoError:
1092 n = repo.manifest.lookup(rev)
1091 n = repo.manifest.lookup(rev)
1093 else:
1092 else:
1094 n = repo.manifest.tip()
1093 n = repo.manifest.tip()
1095 m = repo.manifest.read(n)
1094 m = repo.manifest.read(n)
1096 mf = repo.manifest.readflags(n)
1095 mf = repo.manifest.readflags(n)
1097 files = m.keys()
1096 files = m.keys()
1098 files.sort()
1097 files.sort()
1099
1098
1100 for f in files:
1099 for f in files:
1101 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1100 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1102
1101
1103 def outgoing(ui, repo, dest="default-push"):
1102 def outgoing(ui, repo, dest="default-push"):
1104 """show changesets not found in destination"""
1103 """show changesets not found in destination"""
1105 dest = ui.expandpath(dest)
1104 dest = ui.expandpath(dest)
1106 other = hg.repository(ui, dest)
1105 other = hg.repository(ui, dest)
1107 o = repo.findoutgoing(other)
1106 o = repo.findoutgoing(other)
1108 o = repo.newer(o)
1107 o = repo.newer(o)
1109 o.reverse()
1108 o.reverse()
1110 for n in o:
1109 for n in o:
1111 show_changeset(ui, repo, changenode=n)
1110 show_changeset(ui, repo, changenode=n)
1112
1111
1113 def parents(ui, repo, rev=None):
1112 def parents(ui, repo, rev=None):
1114 """show the parents of the working dir or revision"""
1113 """show the parents of the working dir or revision"""
1115 if rev:
1114 if rev:
1116 p = repo.changelog.parents(repo.lookup(rev))
1115 p = repo.changelog.parents(repo.lookup(rev))
1117 else:
1116 else:
1118 p = repo.dirstate.parents()
1117 p = repo.dirstate.parents()
1119
1118
1120 for n in p:
1119 for n in p:
1121 if n != nullid:
1120 if n != nullid:
1122 show_changeset(ui, repo, changenode=n)
1121 show_changeset(ui, repo, changenode=n)
1123
1122
1124 def paths(ui, search=None):
1123 def paths(ui, search=None):
1125 """show definition of symbolic path names"""
1124 """show definition of symbolic path names"""
1126 try:
1125 try:
1127 repo = hg.repository(ui=ui)
1126 repo = hg.repository(ui=ui)
1128 except hg.RepoError:
1127 except hg.RepoError:
1129 pass
1128 pass
1130
1129
1131 if search:
1130 if search:
1132 for name, path in ui.configitems("paths"):
1131 for name, path in ui.configitems("paths"):
1133 if name == search:
1132 if name == search:
1134 ui.write("%s\n" % path)
1133 ui.write("%s\n" % path)
1135 return
1134 return
1136 ui.warn("not found!\n")
1135 ui.warn("not found!\n")
1137 return 1
1136 return 1
1138 else:
1137 else:
1139 for name, path in ui.configitems("paths"):
1138 for name, path in ui.configitems("paths"):
1140 ui.write("%s = %s\n" % (name, path))
1139 ui.write("%s = %s\n" % (name, path))
1141
1140
1142 def pull(ui, repo, source="default", **opts):
1141 def pull(ui, repo, source="default", **opts):
1143 """pull changes from the specified source"""
1142 """pull changes from the specified source"""
1144 source = ui.expandpath(source)
1143 source = ui.expandpath(source)
1145 ui.status('pulling from %s\n' % (source))
1144 ui.status('pulling from %s\n' % (source))
1146
1145
1147 if opts['ssh']:
1146 if opts['ssh']:
1148 ui.setconfig("ui", "ssh", opts['ssh'])
1147 ui.setconfig("ui", "ssh", opts['ssh'])
1149 if opts['remotecmd']:
1148 if opts['remotecmd']:
1150 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1149 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1151
1150
1152 other = hg.repository(ui, source)
1151 other = hg.repository(ui, source)
1153 r = repo.pull(other)
1152 r = repo.pull(other)
1154 if not r:
1153 if not r:
1155 if opts['update']:
1154 if opts['update']:
1156 return update(ui, repo)
1155 return update(ui, repo)
1157 else:
1156 else:
1158 ui.status("(run 'hg update' to get a working copy)\n")
1157 ui.status("(run 'hg update' to get a working copy)\n")
1159
1158
1160 return r
1159 return r
1161
1160
1162 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1161 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1163 """push changes to the specified destination"""
1162 """push changes to the specified destination"""
1164 dest = ui.expandpath(dest)
1163 dest = ui.expandpath(dest)
1165 ui.status('pushing to %s\n' % (dest))
1164 ui.status('pushing to %s\n' % (dest))
1166
1165
1167 if ssh:
1166 if ssh:
1168 ui.setconfig("ui", "ssh", ssh)
1167 ui.setconfig("ui", "ssh", ssh)
1169 if remotecmd:
1168 if remotecmd:
1170 ui.setconfig("ui", "remotecmd", remotecmd)
1169 ui.setconfig("ui", "remotecmd", remotecmd)
1171
1170
1172 other = hg.repository(ui, dest)
1171 other = hg.repository(ui, dest)
1173 r = repo.push(other, force)
1172 r = repo.push(other, force)
1174 return r
1173 return r
1175
1174
1176 def rawcommit(ui, repo, *flist, **rc):
1175 def rawcommit(ui, repo, *flist, **rc):
1177 "raw commit interface"
1176 "raw commit interface"
1178 if rc['text']:
1177 if rc['text']:
1179 ui.warn("Warning: -t and --text is deprecated,"
1178 ui.warn("Warning: -t and --text is deprecated,"
1180 " please use -m or --message instead.\n")
1179 " please use -m or --message instead.\n")
1181 message = rc['message'] or rc['text']
1180 message = rc['message'] or rc['text']
1182 if not message and rc['logfile']:
1181 if not message and rc['logfile']:
1183 try:
1182 try:
1184 message = open(rc['logfile']).read()
1183 message = open(rc['logfile']).read()
1185 except IOError:
1184 except IOError:
1186 pass
1185 pass
1187 if not message and not rc['logfile']:
1186 if not message and not rc['logfile']:
1188 ui.warn("abort: missing commit message\n")
1187 ui.warn("abort: missing commit message\n")
1189 return 1
1188 return 1
1190
1189
1191 files = relpath(repo, list(flist))
1190 files = relpath(repo, list(flist))
1192 if rc['files']:
1191 if rc['files']:
1193 files += open(rc['files']).read().splitlines()
1192 files += open(rc['files']).read().splitlines()
1194
1193
1195 rc['parent'] = map(repo.lookup, rc['parent'])
1194 rc['parent'] = map(repo.lookup, rc['parent'])
1196
1195
1197 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1196 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1198
1197
1199 def recover(ui, repo):
1198 def recover(ui, repo):
1200 """roll back an interrupted transaction"""
1199 """roll back an interrupted transaction"""
1201 repo.recover()
1200 repo.recover()
1202
1201
1203 def remove(ui, repo, file1, *files):
1202 def remove(ui, repo, file1, *files):
1204 """remove the specified files on the next commit"""
1203 """remove the specified files on the next commit"""
1205 repo.remove(relpath(repo, (file1,) + files))
1204 repo.remove(relpath(repo, (file1,) + files))
1206
1205
1207 def revert(ui, repo, *names, **opts):
1206 def revert(ui, repo, *names, **opts):
1208 """revert modified files or dirs back to their unmodified states"""
1207 """revert modified files or dirs back to their unmodified states"""
1209 node = opts['rev'] and repo.lookup(opts['rev']) or \
1208 node = opts['rev'] and repo.lookup(opts['rev']) or \
1210 repo.dirstate.parents()[0]
1209 repo.dirstate.parents()[0]
1211 root = os.path.realpath(repo.root)
1210 root = os.path.realpath(repo.root)
1212
1211
1213 def trimpath(p):
1212 def trimpath(p):
1214 p = os.path.realpath(p)
1213 p = os.path.realpath(p)
1215 if p.startswith(root):
1214 if p.startswith(root):
1216 rest = p[len(root):]
1215 rest = p[len(root):]
1217 if not rest:
1216 if not rest:
1218 return rest
1217 return rest
1219 if p.startswith(os.sep):
1218 if p.startswith(os.sep):
1220 return rest[1:]
1219 return rest[1:]
1221 return p
1220 return p
1222
1221
1223 relnames = map(trimpath, names or [os.getcwd()])
1222 relnames = map(trimpath, names or [os.getcwd()])
1224 chosen = {}
1223 chosen = {}
1225
1224
1226 def choose(name):
1225 def choose(name):
1227 def body(name):
1226 def body(name):
1228 for r in relnames:
1227 for r in relnames:
1229 if not name.startswith(r):
1228 if not name.startswith(r):
1230 continue
1229 continue
1231 rest = name[len(r):]
1230 rest = name[len(r):]
1232 if not rest:
1231 if not rest:
1233 return r, True
1232 return r, True
1234 depth = rest.count(os.sep)
1233 depth = rest.count(os.sep)
1235 if not r:
1234 if not r:
1236 if depth == 0 or not opts['nonrecursive']:
1235 if depth == 0 or not opts['nonrecursive']:
1237 return r, True
1236 return r, True
1238 elif rest[0] == os.sep:
1237 elif rest[0] == os.sep:
1239 if depth == 1 or not opts['nonrecursive']:
1238 if depth == 1 or not opts['nonrecursive']:
1240 return r, True
1239 return r, True
1241 return None, False
1240 return None, False
1242 relname, ret = body(name)
1241 relname, ret = body(name)
1243 if ret:
1242 if ret:
1244 chosen[relname] = 1
1243 chosen[relname] = 1
1245 return ret
1244 return ret
1246
1245
1247 r = repo.update(node, False, True, choose, False)
1246 r = repo.update(node, False, True, choose, False)
1248 for n in relnames:
1247 for n in relnames:
1249 if n not in chosen:
1248 if n not in chosen:
1250 ui.warn('error: no matches for %s\n' % n)
1249 ui.warn('error: no matches for %s\n' % n)
1251 r = 1
1250 r = 1
1252 sys.stdout.flush()
1251 sys.stdout.flush()
1253 return r
1252 return r
1254
1253
1255 def root(ui, repo):
1254 def root(ui, repo):
1256 """print the root (top) of the current working dir"""
1255 """print the root (top) of the current working dir"""
1257 ui.write(repo.root + "\n")
1256 ui.write(repo.root + "\n")
1258
1257
1259 def serve(ui, repo, **opts):
1258 def serve(ui, repo, **opts):
1260 """export the repository via HTTP"""
1259 """export the repository via HTTP"""
1261
1260
1262 if opts["stdio"]:
1261 if opts["stdio"]:
1263 fin, fout = sys.stdin, sys.stdout
1262 fin, fout = sys.stdin, sys.stdout
1264 sys.stdout = sys.stderr
1263 sys.stdout = sys.stderr
1265
1264
1266 def getarg():
1265 def getarg():
1267 argline = fin.readline()[:-1]
1266 argline = fin.readline()[:-1]
1268 arg, l = argline.split()
1267 arg, l = argline.split()
1269 val = fin.read(int(l))
1268 val = fin.read(int(l))
1270 return arg, val
1269 return arg, val
1271 def respond(v):
1270 def respond(v):
1272 fout.write("%d\n" % len(v))
1271 fout.write("%d\n" % len(v))
1273 fout.write(v)
1272 fout.write(v)
1274 fout.flush()
1273 fout.flush()
1275
1274
1276 lock = None
1275 lock = None
1277
1276
1278 while 1:
1277 while 1:
1279 cmd = fin.readline()[:-1]
1278 cmd = fin.readline()[:-1]
1280 if cmd == '':
1279 if cmd == '':
1281 return
1280 return
1282 if cmd == "heads":
1281 if cmd == "heads":
1283 h = repo.heads()
1282 h = repo.heads()
1284 respond(" ".join(map(hex, h)) + "\n")
1283 respond(" ".join(map(hex, h)) + "\n")
1285 if cmd == "lock":
1284 if cmd == "lock":
1286 lock = repo.lock()
1285 lock = repo.lock()
1287 respond("")
1286 respond("")
1288 if cmd == "unlock":
1287 if cmd == "unlock":
1289 if lock:
1288 if lock:
1290 lock.release()
1289 lock.release()
1291 lock = None
1290 lock = None
1292 respond("")
1291 respond("")
1293 elif cmd == "branches":
1292 elif cmd == "branches":
1294 arg, nodes = getarg()
1293 arg, nodes = getarg()
1295 nodes = map(bin, nodes.split(" "))
1294 nodes = map(bin, nodes.split(" "))
1296 r = []
1295 r = []
1297 for b in repo.branches(nodes):
1296 for b in repo.branches(nodes):
1298 r.append(" ".join(map(hex, b)) + "\n")
1297 r.append(" ".join(map(hex, b)) + "\n")
1299 respond("".join(r))
1298 respond("".join(r))
1300 elif cmd == "between":
1299 elif cmd == "between":
1301 arg, pairs = getarg()
1300 arg, pairs = getarg()
1302 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1301 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1303 r = []
1302 r = []
1304 for b in repo.between(pairs):
1303 for b in repo.between(pairs):
1305 r.append(" ".join(map(hex, b)) + "\n")
1304 r.append(" ".join(map(hex, b)) + "\n")
1306 respond("".join(r))
1305 respond("".join(r))
1307 elif cmd == "changegroup":
1306 elif cmd == "changegroup":
1308 nodes = []
1307 nodes = []
1309 arg, roots = getarg()
1308 arg, roots = getarg()
1310 nodes = map(bin, roots.split(" "))
1309 nodes = map(bin, roots.split(" "))
1311
1310
1312 cg = repo.changegroup(nodes)
1311 cg = repo.changegroup(nodes)
1313 while 1:
1312 while 1:
1314 d = cg.read(4096)
1313 d = cg.read(4096)
1315 if not d:
1314 if not d:
1316 break
1315 break
1317 fout.write(d)
1316 fout.write(d)
1318
1317
1319 fout.flush()
1318 fout.flush()
1320
1319
1321 elif cmd == "addchangegroup":
1320 elif cmd == "addchangegroup":
1322 if not lock:
1321 if not lock:
1323 respond("not locked")
1322 respond("not locked")
1324 continue
1323 continue
1325 respond("")
1324 respond("")
1326
1325
1327 r = repo.addchangegroup(fin)
1326 r = repo.addchangegroup(fin)
1328 respond("")
1327 respond("")
1329
1328
1330 optlist = "name templates style address port ipv6 accesslog errorlog"
1329 optlist = "name templates style address port ipv6 accesslog errorlog"
1331 for o in optlist.split():
1330 for o in optlist.split():
1332 if opts[o]:
1331 if opts[o]:
1333 ui.setconfig("web", o, opts[o])
1332 ui.setconfig("web", o, opts[o])
1334
1333
1335 httpd = hgweb.create_server(repo)
1334 httpd = hgweb.create_server(repo)
1336
1335
1337 if ui.verbose:
1336 if ui.verbose:
1338 addr, port = httpd.socket.getsockname()
1337 addr, port = httpd.socket.getsockname()
1339 if addr == '0.0.0.0':
1338 if addr == '0.0.0.0':
1340 addr = socket.gethostname()
1339 addr = socket.gethostname()
1341 else:
1340 else:
1342 try:
1341 try:
1343 addr = socket.gethostbyaddr(addr)[0]
1342 addr = socket.gethostbyaddr(addr)[0]
1344 except socket.error:
1343 except socket.error:
1345 pass
1344 pass
1346 if port != 80:
1345 if port != 80:
1347 ui.status('listening at http://%s:%d/\n' % (addr, port))
1346 ui.status('listening at http://%s:%d/\n' % (addr, port))
1348 else:
1347 else:
1349 ui.status('listening at http://%s/\n' % addr)
1348 ui.status('listening at http://%s/\n' % addr)
1350 httpd.serve_forever()
1349 httpd.serve_forever()
1351
1350
1352 def status(ui, repo, *pats, **opts):
1351 def status(ui, repo, *pats, **opts):
1353 '''show changed files in the working directory
1352 '''show changed files in the working directory
1354
1353
1355 M = modified
1354 M = modified
1356 A = added
1355 A = added
1357 R = removed
1356 R = removed
1358 ? = not tracked
1357 ? = not tracked
1359 '''
1358 '''
1360
1359
1361 cwd = repo.getcwd()
1360 cwd = repo.getcwd()
1362 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1361 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1363 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1362 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1364 for n in repo.changes(files=files, match=matchfn)]
1363 for n in repo.changes(files=files, match=matchfn)]
1365
1364
1366 changetypes = [('modified', 'M', c),
1365 changetypes = [('modified', 'M', c),
1367 ('added', 'A', a),
1366 ('added', 'A', a),
1368 ('removed', 'R', d),
1367 ('removed', 'R', d),
1369 ('unknown', '?', u)]
1368 ('unknown', '?', u)]
1370
1369
1371 end = opts['print0'] and '\0' or '\n'
1370 end = opts['print0'] and '\0' or '\n'
1372
1371
1373 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1372 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1374 or changetypes):
1373 or changetypes):
1375 if opts['no_status']:
1374 if opts['no_status']:
1376 format = "%%s%s" % end
1375 format = "%%s%s" % end
1377 else:
1376 else:
1378 format = "%s %%s%s" % (char, end);
1377 format = "%s %%s%s" % (char, end);
1379
1378
1380 for f in changes:
1379 for f in changes:
1381 ui.write(format % f)
1380 ui.write(format % f)
1382
1381
1383 def tag(ui, repo, name, rev=None, **opts):
1382 def tag(ui, repo, name, rev=None, **opts):
1384 """add a tag for the current tip or a given revision"""
1383 """add a tag for the current tip or a given revision"""
1385 if opts['text']:
1384 if opts['text']:
1386 ui.warn("Warning: -t and --text is deprecated,"
1385 ui.warn("Warning: -t and --text is deprecated,"
1387 " please use -m or --message instead.\n")
1386 " please use -m or --message instead.\n")
1388 if name == "tip":
1387 if name == "tip":
1389 ui.warn("abort: 'tip' is a reserved name!\n")
1388 ui.warn("abort: 'tip' is a reserved name!\n")
1390 return -1
1389 return -1
1391 if rev:
1390 if rev:
1392 r = hex(repo.lookup(rev))
1391 r = hex(repo.lookup(rev))
1393 else:
1392 else:
1394 r = hex(repo.changelog.tip())
1393 r = hex(repo.changelog.tip())
1395
1394
1396 if name.find(revrangesep) >= 0:
1395 if name.find(revrangesep) >= 0:
1397 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1396 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
1398 return -1
1397 return -1
1399
1398
1400 if opts['local']:
1399 if opts['local']:
1401 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1400 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1402 return
1401 return
1403
1402
1404 (c, a, d, u) = repo.changes()
1403 (c, a, d, u) = repo.changes()
1405 for x in (c, a, d, u):
1404 for x in (c, a, d, u):
1406 if ".hgtags" in x:
1405 if ".hgtags" in x:
1407 ui.warn("abort: working copy of .hgtags is changed!\n")
1406 ui.warn("abort: working copy of .hgtags is changed!\n")
1408 ui.status("(please commit .hgtags manually)\n")
1407 ui.status("(please commit .hgtags manually)\n")
1409 return -1
1408 return -1
1410
1409
1411 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1410 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1412 if repo.dirstate.state(".hgtags") == '?':
1411 if repo.dirstate.state(".hgtags") == '?':
1413 repo.add([".hgtags"])
1412 repo.add([".hgtags"])
1414
1413
1415 message = (opts['message'] or opts['text'] or
1414 message = (opts['message'] or opts['text'] or
1416 "Added tag %s for changeset %s" % (name, r))
1415 "Added tag %s for changeset %s" % (name, r))
1417 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1416 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1418
1417
1419 def tags(ui, repo):
1418 def tags(ui, repo):
1420 """list repository tags"""
1419 """list repository tags"""
1421
1420
1422 l = repo.tagslist()
1421 l = repo.tagslist()
1423 l.reverse()
1422 l.reverse()
1424 for t, n in l:
1423 for t, n in l:
1425 try:
1424 try:
1426 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1425 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1427 except KeyError:
1426 except KeyError:
1428 r = " ?:?"
1427 r = " ?:?"
1429 ui.write("%-30s %s\n" % (t, r))
1428 ui.write("%-30s %s\n" % (t, r))
1430
1429
1431 def tip(ui, repo):
1430 def tip(ui, repo):
1432 """show the tip revision"""
1431 """show the tip revision"""
1433 n = repo.changelog.tip()
1432 n = repo.changelog.tip()
1434 show_changeset(ui, repo, changenode=n)
1433 show_changeset(ui, repo, changenode=n)
1435
1434
1436 def undo(ui, repo):
1435 def undo(ui, repo):
1437 """undo the last commit or pull
1436 """undo the last commit or pull
1438
1437
1439 Roll back the last pull or commit transaction on the
1438 Roll back the last pull or commit transaction on the
1440 repository, restoring the project to its earlier state.
1439 repository, restoring the project to its earlier state.
1441
1440
1442 This command should be used with care. There is only one level of
1441 This command should be used with care. There is only one level of
1443 undo and there is no redo.
1442 undo and there is no redo.
1444
1443
1445 This command is not intended for use on public repositories. Once
1444 This command is not intended for use on public repositories. Once
1446 a change is visible for pull by other users, undoing it locally is
1445 a change is visible for pull by other users, undoing it locally is
1447 ineffective.
1446 ineffective.
1448 """
1447 """
1449 repo.undo()
1448 repo.undo()
1450
1449
1451 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1450 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1452 '''update or merge working directory
1451 '''update or merge working directory
1453
1452
1454 If there are no outstanding changes in the working directory and
1453 If there are no outstanding changes in the working directory and
1455 there is a linear relationship between the current version and the
1454 there is a linear relationship between the current version and the
1456 requested version, the result is the requested version.
1455 requested version, the result is the requested version.
1457
1456
1458 Otherwise the result is a merge between the contents of the
1457 Otherwise the result is a merge between the contents of the
1459 current working directory and the requested version. Files that
1458 current working directory and the requested version. Files that
1460 changed between either parent are marked as changed for the next
1459 changed between either parent are marked as changed for the next
1461 commit and a commit must be performed before any further updates
1460 commit and a commit must be performed before any further updates
1462 are allowed.
1461 are allowed.
1463 '''
1462 '''
1464 if branch:
1463 if branch:
1465 br = repo.branchlookup(branch=branch)
1464 br = repo.branchlookup(branch=branch)
1466 found = []
1465 found = []
1467 for x in br:
1466 for x in br:
1468 if branch in br[x]:
1467 if branch in br[x]:
1469 found.append(x)
1468 found.append(x)
1470 if len(found) > 1:
1469 if len(found) > 1:
1471 ui.warn("Found multiple heads for %s\n" % branch)
1470 ui.warn("Found multiple heads for %s\n" % branch)
1472 for x in found:
1471 for x in found:
1473 show_changeset(ui, repo, changenode=x, brinfo=br)
1472 show_changeset(ui, repo, changenode=x, brinfo=br)
1474 return 1
1473 return 1
1475 if len(found) == 1:
1474 if len(found) == 1:
1476 node = found[0]
1475 node = found[0]
1477 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1476 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1478 else:
1477 else:
1479 ui.warn("branch %s not found\n" % (branch))
1478 ui.warn("branch %s not found\n" % (branch))
1480 return 1
1479 return 1
1481 else:
1480 else:
1482 node = node and repo.lookup(node) or repo.changelog.tip()
1481 node = node and repo.lookup(node) or repo.changelog.tip()
1483 return repo.update(node, allow=merge, force=clean)
1482 return repo.update(node, allow=merge, force=clean)
1484
1483
1485 def verify(ui, repo):
1484 def verify(ui, repo):
1486 """verify the integrity of the repository"""
1485 """verify the integrity of the repository"""
1487 return repo.verify()
1486 return repo.verify()
1488
1487
1489 # Command options and aliases are listed here, alphabetically
1488 # Command options and aliases are listed here, alphabetically
1490
1489
1491 table = {
1490 table = {
1492 "^add":
1491 "^add":
1493 (add,
1492 (add,
1494 [('I', 'include', [], 'include path in search'),
1493 [('I', 'include', [], 'include path in search'),
1495 ('X', 'exclude', [], 'exclude path from search')],
1494 ('X', 'exclude', [], 'exclude path from search')],
1496 "hg add [OPTION]... [FILE]..."),
1495 "hg add [OPTION]... [FILE]..."),
1497 "addremove":
1496 "addremove":
1498 (addremove,
1497 (addremove,
1499 [('I', 'include', [], 'include path in search'),
1498 [('I', 'include', [], 'include path in search'),
1500 ('X', 'exclude', [], 'exclude path from search')],
1499 ('X', 'exclude', [], 'exclude path from search')],
1501 "hg addremove [OPTION]... [FILE]..."),
1500 "hg addremove [OPTION]... [FILE]..."),
1502 "^annotate":
1501 "^annotate":
1503 (annotate,
1502 (annotate,
1504 [('r', 'rev', '', 'revision'),
1503 [('r', 'rev', '', 'revision'),
1505 ('a', 'text', None, 'treat all files as text'),
1504 ('a', 'text', None, 'treat all files as text'),
1506 ('u', 'user', None, 'show user'),
1505 ('u', 'user', None, 'show user'),
1507 ('n', 'number', None, 'show revision number'),
1506 ('n', 'number', None, 'show revision number'),
1508 ('c', 'changeset', None, 'show changeset'),
1507 ('c', 'changeset', None, 'show changeset'),
1509 ('I', 'include', [], 'include path in search'),
1508 ('I', 'include', [], 'include path in search'),
1510 ('X', 'exclude', [], 'exclude path from search')],
1509 ('X', 'exclude', [], 'exclude path from search')],
1511 'hg annotate [OPTION]... FILE...'),
1510 'hg annotate [OPTION]... FILE...'),
1512 "cat":
1511 "cat":
1513 (cat,
1512 (cat,
1514 [('o', 'output', "", 'output to file')],
1513 [('o', 'output', "", 'output to file')],
1515 'hg cat [-o OUTFILE] FILE [REV]'),
1514 'hg cat [-o OUTFILE] FILE [REV]'),
1516 "^clone":
1515 "^clone":
1517 (clone,
1516 (clone,
1518 [('U', 'noupdate', None, 'skip update after cloning'),
1517 [('U', 'noupdate', None, 'skip update after cloning'),
1519 ('e', 'ssh', "", 'ssh command'),
1518 ('e', 'ssh', "", 'ssh command'),
1520 ('', 'remotecmd', "", 'remote hg command')],
1519 ('', 'remotecmd', "", 'remote hg command')],
1521 'hg clone [OPTION]... SOURCE [DEST]'),
1520 'hg clone [OPTION]... SOURCE [DEST]'),
1522 "^commit|ci":
1521 "^commit|ci":
1523 (commit,
1522 (commit,
1524 [('A', 'addremove', None, 'run add/remove during commit'),
1523 [('A', 'addremove', None, 'run add/remove during commit'),
1525 ('I', 'include', [], 'include path in search'),
1524 ('I', 'include', [], 'include path in search'),
1526 ('X', 'exclude', [], 'exclude path from search'),
1525 ('X', 'exclude', [], 'exclude path from search'),
1527 ('m', 'message', "", 'commit message'),
1526 ('m', 'message', "", 'commit message'),
1528 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1527 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1529 ('l', 'logfile', "", 'commit message file'),
1528 ('l', 'logfile', "", 'commit message file'),
1530 ('d', 'date', "", 'date code'),
1529 ('d', 'date', "", 'date code'),
1531 ('u', 'user', "", 'user')],
1530 ('u', 'user', "", 'user')],
1532 'hg commit [OPTION]... [FILE]...'),
1531 'hg commit [OPTION]... [FILE]...'),
1533 "copy": (copy, [], 'hg copy SOURCE DEST'),
1532 "copy": (copy, [], 'hg copy SOURCE DEST'),
1534 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1533 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1535 "debugconfig": (debugconfig, [], 'debugconfig'),
1534 "debugconfig": (debugconfig, [], 'debugconfig'),
1536 "debugstate": (debugstate, [], 'debugstate'),
1535 "debugstate": (debugstate, [], 'debugstate'),
1537 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1536 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1538 "debugindex": (debugindex, [], 'debugindex FILE'),
1537 "debugindex": (debugindex, [], 'debugindex FILE'),
1539 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1538 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1540 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1539 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1541 "debugwalk":
1540 "debugwalk":
1542 (debugwalk,
1541 (debugwalk,
1543 [('I', 'include', [], 'include path in search'),
1542 [('I', 'include', [], 'include path in search'),
1544 ('X', 'exclude', [], 'exclude path from search')],
1543 ('X', 'exclude', [], 'exclude path from search')],
1545 'debugwalk [OPTION]... [FILE]...'),
1544 'debugwalk [OPTION]... [FILE]...'),
1546 "^diff":
1545 "^diff":
1547 (diff,
1546 (diff,
1548 [('r', 'rev', [], 'revision'),
1547 [('r', 'rev', [], 'revision'),
1549 ('a', 'text', None, 'treat all files as text'),
1548 ('a', 'text', None, 'treat all files as text'),
1550 ('I', 'include', [], 'include path in search'),
1549 ('I', 'include', [], 'include path in search'),
1551 ('X', 'exclude', [], 'exclude path from search')],
1550 ('X', 'exclude', [], 'exclude path from search')],
1552 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1551 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1553 "^export":
1552 "^export":
1554 (export,
1553 (export,
1555 [('o', 'output', "", 'output to file'),
1554 [('o', 'output', "", 'output to file'),
1556 ('a', 'text', None, 'treat all files as text')],
1555 ('a', 'text', None, 'treat all files as text')],
1557 "hg export [-a] [-o OUTFILE] REV..."),
1556 "hg export [-a] [-o OUTFILE] REV..."),
1558 "forget":
1557 "forget":
1559 (forget,
1558 (forget,
1560 [('I', 'include', [], 'include path in search'),
1559 [('I', 'include', [], 'include path in search'),
1561 ('X', 'exclude', [], 'exclude path from search')],
1560 ('X', 'exclude', [], 'exclude path from search')],
1562 "hg forget [OPTION]... FILE..."),
1561 "hg forget [OPTION]... FILE..."),
1563 "grep":
1562 "grep":
1564 (grep,
1563 (grep,
1565 [('0', 'print0', None, 'end filenames with NUL'),
1564 [('0', 'print0', None, 'end filenames with NUL'),
1566 ('I', 'include', [], 'include path in search'),
1565 ('I', 'include', [], 'include path in search'),
1567 ('X', 'exclude', [], 'include path in search'),
1566 ('X', 'exclude', [], 'include path in search'),
1568 ('i', 'ignore-case', None, 'ignore case when matching'),
1567 ('i', 'ignore-case', None, 'ignore case when matching'),
1569 ('l', 'files-with-matches', None, 'print names of files with matches'),
1568 ('l', 'files-with-matches', None, 'print names of files with matches'),
1570 ('n', 'line-number', '', 'print line numbers'),
1569 ('n', 'line-number', '', 'print line numbers'),
1571 ('r', 'rev', [], 'search in revision rev')],
1570 ('r', 'rev', [], 'search in revision rev')],
1572 "hg grep [OPTION]... PATTERN [FILE]..."),
1571 "hg grep [OPTION]... PATTERN [FILE]..."),
1573 "heads":
1572 "heads":
1574 (heads,
1573 (heads,
1575 [('b', 'branches', None, 'find branch info')],
1574 [('b', 'branches', None, 'find branch info')],
1576 'hg heads [-b]'),
1575 'hg heads [-b]'),
1577 "help": (help_, [], 'hg help [COMMAND]'),
1576 "help": (help_, [], 'hg help [COMMAND]'),
1578 "identify|id": (identify, [], 'hg identify'),
1577 "identify|id": (identify, [], 'hg identify'),
1579 "import|patch":
1578 "import|patch":
1580 (import_,
1579 (import_,
1581 [('p', 'strip', 1, 'path strip'),
1580 [('p', 'strip', 1, 'path strip'),
1582 ('f', 'force', None, 'skip check for outstanding changes'),
1581 ('f', 'force', None, 'skip check for outstanding changes'),
1583 ('b', 'base', "", 'base path')],
1582 ('b', 'base', "", 'base path')],
1584 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1583 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1585 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1584 "incoming|in": (incoming, [], 'hg incoming [SOURCE]'),
1586 "^init": (init, [], 'hg init [DEST]'),
1585 "^init": (init, [], 'hg init [DEST]'),
1587 "locate":
1586 "locate":
1588 (locate,
1587 (locate,
1589 [('r', 'rev', '', 'revision'),
1588 [('r', 'rev', '', 'revision'),
1590 ('0', 'print0', None, 'end filenames with NUL'),
1589 ('0', 'print0', None, 'end filenames with NUL'),
1591 ('f', 'fullpath', None, 'print complete paths'),
1590 ('f', 'fullpath', None, 'print complete paths'),
1592 ('I', 'include', [], 'include path in search'),
1591 ('I', 'include', [], 'include path in search'),
1593 ('X', 'exclude', [], 'exclude path from search')],
1592 ('X', 'exclude', [], 'exclude path from search')],
1594 'hg locate [OPTION]... [PATTERN]...'),
1593 'hg locate [OPTION]... [PATTERN]...'),
1595 "^log|history":
1594 "^log|history":
1596 (log,
1595 (log,
1597 [('I', 'include', [], 'include path in search'),
1596 [('I', 'include', [], 'include path in search'),
1598 ('X', 'exclude', [], 'exclude path from search'),
1597 ('X', 'exclude', [], 'exclude path from search'),
1599 ('r', 'rev', [], 'revision'),
1598 ('r', 'rev', [], 'revision'),
1600 ('p', 'patch', None, 'show patch')],
1599 ('p', 'patch', None, 'show patch')],
1601 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1600 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1602 "manifest": (manifest, [], 'hg manifest [REV]'),
1601 "manifest": (manifest, [], 'hg manifest [REV]'),
1603 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1602 "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
1604 "parents": (parents, [], 'hg parents [REV]'),
1603 "parents": (parents, [], 'hg parents [REV]'),
1605 "paths": (paths, [], 'hg paths [NAME]'),
1604 "paths": (paths, [], 'hg paths [NAME]'),
1606 "^pull":
1605 "^pull":
1607 (pull,
1606 (pull,
1608 [('u', 'update', None, 'update working directory'),
1607 [('u', 'update', None, 'update working directory'),
1609 ('e', 'ssh', "", 'ssh command'),
1608 ('e', 'ssh', "", 'ssh command'),
1610 ('', 'remotecmd', "", 'remote hg command')],
1609 ('', 'remotecmd', "", 'remote hg command')],
1611 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1610 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1612 "^push":
1611 "^push":
1613 (push,
1612 (push,
1614 [('f', 'force', None, 'force push'),
1613 [('f', 'force', None, 'force push'),
1615 ('e', 'ssh', "", 'ssh command'),
1614 ('e', 'ssh', "", 'ssh command'),
1616 ('', 'remotecmd', "", 'remote hg command')],
1615 ('', 'remotecmd', "", 'remote hg command')],
1617 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1616 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1618 "rawcommit":
1617 "rawcommit":
1619 (rawcommit,
1618 (rawcommit,
1620 [('p', 'parent', [], 'parent'),
1619 [('p', 'parent', [], 'parent'),
1621 ('d', 'date', "", 'date code'),
1620 ('d', 'date', "", 'date code'),
1622 ('u', 'user', "", 'user'),
1621 ('u', 'user', "", 'user'),
1623 ('F', 'files', "", 'file list'),
1622 ('F', 'files', "", 'file list'),
1624 ('m', 'message', "", 'commit message'),
1623 ('m', 'message', "", 'commit message'),
1625 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1624 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1626 ('l', 'logfile', "", 'commit message file')],
1625 ('l', 'logfile', "", 'commit message file')],
1627 'hg rawcommit [OPTION]... [FILE]...'),
1626 'hg rawcommit [OPTION]... [FILE]...'),
1628 "recover": (recover, [], "hg recover"),
1627 "recover": (recover, [], "hg recover"),
1629 "^remove|rm": (remove, [], "hg remove FILE..."),
1628 "^remove|rm": (remove, [], "hg remove FILE..."),
1630 "^revert":
1629 "^revert":
1631 (revert,
1630 (revert,
1632 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1631 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1633 ("r", "rev", "", "revision")],
1632 ("r", "rev", "", "revision")],
1634 "hg revert [-n] [-r REV] [NAME]..."),
1633 "hg revert [-n] [-r REV] [NAME]..."),
1635 "root": (root, [], "hg root"),
1634 "root": (root, [], "hg root"),
1636 "^serve":
1635 "^serve":
1637 (serve,
1636 (serve,
1638 [('A', 'accesslog', '', 'access log file'),
1637 [('A', 'accesslog', '', 'access log file'),
1639 ('E', 'errorlog', '', 'error log file'),
1638 ('E', 'errorlog', '', 'error log file'),
1640 ('p', 'port', 0, 'listen port'),
1639 ('p', 'port', 0, 'listen port'),
1641 ('a', 'address', '', 'interface address'),
1640 ('a', 'address', '', 'interface address'),
1642 ('n', 'name', "", 'repository name'),
1641 ('n', 'name', "", 'repository name'),
1643 ('', 'stdio', None, 'for remote clients'),
1642 ('', 'stdio', None, 'for remote clients'),
1644 ('t', 'templates', "", 'template directory'),
1643 ('t', 'templates', "", 'template directory'),
1645 ('', 'style', "", 'template style'),
1644 ('', 'style', "", 'template style'),
1646 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1645 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1647 "hg serve [OPTION]..."),
1646 "hg serve [OPTION]..."),
1648 "^status":
1647 "^status":
1649 (status,
1648 (status,
1650 [('m', 'modified', None, 'show only modified files'),
1649 [('m', 'modified', None, 'show only modified files'),
1651 ('a', 'added', None, 'show only added files'),
1650 ('a', 'added', None, 'show only added files'),
1652 ('r', 'removed', None, 'show only removed files'),
1651 ('r', 'removed', None, 'show only removed files'),
1653 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1652 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1654 ('n', 'no-status', None, 'hide status prefix'),
1653 ('n', 'no-status', None, 'hide status prefix'),
1655 ('0', 'print0', None, 'end filenames with NUL'),
1654 ('0', 'print0', None, 'end filenames with NUL'),
1656 ('I', 'include', [], 'include path in search'),
1655 ('I', 'include', [], 'include path in search'),
1657 ('X', 'exclude', [], 'exclude path from search')],
1656 ('X', 'exclude', [], 'exclude path from search')],
1658 "hg status [OPTION]... [FILE]..."),
1657 "hg status [OPTION]... [FILE]..."),
1659 "tag":
1658 "tag":
1660 (tag,
1659 (tag,
1661 [('l', 'local', None, 'make the tag local'),
1660 [('l', 'local', None, 'make the tag local'),
1662 ('m', 'message', "", 'commit message'),
1661 ('m', 'message', "", 'commit message'),
1663 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1662 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1664 ('d', 'date', "", 'date code'),
1663 ('d', 'date', "", 'date code'),
1665 ('u', 'user', "", 'user')],
1664 ('u', 'user', "", 'user')],
1666 'hg tag [OPTION]... NAME [REV]'),
1665 'hg tag [OPTION]... NAME [REV]'),
1667 "tags": (tags, [], 'hg tags'),
1666 "tags": (tags, [], 'hg tags'),
1668 "tip": (tip, [], 'hg tip'),
1667 "tip": (tip, [], 'hg tip'),
1669 "undo": (undo, [], 'hg undo'),
1668 "undo": (undo, [], 'hg undo'),
1670 "^update|up|checkout|co":
1669 "^update|up|checkout|co":
1671 (update,
1670 (update,
1672 [('b', 'branch', "", 'checkout the head of a specific branch'),
1671 [('b', 'branch', "", 'checkout the head of a specific branch'),
1673 ('m', 'merge', None, 'allow merging of conflicts'),
1672 ('m', 'merge', None, 'allow merging of conflicts'),
1674 ('C', 'clean', None, 'overwrite locally modified files')],
1673 ('C', 'clean', None, 'overwrite locally modified files')],
1675 'hg update [-b TAG] [-m] [-C] [REV]'),
1674 'hg update [-b TAG] [-m] [-C] [REV]'),
1676 "verify": (verify, [], 'hg verify'),
1675 "verify": (verify, [], 'hg verify'),
1677 "version": (show_version, [], 'hg version'),
1676 "version": (show_version, [], 'hg version'),
1678 }
1677 }
1679
1678
1680 globalopts = [
1679 globalopts = [
1681 ('R', 'repository', "", 'repository root directory'),
1680 ('R', 'repository', "", 'repository root directory'),
1682 ('', 'cwd', '', 'change working directory'),
1681 ('', 'cwd', '', 'change working directory'),
1683 ('y', 'noninteractive', None, 'run non-interactively'),
1682 ('y', 'noninteractive', None, 'run non-interactively'),
1684 ('q', 'quiet', None, 'quiet mode'),
1683 ('q', 'quiet', None, 'quiet mode'),
1685 ('v', 'verbose', None, 'verbose mode'),
1684 ('v', 'verbose', None, 'verbose mode'),
1686 ('', 'debug', None, 'debug mode'),
1685 ('', 'debug', None, 'debug mode'),
1687 ('', 'traceback', None, 'print traceback on exception'),
1686 ('', 'traceback', None, 'print traceback on exception'),
1688 ('', 'time', None, 'time how long the command takes'),
1687 ('', 'time', None, 'time how long the command takes'),
1689 ('', 'profile', None, 'profile'),
1688 ('', 'profile', None, 'profile'),
1690 ('', 'version', None, 'output version information and exit'),
1689 ('', 'version', None, 'output version information and exit'),
1691 ('h', 'help', None, 'display help and exit'),
1690 ('h', 'help', None, 'display help and exit'),
1692 ]
1691 ]
1693
1692
1694 norepo = ("clone init version help debugconfig debugdata"
1693 norepo = ("clone init version help debugconfig debugdata"
1695 " debugindex debugindexdot paths")
1694 " debugindex debugindexdot paths")
1696
1695
1697 def find(cmd):
1696 def find(cmd):
1698 for e in table.keys():
1697 for e in table.keys():
1699 if re.match("(%s)$" % e, cmd):
1698 if re.match("(%s)$" % e, cmd):
1700 return e, table[e]
1699 return e, table[e]
1701
1700
1702 raise UnknownCommand(cmd)
1701 raise UnknownCommand(cmd)
1703
1702
1704 class SignalInterrupt(Exception):
1703 class SignalInterrupt(Exception):
1705 """Exception raised on SIGTERM and SIGHUP."""
1704 """Exception raised on SIGTERM and SIGHUP."""
1706
1705
1707 def catchterm(*args):
1706 def catchterm(*args):
1708 raise SignalInterrupt
1707 raise SignalInterrupt
1709
1708
1710 def run():
1709 def run():
1711 sys.exit(dispatch(sys.argv[1:]))
1710 sys.exit(dispatch(sys.argv[1:]))
1712
1711
1713 class ParseError(Exception):
1712 class ParseError(Exception):
1714 """Exception raised on errors in parsing the command line."""
1713 """Exception raised on errors in parsing the command line."""
1715
1714
1716 def parse(args):
1715 def parse(args):
1717 options = {}
1716 options = {}
1718 cmdoptions = {}
1717 cmdoptions = {}
1719
1718
1720 try:
1719 try:
1721 args = fancyopts.fancyopts(args, globalopts, options)
1720 args = fancyopts.fancyopts(args, globalopts, options)
1722 except fancyopts.getopt.GetoptError, inst:
1721 except fancyopts.getopt.GetoptError, inst:
1723 raise ParseError(None, inst)
1722 raise ParseError(None, inst)
1724
1723
1725 if args:
1724 if args:
1726 cmd, args = args[0], args[1:]
1725 cmd, args = args[0], args[1:]
1727 i = find(cmd)[1]
1726 i = find(cmd)[1]
1728 c = list(i[1])
1727 c = list(i[1])
1729 else:
1728 else:
1730 cmd = None
1729 cmd = None
1731 c = []
1730 c = []
1732
1731
1733 # combine global options into local
1732 # combine global options into local
1734 for o in globalopts:
1733 for o in globalopts:
1735 c.append((o[0], o[1], options[o[1]], o[3]))
1734 c.append((o[0], o[1], options[o[1]], o[3]))
1736
1735
1737 try:
1736 try:
1738 args = fancyopts.fancyopts(args, c, cmdoptions)
1737 args = fancyopts.fancyopts(args, c, cmdoptions)
1739 except fancyopts.getopt.GetoptError, inst:
1738 except fancyopts.getopt.GetoptError, inst:
1740 raise ParseError(cmd, inst)
1739 raise ParseError(cmd, inst)
1741
1740
1742 # separate global options back out
1741 # separate global options back out
1743 for o in globalopts:
1742 for o in globalopts:
1744 n = o[1]
1743 n = o[1]
1745 options[n] = cmdoptions[n]
1744 options[n] = cmdoptions[n]
1746 del cmdoptions[n]
1745 del cmdoptions[n]
1747
1746
1748 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1747 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
1749
1748
1750 def dispatch(args):
1749 def dispatch(args):
1751 signal.signal(signal.SIGTERM, catchterm)
1750 signal.signal(signal.SIGTERM, catchterm)
1752 try:
1751 try:
1753 signal.signal(signal.SIGHUP, catchterm)
1752 signal.signal(signal.SIGHUP, catchterm)
1754 except AttributeError:
1753 except AttributeError:
1755 pass
1754 pass
1756
1755
1757 u = ui.ui()
1756 u = ui.ui()
1758 external = []
1757 external = []
1759 for x in u.extensions():
1758 for x in u.extensions():
1760 if x[1]:
1759 if x[1]:
1761 mod = imp.load_source(x[0], x[1])
1760 mod = imp.load_source(x[0], x[1])
1762 else:
1761 else:
1763 def importh(name):
1762 def importh(name):
1764 mod = __import__(name)
1763 mod = __import__(name)
1765 components = name.split('.')
1764 components = name.split('.')
1766 for comp in components[1:]:
1765 for comp in components[1:]:
1767 mod = getattr(mod, comp)
1766 mod = getattr(mod, comp)
1768 return mod
1767 return mod
1769 mod = importh(x[0])
1768 mod = importh(x[0])
1770 external.append(mod)
1769 external.append(mod)
1771 for x in external:
1770 for x in external:
1772 for t in x.cmdtable:
1771 for t in x.cmdtable:
1773 if t in table:
1772 if t in table:
1774 u.warn("module %s override %s\n" % (x.__name__, t))
1773 u.warn("module %s override %s\n" % (x.__name__, t))
1775 table.update(x.cmdtable)
1774 table.update(x.cmdtable)
1776
1775
1777 try:
1776 try:
1778 cmd, func, args, options, cmdoptions = parse(args)
1777 cmd, func, args, options, cmdoptions = parse(args)
1779 except ParseError, inst:
1778 except ParseError, inst:
1780 if inst.args[0]:
1779 if inst.args[0]:
1781 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1780 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
1782 help_(u, inst.args[0])
1781 help_(u, inst.args[0])
1783 else:
1782 else:
1784 u.warn("hg: %s\n" % inst.args[1])
1783 u.warn("hg: %s\n" % inst.args[1])
1785 help_(u, 'shortlist')
1784 help_(u, 'shortlist')
1786 sys.exit(-1)
1785 sys.exit(-1)
1787 except UnknownCommand, inst:
1786 except UnknownCommand, inst:
1788 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1787 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1789 help_(u, 'shortlist')
1788 help_(u, 'shortlist')
1790 sys.exit(1)
1789 sys.exit(1)
1791
1790
1792 if options["time"]:
1791 if options["time"]:
1793 def get_times():
1792 def get_times():
1794 t = os.times()
1793 t = os.times()
1795 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1794 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
1796 t = (t[0], t[1], t[2], t[3], time.clock())
1795 t = (t[0], t[1], t[2], t[3], time.clock())
1797 return t
1796 return t
1798 s = get_times()
1797 s = get_times()
1799 def print_time():
1798 def print_time():
1800 t = get_times()
1799 t = get_times()
1801 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1800 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
1802 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1801 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
1803 atexit.register(print_time)
1802 atexit.register(print_time)
1804
1803
1805 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1804 u.updateopts(options["verbose"], options["debug"], options["quiet"],
1806 not options["noninteractive"])
1805 not options["noninteractive"])
1807
1806
1808 try:
1807 try:
1809 try:
1808 try:
1810 if options['help']:
1809 if options['help']:
1811 help_(u, cmd, options['version'])
1810 help_(u, cmd, options['version'])
1812 sys.exit(0)
1811 sys.exit(0)
1813 elif options['version']:
1812 elif options['version']:
1814 show_version(u)
1813 show_version(u)
1815 sys.exit(0)
1814 sys.exit(0)
1816 elif not cmd:
1815 elif not cmd:
1817 help_(u, 'shortlist')
1816 help_(u, 'shortlist')
1818 sys.exit(0)
1817 sys.exit(0)
1819
1818
1820 if options['cwd']:
1819 if options['cwd']:
1821 try:
1820 try:
1822 os.chdir(options['cwd'])
1821 os.chdir(options['cwd'])
1823 except OSError, inst:
1822 except OSError, inst:
1824 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1823 u.warn('abort: %s: %s\n' % (options['cwd'], inst.strerror))
1825 sys.exit(1)
1824 sys.exit(1)
1826
1825
1827 if cmd not in norepo.split():
1826 if cmd not in norepo.split():
1828 path = options["repository"] or ""
1827 path = options["repository"] or ""
1829 repo = hg.repository(ui=u, path=path)
1828 repo = hg.repository(ui=u, path=path)
1830 for x in external:
1829 for x in external:
1831 x.reposetup(u, repo)
1830 x.reposetup(u, repo)
1832 d = lambda: func(u, repo, *args, **cmdoptions)
1831 d = lambda: func(u, repo, *args, **cmdoptions)
1833 else:
1832 else:
1834 d = lambda: func(u, *args, **cmdoptions)
1833 d = lambda: func(u, *args, **cmdoptions)
1835
1834
1836 if options['profile']:
1835 if options['profile']:
1837 import hotshot, hotshot.stats
1836 import hotshot, hotshot.stats
1838 prof = hotshot.Profile("hg.prof")
1837 prof = hotshot.Profile("hg.prof")
1839 r = prof.runcall(d)
1838 r = prof.runcall(d)
1840 prof.close()
1839 prof.close()
1841 stats = hotshot.stats.load("hg.prof")
1840 stats = hotshot.stats.load("hg.prof")
1842 stats.strip_dirs()
1841 stats.strip_dirs()
1843 stats.sort_stats('time', 'calls')
1842 stats.sort_stats('time', 'calls')
1844 stats.print_stats(40)
1843 stats.print_stats(40)
1845 return r
1844 return r
1846 else:
1845 else:
1847 return d()
1846 return d()
1848 except:
1847 except:
1849 if options['traceback']:
1848 if options['traceback']:
1850 traceback.print_exc()
1849 traceback.print_exc()
1851 raise
1850 raise
1852 except hg.RepoError, inst:
1851 except hg.RepoError, inst:
1853 u.warn("abort: ", inst, "!\n")
1852 u.warn("abort: ", inst, "!\n")
1854 except SignalInterrupt:
1853 except SignalInterrupt:
1855 u.warn("killed!\n")
1854 u.warn("killed!\n")
1856 except KeyboardInterrupt:
1855 except KeyboardInterrupt:
1857 try:
1856 try:
1858 u.warn("interrupted!\n")
1857 u.warn("interrupted!\n")
1859 except IOError, inst:
1858 except IOError, inst:
1860 if inst.errno == errno.EPIPE:
1859 if inst.errno == errno.EPIPE:
1861 if u.debugflag:
1860 if u.debugflag:
1862 u.warn("\nbroken pipe\n")
1861 u.warn("\nbroken pipe\n")
1863 else:
1862 else:
1864 raise
1863 raise
1865 except IOError, inst:
1864 except IOError, inst:
1866 if hasattr(inst, "code"):
1865 if hasattr(inst, "code"):
1867 u.warn("abort: %s\n" % inst)
1866 u.warn("abort: %s\n" % inst)
1868 elif hasattr(inst, "reason"):
1867 elif hasattr(inst, "reason"):
1869 u.warn("abort: error: %s\n" % inst.reason[1])
1868 u.warn("abort: error: %s\n" % inst.reason[1])
1870 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1869 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
1871 if u.debugflag:
1870 if u.debugflag:
1872 u.warn("broken pipe\n")
1871 u.warn("broken pipe\n")
1873 else:
1872 else:
1874 raise
1873 raise
1875 except OSError, inst:
1874 except OSError, inst:
1876 if hasattr(inst, "filename"):
1875 if hasattr(inst, "filename"):
1877 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1876 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
1878 else:
1877 else:
1879 u.warn("abort: %s\n" % inst.strerror)
1878 u.warn("abort: %s\n" % inst.strerror)
1880 except util.Abort, inst:
1879 except util.Abort, inst:
1881 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1880 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
1882 sys.exit(1)
1881 sys.exit(1)
1883 except TypeError, inst:
1882 except TypeError, inst:
1884 # was this an argument error?
1883 # was this an argument error?
1885 tb = traceback.extract_tb(sys.exc_info()[2])
1884 tb = traceback.extract_tb(sys.exc_info()[2])
1886 if len(tb) > 2: # no
1885 if len(tb) > 2: # no
1887 raise
1886 raise
1888 u.debug(inst, "\n")
1887 u.debug(inst, "\n")
1889 u.warn("%s: invalid arguments\n" % cmd)
1888 u.warn("%s: invalid arguments\n" % cmd)
1890 help_(u, cmd)
1889 help_(u, cmd)
1891 except UnknownCommand, inst:
1890 except UnknownCommand, inst:
1892 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1891 u.warn("hg: unknown command '%s'\n" % inst.args[0])
1893 help_(u, 'shortlist')
1892 help_(u, 'shortlist')
1894
1893
1895 sys.exit(-1)
1894 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now