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