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