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