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