##// END OF EJS Templates
Fix default clone destination...
mpm@selenic.com -
r1314:d37a4685 default
parent child Browse files
Show More
@@ -1,2198 +1,2199 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: num += revcount
166 if num < 0: num += revcount
167 if num < 0: num = 0
167 if num < 0: num = 0
168 elif num >= revcount:
168 elif 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 if ui.verbose: ui.status('adding %s\n' % rel)
489 names.append(abs)
489 names.append(abs)
490 elif repo.dirstate.state(abs) == '?':
490 elif repo.dirstate.state(abs) == '?':
491 ui.status('adding %s\n' % rel)
491 ui.status('adding %s\n' % rel)
492 names.append(abs)
492 names.append(abs)
493 repo.add(names)
493 repo.add(names)
494
494
495 def addremove(ui, repo, *pats, **opts):
495 def addremove(ui, repo, *pats, **opts):
496 """add all new files, delete all missing files"""
496 """add all new files, delete all missing files"""
497 add, remove = [], []
497 add, remove = [], []
498 for src, abs, rel, exact in walk(repo, pats, opts):
498 for src, abs, rel, exact in walk(repo, pats, opts):
499 if src == 'f' and repo.dirstate.state(abs) == '?':
499 if src == 'f' and repo.dirstate.state(abs) == '?':
500 add.append(abs)
500 add.append(abs)
501 if ui.verbose or not exact:
501 if ui.verbose or not exact:
502 ui.status('adding ', rel, '\n')
502 ui.status('adding ', rel, '\n')
503 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):
504 remove.append(abs)
504 remove.append(abs)
505 if ui.verbose or not exact:
505 if ui.verbose or not exact:
506 ui.status('removing ', rel, '\n')
506 ui.status('removing ', rel, '\n')
507 repo.add(add)
507 repo.add(add)
508 repo.remove(remove)
508 repo.remove(remove)
509
509
510 def annotate(ui, repo, *pats, **opts):
510 def annotate(ui, repo, *pats, **opts):
511 """show changeset information per file line"""
511 """show changeset information per file line"""
512 def getnode(rev):
512 def getnode(rev):
513 return short(repo.changelog.node(rev))
513 return short(repo.changelog.node(rev))
514
514
515 ucache = {}
515 ucache = {}
516 def getname(rev):
516 def getname(rev):
517 cl = repo.changelog.read(repo.changelog.node(rev))
517 cl = repo.changelog.read(repo.changelog.node(rev))
518 return trimuser(ui, cl[1], rev, ucache)
518 return trimuser(ui, cl[1], rev, ucache)
519
519
520 if not pats:
520 if not pats:
521 raise util.Abort('at least one file name or pattern required')
521 raise util.Abort('at least one file name or pattern required')
522
522
523 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
523 opmap = [['user', getname], ['number', str], ['changeset', getnode]]
524 if not opts['user'] and not opts['changeset']:
524 if not opts['user'] and not opts['changeset']:
525 opts['number'] = 1
525 opts['number'] = 1
526
526
527 if opts['rev']:
527 if opts['rev']:
528 node = repo.changelog.lookup(opts['rev'])
528 node = repo.changelog.lookup(opts['rev'])
529 else:
529 else:
530 node = repo.dirstate.parents()[0]
530 node = repo.dirstate.parents()[0]
531 change = repo.changelog.read(node)
531 change = repo.changelog.read(node)
532 mmap = repo.manifest.read(change[0])
532 mmap = repo.manifest.read(change[0])
533
533
534 for src, abs, rel, exact in walk(repo, pats, opts):
534 for src, abs, rel, exact in walk(repo, pats, opts):
535 if abs not in mmap:
535 if abs not in mmap:
536 ui.warn("warning: %s is not in the repository!\n" % rel)
536 ui.warn("warning: %s is not in the repository!\n" % rel)
537 continue
537 continue
538
538
539 f = repo.file(abs)
539 f = repo.file(abs)
540 if not opts['text'] and util.binary(f.read(mmap[abs])):
540 if not opts['text'] and util.binary(f.read(mmap[abs])):
541 ui.write("%s: binary file\n" % rel)
541 ui.write("%s: binary file\n" % rel)
542 continue
542 continue
543
543
544 lines = f.annotate(mmap[abs])
544 lines = f.annotate(mmap[abs])
545 pieces = []
545 pieces = []
546
546
547 for o, f in opmap:
547 for o, f in opmap:
548 if opts[o]:
548 if opts[o]:
549 l = [f(n) for n, dummy in lines]
549 l = [f(n) for n, dummy in lines]
550 if l:
550 if l:
551 m = max(map(len, l))
551 m = max(map(len, l))
552 pieces.append(["%*s" % (m, x) for x in l])
552 pieces.append(["%*s" % (m, x) for x in l])
553
553
554 if pieces:
554 if pieces:
555 for p, l in zip(zip(*pieces), lines):
555 for p, l in zip(zip(*pieces), lines):
556 ui.write("%s: %s" % (" ".join(p), l[1]))
556 ui.write("%s: %s" % (" ".join(p), l[1]))
557
557
558 def bundle(ui, repo, fname, dest="default-push", **opts):
558 def bundle(ui, repo, fname, dest="default-push", **opts):
559 """create a changegroup file"""
559 """create a changegroup file"""
560 f = open(fname, "wb")
560 f = open(fname, "wb")
561 dest = ui.expandpath(dest)
561 dest = ui.expandpath(dest)
562 other = hg.repository(ui, dest)
562 other = hg.repository(ui, dest)
563 o = repo.findoutgoing(other)
563 o = repo.findoutgoing(other)
564 cg = repo.changegroup(o)
564 cg = repo.changegroup(o)
565
565
566 try:
566 try:
567 f.write("HG10")
567 f.write("HG10")
568 z = bz2.BZ2Compressor(9)
568 z = bz2.BZ2Compressor(9)
569 while 1:
569 while 1:
570 chunk = cg.read(4096)
570 chunk = cg.read(4096)
571 if not chunk:
571 if not chunk:
572 break
572 break
573 f.write(z.compress(chunk))
573 f.write(z.compress(chunk))
574 f.write(z.flush())
574 f.write(z.flush())
575 except:
575 except:
576 os.unlink(fname)
576 os.unlink(fname)
577
577
578 def cat(ui, repo, file1, *pats, **opts):
578 def cat(ui, repo, file1, *pats, **opts):
579 """output the latest or given revisions of files"""
579 """output the latest or given revisions of files"""
580 mf = {}
580 mf = {}
581 if opts['rev']:
581 if opts['rev']:
582 change = repo.changelog.read(repo.lookup(opts['rev']))
582 change = repo.changelog.read(repo.lookup(opts['rev']))
583 mf = repo.manifest.read(change[0])
583 mf = repo.manifest.read(change[0])
584 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
584 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts):
585 r = repo.file(abs)
585 r = repo.file(abs)
586 if opts['rev']:
586 if opts['rev']:
587 try:
587 try:
588 n = mf[abs]
588 n = mf[abs]
589 except (hg.RepoError, KeyError):
589 except (hg.RepoError, KeyError):
590 try:
590 try:
591 n = r.lookup(rev)
591 n = r.lookup(rev)
592 except KeyError, inst:
592 except KeyError, inst:
593 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)
594 else:
594 else:
595 n = r.tip()
595 n = r.tip()
596 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
596 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
597 fp.write(r.read(n))
597 fp.write(r.read(n))
598
598
599 def clone(ui, source, dest=None, **opts):
599 def clone(ui, source, dest=None, **opts):
600 """make a copy of an existing repository"""
600 """make a copy of an existing repository"""
601 if dest is None:
601 if dest is None:
602 dest = os.path.basename(os.path.normpath(source))
602 dest = os.path.basename(os.path.normpath(source))
603
603
604 if os.path.exists(dest):
604 if os.path.exists(dest):
605 raise util.Abort("destination '%s' already exists", dest)
605 raise util.Abort("destination '%s' already exists", dest)
606
606
607 dest = os.path.realpath(dest)
607 dest = os.path.realpath(dest)
608
608
609 class Dircleanup:
609 class Dircleanup:
610 def __init__(self, dir_):
610 def __init__(self, dir_):
611 self.rmtree = shutil.rmtree
611 self.rmtree = shutil.rmtree
612 self.dir_ = dir_
612 self.dir_ = dir_
613 os.mkdir(dir_)
613 os.mkdir(dir_)
614 def close(self):
614 def close(self):
615 self.dir_ = None
615 self.dir_ = None
616 def __del__(self):
616 def __del__(self):
617 if self.dir_:
617 if self.dir_:
618 self.rmtree(self.dir_, True)
618 self.rmtree(self.dir_, True)
619
619
620 if opts['ssh']:
620 if opts['ssh']:
621 ui.setconfig("ui", "ssh", opts['ssh'])
621 ui.setconfig("ui", "ssh", opts['ssh'])
622 if opts['remotecmd']:
622 if opts['remotecmd']:
623 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
623 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
624
624
625 d = Dircleanup(dest)
626 if not os.path.exists(source):
625 if not os.path.exists(source):
627 source = ui.expandpath(source)
626 source = ui.expandpath(source)
627
628 d = Dircleanup(dest)
628 abspath = source
629 abspath = source
629 other = hg.repository(ui, source)
630 other = hg.repository(ui, source)
630
631
631 copy = False
632 copy = False
632 if not opts['pull'] and other.dev() != -1:
633 if not opts['pull'] and other.dev() != -1:
633 abspath = os.path.abspath(source)
634 abspath = os.path.abspath(source)
634 copy = True
635 copy = True
635
636
636 if copy:
637 if copy:
637 try:
638 try:
638 # we use a lock here because if we race with commit, we
639 # we use a lock here because if we race with commit, we
639 # can end up with extra data in the cloned revlogs that's
640 # can end up with extra data in the cloned revlogs that's
640 # not pointed to by changesets, thus causing verify to
641 # not pointed to by changesets, thus causing verify to
641 # fail
642 # fail
642 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
643 l1 = lock.lock(os.path.join(source, ".hg", "lock"))
643 except OSError:
644 except OSError:
644 copy = False
645 copy = False
645
646
646 if copy:
647 if copy:
647 # we lock here to avoid premature writing to the target
648 # we lock here to avoid premature writing to the target
648 os.mkdir(os.path.join(dest, ".hg"))
649 os.mkdir(os.path.join(dest, ".hg"))
649 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
650 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
650
651
651 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
652 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
652 for f in files.split():
653 for f in files.split():
653 src = os.path.join(source, ".hg", f)
654 src = os.path.join(source, ".hg", f)
654 dst = os.path.join(dest, ".hg", f)
655 dst = os.path.join(dest, ".hg", f)
655 util.copyfiles(src, dst)
656 util.copyfiles(src, dst)
656
657
657 repo = hg.repository(ui, dest)
658 repo = hg.repository(ui, dest)
658
659
659 else:
660 else:
660 repo = hg.repository(ui, dest, create=1)
661 repo = hg.repository(ui, dest, create=1)
661 repo.pull(other)
662 repo.pull(other)
662
663
663 f = repo.opener("hgrc", "w")
664 f = repo.opener("hgrc", "w")
664 f.write("[paths]\n")
665 f.write("[paths]\n")
665 f.write("default = %s\n" % abspath)
666 f.write("default = %s\n" % abspath)
666
667
667 if not opts['noupdate']:
668 if not opts['noupdate']:
668 update(ui, repo)
669 update(ui, repo)
669
670
670 d.close()
671 d.close()
671
672
672 def commit(ui, repo, *pats, **opts):
673 def commit(ui, repo, *pats, **opts):
673 """commit the specified files or all outstanding changes"""
674 """commit the specified files or all outstanding changes"""
674 if opts['text']:
675 if opts['text']:
675 ui.warn("Warning: -t and --text is deprecated,"
676 ui.warn("Warning: -t and --text is deprecated,"
676 " please use -m or --message instead.\n")
677 " please use -m or --message instead.\n")
677 message = opts['message'] or opts['text']
678 message = opts['message'] or opts['text']
678 logfile = opts['logfile']
679 logfile = opts['logfile']
679 if not message and logfile:
680 if not message and logfile:
680 try:
681 try:
681 if logfile == '-':
682 if logfile == '-':
682 message = sys.stdin.read()
683 message = sys.stdin.read()
683 else:
684 else:
684 message = open(logfile).read()
685 message = open(logfile).read()
685 except IOError, why:
686 except IOError, why:
686 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
687 ui.warn("Can't read commit message %s: %s\n" % (logfile, why))
687
688
688 if opts['addremove']:
689 if opts['addremove']:
689 addremove(ui, repo, *pats, **opts)
690 addremove(ui, repo, *pats, **opts)
690 cwd = repo.getcwd()
691 cwd = repo.getcwd()
691 if not pats and cwd:
692 if not pats and cwd:
692 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
693 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
693 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
694 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
694 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
695 fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
695 pats, opts)
696 pats, opts)
696 if pats:
697 if pats:
697 c, a, d, u = repo.changes(files=fns, match=match)
698 c, a, d, u = repo.changes(files=fns, match=match)
698 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
699 files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
699 else:
700 else:
700 files = []
701 files = []
701 try:
702 try:
702 repo.commit(files, message, opts['user'], opts['date'], match)
703 repo.commit(files, message, opts['user'], opts['date'], match)
703 except ValueError, inst:
704 except ValueError, inst:
704 raise util.Abort(str(inst))
705 raise util.Abort(str(inst))
705
706
706 def docopy(ui, repo, pats, opts):
707 def docopy(ui, repo, pats, opts):
707 if not pats:
708 if not pats:
708 raise util.Abort('no source or destination specified')
709 raise util.Abort('no source or destination specified')
709 elif len(pats) == 1:
710 elif len(pats) == 1:
710 raise util.Abort('no destination specified')
711 raise util.Abort('no destination specified')
711 pats = list(pats)
712 pats = list(pats)
712 dest = pats.pop()
713 dest = pats.pop()
713 sources = []
714 sources = []
714
715
715 def okaytocopy(abs, rel, exact):
716 def okaytocopy(abs, rel, exact):
716 reasons = {'?': 'is not managed',
717 reasons = {'?': 'is not managed',
717 'a': 'has been marked for add'}
718 'a': 'has been marked for add'}
718 reason = reasons.get(repo.dirstate.state(abs))
719 reason = reasons.get(repo.dirstate.state(abs))
719 if reason:
720 if reason:
720 if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
721 if exact: ui.warn('%s: not copying - file %s\n' % (rel, reason))
721 else:
722 else:
722 return True
723 return True
723
724
724 for src, abs, rel, exact in walk(repo, pats, opts):
725 for src, abs, rel, exact in walk(repo, pats, opts):
725 if okaytocopy(abs, rel, exact):
726 if okaytocopy(abs, rel, exact):
726 sources.append((abs, rel, exact))
727 sources.append((abs, rel, exact))
727 if not sources:
728 if not sources:
728 raise util.Abort('no files to copy')
729 raise util.Abort('no files to copy')
729
730
730 cwd = repo.getcwd()
731 cwd = repo.getcwd()
731 absdest = util.canonpath(repo.root, cwd, dest)
732 absdest = util.canonpath(repo.root, cwd, dest)
732 reldest = util.pathto(cwd, absdest)
733 reldest = util.pathto(cwd, absdest)
733 if os.path.exists(reldest):
734 if os.path.exists(reldest):
734 destisfile = not os.path.isdir(reldest)
735 destisfile = not os.path.isdir(reldest)
735 else:
736 else:
736 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
737 destisfile = len(sources) == 1 or repo.dirstate.state(absdest) != '?'
737
738
738 if destisfile:
739 if destisfile:
739 if opts['parents']:
740 if opts['parents']:
740 raise util.Abort('with --parents, destination must be a directory')
741 raise util.Abort('with --parents, destination must be a directory')
741 elif len(sources) > 1:
742 elif len(sources) > 1:
742 raise util.Abort('with multiple sources, destination must be a '
743 raise util.Abort('with multiple sources, destination must be a '
743 'directory')
744 'directory')
744 errs, copied = 0, []
745 errs, copied = 0, []
745 for abs, rel, exact in sources:
746 for abs, rel, exact in sources:
746 if opts['parents']:
747 if opts['parents']:
747 mydest = os.path.join(dest, rel)
748 mydest = os.path.join(dest, rel)
748 elif destisfile:
749 elif destisfile:
749 mydest = reldest
750 mydest = reldest
750 else:
751 else:
751 mydest = os.path.join(dest, os.path.basename(rel))
752 mydest = os.path.join(dest, os.path.basename(rel))
752 myabsdest = util.canonpath(repo.root, cwd, mydest)
753 myabsdest = util.canonpath(repo.root, cwd, mydest)
753 myreldest = util.pathto(cwd, myabsdest)
754 myreldest = util.pathto(cwd, myabsdest)
754 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
755 if not opts['force'] and repo.dirstate.state(myabsdest) not in 'a?':
755 ui.warn('%s: not overwriting - file already managed\n' % myreldest)
756 ui.warn('%s: not overwriting - file already managed\n' % myreldest)
756 continue
757 continue
757 mydestdir = os.path.dirname(myreldest) or '.'
758 mydestdir = os.path.dirname(myreldest) or '.'
758 if not opts['after']:
759 if not opts['after']:
759 try:
760 try:
760 if opts['parents']: os.makedirs(mydestdir)
761 if opts['parents']: os.makedirs(mydestdir)
761 elif not destisfile: os.mkdir(mydestdir)
762 elif not destisfile: os.mkdir(mydestdir)
762 except OSError, inst:
763 except OSError, inst:
763 if inst.errno != errno.EEXIST: raise
764 if inst.errno != errno.EEXIST: raise
764 if ui.verbose or not exact:
765 if ui.verbose or not exact:
765 ui.status('copying %s to %s\n' % (rel, myreldest))
766 ui.status('copying %s to %s\n' % (rel, myreldest))
766 if not opts['after']:
767 if not opts['after']:
767 try:
768 try:
768 shutil.copyfile(rel, myreldest)
769 shutil.copyfile(rel, myreldest)
769 n = repo.manifest.tip()
770 n = repo.manifest.tip()
770 mf = repo.manifest.readflags(n)
771 mf = repo.manifest.readflags(n)
771 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
772 util.set_exec(myreldest, util.is_exec(rel, mf[abs]))
772 except shutil.Error, inst:
773 except shutil.Error, inst:
773 raise util.Abort(str(inst))
774 raise util.Abort(str(inst))
774 except IOError, inst:
775 except IOError, inst:
775 if inst.errno == errno.ENOENT:
776 if inst.errno == errno.ENOENT:
776 ui.warn('%s: deleted in working copy\n' % rel)
777 ui.warn('%s: deleted in working copy\n' % rel)
777 else:
778 else:
778 ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
779 ui.warn('%s: cannot copy - %s\n' % (rel, inst.strerror))
779 errs += 1
780 errs += 1
780 continue
781 continue
781 repo.copy(abs, myabsdest)
782 repo.copy(abs, myabsdest)
782 copied.append((abs, rel, exact))
783 copied.append((abs, rel, exact))
783 if errs:
784 if errs:
784 ui.warn('(consider using --after)\n')
785 ui.warn('(consider using --after)\n')
785 return errs, copied
786 return errs, copied
786
787
787 def copy(ui, repo, *pats, **opts):
788 def copy(ui, repo, *pats, **opts):
788 """mark files as copied for the next commit"""
789 """mark files as copied for the next commit"""
789 errs, copied = docopy(ui, repo, pats, opts)
790 errs, copied = docopy(ui, repo, pats, opts)
790 return errs
791 return errs
791
792
792 def debugancestor(ui, index, rev1, rev2):
793 def debugancestor(ui, index, rev1, rev2):
793 """find the ancestor revision of two revisions in a given index"""
794 """find the ancestor revision of two revisions in a given index"""
794 r = revlog.revlog(file, index, "")
795 r = revlog.revlog(file, index, "")
795 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
796 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
796 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
797 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
797
798
798 def debugcheckstate(ui, repo):
799 def debugcheckstate(ui, repo):
799 """validate the correctness of the current dirstate"""
800 """validate the correctness of the current dirstate"""
800 parent1, parent2 = repo.dirstate.parents()
801 parent1, parent2 = repo.dirstate.parents()
801 repo.dirstate.read()
802 repo.dirstate.read()
802 dc = repo.dirstate.map
803 dc = repo.dirstate.map
803 keys = dc.keys()
804 keys = dc.keys()
804 keys.sort()
805 keys.sort()
805 m1n = repo.changelog.read(parent1)[0]
806 m1n = repo.changelog.read(parent1)[0]
806 m2n = repo.changelog.read(parent2)[0]
807 m2n = repo.changelog.read(parent2)[0]
807 m1 = repo.manifest.read(m1n)
808 m1 = repo.manifest.read(m1n)
808 m2 = repo.manifest.read(m2n)
809 m2 = repo.manifest.read(m2n)
809 errors = 0
810 errors = 0
810 for f in dc:
811 for f in dc:
811 state = repo.dirstate.state(f)
812 state = repo.dirstate.state(f)
812 if state in "nr" and f not in m1:
813 if state in "nr" and f not in m1:
813 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
814 ui.warn("%s in state %s, but not in manifest1\n" % (f, state))
814 errors += 1
815 errors += 1
815 if state in "a" and f in m1:
816 if state in "a" and f in m1:
816 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
817 ui.warn("%s in state %s, but also in manifest1\n" % (f, state))
817 errors += 1
818 errors += 1
818 if state in "m" and f not in m1 and f not in m2:
819 if state in "m" and f not in m1 and f not in m2:
819 ui.warn("%s in state %s, but not in either manifest\n" %
820 ui.warn("%s in state %s, but not in either manifest\n" %
820 (f, state))
821 (f, state))
821 errors += 1
822 errors += 1
822 for f in m1:
823 for f in m1:
823 state = repo.dirstate.state(f)
824 state = repo.dirstate.state(f)
824 if state not in "nrm":
825 if state not in "nrm":
825 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
826 ui.warn("%s in manifest1, but listed as state %s" % (f, state))
826 errors += 1
827 errors += 1
827 if errors:
828 if errors:
828 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
829 raise util.Abort(".hg/dirstate inconsistent with current parent's manifest")
829
830
830 def debugconfig(ui):
831 def debugconfig(ui):
831 """show combined config settings from all hgrc files"""
832 """show combined config settings from all hgrc files"""
832 try:
833 try:
833 repo = hg.repository(ui)
834 repo = hg.repository(ui)
834 except hg.RepoError:
835 except hg.RepoError:
835 pass
836 pass
836 for section, name, value in ui.walkconfig():
837 for section, name, value in ui.walkconfig():
837 ui.write('%s.%s=%s\n' % (section, name, value))
838 ui.write('%s.%s=%s\n' % (section, name, value))
838
839
839 def debugstate(ui, repo):
840 def debugstate(ui, repo):
840 """show the contents of the current dirstate"""
841 """show the contents of the current dirstate"""
841 repo.dirstate.read()
842 repo.dirstate.read()
842 dc = repo.dirstate.map
843 dc = repo.dirstate.map
843 keys = dc.keys()
844 keys = dc.keys()
844 keys.sort()
845 keys.sort()
845 for file_ in keys:
846 for file_ in keys:
846 ui.write("%c %3o %10d %s %s\n"
847 ui.write("%c %3o %10d %s %s\n"
847 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
848 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
848 time.strftime("%x %X",
849 time.strftime("%x %X",
849 time.localtime(dc[file_][3])), file_))
850 time.localtime(dc[file_][3])), file_))
850 for f in repo.dirstate.copies:
851 for f in repo.dirstate.copies:
851 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
852 ui.write("copy: %s -> %s\n" % (repo.dirstate.copies[f], f))
852
853
853 def debugdata(ui, file_, rev):
854 def debugdata(ui, file_, rev):
854 """dump the contents of an data file revision"""
855 """dump the contents of an data file revision"""
855 r = revlog.revlog(file, file_[:-2] + ".i", file_)
856 r = revlog.revlog(file, file_[:-2] + ".i", file_)
856 try:
857 try:
857 ui.write(r.revision(r.lookup(rev)))
858 ui.write(r.revision(r.lookup(rev)))
858 except KeyError:
859 except KeyError:
859 raise util.Abort('invalid revision identifier %s', rev)
860 raise util.Abort('invalid revision identifier %s', rev)
860
861
861 def debugindex(ui, file_):
862 def debugindex(ui, file_):
862 """dump the contents of an index file"""
863 """dump the contents of an index file"""
863 r = revlog.revlog(file, file_, "")
864 r = revlog.revlog(file, file_, "")
864 ui.write(" rev offset length base linkrev" +
865 ui.write(" rev offset length base linkrev" +
865 " nodeid p1 p2\n")
866 " nodeid p1 p2\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("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
869 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
869 i, e[0], e[1], e[2], e[3],
870 i, e[0], e[1], e[2], e[3],
870 short(e[6]), short(e[4]), short(e[5])))
871 short(e[6]), short(e[4]), short(e[5])))
871
872
872 def debugindexdot(ui, file_):
873 def debugindexdot(ui, file_):
873 """dump an index DAG as a .dot file"""
874 """dump an index DAG as a .dot file"""
874 r = revlog.revlog(file, file_, "")
875 r = revlog.revlog(file, file_, "")
875 ui.write("digraph G {\n")
876 ui.write("digraph G {\n")
876 for i in range(r.count()):
877 for i in range(r.count()):
877 e = r.index[i]
878 e = r.index[i]
878 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
879 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
879 if e[5] != nullid:
880 if e[5] != nullid:
880 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
881 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
881 ui.write("}\n")
882 ui.write("}\n")
882
883
883 def debugrename(ui, repo, file, rev=None):
884 def debugrename(ui, repo, file, rev=None):
884 """dump rename information"""
885 """dump rename information"""
885 r = repo.file(relpath(repo, [file])[0])
886 r = repo.file(relpath(repo, [file])[0])
886 if rev:
887 if rev:
887 try:
888 try:
888 # assume all revision numbers are for changesets
889 # assume all revision numbers are for changesets
889 n = repo.lookup(rev)
890 n = repo.lookup(rev)
890 change = repo.changelog.read(n)
891 change = repo.changelog.read(n)
891 m = repo.manifest.read(change[0])
892 m = repo.manifest.read(change[0])
892 n = m[relpath(repo, [file])[0]]
893 n = m[relpath(repo, [file])[0]]
893 except hg.RepoError, KeyError:
894 except hg.RepoError, KeyError:
894 n = r.lookup(rev)
895 n = r.lookup(rev)
895 else:
896 else:
896 n = r.tip()
897 n = r.tip()
897 m = r.renamed(n)
898 m = r.renamed(n)
898 if m:
899 if m:
899 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
900 ui.write("renamed from %s:%s\n" % (m[0], hex(m[1])))
900 else:
901 else:
901 ui.write("not renamed\n")
902 ui.write("not renamed\n")
902
903
903 def debugwalk(ui, repo, *pats, **opts):
904 def debugwalk(ui, repo, *pats, **opts):
904 """show how files match on given patterns"""
905 """show how files match on given patterns"""
905 items = list(walk(repo, pats, opts))
906 items = list(walk(repo, pats, opts))
906 if not items:
907 if not items:
907 return
908 return
908 fmt = '%%s %%-%ds %%-%ds %%s' % (
909 fmt = '%%s %%-%ds %%-%ds %%s' % (
909 max([len(abs) for (src, abs, rel, exact) in items]),
910 max([len(abs) for (src, abs, rel, exact) in items]),
910 max([len(rel) for (src, abs, rel, exact) in items]))
911 max([len(rel) for (src, abs, rel, exact) in items]))
911 for src, abs, rel, exact in items:
912 for src, abs, rel, exact in items:
912 line = fmt % (src, abs, rel, exact and 'exact' or '')
913 line = fmt % (src, abs, rel, exact and 'exact' or '')
913 ui.write("%s\n" % line.rstrip())
914 ui.write("%s\n" % line.rstrip())
914
915
915 def diff(ui, repo, *pats, **opts):
916 def diff(ui, repo, *pats, **opts):
916 """diff working directory (or selected files)"""
917 """diff working directory (or selected files)"""
917 node1, node2 = None, None
918 node1, node2 = None, None
918 revs = [repo.lookup(x) for x in opts['rev']]
919 revs = [repo.lookup(x) for x in opts['rev']]
919
920
920 if len(revs) > 0:
921 if len(revs) > 0:
921 node1 = revs[0]
922 node1 = revs[0]
922 if len(revs) > 1:
923 if len(revs) > 1:
923 node2 = revs[1]
924 node2 = revs[1]
924 if len(revs) > 2:
925 if len(revs) > 2:
925 raise util.Abort("too many revisions to diff")
926 raise util.Abort("too many revisions to diff")
926
927
927 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
928 fns, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
928
929
929 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
930 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
930 text=opts['text'])
931 text=opts['text'])
931
932
932 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
933 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
933 node = repo.lookup(changeset)
934 node = repo.lookup(changeset)
934 prev, other = repo.changelog.parents(node)
935 prev, other = repo.changelog.parents(node)
935 change = repo.changelog.read(node)
936 change = repo.changelog.read(node)
936
937
937 fp = make_file(repo, repo.changelog, opts['output'],
938 fp = make_file(repo, repo.changelog, opts['output'],
938 node=node, total=total, seqno=seqno,
939 node=node, total=total, seqno=seqno,
939 revwidth=revwidth)
940 revwidth=revwidth)
940 if fp != sys.stdout:
941 if fp != sys.stdout:
941 ui.note("%s\n" % fp.name)
942 ui.note("%s\n" % fp.name)
942
943
943 fp.write("# HG changeset patch\n")
944 fp.write("# HG changeset patch\n")
944 fp.write("# User %s\n" % change[1])
945 fp.write("# User %s\n" % change[1])
945 fp.write("# Node ID %s\n" % hex(node))
946 fp.write("# Node ID %s\n" % hex(node))
946 fp.write("# Parent %s\n" % hex(prev))
947 fp.write("# Parent %s\n" % hex(prev))
947 if other != nullid:
948 if other != nullid:
948 fp.write("# Parent %s\n" % hex(other))
949 fp.write("# Parent %s\n" % hex(other))
949 fp.write(change[4].rstrip())
950 fp.write(change[4].rstrip())
950 fp.write("\n\n")
951 fp.write("\n\n")
951
952
952 dodiff(fp, ui, repo, prev, node, text=opts['text'])
953 dodiff(fp, ui, repo, prev, node, text=opts['text'])
953 if fp != sys.stdout:
954 if fp != sys.stdout:
954 fp.close()
955 fp.close()
955
956
956 def export(ui, repo, *changesets, **opts):
957 def export(ui, repo, *changesets, **opts):
957 """dump the header and diffs for one or more changesets"""
958 """dump the header and diffs for one or more changesets"""
958 if not changesets:
959 if not changesets:
959 raise util.Abort("export requires at least one changeset")
960 raise util.Abort("export requires at least one changeset")
960 seqno = 0
961 seqno = 0
961 revs = list(revrange(ui, repo, changesets))
962 revs = list(revrange(ui, repo, changesets))
962 total = len(revs)
963 total = len(revs)
963 revwidth = max(map(len, revs))
964 revwidth = max(map(len, revs))
964 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
965 ui.note(len(revs) > 1 and "Exporting patches:\n" or "Exporting patch:\n")
965 for cset in revs:
966 for cset in revs:
966 seqno += 1
967 seqno += 1
967 doexport(ui, repo, cset, seqno, total, revwidth, opts)
968 doexport(ui, repo, cset, seqno, total, revwidth, opts)
968
969
969 def forget(ui, repo, *pats, **opts):
970 def forget(ui, repo, *pats, **opts):
970 """don't add the specified files on the next commit"""
971 """don't add the specified files on the next commit"""
971 forget = []
972 forget = []
972 for src, abs, rel, exact in walk(repo, pats, opts):
973 for src, abs, rel, exact in walk(repo, pats, opts):
973 if repo.dirstate.state(abs) == 'a':
974 if repo.dirstate.state(abs) == 'a':
974 forget.append(abs)
975 forget.append(abs)
975 if ui.verbose or not exact:
976 if ui.verbose or not exact:
976 ui.status('forgetting ', rel, '\n')
977 ui.status('forgetting ', rel, '\n')
977 repo.forget(forget)
978 repo.forget(forget)
978
979
979 def grep(ui, repo, pattern, *pats, **opts):
980 def grep(ui, repo, pattern, *pats, **opts):
980 """search for a pattern in specified files and revisions"""
981 """search for a pattern in specified files and revisions"""
981 reflags = 0
982 reflags = 0
982 if opts['ignore_case']:
983 if opts['ignore_case']:
983 reflags |= re.I
984 reflags |= re.I
984 regexp = re.compile(pattern, reflags)
985 regexp = re.compile(pattern, reflags)
985 sep, eol = ':', '\n'
986 sep, eol = ':', '\n'
986 if opts['print0']:
987 if opts['print0']:
987 sep = eol = '\0'
988 sep = eol = '\0'
988
989
989 fcache = {}
990 fcache = {}
990 def getfile(fn):
991 def getfile(fn):
991 if fn not in fcache:
992 if fn not in fcache:
992 fcache[fn] = repo.file(fn)
993 fcache[fn] = repo.file(fn)
993 return fcache[fn]
994 return fcache[fn]
994
995
995 def matchlines(body):
996 def matchlines(body):
996 begin = 0
997 begin = 0
997 linenum = 0
998 linenum = 0
998 while True:
999 while True:
999 match = regexp.search(body, begin)
1000 match = regexp.search(body, begin)
1000 if not match:
1001 if not match:
1001 break
1002 break
1002 mstart, mend = match.span()
1003 mstart, mend = match.span()
1003 linenum += body.count('\n', begin, mstart) + 1
1004 linenum += body.count('\n', begin, mstart) + 1
1004 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1005 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1005 lend = body.find('\n', mend)
1006 lend = body.find('\n', mend)
1006 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1007 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1007 begin = lend + 1
1008 begin = lend + 1
1008
1009
1009 class linestate:
1010 class linestate:
1010 def __init__(self, line, linenum, colstart, colend):
1011 def __init__(self, line, linenum, colstart, colend):
1011 self.line = line
1012 self.line = line
1012 self.linenum = linenum
1013 self.linenum = linenum
1013 self.colstart = colstart
1014 self.colstart = colstart
1014 self.colend = colend
1015 self.colend = colend
1015 def __eq__(self, other):
1016 def __eq__(self, other):
1016 return self.line == other.line
1017 return self.line == other.line
1017 def __hash__(self):
1018 def __hash__(self):
1018 return hash(self.line)
1019 return hash(self.line)
1019
1020
1020 matches = {}
1021 matches = {}
1021 def grepbody(fn, rev, body):
1022 def grepbody(fn, rev, body):
1022 matches[rev].setdefault(fn, {})
1023 matches[rev].setdefault(fn, {})
1023 m = matches[rev][fn]
1024 m = matches[rev][fn]
1024 for lnum, cstart, cend, line in matchlines(body):
1025 for lnum, cstart, cend, line in matchlines(body):
1025 s = linestate(line, lnum, cstart, cend)
1026 s = linestate(line, lnum, cstart, cend)
1026 m[s] = s
1027 m[s] = s
1027
1028
1028 prev = {}
1029 prev = {}
1029 ucache = {}
1030 ucache = {}
1030 def display(fn, rev, states, prevstates):
1031 def display(fn, rev, states, prevstates):
1031 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1032 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1032 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1033 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1033 counts = {'-': 0, '+': 0}
1034 counts = {'-': 0, '+': 0}
1034 filerevmatches = {}
1035 filerevmatches = {}
1035 for l in diff:
1036 for l in diff:
1036 if incrementing or not opts['all']:
1037 if incrementing or not opts['all']:
1037 change = ((l in prevstates) and '-') or '+'
1038 change = ((l in prevstates) and '-') or '+'
1038 r = rev
1039 r = rev
1039 else:
1040 else:
1040 change = ((l in states) and '-') or '+'
1041 change = ((l in states) and '-') or '+'
1041 r = prev[fn]
1042 r = prev[fn]
1042 cols = [fn, str(rev)]
1043 cols = [fn, str(rev)]
1043 if opts['line_number']: cols.append(str(l.linenum))
1044 if opts['line_number']: cols.append(str(l.linenum))
1044 if opts['all']: cols.append(change)
1045 if opts['all']: cols.append(change)
1045 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1046 if opts['user']: cols.append(trimuser(ui, getchange(rev)[1], rev,
1046 ucache))
1047 ucache))
1047 if opts['files_with_matches']:
1048 if opts['files_with_matches']:
1048 c = (fn, rev)
1049 c = (fn, rev)
1049 if c in filerevmatches: continue
1050 if c in filerevmatches: continue
1050 filerevmatches[c] = 1
1051 filerevmatches[c] = 1
1051 else:
1052 else:
1052 cols.append(l.line)
1053 cols.append(l.line)
1053 ui.write(sep.join(cols), eol)
1054 ui.write(sep.join(cols), eol)
1054 counts[change] += 1
1055 counts[change] += 1
1055 return counts['+'], counts['-']
1056 return counts['+'], counts['-']
1056
1057
1057 fstate = {}
1058 fstate = {}
1058 skip = {}
1059 skip = {}
1059 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1060 changeiter, getchange = walkchangerevs(ui, repo, repo.getcwd(), pats, opts)
1060 count = 0
1061 count = 0
1061 for st, rev, fns in changeiter:
1062 for st, rev, fns in changeiter:
1062 if st == 'window':
1063 if st == 'window':
1063 incrementing = rev
1064 incrementing = rev
1064 matches.clear()
1065 matches.clear()
1065 elif st == 'add':
1066 elif st == 'add':
1066 change = repo.changelog.read(repo.lookup(str(rev)))
1067 change = repo.changelog.read(repo.lookup(str(rev)))
1067 mf = repo.manifest.read(change[0])
1068 mf = repo.manifest.read(change[0])
1068 matches[rev] = {}
1069 matches[rev] = {}
1069 for fn in fns:
1070 for fn in fns:
1070 if fn in skip: continue
1071 if fn in skip: continue
1071 fstate.setdefault(fn, {})
1072 fstate.setdefault(fn, {})
1072 try:
1073 try:
1073 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1074 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1074 except KeyError:
1075 except KeyError:
1075 pass
1076 pass
1076 elif st == 'iter':
1077 elif st == 'iter':
1077 states = matches[rev].items()
1078 states = matches[rev].items()
1078 states.sort()
1079 states.sort()
1079 for fn, m in states:
1080 for fn, m in states:
1080 if fn in skip: continue
1081 if fn in skip: continue
1081 if incrementing or not opts['all'] or fstate[fn]:
1082 if incrementing or not opts['all'] or fstate[fn]:
1082 pos, neg = display(fn, rev, m, fstate[fn])
1083 pos, neg = display(fn, rev, m, fstate[fn])
1083 count += pos + neg
1084 count += pos + neg
1084 if pos and not opts['all']:
1085 if pos and not opts['all']:
1085 skip[fn] = True
1086 skip[fn] = True
1086 fstate[fn] = m
1087 fstate[fn] = m
1087 prev[fn] = rev
1088 prev[fn] = rev
1088
1089
1089 if not incrementing:
1090 if not incrementing:
1090 fstate = fstate.items()
1091 fstate = fstate.items()
1091 fstate.sort()
1092 fstate.sort()
1092 for fn, state in fstate:
1093 for fn, state in fstate:
1093 if fn in skip: continue
1094 if fn in skip: continue
1094 display(fn, rev, {}, state)
1095 display(fn, rev, {}, state)
1095 return (count == 0 and 1) or 0
1096 return (count == 0 and 1) or 0
1096
1097
1097 def heads(ui, repo, **opts):
1098 def heads(ui, repo, **opts):
1098 """show current repository heads"""
1099 """show current repository heads"""
1099 heads = repo.changelog.heads()
1100 heads = repo.changelog.heads()
1100 br = None
1101 br = None
1101 if opts['branches']:
1102 if opts['branches']:
1102 br = repo.branchlookup(heads)
1103 br = repo.branchlookup(heads)
1103 for n in repo.changelog.heads():
1104 for n in repo.changelog.heads():
1104 show_changeset(ui, repo, changenode=n, brinfo=br)
1105 show_changeset(ui, repo, changenode=n, brinfo=br)
1105
1106
1106 def identify(ui, repo):
1107 def identify(ui, repo):
1107 """print information about the working copy"""
1108 """print information about the working copy"""
1108 parents = [p for p in repo.dirstate.parents() if p != nullid]
1109 parents = [p for p in repo.dirstate.parents() if p != nullid]
1109 if not parents:
1110 if not parents:
1110 ui.write("unknown\n")
1111 ui.write("unknown\n")
1111 return
1112 return
1112
1113
1113 hexfunc = ui.verbose and hex or short
1114 hexfunc = ui.verbose and hex or short
1114 (c, a, d, u) = repo.changes()
1115 (c, a, d, u) = repo.changes()
1115 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1116 output = ["%s%s" % ('+'.join([hexfunc(parent) for parent in parents]),
1116 (c or a or d) and "+" or "")]
1117 (c or a or d) and "+" or "")]
1117
1118
1118 if not ui.quiet:
1119 if not ui.quiet:
1119 # multiple tags for a single parent separated by '/'
1120 # multiple tags for a single parent separated by '/'
1120 parenttags = ['/'.join(tags)
1121 parenttags = ['/'.join(tags)
1121 for tags in map(repo.nodetags, parents) if tags]
1122 for tags in map(repo.nodetags, parents) if tags]
1122 # tags for multiple parents separated by ' + '
1123 # tags for multiple parents separated by ' + '
1123 if parenttags:
1124 if parenttags:
1124 output.append(' + '.join(parenttags))
1125 output.append(' + '.join(parenttags))
1125
1126
1126 ui.write("%s\n" % ' '.join(output))
1127 ui.write("%s\n" % ' '.join(output))
1127
1128
1128 def import_(ui, repo, patch1, *patches, **opts):
1129 def import_(ui, repo, patch1, *patches, **opts):
1129 """import an ordered set of patches"""
1130 """import an ordered set of patches"""
1130 patches = (patch1,) + patches
1131 patches = (patch1,) + patches
1131
1132
1132 if not opts['force']:
1133 if not opts['force']:
1133 (c, a, d, u) = repo.changes()
1134 (c, a, d, u) = repo.changes()
1134 if c or a or d:
1135 if c or a or d:
1135 raise util.Abort("outstanding uncommitted changes")
1136 raise util.Abort("outstanding uncommitted changes")
1136
1137
1137 d = opts["base"]
1138 d = opts["base"]
1138 strip = opts["strip"]
1139 strip = opts["strip"]
1139
1140
1140 mailre = re.compile(r'(?:From |[\w-]+:)')
1141 mailre = re.compile(r'(?:From |[\w-]+:)')
1141 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1142 diffre = re.compile(r'(?:diff -|--- .*\s+\w+ \w+ +\d+ \d+:\d+:\d+ \d+)')
1142
1143
1143 for patch in patches:
1144 for patch in patches:
1144 ui.status("applying %s\n" % patch)
1145 ui.status("applying %s\n" % patch)
1145 pf = os.path.join(d, patch)
1146 pf = os.path.join(d, patch)
1146
1147
1147 message = []
1148 message = []
1148 user = None
1149 user = None
1149 hgpatch = False
1150 hgpatch = False
1150 for line in file(pf):
1151 for line in file(pf):
1151 line = line.rstrip()
1152 line = line.rstrip()
1152 if (not message and not hgpatch and
1153 if (not message and not hgpatch and
1153 mailre.match(line) and not opts['force']):
1154 mailre.match(line) and not opts['force']):
1154 if len(line) > 35: line = line[:32] + '...'
1155 if len(line) > 35: line = line[:32] + '...'
1155 raise util.Abort('first line looks like a '
1156 raise util.Abort('first line looks like a '
1156 'mail header: ' + line)
1157 'mail header: ' + line)
1157 if diffre.match(line):
1158 if diffre.match(line):
1158 break
1159 break
1159 elif hgpatch:
1160 elif hgpatch:
1160 # parse values when importing the result of an hg export
1161 # parse values when importing the result of an hg export
1161 if line.startswith("# User "):
1162 if line.startswith("# User "):
1162 user = line[7:]
1163 user = line[7:]
1163 ui.debug('User: %s\n' % user)
1164 ui.debug('User: %s\n' % user)
1164 elif not line.startswith("# ") and line:
1165 elif not line.startswith("# ") and line:
1165 message.append(line)
1166 message.append(line)
1166 hgpatch = False
1167 hgpatch = False
1167 elif line == '# HG changeset patch':
1168 elif line == '# HG changeset patch':
1168 hgpatch = True
1169 hgpatch = True
1169 message = [] # We may have collected garbage
1170 message = [] # We may have collected garbage
1170 else:
1171 else:
1171 message.append(line)
1172 message.append(line)
1172
1173
1173 # make sure message isn't empty
1174 # make sure message isn't empty
1174 if not message:
1175 if not message:
1175 message = "imported patch %s\n" % patch
1176 message = "imported patch %s\n" % patch
1176 else:
1177 else:
1177 message = "%s\n" % '\n'.join(message)
1178 message = "%s\n" % '\n'.join(message)
1178 ui.debug('message:\n%s\n' % message)
1179 ui.debug('message:\n%s\n' % message)
1179
1180
1180 files = util.patch(strip, pf, ui)
1181 files = util.patch(strip, pf, ui)
1181
1182
1182 if len(files) > 0:
1183 if len(files) > 0:
1183 addremove(ui, repo, *files)
1184 addremove(ui, repo, *files)
1184 repo.commit(files, message, user)
1185 repo.commit(files, message, user)
1185
1186
1186 def incoming(ui, repo, source="default", **opts):
1187 def incoming(ui, repo, source="default", **opts):
1187 """show new changesets found in source"""
1188 """show new changesets found in source"""
1188 source = ui.expandpath(source)
1189 source = ui.expandpath(source)
1189 other = hg.repository(ui, source)
1190 other = hg.repository(ui, source)
1190 if not other.local():
1191 if not other.local():
1191 raise util.Abort("incoming doesn't work for remote repositories yet")
1192 raise util.Abort("incoming doesn't work for remote repositories yet")
1192 o = repo.findincoming(other)
1193 o = repo.findincoming(other)
1193 if not o:
1194 if not o:
1194 return
1195 return
1195 o = other.newer(o)
1196 o = other.newer(o)
1196 for n in o:
1197 for n in o:
1197 show_changeset(ui, other, changenode=n)
1198 show_changeset(ui, other, changenode=n)
1198 if opts['patch']:
1199 if opts['patch']:
1199 prev = other.changelog.parents(n)[0]
1200 prev = other.changelog.parents(n)[0]
1200 dodiff(ui, ui, other, prev, n)
1201 dodiff(ui, ui, other, prev, n)
1201 ui.write("\n")
1202 ui.write("\n")
1202
1203
1203 def init(ui, dest="."):
1204 def init(ui, dest="."):
1204 """create a new repository in the given directory"""
1205 """create a new repository in the given directory"""
1205 if not os.path.exists(dest):
1206 if not os.path.exists(dest):
1206 os.mkdir(dest)
1207 os.mkdir(dest)
1207 hg.repository(ui, dest, create=1)
1208 hg.repository(ui, dest, create=1)
1208
1209
1209 def locate(ui, repo, *pats, **opts):
1210 def locate(ui, repo, *pats, **opts):
1210 """locate files matching specific patterns"""
1211 """locate files matching specific patterns"""
1211 end = opts['print0'] and '\0' or '\n'
1212 end = opts['print0'] and '\0' or '\n'
1212
1213
1213 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1214 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'):
1214 if repo.dirstate.state(abs) == '?':
1215 if repo.dirstate.state(abs) == '?':
1215 continue
1216 continue
1216 if opts['fullpath']:
1217 if opts['fullpath']:
1217 ui.write(os.path.join(repo.root, abs), end)
1218 ui.write(os.path.join(repo.root, abs), end)
1218 else:
1219 else:
1219 ui.write(rel, end)
1220 ui.write(rel, end)
1220
1221
1221 def log(ui, repo, *pats, **opts):
1222 def log(ui, repo, *pats, **opts):
1222 """show revision history of entire repository or files"""
1223 """show revision history of entire repository or files"""
1223 class dui:
1224 class dui:
1224 # Implement and delegate some ui protocol. Save hunks of
1225 # Implement and delegate some ui protocol. Save hunks of
1225 # output for later display in the desired order.
1226 # output for later display in the desired order.
1226 def __init__(self, ui):
1227 def __init__(self, ui):
1227 self.ui = ui
1228 self.ui = ui
1228 self.hunk = {}
1229 self.hunk = {}
1229 def bump(self, rev):
1230 def bump(self, rev):
1230 self.rev = rev
1231 self.rev = rev
1231 self.hunk[rev] = []
1232 self.hunk[rev] = []
1232 def note(self, *args):
1233 def note(self, *args):
1233 if self.verbose:
1234 if self.verbose:
1234 self.write(*args)
1235 self.write(*args)
1235 def status(self, *args):
1236 def status(self, *args):
1236 if not self.quiet:
1237 if not self.quiet:
1237 self.write(*args)
1238 self.write(*args)
1238 def write(self, *args):
1239 def write(self, *args):
1239 self.hunk[self.rev].append(args)
1240 self.hunk[self.rev].append(args)
1240 def __getattr__(self, key):
1241 def __getattr__(self, key):
1241 return getattr(self.ui, key)
1242 return getattr(self.ui, key)
1242 cwd = repo.getcwd()
1243 cwd = repo.getcwd()
1243 if not pats and cwd:
1244 if not pats and cwd:
1244 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1245 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
1245 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1246 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
1246 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1247 changeiter, getchange = walkchangerevs(ui, repo, (pats and cwd) or '',
1247 pats, opts)
1248 pats, opts)
1248 for st, rev, fns in changeiter:
1249 for st, rev, fns in changeiter:
1249 if st == 'window':
1250 if st == 'window':
1250 du = dui(ui)
1251 du = dui(ui)
1251 elif st == 'add':
1252 elif st == 'add':
1252 du.bump(rev)
1253 du.bump(rev)
1253 br = None
1254 br = None
1254 if opts['branch']:
1255 if opts['branch']:
1255 br = repo.branchlookup([repo.changelog.node(rev)])
1256 br = repo.branchlookup([repo.changelog.node(rev)])
1256 show_changeset(du, repo, rev, brinfo=br)
1257 show_changeset(du, repo, rev, brinfo=br)
1257 if opts['patch']:
1258 if opts['patch']:
1258 changenode = repo.changelog.node(rev)
1259 changenode = repo.changelog.node(rev)
1259 prev, other = repo.changelog.parents(changenode)
1260 prev, other = repo.changelog.parents(changenode)
1260 dodiff(du, du, repo, prev, changenode, fns)
1261 dodiff(du, du, repo, prev, changenode, fns)
1261 du.write("\n\n")
1262 du.write("\n\n")
1262 elif st == 'iter':
1263 elif st == 'iter':
1263 for args in du.hunk[rev]:
1264 for args in du.hunk[rev]:
1264 ui.write(*args)
1265 ui.write(*args)
1265
1266
1266 def manifest(ui, repo, rev=None):
1267 def manifest(ui, repo, rev=None):
1267 """output the latest or given revision of the project manifest"""
1268 """output the latest or given revision of the project manifest"""
1268 if rev:
1269 if rev:
1269 try:
1270 try:
1270 # assume all revision numbers are for changesets
1271 # assume all revision numbers are for changesets
1271 n = repo.lookup(rev)
1272 n = repo.lookup(rev)
1272 change = repo.changelog.read(n)
1273 change = repo.changelog.read(n)
1273 n = change[0]
1274 n = change[0]
1274 except hg.RepoError:
1275 except hg.RepoError:
1275 n = repo.manifest.lookup(rev)
1276 n = repo.manifest.lookup(rev)
1276 else:
1277 else:
1277 n = repo.manifest.tip()
1278 n = repo.manifest.tip()
1278 m = repo.manifest.read(n)
1279 m = repo.manifest.read(n)
1279 mf = repo.manifest.readflags(n)
1280 mf = repo.manifest.readflags(n)
1280 files = m.keys()
1281 files = m.keys()
1281 files.sort()
1282 files.sort()
1282
1283
1283 for f in files:
1284 for f in files:
1284 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1285 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1285
1286
1286 def outgoing(ui, repo, dest="default-push", **opts):
1287 def outgoing(ui, repo, dest="default-push", **opts):
1287 """show changesets not found in destination"""
1288 """show changesets not found in destination"""
1288 dest = ui.expandpath(dest)
1289 dest = ui.expandpath(dest)
1289 other = hg.repository(ui, dest)
1290 other = hg.repository(ui, dest)
1290 o = repo.findoutgoing(other)
1291 o = repo.findoutgoing(other)
1291 o = repo.newer(o)
1292 o = repo.newer(o)
1292 for n in o:
1293 for n in o:
1293 show_changeset(ui, repo, changenode=n)
1294 show_changeset(ui, repo, changenode=n)
1294 if opts['patch']:
1295 if opts['patch']:
1295 prev = repo.changelog.parents(n)[0]
1296 prev = repo.changelog.parents(n)[0]
1296 dodiff(ui, ui, repo, prev, n)
1297 dodiff(ui, ui, repo, prev, n)
1297 ui.write("\n")
1298 ui.write("\n")
1298
1299
1299 def parents(ui, repo, rev=None):
1300 def parents(ui, repo, rev=None):
1300 """show the parents of the working dir or revision"""
1301 """show the parents of the working dir or revision"""
1301 if rev:
1302 if rev:
1302 p = repo.changelog.parents(repo.lookup(rev))
1303 p = repo.changelog.parents(repo.lookup(rev))
1303 else:
1304 else:
1304 p = repo.dirstate.parents()
1305 p = repo.dirstate.parents()
1305
1306
1306 for n in p:
1307 for n in p:
1307 if n != nullid:
1308 if n != nullid:
1308 show_changeset(ui, repo, changenode=n)
1309 show_changeset(ui, repo, changenode=n)
1309
1310
1310 def paths(ui, search=None):
1311 def paths(ui, search=None):
1311 """show definition of symbolic path names"""
1312 """show definition of symbolic path names"""
1312 try:
1313 try:
1313 repo = hg.repository(ui=ui)
1314 repo = hg.repository(ui=ui)
1314 except hg.RepoError:
1315 except hg.RepoError:
1315 pass
1316 pass
1316
1317
1317 if search:
1318 if search:
1318 for name, path in ui.configitems("paths"):
1319 for name, path in ui.configitems("paths"):
1319 if name == search:
1320 if name == search:
1320 ui.write("%s\n" % path)
1321 ui.write("%s\n" % path)
1321 return
1322 return
1322 ui.warn("not found!\n")
1323 ui.warn("not found!\n")
1323 return 1
1324 return 1
1324 else:
1325 else:
1325 for name, path in ui.configitems("paths"):
1326 for name, path in ui.configitems("paths"):
1326 ui.write("%s = %s\n" % (name, path))
1327 ui.write("%s = %s\n" % (name, path))
1327
1328
1328 def pull(ui, repo, source="default", **opts):
1329 def pull(ui, repo, source="default", **opts):
1329 """pull changes from the specified source"""
1330 """pull changes from the specified source"""
1330 source = ui.expandpath(source)
1331 source = ui.expandpath(source)
1331 ui.status('pulling from %s\n' % (source))
1332 ui.status('pulling from %s\n' % (source))
1332
1333
1333 if opts['ssh']:
1334 if opts['ssh']:
1334 ui.setconfig("ui", "ssh", opts['ssh'])
1335 ui.setconfig("ui", "ssh", opts['ssh'])
1335 if opts['remotecmd']:
1336 if opts['remotecmd']:
1336 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1337 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1337
1338
1338 other = hg.repository(ui, source)
1339 other = hg.repository(ui, source)
1339 r = repo.pull(other)
1340 r = repo.pull(other)
1340 if not r:
1341 if not r:
1341 if opts['update']:
1342 if opts['update']:
1342 return update(ui, repo)
1343 return update(ui, repo)
1343 else:
1344 else:
1344 ui.status("(run 'hg update' to get a working copy)\n")
1345 ui.status("(run 'hg update' to get a working copy)\n")
1345
1346
1346 return r
1347 return r
1347
1348
1348 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1349 def push(ui, repo, dest="default-push", force=False, ssh=None, remotecmd=None):
1349 """push changes to the specified destination"""
1350 """push changes to the specified destination"""
1350 dest = ui.expandpath(dest)
1351 dest = ui.expandpath(dest)
1351 ui.status('pushing to %s\n' % (dest))
1352 ui.status('pushing to %s\n' % (dest))
1352
1353
1353 if ssh:
1354 if ssh:
1354 ui.setconfig("ui", "ssh", ssh)
1355 ui.setconfig("ui", "ssh", ssh)
1355 if remotecmd:
1356 if remotecmd:
1356 ui.setconfig("ui", "remotecmd", remotecmd)
1357 ui.setconfig("ui", "remotecmd", remotecmd)
1357
1358
1358 other = hg.repository(ui, dest)
1359 other = hg.repository(ui, dest)
1359 r = repo.push(other, force)
1360 r = repo.push(other, force)
1360 return r
1361 return r
1361
1362
1362 def rawcommit(ui, repo, *flist, **rc):
1363 def rawcommit(ui, repo, *flist, **rc):
1363 "raw commit interface"
1364 "raw commit interface"
1364 if rc['text']:
1365 if rc['text']:
1365 ui.warn("Warning: -t and --text is deprecated,"
1366 ui.warn("Warning: -t and --text is deprecated,"
1366 " please use -m or --message instead.\n")
1367 " please use -m or --message instead.\n")
1367 message = rc['message'] or rc['text']
1368 message = rc['message'] or rc['text']
1368 if not message and rc['logfile']:
1369 if not message and rc['logfile']:
1369 try:
1370 try:
1370 message = open(rc['logfile']).read()
1371 message = open(rc['logfile']).read()
1371 except IOError:
1372 except IOError:
1372 pass
1373 pass
1373 if not message and not rc['logfile']:
1374 if not message and not rc['logfile']:
1374 raise util.Abort("missing commit message")
1375 raise util.Abort("missing commit message")
1375
1376
1376 files = relpath(repo, list(flist))
1377 files = relpath(repo, list(flist))
1377 if rc['files']:
1378 if rc['files']:
1378 files += open(rc['files']).read().splitlines()
1379 files += open(rc['files']).read().splitlines()
1379
1380
1380 rc['parent'] = map(repo.lookup, rc['parent'])
1381 rc['parent'] = map(repo.lookup, rc['parent'])
1381
1382
1382 try:
1383 try:
1383 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1384 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1384 except ValueError, inst:
1385 except ValueError, inst:
1385 raise util.Abort(str(inst))
1386 raise util.Abort(str(inst))
1386
1387
1387 def recover(ui, repo):
1388 def recover(ui, repo):
1388 """roll back an interrupted transaction"""
1389 """roll back an interrupted transaction"""
1389 repo.recover()
1390 repo.recover()
1390
1391
1391 def remove(ui, repo, pat, *pats, **opts):
1392 def remove(ui, repo, pat, *pats, **opts):
1392 """remove the specified files on the next commit"""
1393 """remove the specified files on the next commit"""
1393 names = []
1394 names = []
1394 def okaytoremove(abs, rel, exact):
1395 def okaytoremove(abs, rel, exact):
1395 c, a, d, u = repo.changes(files = [abs])
1396 c, a, d, u = repo.changes(files = [abs])
1396 reason = None
1397 reason = None
1397 if c: reason = 'is modified'
1398 if c: reason = 'is modified'
1398 elif a: reason = 'has been marked for add'
1399 elif a: reason = 'has been marked for add'
1399 elif u: reason = 'is not managed'
1400 elif u: reason = 'is not managed'
1400 if reason:
1401 if reason:
1401 if exact: ui.warn('not removing %s: file %s\n' % (rel, reason))
1402 if exact: ui.warn('not removing %s: file %s\n' % (rel, reason))
1402 else:
1403 else:
1403 return True
1404 return True
1404 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1405 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1405 if okaytoremove(abs, rel, exact):
1406 if okaytoremove(abs, rel, exact):
1406 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1407 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1407 names.append(abs)
1408 names.append(abs)
1408 for name in names:
1409 for name in names:
1409 try:
1410 try:
1410 os.unlink(name)
1411 os.unlink(name)
1411 except OSError, inst:
1412 except OSError, inst:
1412 if inst.errno != errno.ENOENT: raise
1413 if inst.errno != errno.ENOENT: raise
1413 repo.remove(names)
1414 repo.remove(names)
1414
1415
1415 def rename(ui, repo, *pats, **opts):
1416 def rename(ui, repo, *pats, **opts):
1416 """rename files; equivalent of copy + remove"""
1417 """rename files; equivalent of copy + remove"""
1417 errs, copied = docopy(ui, repo, pats, opts)
1418 errs, copied = docopy(ui, repo, pats, opts)
1418 names = []
1419 names = []
1419 for abs, rel, exact in copied:
1420 for abs, rel, exact in copied:
1420 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1421 if ui.verbose or not exact: ui.status('removing %s\n' % rel)
1421 try:
1422 try:
1422 os.unlink(rel)
1423 os.unlink(rel)
1423 except OSError, inst:
1424 except OSError, inst:
1424 if inst.errno != errno.ENOENT: raise
1425 if inst.errno != errno.ENOENT: raise
1425 names.append(abs)
1426 names.append(abs)
1426 repo.remove(names)
1427 repo.remove(names)
1427 return errs
1428 return errs
1428
1429
1429 def revert(ui, repo, *names, **opts):
1430 def revert(ui, repo, *names, **opts):
1430 """revert modified files or dirs back to their unmodified states"""
1431 """revert modified files or dirs back to their unmodified states"""
1431 node = opts['rev'] and repo.lookup(opts['rev']) or \
1432 node = opts['rev'] and repo.lookup(opts['rev']) or \
1432 repo.dirstate.parents()[0]
1433 repo.dirstate.parents()[0]
1433 root = os.path.realpath(repo.root)
1434 root = os.path.realpath(repo.root)
1434
1435
1435 def trimpath(p):
1436 def trimpath(p):
1436 p = os.path.realpath(p)
1437 p = os.path.realpath(p)
1437 if p.startswith(root):
1438 if p.startswith(root):
1438 rest = p[len(root):]
1439 rest = p[len(root):]
1439 if not rest:
1440 if not rest:
1440 return rest
1441 return rest
1441 if p.startswith(os.sep):
1442 if p.startswith(os.sep):
1442 return rest[1:]
1443 return rest[1:]
1443 return p
1444 return p
1444
1445
1445 relnames = map(trimpath, names or [os.getcwd()])
1446 relnames = map(trimpath, names or [os.getcwd()])
1446 chosen = {}
1447 chosen = {}
1447
1448
1448 def choose(name):
1449 def choose(name):
1449 def body(name):
1450 def body(name):
1450 for r in relnames:
1451 for r in relnames:
1451 if not name.startswith(r):
1452 if not name.startswith(r):
1452 continue
1453 continue
1453 rest = name[len(r):]
1454 rest = name[len(r):]
1454 if not rest:
1455 if not rest:
1455 return r, True
1456 return r, True
1456 depth = rest.count(os.sep)
1457 depth = rest.count(os.sep)
1457 if not r:
1458 if not r:
1458 if depth == 0 or not opts['nonrecursive']:
1459 if depth == 0 or not opts['nonrecursive']:
1459 return r, True
1460 return r, True
1460 elif rest[0] == os.sep:
1461 elif rest[0] == os.sep:
1461 if depth == 1 or not opts['nonrecursive']:
1462 if depth == 1 or not opts['nonrecursive']:
1462 return r, True
1463 return r, True
1463 return None, False
1464 return None, False
1464 relname, ret = body(name)
1465 relname, ret = body(name)
1465 if ret:
1466 if ret:
1466 chosen[relname] = 1
1467 chosen[relname] = 1
1467 return ret
1468 return ret
1468
1469
1469 r = repo.update(node, False, True, choose, False)
1470 r = repo.update(node, False, True, choose, False)
1470 for n in relnames:
1471 for n in relnames:
1471 if n not in chosen:
1472 if n not in chosen:
1472 ui.warn('error: no matches for %s\n' % n)
1473 ui.warn('error: no matches for %s\n' % n)
1473 r = 1
1474 r = 1
1474 sys.stdout.flush()
1475 sys.stdout.flush()
1475 return r
1476 return r
1476
1477
1477 def root(ui, repo):
1478 def root(ui, repo):
1478 """print the root (top) of the current working dir"""
1479 """print the root (top) of the current working dir"""
1479 ui.write(repo.root + "\n")
1480 ui.write(repo.root + "\n")
1480
1481
1481 def serve(ui, repo, **opts):
1482 def serve(ui, repo, **opts):
1482 """export the repository via HTTP"""
1483 """export the repository via HTTP"""
1483
1484
1484 if opts["stdio"]:
1485 if opts["stdio"]:
1485 fin, fout = sys.stdin, sys.stdout
1486 fin, fout = sys.stdin, sys.stdout
1486 sys.stdout = sys.stderr
1487 sys.stdout = sys.stderr
1487
1488
1488 def getarg():
1489 def getarg():
1489 argline = fin.readline()[:-1]
1490 argline = fin.readline()[:-1]
1490 arg, l = argline.split()
1491 arg, l = argline.split()
1491 val = fin.read(int(l))
1492 val = fin.read(int(l))
1492 return arg, val
1493 return arg, val
1493 def respond(v):
1494 def respond(v):
1494 fout.write("%d\n" % len(v))
1495 fout.write("%d\n" % len(v))
1495 fout.write(v)
1496 fout.write(v)
1496 fout.flush()
1497 fout.flush()
1497
1498
1498 lock = None
1499 lock = None
1499
1500
1500 while 1:
1501 while 1:
1501 cmd = fin.readline()[:-1]
1502 cmd = fin.readline()[:-1]
1502 if cmd == '':
1503 if cmd == '':
1503 return
1504 return
1504 if cmd == "heads":
1505 if cmd == "heads":
1505 h = repo.heads()
1506 h = repo.heads()
1506 respond(" ".join(map(hex, h)) + "\n")
1507 respond(" ".join(map(hex, h)) + "\n")
1507 if cmd == "lock":
1508 if cmd == "lock":
1508 lock = repo.lock()
1509 lock = repo.lock()
1509 respond("")
1510 respond("")
1510 if cmd == "unlock":
1511 if cmd == "unlock":
1511 if lock:
1512 if lock:
1512 lock.release()
1513 lock.release()
1513 lock = None
1514 lock = None
1514 respond("")
1515 respond("")
1515 elif cmd == "branches":
1516 elif cmd == "branches":
1516 arg, nodes = getarg()
1517 arg, nodes = getarg()
1517 nodes = map(bin, nodes.split(" "))
1518 nodes = map(bin, nodes.split(" "))
1518 r = []
1519 r = []
1519 for b in repo.branches(nodes):
1520 for b in repo.branches(nodes):
1520 r.append(" ".join(map(hex, b)) + "\n")
1521 r.append(" ".join(map(hex, b)) + "\n")
1521 respond("".join(r))
1522 respond("".join(r))
1522 elif cmd == "between":
1523 elif cmd == "between":
1523 arg, pairs = getarg()
1524 arg, pairs = getarg()
1524 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1525 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
1525 r = []
1526 r = []
1526 for b in repo.between(pairs):
1527 for b in repo.between(pairs):
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 == "changegroup":
1530 elif cmd == "changegroup":
1530 nodes = []
1531 nodes = []
1531 arg, roots = getarg()
1532 arg, roots = getarg()
1532 nodes = map(bin, roots.split(" "))
1533 nodes = map(bin, roots.split(" "))
1533
1534
1534 cg = repo.changegroup(nodes)
1535 cg = repo.changegroup(nodes)
1535 while 1:
1536 while 1:
1536 d = cg.read(4096)
1537 d = cg.read(4096)
1537 if not d:
1538 if not d:
1538 break
1539 break
1539 fout.write(d)
1540 fout.write(d)
1540
1541
1541 fout.flush()
1542 fout.flush()
1542
1543
1543 elif cmd == "addchangegroup":
1544 elif cmd == "addchangegroup":
1544 if not lock:
1545 if not lock:
1545 respond("not locked")
1546 respond("not locked")
1546 continue
1547 continue
1547 respond("")
1548 respond("")
1548
1549
1549 r = repo.addchangegroup(fin)
1550 r = repo.addchangegroup(fin)
1550 respond("")
1551 respond("")
1551
1552
1552 optlist = "name templates style address port ipv6 accesslog errorlog"
1553 optlist = "name templates style address port ipv6 accesslog errorlog"
1553 for o in optlist.split():
1554 for o in optlist.split():
1554 if opts[o]:
1555 if opts[o]:
1555 ui.setconfig("web", o, opts[o])
1556 ui.setconfig("web", o, opts[o])
1556
1557
1557 try:
1558 try:
1558 httpd = hgweb.create_server(repo)
1559 httpd = hgweb.create_server(repo)
1559 except socket.error, inst:
1560 except socket.error, inst:
1560 raise util.Abort('cannot start server: ' + inst.args[1])
1561 raise util.Abort('cannot start server: ' + inst.args[1])
1561
1562
1562 if ui.verbose:
1563 if ui.verbose:
1563 addr, port = httpd.socket.getsockname()
1564 addr, port = httpd.socket.getsockname()
1564 if addr == '0.0.0.0':
1565 if addr == '0.0.0.0':
1565 addr = socket.gethostname()
1566 addr = socket.gethostname()
1566 else:
1567 else:
1567 try:
1568 try:
1568 addr = socket.gethostbyaddr(addr)[0]
1569 addr = socket.gethostbyaddr(addr)[0]
1569 except socket.error:
1570 except socket.error:
1570 pass
1571 pass
1571 if port != 80:
1572 if port != 80:
1572 ui.status('listening at http://%s:%d/\n' % (addr, port))
1573 ui.status('listening at http://%s:%d/\n' % (addr, port))
1573 else:
1574 else:
1574 ui.status('listening at http://%s/\n' % addr)
1575 ui.status('listening at http://%s/\n' % addr)
1575 httpd.serve_forever()
1576 httpd.serve_forever()
1576
1577
1577 def status(ui, repo, *pats, **opts):
1578 def status(ui, repo, *pats, **opts):
1578 '''show changed files in the working directory
1579 '''show changed files in the working directory
1579
1580
1580 M = modified
1581 M = modified
1581 A = added
1582 A = added
1582 R = removed
1583 R = removed
1583 ? = not tracked
1584 ? = not tracked
1584 '''
1585 '''
1585
1586
1586 cwd = repo.getcwd()
1587 cwd = repo.getcwd()
1587 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1588 files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
1588 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1589 (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
1589 for n in repo.changes(files=files, match=matchfn)]
1590 for n in repo.changes(files=files, match=matchfn)]
1590
1591
1591 changetypes = [('modified', 'M', c),
1592 changetypes = [('modified', 'M', c),
1592 ('added', 'A', a),
1593 ('added', 'A', a),
1593 ('removed', 'R', d),
1594 ('removed', 'R', d),
1594 ('unknown', '?', u)]
1595 ('unknown', '?', u)]
1595
1596
1596 end = opts['print0'] and '\0' or '\n'
1597 end = opts['print0'] and '\0' or '\n'
1597
1598
1598 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1599 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
1599 or changetypes):
1600 or changetypes):
1600 if opts['no_status']:
1601 if opts['no_status']:
1601 format = "%%s%s" % end
1602 format = "%%s%s" % end
1602 else:
1603 else:
1603 format = "%s %%s%s" % (char, end);
1604 format = "%s %%s%s" % (char, end);
1604
1605
1605 for f in changes:
1606 for f in changes:
1606 ui.write(format % f)
1607 ui.write(format % f)
1607
1608
1608 def tag(ui, repo, name, rev=None, **opts):
1609 def tag(ui, repo, name, rev=None, **opts):
1609 """add a tag for the current tip or a given revision"""
1610 """add a tag for the current tip or a given revision"""
1610 if opts['text']:
1611 if opts['text']:
1611 ui.warn("Warning: -t and --text is deprecated,"
1612 ui.warn("Warning: -t and --text is deprecated,"
1612 " please use -m or --message instead.\n")
1613 " please use -m or --message instead.\n")
1613 if name == "tip":
1614 if name == "tip":
1614 raise util.Abort("the name 'tip' is reserved")
1615 raise util.Abort("the name 'tip' is reserved")
1615 if rev:
1616 if rev:
1616 r = hex(repo.lookup(rev))
1617 r = hex(repo.lookup(rev))
1617 else:
1618 else:
1618 r = hex(repo.changelog.tip())
1619 r = hex(repo.changelog.tip())
1619
1620
1620 if name.find(revrangesep) >= 0:
1621 if name.find(revrangesep) >= 0:
1621 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1622 raise util.Abort("'%s' cannot be used in a tag name" % revrangesep)
1622
1623
1623 if opts['local']:
1624 if opts['local']:
1624 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1625 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
1625 return
1626 return
1626
1627
1627 (c, a, d, u) = repo.changes()
1628 (c, a, d, u) = repo.changes()
1628 for x in (c, a, d, u):
1629 for x in (c, a, d, u):
1629 if ".hgtags" in x:
1630 if ".hgtags" in x:
1630 raise util.Abort("working copy of .hgtags is changed "
1631 raise util.Abort("working copy of .hgtags is changed "
1631 "(please commit .hgtags manually)")
1632 "(please commit .hgtags manually)")
1632
1633
1633 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1634 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
1634 if repo.dirstate.state(".hgtags") == '?':
1635 if repo.dirstate.state(".hgtags") == '?':
1635 repo.add([".hgtags"])
1636 repo.add([".hgtags"])
1636
1637
1637 message = (opts['message'] or opts['text'] or
1638 message = (opts['message'] or opts['text'] or
1638 "Added tag %s for changeset %s" % (name, r))
1639 "Added tag %s for changeset %s" % (name, r))
1639 try:
1640 try:
1640 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1641 repo.commit([".hgtags"], message, opts['user'], opts['date'])
1641 except ValueError, inst:
1642 except ValueError, inst:
1642 raise util.Abort(str(inst))
1643 raise util.Abort(str(inst))
1643
1644
1644 def tags(ui, repo):
1645 def tags(ui, repo):
1645 """list repository tags"""
1646 """list repository tags"""
1646
1647
1647 l = repo.tagslist()
1648 l = repo.tagslist()
1648 l.reverse()
1649 l.reverse()
1649 for t, n in l:
1650 for t, n in l:
1650 try:
1651 try:
1651 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1652 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
1652 except KeyError:
1653 except KeyError:
1653 r = " ?:?"
1654 r = " ?:?"
1654 ui.write("%-30s %s\n" % (t, r))
1655 ui.write("%-30s %s\n" % (t, r))
1655
1656
1656 def tip(ui, repo):
1657 def tip(ui, repo):
1657 """show the tip revision"""
1658 """show the tip revision"""
1658 n = repo.changelog.tip()
1659 n = repo.changelog.tip()
1659 show_changeset(ui, repo, changenode=n)
1660 show_changeset(ui, repo, changenode=n)
1660
1661
1661 def unbundle(ui, repo, fname):
1662 def unbundle(ui, repo, fname):
1662 """apply a changegroup file"""
1663 """apply a changegroup file"""
1663 f = urllib.urlopen(fname)
1664 f = urllib.urlopen(fname)
1664
1665
1665 if f.read(4) != "HG10":
1666 if f.read(4) != "HG10":
1666 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1667 raise util.Abort("%s: not a Mercurial bundle file" % fname)
1667
1668
1668 class bzread:
1669 class bzread:
1669 def __init__(self, f):
1670 def __init__(self, f):
1670 self.zd = bz2.BZ2Decompressor()
1671 self.zd = bz2.BZ2Decompressor()
1671 self.f = f
1672 self.f = f
1672 self.buf = ""
1673 self.buf = ""
1673 def read(self, l):
1674 def read(self, l):
1674 while l > len(self.buf):
1675 while l > len(self.buf):
1675 r = self.f.read(4096)
1676 r = self.f.read(4096)
1676 if r:
1677 if r:
1677 self.buf += self.zd.decompress(r)
1678 self.buf += self.zd.decompress(r)
1678 else:
1679 else:
1679 break
1680 break
1680 d, self.buf = self.buf[:l], self.buf[l:]
1681 d, self.buf = self.buf[:l], self.buf[l:]
1681 return d
1682 return d
1682
1683
1683 repo.addchangegroup(bzread(f))
1684 repo.addchangegroup(bzread(f))
1684
1685
1685 def undo(ui, repo):
1686 def undo(ui, repo):
1686 """undo the last commit or pull
1687 """undo the last commit or pull
1687
1688
1688 Roll back the last pull or commit transaction on the
1689 Roll back the last pull or commit transaction on the
1689 repository, restoring the project to its earlier state.
1690 repository, restoring the project to its earlier state.
1690
1691
1691 This command should be used with care. There is only one level of
1692 This command should be used with care. There is only one level of
1692 undo and there is no redo.
1693 undo and there is no redo.
1693
1694
1694 This command is not intended for use on public repositories. Once
1695 This command is not intended for use on public repositories. Once
1695 a change is visible for pull by other users, undoing it locally is
1696 a change is visible for pull by other users, undoing it locally is
1696 ineffective.
1697 ineffective.
1697 """
1698 """
1698 repo.undo()
1699 repo.undo()
1699
1700
1700 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1701 def update(ui, repo, node=None, merge=False, clean=False, branch=None):
1701 '''update or merge working directory
1702 '''update or merge working directory
1702
1703
1703 If there are no outstanding changes in the working directory and
1704 If there are no outstanding changes in the working directory and
1704 there is a linear relationship between the current version and the
1705 there is a linear relationship between the current version and the
1705 requested version, the result is the requested version.
1706 requested version, the result is the requested version.
1706
1707
1707 Otherwise the result is a merge between the contents of the
1708 Otherwise the result is a merge between the contents of the
1708 current working directory and the requested version. Files that
1709 current working directory and the requested version. Files that
1709 changed between either parent are marked as changed for the next
1710 changed between either parent are marked as changed for the next
1710 commit and a commit must be performed before any further updates
1711 commit and a commit must be performed before any further updates
1711 are allowed.
1712 are allowed.
1712 '''
1713 '''
1713 if branch:
1714 if branch:
1714 br = repo.branchlookup(branch=branch)
1715 br = repo.branchlookup(branch=branch)
1715 found = []
1716 found = []
1716 for x in br:
1717 for x in br:
1717 if branch in br[x]:
1718 if branch in br[x]:
1718 found.append(x)
1719 found.append(x)
1719 if len(found) > 1:
1720 if len(found) > 1:
1720 ui.warn("Found multiple heads for %s\n" % branch)
1721 ui.warn("Found multiple heads for %s\n" % branch)
1721 for x in found:
1722 for x in found:
1722 show_changeset(ui, repo, changenode=x, brinfo=br)
1723 show_changeset(ui, repo, changenode=x, brinfo=br)
1723 return 1
1724 return 1
1724 if len(found) == 1:
1725 if len(found) == 1:
1725 node = found[0]
1726 node = found[0]
1726 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1727 ui.warn("Using head %s for branch %s\n" % (short(node), branch))
1727 else:
1728 else:
1728 ui.warn("branch %s not found\n" % (branch))
1729 ui.warn("branch %s not found\n" % (branch))
1729 return 1
1730 return 1
1730 else:
1731 else:
1731 node = node and repo.lookup(node) or repo.changelog.tip()
1732 node = node and repo.lookup(node) or repo.changelog.tip()
1732 return repo.update(node, allow=merge, force=clean)
1733 return repo.update(node, allow=merge, force=clean)
1733
1734
1734 def verify(ui, repo):
1735 def verify(ui, repo):
1735 """verify the integrity of the repository"""
1736 """verify the integrity of the repository"""
1736 return repo.verify()
1737 return repo.verify()
1737
1738
1738 # Command options and aliases are listed here, alphabetically
1739 # Command options and aliases are listed here, alphabetically
1739
1740
1740 table = {
1741 table = {
1741 "^add":
1742 "^add":
1742 (add,
1743 (add,
1743 [('I', 'include', [], 'include path in search'),
1744 [('I', 'include', [], 'include path in search'),
1744 ('X', 'exclude', [], 'exclude path from search')],
1745 ('X', 'exclude', [], 'exclude path from search')],
1745 "hg add [OPTION]... [FILE]..."),
1746 "hg add [OPTION]... [FILE]..."),
1746 "addremove":
1747 "addremove":
1747 (addremove,
1748 (addremove,
1748 [('I', 'include', [], 'include path in search'),
1749 [('I', 'include', [], 'include path in search'),
1749 ('X', 'exclude', [], 'exclude path from search')],
1750 ('X', 'exclude', [], 'exclude path from search')],
1750 "hg addremove [OPTION]... [FILE]..."),
1751 "hg addremove [OPTION]... [FILE]..."),
1751 "^annotate":
1752 "^annotate":
1752 (annotate,
1753 (annotate,
1753 [('r', 'rev', '', 'revision'),
1754 [('r', 'rev', '', 'revision'),
1754 ('a', 'text', None, 'treat all files as text'),
1755 ('a', 'text', None, 'treat all files as text'),
1755 ('u', 'user', None, 'show user'),
1756 ('u', 'user', None, 'show user'),
1756 ('n', 'number', None, 'show revision number'),
1757 ('n', 'number', None, 'show revision number'),
1757 ('c', 'changeset', None, 'show changeset'),
1758 ('c', 'changeset', None, 'show changeset'),
1758 ('I', 'include', [], 'include path in search'),
1759 ('I', 'include', [], 'include path in search'),
1759 ('X', 'exclude', [], 'exclude path from search')],
1760 ('X', 'exclude', [], 'exclude path from search')],
1760 'hg annotate [OPTION]... FILE...'),
1761 'hg annotate [OPTION]... FILE...'),
1761 "bundle":
1762 "bundle":
1762 (bundle,
1763 (bundle,
1763 [],
1764 [],
1764 'hg bundle FILE DEST'),
1765 'hg bundle FILE DEST'),
1765 "cat":
1766 "cat":
1766 (cat,
1767 (cat,
1767 [('I', 'include', [], 'include path in search'),
1768 [('I', 'include', [], 'include path in search'),
1768 ('X', 'exclude', [], 'exclude path from search'),
1769 ('X', 'exclude', [], 'exclude path from search'),
1769 ('o', 'output', "", 'output to file'),
1770 ('o', 'output', "", 'output to file'),
1770 ('r', 'rev', '', 'revision')],
1771 ('r', 'rev', '', 'revision')],
1771 'hg cat [OPTION]... FILE...'),
1772 'hg cat [OPTION]... FILE...'),
1772 "^clone":
1773 "^clone":
1773 (clone,
1774 (clone,
1774 [('U', 'noupdate', None, 'skip update after cloning'),
1775 [('U', 'noupdate', None, 'skip update after cloning'),
1775 ('e', 'ssh', "", 'ssh command'),
1776 ('e', 'ssh', "", 'ssh command'),
1776 ('', 'pull', None, 'use pull protocol to copy metadata'),
1777 ('', 'pull', None, 'use pull protocol to copy metadata'),
1777 ('', 'remotecmd', "", 'remote hg command')],
1778 ('', 'remotecmd', "", 'remote hg command')],
1778 'hg clone [OPTION]... SOURCE [DEST]'),
1779 'hg clone [OPTION]... SOURCE [DEST]'),
1779 "^commit|ci":
1780 "^commit|ci":
1780 (commit,
1781 (commit,
1781 [('A', 'addremove', None, 'run add/remove during commit'),
1782 [('A', 'addremove', None, 'run add/remove during commit'),
1782 ('I', 'include', [], 'include path in search'),
1783 ('I', 'include', [], 'include path in search'),
1783 ('X', 'exclude', [], 'exclude path from search'),
1784 ('X', 'exclude', [], 'exclude path from search'),
1784 ('m', 'message', "", 'commit message'),
1785 ('m', 'message', "", 'commit message'),
1785 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1786 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1786 ('l', 'logfile', "", 'commit message file'),
1787 ('l', 'logfile', "", 'commit message file'),
1787 ('d', 'date', "", 'date code'),
1788 ('d', 'date', "", 'date code'),
1788 ('u', 'user', "", 'user')],
1789 ('u', 'user', "", 'user')],
1789 'hg commit [OPTION]... [FILE]...'),
1790 'hg commit [OPTION]... [FILE]...'),
1790 "copy|cp": (copy,
1791 "copy|cp": (copy,
1791 [('I', 'include', [], 'include path in search'),
1792 [('I', 'include', [], 'include path in search'),
1792 ('X', 'exclude', [], 'exclude path from search'),
1793 ('X', 'exclude', [], 'exclude path from search'),
1793 ('A', 'after', None, 'record a copy after it has happened'),
1794 ('A', 'after', None, 'record a copy after it has happened'),
1794 ('f', 'force', None, 'replace destination if it exists'),
1795 ('f', 'force', None, 'replace destination if it exists'),
1795 ('p', 'parents', None, 'append source path to dest')],
1796 ('p', 'parents', None, 'append source path to dest')],
1796 'hg copy [OPTION]... [SOURCE]... DEST'),
1797 'hg copy [OPTION]... [SOURCE]... DEST'),
1797 "debugancestor": (debugancestor, [], 'debugancestor INDEX REV1 REV2'),
1798 "debugancestor": (debugancestor, [], 'debugancestor INDEX REV1 REV2'),
1798 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1799 "debugcheckstate": (debugcheckstate, [], 'debugcheckstate'),
1799 "debugconfig": (debugconfig, [], 'debugconfig'),
1800 "debugconfig": (debugconfig, [], 'debugconfig'),
1800 "debugstate": (debugstate, [], 'debugstate'),
1801 "debugstate": (debugstate, [], 'debugstate'),
1801 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1802 "debugdata": (debugdata, [], 'debugdata FILE REV'),
1802 "debugindex": (debugindex, [], 'debugindex FILE'),
1803 "debugindex": (debugindex, [], 'debugindex FILE'),
1803 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1804 "debugindexdot": (debugindexdot, [], 'debugindexdot FILE'),
1804 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1805 "debugrename": (debugrename, [], 'debugrename FILE [REV]'),
1805 "debugwalk":
1806 "debugwalk":
1806 (debugwalk,
1807 (debugwalk,
1807 [('I', 'include', [], 'include path in search'),
1808 [('I', 'include', [], 'include path in search'),
1808 ('X', 'exclude', [], 'exclude path from search')],
1809 ('X', 'exclude', [], 'exclude path from search')],
1809 'debugwalk [OPTION]... [FILE]...'),
1810 'debugwalk [OPTION]... [FILE]...'),
1810 "^diff":
1811 "^diff":
1811 (diff,
1812 (diff,
1812 [('r', 'rev', [], 'revision'),
1813 [('r', 'rev', [], 'revision'),
1813 ('a', 'text', None, 'treat all files as text'),
1814 ('a', 'text', None, 'treat all files as text'),
1814 ('I', 'include', [], 'include path in search'),
1815 ('I', 'include', [], 'include path in search'),
1815 ('X', 'exclude', [], 'exclude path from search')],
1816 ('X', 'exclude', [], 'exclude path from search')],
1816 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1817 'hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...'),
1817 "^export":
1818 "^export":
1818 (export,
1819 (export,
1819 [('o', 'output', "", 'output to file'),
1820 [('o', 'output', "", 'output to file'),
1820 ('a', 'text', None, 'treat all files as text')],
1821 ('a', 'text', None, 'treat all files as text')],
1821 "hg export [-a] [-o OUTFILE] REV..."),
1822 "hg export [-a] [-o OUTFILE] REV..."),
1822 "forget":
1823 "forget":
1823 (forget,
1824 (forget,
1824 [('I', 'include', [], 'include path in search'),
1825 [('I', 'include', [], 'include path in search'),
1825 ('X', 'exclude', [], 'exclude path from search')],
1826 ('X', 'exclude', [], 'exclude path from search')],
1826 "hg forget [OPTION]... FILE..."),
1827 "hg forget [OPTION]... FILE..."),
1827 "grep":
1828 "grep":
1828 (grep,
1829 (grep,
1829 [('0', 'print0', None, 'end fields with NUL'),
1830 [('0', 'print0', None, 'end fields with NUL'),
1830 ('I', 'include', [], 'include path in search'),
1831 ('I', 'include', [], 'include path in search'),
1831 ('X', 'exclude', [], 'include path in search'),
1832 ('X', 'exclude', [], 'include path in search'),
1832 ('', 'all', None, 'print all revisions with matches'),
1833 ('', 'all', None, 'print all revisions with matches'),
1833 ('i', 'ignore-case', None, 'ignore case when matching'),
1834 ('i', 'ignore-case', None, 'ignore case when matching'),
1834 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1835 ('l', 'files-with-matches', None, 'print names of files and revs with matches'),
1835 ('n', 'line-number', None, 'print line numbers'),
1836 ('n', 'line-number', None, 'print line numbers'),
1836 ('r', 'rev', [], 'search in revision rev'),
1837 ('r', 'rev', [], 'search in revision rev'),
1837 ('u', 'user', None, 'print user who made change')],
1838 ('u', 'user', None, 'print user who made change')],
1838 "hg grep [OPTION]... PATTERN [FILE]..."),
1839 "hg grep [OPTION]... PATTERN [FILE]..."),
1839 "heads":
1840 "heads":
1840 (heads,
1841 (heads,
1841 [('b', 'branches', None, 'find branch info')],
1842 [('b', 'branches', None, 'find branch info')],
1842 'hg heads [-b]'),
1843 'hg heads [-b]'),
1843 "help": (help_, [], 'hg help [COMMAND]'),
1844 "help": (help_, [], 'hg help [COMMAND]'),
1844 "identify|id": (identify, [], 'hg identify'),
1845 "identify|id": (identify, [], 'hg identify'),
1845 "import|patch":
1846 "import|patch":
1846 (import_,
1847 (import_,
1847 [('p', 'strip', 1, 'path strip'),
1848 [('p', 'strip', 1, 'path strip'),
1848 ('f', 'force', None, 'skip check for outstanding changes'),
1849 ('f', 'force', None, 'skip check for outstanding changes'),
1849 ('b', 'base', "", 'base path')],
1850 ('b', 'base', "", 'base path')],
1850 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1851 "hg import [-f] [-p NUM] [-b BASE] PATCH..."),
1851 "incoming|in": (incoming,
1852 "incoming|in": (incoming,
1852 [('p', 'patch', None, 'show patch')],
1853 [('p', 'patch', None, 'show patch')],
1853 'hg incoming [-p] [SOURCE]'),
1854 'hg incoming [-p] [SOURCE]'),
1854 "^init": (init, [], 'hg init [DEST]'),
1855 "^init": (init, [], 'hg init [DEST]'),
1855 "locate":
1856 "locate":
1856 (locate,
1857 (locate,
1857 [('r', 'rev', '', 'revision'),
1858 [('r', 'rev', '', 'revision'),
1858 ('0', 'print0', None, 'end filenames with NUL'),
1859 ('0', 'print0', None, 'end filenames with NUL'),
1859 ('f', 'fullpath', None, 'print complete paths'),
1860 ('f', 'fullpath', None, 'print complete paths'),
1860 ('I', 'include', [], 'include path in search'),
1861 ('I', 'include', [], 'include path in search'),
1861 ('X', 'exclude', [], 'exclude path from search')],
1862 ('X', 'exclude', [], 'exclude path from search')],
1862 'hg locate [OPTION]... [PATTERN]...'),
1863 'hg locate [OPTION]... [PATTERN]...'),
1863 "^log|history":
1864 "^log|history":
1864 (log,
1865 (log,
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 ('b', 'branch', None, 'show branches'),
1868 ('b', 'branch', None, 'show branches'),
1868 ('r', 'rev', [], 'revision'),
1869 ('r', 'rev', [], 'revision'),
1869 ('p', 'patch', None, 'show patch')],
1870 ('p', 'patch', None, 'show patch')],
1870 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1871 'hg log [-I] [-X] [-r REV]... [-p] [FILE]'),
1871 "manifest": (manifest, [], 'hg manifest [REV]'),
1872 "manifest": (manifest, [], 'hg manifest [REV]'),
1872 "outgoing|out": (outgoing,
1873 "outgoing|out": (outgoing,
1873 [('p', 'patch', None, 'show patch')],
1874 [('p', 'patch', None, 'show patch')],
1874 'hg outgoing [-p] [DEST]'),
1875 'hg outgoing [-p] [DEST]'),
1875 "parents": (parents, [], 'hg parents [REV]'),
1876 "parents": (parents, [], 'hg parents [REV]'),
1876 "paths": (paths, [], 'hg paths [NAME]'),
1877 "paths": (paths, [], 'hg paths [NAME]'),
1877 "^pull":
1878 "^pull":
1878 (pull,
1879 (pull,
1879 [('u', 'update', None, 'update working directory'),
1880 [('u', 'update', None, 'update working directory'),
1880 ('e', 'ssh', "", 'ssh command'),
1881 ('e', 'ssh', "", 'ssh command'),
1881 ('', 'remotecmd', "", 'remote hg command')],
1882 ('', 'remotecmd', "", 'remote hg command')],
1882 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1883 'hg pull [-u] [-e FILE] [--remotecmd FILE] [SOURCE]'),
1883 "^push":
1884 "^push":
1884 (push,
1885 (push,
1885 [('f', 'force', None, 'force push'),
1886 [('f', 'force', None, 'force push'),
1886 ('e', 'ssh', "", 'ssh command'),
1887 ('e', 'ssh', "", 'ssh command'),
1887 ('', 'remotecmd', "", 'remote hg command')],
1888 ('', 'remotecmd', "", 'remote hg command')],
1888 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1889 'hg push [-f] [-e FILE] [--remotecmd FILE] [DEST]'),
1889 "rawcommit":
1890 "rawcommit":
1890 (rawcommit,
1891 (rawcommit,
1891 [('p', 'parent', [], 'parent'),
1892 [('p', 'parent', [], 'parent'),
1892 ('d', 'date', "", 'date code'),
1893 ('d', 'date', "", 'date code'),
1893 ('u', 'user', "", 'user'),
1894 ('u', 'user', "", 'user'),
1894 ('F', 'files', "", 'file list'),
1895 ('F', 'files', "", 'file list'),
1895 ('m', 'message', "", 'commit message'),
1896 ('m', 'message', "", 'commit message'),
1896 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1897 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1897 ('l', 'logfile', "", 'commit message file')],
1898 ('l', 'logfile', "", 'commit message file')],
1898 'hg rawcommit [OPTION]... [FILE]...'),
1899 'hg rawcommit [OPTION]... [FILE]...'),
1899 "recover": (recover, [], "hg recover"),
1900 "recover": (recover, [], "hg recover"),
1900 "^remove|rm": (remove,
1901 "^remove|rm": (remove,
1901 [('I', 'include', [], 'include path in search'),
1902 [('I', 'include', [], 'include path in search'),
1902 ('X', 'exclude', [], 'exclude path from search')],
1903 ('X', 'exclude', [], 'exclude path from search')],
1903 "hg remove [OPTION]... FILE..."),
1904 "hg remove [OPTION]... FILE..."),
1904 "rename|mv": (rename,
1905 "rename|mv": (rename,
1905 [('I', 'include', [], 'include path in search'),
1906 [('I', 'include', [], 'include path in search'),
1906 ('X', 'exclude', [], 'exclude path from search'),
1907 ('X', 'exclude', [], 'exclude path from search'),
1907 ('A', 'after', None, 'record a copy after it has happened'),
1908 ('A', 'after', None, 'record a copy after it has happened'),
1908 ('f', 'force', None, 'replace destination if it exists'),
1909 ('f', 'force', None, 'replace destination if it exists'),
1909 ('p', 'parents', None, 'append source path to dest')],
1910 ('p', 'parents', None, 'append source path to dest')],
1910 'hg rename [OPTION]... [SOURCE]... DEST'),
1911 'hg rename [OPTION]... [SOURCE]... DEST'),
1911 "^revert":
1912 "^revert":
1912 (revert,
1913 (revert,
1913 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1914 [("n", "nonrecursive", None, "don't recurse into subdirs"),
1914 ("r", "rev", "", "revision")],
1915 ("r", "rev", "", "revision")],
1915 "hg revert [-n] [-r REV] [NAME]..."),
1916 "hg revert [-n] [-r REV] [NAME]..."),
1916 "root": (root, [], "hg root"),
1917 "root": (root, [], "hg root"),
1917 "^serve":
1918 "^serve":
1918 (serve,
1919 (serve,
1919 [('A', 'accesslog', '', 'access log file'),
1920 [('A', 'accesslog', '', 'access log file'),
1920 ('E', 'errorlog', '', 'error log file'),
1921 ('E', 'errorlog', '', 'error log file'),
1921 ('p', 'port', 0, 'listen port'),
1922 ('p', 'port', 0, 'listen port'),
1922 ('a', 'address', '', 'interface address'),
1923 ('a', 'address', '', 'interface address'),
1923 ('n', 'name', "", 'repository name'),
1924 ('n', 'name', "", 'repository name'),
1924 ('', 'stdio', None, 'for remote clients'),
1925 ('', 'stdio', None, 'for remote clients'),
1925 ('t', 'templates', "", 'template directory'),
1926 ('t', 'templates', "", 'template directory'),
1926 ('', 'style', "", 'template style'),
1927 ('', 'style', "", 'template style'),
1927 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1928 ('6', 'ipv6', None, 'use IPv6 in addition to IPv4')],
1928 "hg serve [OPTION]..."),
1929 "hg serve [OPTION]..."),
1929 "^status":
1930 "^status":
1930 (status,
1931 (status,
1931 [('m', 'modified', None, 'show only modified files'),
1932 [('m', 'modified', None, 'show only modified files'),
1932 ('a', 'added', None, 'show only added files'),
1933 ('a', 'added', None, 'show only added files'),
1933 ('r', 'removed', None, 'show only removed files'),
1934 ('r', 'removed', None, 'show only removed files'),
1934 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1935 ('u', 'unknown', None, 'show only unknown (not tracked) files'),
1935 ('n', 'no-status', None, 'hide status prefix'),
1936 ('n', 'no-status', None, 'hide status prefix'),
1936 ('0', 'print0', None, 'end filenames with NUL'),
1937 ('0', 'print0', None, 'end filenames with NUL'),
1937 ('I', 'include', [], 'include path in search'),
1938 ('I', 'include', [], 'include path in search'),
1938 ('X', 'exclude', [], 'exclude path from search')],
1939 ('X', 'exclude', [], 'exclude path from search')],
1939 "hg status [OPTION]... [FILE]..."),
1940 "hg status [OPTION]... [FILE]..."),
1940 "tag":
1941 "tag":
1941 (tag,
1942 (tag,
1942 [('l', 'local', None, 'make the tag local'),
1943 [('l', 'local', None, 'make the tag local'),
1943 ('m', 'message', "", 'commit message'),
1944 ('m', 'message', "", 'commit message'),
1944 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1945 ('t', 'text', "", 'commit message (deprecated: use -m)'),
1945 ('d', 'date', "", 'date code'),
1946 ('d', 'date', "", 'date code'),
1946 ('u', 'user', "", 'user')],
1947 ('u', 'user', "", 'user')],
1947 'hg tag [OPTION]... NAME [REV]'),
1948 'hg tag [OPTION]... NAME [REV]'),
1948 "tags": (tags, [], 'hg tags'),
1949 "tags": (tags, [], 'hg tags'),
1949 "tip": (tip, [], 'hg tip'),
1950 "tip": (tip, [], 'hg tip'),
1950 "unbundle":
1951 "unbundle":
1951 (unbundle,
1952 (unbundle,
1952 [],
1953 [],
1953 'hg unbundle FILE'),
1954 'hg unbundle FILE'),
1954 "undo": (undo, [], 'hg undo'),
1955 "undo": (undo, [], 'hg undo'),
1955 "^update|up|checkout|co":
1956 "^update|up|checkout|co":
1956 (update,
1957 (update,
1957 [('b', 'branch', "", 'checkout the head of a specific branch'),
1958 [('b', 'branch', "", 'checkout the head of a specific branch'),
1958 ('m', 'merge', None, 'allow merging of conflicts'),
1959 ('m', 'merge', None, 'allow merging of conflicts'),
1959 ('C', 'clean', None, 'overwrite locally modified files')],
1960 ('C', 'clean', None, 'overwrite locally modified files')],
1960 'hg update [-b TAG] [-m] [-C] [REV]'),
1961 'hg update [-b TAG] [-m] [-C] [REV]'),
1961 "verify": (verify, [], 'hg verify'),
1962 "verify": (verify, [], 'hg verify'),
1962 "version": (show_version, [], 'hg version'),
1963 "version": (show_version, [], 'hg version'),
1963 }
1964 }
1964
1965
1965 globalopts = [
1966 globalopts = [
1966 ('R', 'repository', "", 'repository root directory'),
1967 ('R', 'repository', "", 'repository root directory'),
1967 ('', 'cwd', '', 'change working directory'),
1968 ('', 'cwd', '', 'change working directory'),
1968 ('y', 'noninteractive', None, 'run non-interactively'),
1969 ('y', 'noninteractive', None, 'run non-interactively'),
1969 ('q', 'quiet', None, 'quiet mode'),
1970 ('q', 'quiet', None, 'quiet mode'),
1970 ('v', 'verbose', None, 'verbose mode'),
1971 ('v', 'verbose', None, 'verbose mode'),
1971 ('', 'debug', None, 'debug mode'),
1972 ('', 'debug', None, 'debug mode'),
1972 ('', 'debugger', None, 'start debugger'),
1973 ('', 'debugger', None, 'start debugger'),
1973 ('', 'traceback', None, 'print traceback on exception'),
1974 ('', 'traceback', None, 'print traceback on exception'),
1974 ('', 'time', None, 'time how long the command takes'),
1975 ('', 'time', None, 'time how long the command takes'),
1975 ('', 'profile', None, 'profile'),
1976 ('', 'profile', None, 'profile'),
1976 ('', 'version', None, 'output version information and exit'),
1977 ('', 'version', None, 'output version information and exit'),
1977 ('h', 'help', None, 'display help and exit'),
1978 ('h', 'help', None, 'display help and exit'),
1978 ]
1979 ]
1979
1980
1980 norepo = ("clone init version help debugancestor debugconfig debugdata"
1981 norepo = ("clone init version help debugancestor debugconfig debugdata"
1981 " debugindex debugindexdot paths")
1982 " debugindex debugindexdot paths")
1982
1983
1983 def find(cmd):
1984 def find(cmd):
1984 for e in table.keys():
1985 for e in table.keys():
1985 if re.match("(%s)$" % e, cmd):
1986 if re.match("(%s)$" % e, cmd):
1986 return e, table[e]
1987 return e, table[e]
1987
1988
1988 raise UnknownCommand(cmd)
1989 raise UnknownCommand(cmd)
1989
1990
1990 class SignalInterrupt(Exception):
1991 class SignalInterrupt(Exception):
1991 """Exception raised on SIGTERM and SIGHUP."""
1992 """Exception raised on SIGTERM and SIGHUP."""
1992
1993
1993 def catchterm(*args):
1994 def catchterm(*args):
1994 raise SignalInterrupt
1995 raise SignalInterrupt
1995
1996
1996 def run():
1997 def run():
1997 sys.exit(dispatch(sys.argv[1:]))
1998 sys.exit(dispatch(sys.argv[1:]))
1998
1999
1999 class ParseError(Exception):
2000 class ParseError(Exception):
2000 """Exception raised on errors in parsing the command line."""
2001 """Exception raised on errors in parsing the command line."""
2001
2002
2002 def parse(args):
2003 def parse(args):
2003 options = {}
2004 options = {}
2004 cmdoptions = {}
2005 cmdoptions = {}
2005
2006
2006 try:
2007 try:
2007 args = fancyopts.fancyopts(args, globalopts, options)
2008 args = fancyopts.fancyopts(args, globalopts, options)
2008 except fancyopts.getopt.GetoptError, inst:
2009 except fancyopts.getopt.GetoptError, inst:
2009 raise ParseError(None, inst)
2010 raise ParseError(None, inst)
2010
2011
2011 if args:
2012 if args:
2012 cmd, args = args[0], args[1:]
2013 cmd, args = args[0], args[1:]
2013 i = find(cmd)[1]
2014 i = find(cmd)[1]
2014 c = list(i[1])
2015 c = list(i[1])
2015 else:
2016 else:
2016 cmd = None
2017 cmd = None
2017 c = []
2018 c = []
2018
2019
2019 # combine global options into local
2020 # combine global options into local
2020 for o in globalopts:
2021 for o in globalopts:
2021 c.append((o[0], o[1], options[o[1]], o[3]))
2022 c.append((o[0], o[1], options[o[1]], o[3]))
2022
2023
2023 try:
2024 try:
2024 args = fancyopts.fancyopts(args, c, cmdoptions)
2025 args = fancyopts.fancyopts(args, c, cmdoptions)
2025 except fancyopts.getopt.GetoptError, inst:
2026 except fancyopts.getopt.GetoptError, inst:
2026 raise ParseError(cmd, inst)
2027 raise ParseError(cmd, inst)
2027
2028
2028 # separate global options back out
2029 # separate global options back out
2029 for o in globalopts:
2030 for o in globalopts:
2030 n = o[1]
2031 n = o[1]
2031 options[n] = cmdoptions[n]
2032 options[n] = cmdoptions[n]
2032 del cmdoptions[n]
2033 del cmdoptions[n]
2033
2034
2034 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2035 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2035
2036
2036 def dispatch(args):
2037 def dispatch(args):
2037 signal.signal(signal.SIGTERM, catchterm)
2038 signal.signal(signal.SIGTERM, catchterm)
2038 try:
2039 try:
2039 signal.signal(signal.SIGHUP, catchterm)
2040 signal.signal(signal.SIGHUP, catchterm)
2040 except AttributeError:
2041 except AttributeError:
2041 pass
2042 pass
2042
2043
2043 u = ui.ui()
2044 u = ui.ui()
2044 external = []
2045 external = []
2045 for x in u.extensions():
2046 for x in u.extensions():
2046 if x[1]:
2047 if x[1]:
2047 mod = imp.load_source(x[0], x[1])
2048 mod = imp.load_source(x[0], x[1])
2048 else:
2049 else:
2049 def importh(name):
2050 def importh(name):
2050 mod = __import__(name)
2051 mod = __import__(name)
2051 components = name.split('.')
2052 components = name.split('.')
2052 for comp in components[1:]:
2053 for comp in components[1:]:
2053 mod = getattr(mod, comp)
2054 mod = getattr(mod, comp)
2054 return mod
2055 return mod
2055 mod = importh(x[0])
2056 mod = importh(x[0])
2056 external.append(mod)
2057 external.append(mod)
2057 for x in external:
2058 for x in external:
2058 cmdtable = getattr(x, 'cmdtable', {})
2059 cmdtable = getattr(x, 'cmdtable', {})
2059 for t in cmdtable:
2060 for t in cmdtable:
2060 if t in table:
2061 if t in table:
2061 u.warn("module %s overrides %s\n" % (x.__name__, t))
2062 u.warn("module %s overrides %s\n" % (x.__name__, t))
2062 table.update(cmdtable)
2063 table.update(cmdtable)
2063
2064
2064 try:
2065 try:
2065 cmd, func, args, options, cmdoptions = parse(args)
2066 cmd, func, args, options, cmdoptions = parse(args)
2066 except ParseError, inst:
2067 except ParseError, inst:
2067 if inst.args[0]:
2068 if inst.args[0]:
2068 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
2069 u.warn("hg %s: %s\n" % (inst.args[0], inst.args[1]))
2069 help_(u, inst.args[0])
2070 help_(u, inst.args[0])
2070 else:
2071 else:
2071 u.warn("hg: %s\n" % inst.args[1])
2072 u.warn("hg: %s\n" % inst.args[1])
2072 help_(u, 'shortlist')
2073 help_(u, 'shortlist')
2073 sys.exit(-1)
2074 sys.exit(-1)
2074 except UnknownCommand, inst:
2075 except UnknownCommand, inst:
2075 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2076 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2076 help_(u, 'shortlist')
2077 help_(u, 'shortlist')
2077 sys.exit(1)
2078 sys.exit(1)
2078
2079
2079 if options["time"]:
2080 if options["time"]:
2080 def get_times():
2081 def get_times():
2081 t = os.times()
2082 t = os.times()
2082 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2083 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2083 t = (t[0], t[1], t[2], t[3], time.clock())
2084 t = (t[0], t[1], t[2], t[3], time.clock())
2084 return t
2085 return t
2085 s = get_times()
2086 s = get_times()
2086 def print_time():
2087 def print_time():
2087 t = get_times()
2088 t = get_times()
2088 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
2089 u.warn("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n" %
2089 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2090 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2090 atexit.register(print_time)
2091 atexit.register(print_time)
2091
2092
2092 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2093 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2093 not options["noninteractive"])
2094 not options["noninteractive"])
2094
2095
2095 # enter the debugger before command execution
2096 # enter the debugger before command execution
2096 if options['debugger']:
2097 if options['debugger']:
2097 pdb.set_trace()
2098 pdb.set_trace()
2098
2099
2099 try:
2100 try:
2100 try:
2101 try:
2101 if options['help']:
2102 if options['help']:
2102 help_(u, cmd, options['version'])
2103 help_(u, cmd, options['version'])
2103 sys.exit(0)
2104 sys.exit(0)
2104 elif options['version']:
2105 elif options['version']:
2105 show_version(u)
2106 show_version(u)
2106 sys.exit(0)
2107 sys.exit(0)
2107 elif not cmd:
2108 elif not cmd:
2108 help_(u, 'shortlist')
2109 help_(u, 'shortlist')
2109 sys.exit(0)
2110 sys.exit(0)
2110
2111
2111 if options['cwd']:
2112 if options['cwd']:
2112 try:
2113 try:
2113 os.chdir(options['cwd'])
2114 os.chdir(options['cwd'])
2114 except OSError, inst:
2115 except OSError, inst:
2115 raise util.Abort('%s: %s' %
2116 raise util.Abort('%s: %s' %
2116 (options['cwd'], inst.strerror))
2117 (options['cwd'], inst.strerror))
2117
2118
2118 if cmd not in norepo.split():
2119 if cmd not in norepo.split():
2119 path = options["repository"] or ""
2120 path = options["repository"] or ""
2120 repo = hg.repository(ui=u, path=path)
2121 repo = hg.repository(ui=u, path=path)
2121 for x in external:
2122 for x in external:
2122 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2123 if hasattr(x, 'reposetup'): x.reposetup(u, repo)
2123 d = lambda: func(u, repo, *args, **cmdoptions)
2124 d = lambda: func(u, repo, *args, **cmdoptions)
2124 else:
2125 else:
2125 d = lambda: func(u, *args, **cmdoptions)
2126 d = lambda: func(u, *args, **cmdoptions)
2126
2127
2127 if options['profile']:
2128 if options['profile']:
2128 import hotshot, hotshot.stats
2129 import hotshot, hotshot.stats
2129 prof = hotshot.Profile("hg.prof")
2130 prof = hotshot.Profile("hg.prof")
2130 r = prof.runcall(d)
2131 r = prof.runcall(d)
2131 prof.close()
2132 prof.close()
2132 stats = hotshot.stats.load("hg.prof")
2133 stats = hotshot.stats.load("hg.prof")
2133 stats.strip_dirs()
2134 stats.strip_dirs()
2134 stats.sort_stats('time', 'calls')
2135 stats.sort_stats('time', 'calls')
2135 stats.print_stats(40)
2136 stats.print_stats(40)
2136 return r
2137 return r
2137 else:
2138 else:
2138 return d()
2139 return d()
2139 except:
2140 except:
2140 # enter the debugger when we hit an exception
2141 # enter the debugger when we hit an exception
2141 if options['debugger']:
2142 if options['debugger']:
2142 pdb.post_mortem(sys.exc_info()[2])
2143 pdb.post_mortem(sys.exc_info()[2])
2143 if options['traceback']:
2144 if options['traceback']:
2144 traceback.print_exc()
2145 traceback.print_exc()
2145 raise
2146 raise
2146 except hg.RepoError, inst:
2147 except hg.RepoError, inst:
2147 u.warn("abort: ", inst, "!\n")
2148 u.warn("abort: ", inst, "!\n")
2148 except revlog.RevlogError, inst:
2149 except revlog.RevlogError, inst:
2149 u.warn("abort: ", inst, "!\n")
2150 u.warn("abort: ", inst, "!\n")
2150 except SignalInterrupt:
2151 except SignalInterrupt:
2151 u.warn("killed!\n")
2152 u.warn("killed!\n")
2152 except KeyboardInterrupt:
2153 except KeyboardInterrupt:
2153 try:
2154 try:
2154 u.warn("interrupted!\n")
2155 u.warn("interrupted!\n")
2155 except IOError, inst:
2156 except IOError, inst:
2156 if inst.errno == errno.EPIPE:
2157 if inst.errno == errno.EPIPE:
2157 if u.debugflag:
2158 if u.debugflag:
2158 u.warn("\nbroken pipe\n")
2159 u.warn("\nbroken pipe\n")
2159 else:
2160 else:
2160 raise
2161 raise
2161 except IOError, inst:
2162 except IOError, inst:
2162 if hasattr(inst, "code"):
2163 if hasattr(inst, "code"):
2163 u.warn("abort: %s\n" % inst)
2164 u.warn("abort: %s\n" % inst)
2164 elif hasattr(inst, "reason"):
2165 elif hasattr(inst, "reason"):
2165 u.warn("abort: error: %s\n" % inst.reason[1])
2166 u.warn("abort: error: %s\n" % inst.reason[1])
2166 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2167 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2167 if u.debugflag:
2168 if u.debugflag:
2168 u.warn("broken pipe\n")
2169 u.warn("broken pipe\n")
2169 else:
2170 else:
2170 raise
2171 raise
2171 except OSError, inst:
2172 except OSError, inst:
2172 if hasattr(inst, "filename"):
2173 if hasattr(inst, "filename"):
2173 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2174 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename))
2174 else:
2175 else:
2175 u.warn("abort: %s\n" % inst.strerror)
2176 u.warn("abort: %s\n" % inst.strerror)
2176 except util.Abort, inst:
2177 except util.Abort, inst:
2177 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2178 u.warn('abort: ', inst.args[0] % inst.args[1:], '\n')
2178 sys.exit(1)
2179 sys.exit(1)
2179 except TypeError, inst:
2180 except TypeError, inst:
2180 # was this an argument error?
2181 # was this an argument error?
2181 tb = traceback.extract_tb(sys.exc_info()[2])
2182 tb = traceback.extract_tb(sys.exc_info()[2])
2182 if len(tb) > 2: # no
2183 if len(tb) > 2: # no
2183 raise
2184 raise
2184 u.debug(inst, "\n")
2185 u.debug(inst, "\n")
2185 u.warn("%s: invalid arguments\n" % cmd)
2186 u.warn("%s: invalid arguments\n" % cmd)
2186 help_(u, cmd)
2187 help_(u, cmd)
2187 except UnknownCommand, inst:
2188 except UnknownCommand, inst:
2188 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2189 u.warn("hg: unknown command '%s'\n" % inst.args[0])
2189 help_(u, 'shortlist')
2190 help_(u, 'shortlist')
2190 except SystemExit:
2191 except SystemExit:
2191 # don't catch this in the catch-all below
2192 # don't catch this in the catch-all below
2192 raise
2193 raise
2193 except:
2194 except:
2194 u.warn("** unknown exception encountered, details follow\n")
2195 u.warn("** unknown exception encountered, details follow\n")
2195 u.warn("** report bug details to mercurial@selenic.com\n")
2196 u.warn("** report bug details to mercurial@selenic.com\n")
2196 raise
2197 raise
2197
2198
2198 sys.exit(-1)
2199 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now