##// END OF EJS Templates
refactor the dodiff optimization
Benoit Boissinot -
r1804:c3f959c1 default
parent child Browse files
Show More
@@ -1,2916 +1,2912 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 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
12 demandload(globals(), "fancyopts ui hg util lock revlog")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
13 demandload(globals(), "fnmatch hgweb mdiff random signal time traceback")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
14 demandload(globals(), "errno socket version struct atexit sets bz2")
15
15
16 class UnknownCommand(Exception):
16 class UnknownCommand(Exception):
17 """Exception raised if command is not in the command table."""
17 """Exception raised if command is not in the command table."""
18 class AmbiguousCommand(Exception):
18 class AmbiguousCommand(Exception):
19 """Exception raised if command shortcut matches more than one command."""
19 """Exception raised if command shortcut matches more than one command."""
20
20
21 def filterfiles(filters, files):
21 def filterfiles(filters, files):
22 l = [x for x in files if x in filters]
22 l = [x for x in files if x in filters]
23
23
24 for t in filters:
24 for t in filters:
25 if t and t[-1] != "/":
25 if t and t[-1] != "/":
26 t += "/"
26 t += "/"
27 l += [x for x in files if x.startswith(t)]
27 l += [x for x in files if x.startswith(t)]
28 return l
28 return l
29
29
30 def relpath(repo, args):
30 def relpath(repo, args):
31 cwd = repo.getcwd()
31 cwd = repo.getcwd()
32 if cwd:
32 if cwd:
33 return [util.normpath(os.path.join(cwd, x)) for x in args]
33 return [util.normpath(os.path.join(cwd, x)) for x in args]
34 return args
34 return args
35
35
36 def matchpats(repo, pats=[], opts={}, head=''):
36 def matchpats(repo, pats=[], opts={}, head=''):
37 cwd = repo.getcwd()
37 cwd = repo.getcwd()
38 if not pats and cwd:
38 if not pats and cwd:
39 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
39 opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
40 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
40 opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
41 cwd = ''
41 cwd = ''
42 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
42 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
43 opts.get('exclude'), head)
43 opts.get('exclude'), head)
44
44
45 def makewalk(repo, pats, opts, node=None, head=''):
45 def makewalk(repo, pats, opts, node=None, head=''):
46 files, matchfn, anypats = matchpats(repo, pats, opts, head)
46 files, matchfn, anypats = matchpats(repo, pats, opts, head)
47 exact = dict(zip(files, files))
47 exact = dict(zip(files, files))
48 def walk():
48 def walk():
49 for src, fn in repo.walk(node=node, files=files, match=matchfn):
49 for src, fn in repo.walk(node=node, files=files, match=matchfn):
50 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
50 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
51 return files, matchfn, walk()
51 return files, matchfn, walk()
52
52
53 def walk(repo, pats, opts, node=None, head=''):
53 def walk(repo, pats, opts, node=None, head=''):
54 files, matchfn, results = makewalk(repo, pats, opts, node, head)
54 files, matchfn, results = makewalk(repo, pats, opts, node, head)
55 for r in results:
55 for r in results:
56 yield r
56 yield r
57
57
58 def walkchangerevs(ui, repo, pats, opts):
58 def walkchangerevs(ui, repo, pats, opts):
59 '''Iterate over files and the revs they changed in.
59 '''Iterate over files and the revs they changed in.
60
60
61 Callers most commonly need to iterate backwards over the history
61 Callers most commonly need to iterate backwards over the history
62 it is interested in. Doing so has awful (quadratic-looking)
62 it is interested in. Doing so has awful (quadratic-looking)
63 performance, so we use iterators in a "windowed" way.
63 performance, so we use iterators in a "windowed" way.
64
64
65 We walk a window of revisions in the desired order. Within the
65 We walk a window of revisions in the desired order. Within the
66 window, we first walk forwards to gather data, then in the desired
66 window, we first walk forwards to gather data, then in the desired
67 order (usually backwards) to display it.
67 order (usually backwards) to display it.
68
68
69 This function returns an (iterator, getchange, matchfn) tuple. The
69 This function returns an (iterator, getchange, matchfn) tuple. The
70 getchange function returns the changelog entry for a numeric
70 getchange function returns the changelog entry for a numeric
71 revision. The iterator yields 3-tuples. They will be of one of
71 revision. The iterator yields 3-tuples. They will be of one of
72 the following forms:
72 the following forms:
73
73
74 "window", incrementing, lastrev: stepping through a window,
74 "window", incrementing, lastrev: stepping through a window,
75 positive if walking forwards through revs, last rev in the
75 positive if walking forwards through revs, last rev in the
76 sequence iterated over - use to reset state for the current window
76 sequence iterated over - use to reset state for the current window
77
77
78 "add", rev, fns: out-of-order traversal of the given file names
78 "add", rev, fns: out-of-order traversal of the given file names
79 fns, which changed during revision rev - use to gather data for
79 fns, which changed during revision rev - use to gather data for
80 possible display
80 possible display
81
81
82 "iter", rev, None: in-order traversal of the revs earlier iterated
82 "iter", rev, None: in-order traversal of the revs earlier iterated
83 over with "add" - use to display data'''
83 over with "add" - use to display data'''
84
84
85 def increasing_windows(start, end, windowsize=8, sizelimit=512):
85 def increasing_windows(start, end, windowsize=8, sizelimit=512):
86 if start < end:
86 if start < end:
87 while start < end:
87 while start < end:
88 yield start, min(windowsize, end-start)
88 yield start, min(windowsize, end-start)
89 start += windowsize
89 start += windowsize
90 if windowsize < sizelimit:
90 if windowsize < sizelimit:
91 windowsize *= 2
91 windowsize *= 2
92 else:
92 else:
93 while start > end:
93 while start > end:
94 yield start, min(windowsize, start-end-1)
94 yield start, min(windowsize, start-end-1)
95 start -= windowsize
95 start -= windowsize
96 if windowsize < sizelimit:
96 if windowsize < sizelimit:
97 windowsize *= 2
97 windowsize *= 2
98
98
99
99
100 files, matchfn, anypats = matchpats(repo, pats, opts)
100 files, matchfn, anypats = matchpats(repo, pats, opts)
101
101
102 if repo.changelog.count() == 0:
102 if repo.changelog.count() == 0:
103 return [], False, matchfn
103 return [], False, matchfn
104
104
105 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
105 revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
106 wanted = {}
106 wanted = {}
107 slowpath = anypats
107 slowpath = anypats
108 fncache = {}
108 fncache = {}
109
109
110 chcache = {}
110 chcache = {}
111 def getchange(rev):
111 def getchange(rev):
112 ch = chcache.get(rev)
112 ch = chcache.get(rev)
113 if ch is None:
113 if ch is None:
114 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
114 chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
115 return ch
115 return ch
116
116
117 if not slowpath and not files:
117 if not slowpath and not files:
118 # No files, no patterns. Display all revs.
118 # No files, no patterns. Display all revs.
119 wanted = dict(zip(revs, revs))
119 wanted = dict(zip(revs, revs))
120 if not slowpath:
120 if not slowpath:
121 # Only files, no patterns. Check the history of each file.
121 # Only files, no patterns. Check the history of each file.
122 def filerevgen(filelog):
122 def filerevgen(filelog):
123 for i, window in increasing_windows(filelog.count()-1, -1):
123 for i, window in increasing_windows(filelog.count()-1, -1):
124 revs = []
124 revs = []
125 for j in xrange(i - window, i + 1):
125 for j in xrange(i - window, i + 1):
126 revs.append(filelog.linkrev(filelog.node(j)))
126 revs.append(filelog.linkrev(filelog.node(j)))
127 revs.reverse()
127 revs.reverse()
128 for rev in revs:
128 for rev in revs:
129 yield rev
129 yield rev
130
130
131 minrev, maxrev = min(revs), max(revs)
131 minrev, maxrev = min(revs), max(revs)
132 for file_ in files:
132 for file_ in files:
133 filelog = repo.file(file_)
133 filelog = repo.file(file_)
134 # A zero count may be a directory or deleted file, so
134 # A zero count may be a directory or deleted file, so
135 # try to find matching entries on the slow path.
135 # try to find matching entries on the slow path.
136 if filelog.count() == 0:
136 if filelog.count() == 0:
137 slowpath = True
137 slowpath = True
138 break
138 break
139 for rev in filerevgen(filelog):
139 for rev in filerevgen(filelog):
140 if rev <= maxrev:
140 if rev <= maxrev:
141 if rev < minrev:
141 if rev < minrev:
142 break
142 break
143 fncache.setdefault(rev, [])
143 fncache.setdefault(rev, [])
144 fncache[rev].append(file_)
144 fncache[rev].append(file_)
145 wanted[rev] = 1
145 wanted[rev] = 1
146 if slowpath:
146 if slowpath:
147 # The slow path checks files modified in every changeset.
147 # The slow path checks files modified in every changeset.
148 def changerevgen():
148 def changerevgen():
149 for i, window in increasing_windows(repo.changelog.count()-1, -1):
149 for i, window in increasing_windows(repo.changelog.count()-1, -1):
150 for j in xrange(i - window, i + 1):
150 for j in xrange(i - window, i + 1):
151 yield j, getchange(j)[3]
151 yield j, getchange(j)[3]
152
152
153 for rev, changefiles in changerevgen():
153 for rev, changefiles in changerevgen():
154 matches = filter(matchfn, changefiles)
154 matches = filter(matchfn, changefiles)
155 if matches:
155 if matches:
156 fncache[rev] = matches
156 fncache[rev] = matches
157 wanted[rev] = 1
157 wanted[rev] = 1
158
158
159 def iterate():
159 def iterate():
160 for i, window in increasing_windows(0, len(revs)):
160 for i, window in increasing_windows(0, len(revs)):
161 yield 'window', revs[0] < revs[-1], revs[-1]
161 yield 'window', revs[0] < revs[-1], revs[-1]
162 nrevs = [rev for rev in revs[i:i+window]
162 nrevs = [rev for rev in revs[i:i+window]
163 if rev in wanted]
163 if rev in wanted]
164 srevs = list(nrevs)
164 srevs = list(nrevs)
165 srevs.sort()
165 srevs.sort()
166 for rev in srevs:
166 for rev in srevs:
167 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
167 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
168 yield 'add', rev, fns
168 yield 'add', rev, fns
169 for rev in nrevs:
169 for rev in nrevs:
170 yield 'iter', rev, None
170 yield 'iter', rev, None
171 return iterate(), getchange, matchfn
171 return iterate(), getchange, matchfn
172
172
173 revrangesep = ':'
173 revrangesep = ':'
174
174
175 def revrange(ui, repo, revs, revlog=None):
175 def revrange(ui, repo, revs, revlog=None):
176 """Yield revision as strings from a list of revision specifications."""
176 """Yield revision as strings from a list of revision specifications."""
177 if revlog is None:
177 if revlog is None:
178 revlog = repo.changelog
178 revlog = repo.changelog
179 revcount = revlog.count()
179 revcount = revlog.count()
180 def fix(val, defval):
180 def fix(val, defval):
181 if not val:
181 if not val:
182 return defval
182 return defval
183 try:
183 try:
184 num = int(val)
184 num = int(val)
185 if str(num) != val:
185 if str(num) != val:
186 raise ValueError
186 raise ValueError
187 if num < 0:
187 if num < 0:
188 num += revcount
188 num += revcount
189 if num < 0:
189 if num < 0:
190 num = 0
190 num = 0
191 elif num >= revcount:
191 elif num >= revcount:
192 raise ValueError
192 raise ValueError
193 except ValueError:
193 except ValueError:
194 try:
194 try:
195 num = repo.changelog.rev(repo.lookup(val))
195 num = repo.changelog.rev(repo.lookup(val))
196 except KeyError:
196 except KeyError:
197 try:
197 try:
198 num = revlog.rev(revlog.lookup(val))
198 num = revlog.rev(revlog.lookup(val))
199 except KeyError:
199 except KeyError:
200 raise util.Abort(_('invalid revision identifier %s'), val)
200 raise util.Abort(_('invalid revision identifier %s'), val)
201 return num
201 return num
202 seen = {}
202 seen = {}
203 for spec in revs:
203 for spec in revs:
204 if spec.find(revrangesep) >= 0:
204 if spec.find(revrangesep) >= 0:
205 start, end = spec.split(revrangesep, 1)
205 start, end = spec.split(revrangesep, 1)
206 start = fix(start, 0)
206 start = fix(start, 0)
207 end = fix(end, revcount - 1)
207 end = fix(end, revcount - 1)
208 step = start > end and -1 or 1
208 step = start > end and -1 or 1
209 for rev in xrange(start, end+step, step):
209 for rev in xrange(start, end+step, step):
210 if rev in seen:
210 if rev in seen:
211 continue
211 continue
212 seen[rev] = 1
212 seen[rev] = 1
213 yield str(rev)
213 yield str(rev)
214 else:
214 else:
215 rev = fix(spec, None)
215 rev = fix(spec, None)
216 if rev in seen:
216 if rev in seen:
217 continue
217 continue
218 seen[rev] = 1
218 seen[rev] = 1
219 yield str(rev)
219 yield str(rev)
220
220
221 def make_filename(repo, r, pat, node=None,
221 def make_filename(repo, r, pat, node=None,
222 total=None, seqno=None, revwidth=None, pathname=None):
222 total=None, seqno=None, revwidth=None, pathname=None):
223 node_expander = {
223 node_expander = {
224 'H': lambda: hex(node),
224 'H': lambda: hex(node),
225 'R': lambda: str(r.rev(node)),
225 'R': lambda: str(r.rev(node)),
226 'h': lambda: short(node),
226 'h': lambda: short(node),
227 }
227 }
228 expander = {
228 expander = {
229 '%': lambda: '%',
229 '%': lambda: '%',
230 'b': lambda: os.path.basename(repo.root),
230 'b': lambda: os.path.basename(repo.root),
231 }
231 }
232
232
233 try:
233 try:
234 if node:
234 if node:
235 expander.update(node_expander)
235 expander.update(node_expander)
236 if node and revwidth is not None:
236 if node and revwidth is not None:
237 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
237 expander['r'] = lambda: str(r.rev(node)).zfill(revwidth)
238 if total is not None:
238 if total is not None:
239 expander['N'] = lambda: str(total)
239 expander['N'] = lambda: str(total)
240 if seqno is not None:
240 if seqno is not None:
241 expander['n'] = lambda: str(seqno)
241 expander['n'] = lambda: str(seqno)
242 if total is not None and seqno is not None:
242 if total is not None and seqno is not None:
243 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
243 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
244 if pathname is not None:
244 if pathname is not None:
245 expander['s'] = lambda: os.path.basename(pathname)
245 expander['s'] = lambda: os.path.basename(pathname)
246 expander['d'] = lambda: os.path.dirname(pathname) or '.'
246 expander['d'] = lambda: os.path.dirname(pathname) or '.'
247 expander['p'] = lambda: pathname
247 expander['p'] = lambda: pathname
248
248
249 newname = []
249 newname = []
250 patlen = len(pat)
250 patlen = len(pat)
251 i = 0
251 i = 0
252 while i < patlen:
252 while i < patlen:
253 c = pat[i]
253 c = pat[i]
254 if c == '%':
254 if c == '%':
255 i += 1
255 i += 1
256 c = pat[i]
256 c = pat[i]
257 c = expander[c]()
257 c = expander[c]()
258 newname.append(c)
258 newname.append(c)
259 i += 1
259 i += 1
260 return ''.join(newname)
260 return ''.join(newname)
261 except KeyError, inst:
261 except KeyError, inst:
262 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
262 raise util.Abort(_("invalid format spec '%%%s' in output file name"),
263 inst.args[0])
263 inst.args[0])
264
264
265 def make_file(repo, r, pat, node=None,
265 def make_file(repo, r, pat, node=None,
266 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
266 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
267 if not pat or pat == '-':
267 if not pat or pat == '-':
268 return 'w' in mode and sys.stdout or sys.stdin
268 return 'w' in mode and sys.stdout or sys.stdin
269 if hasattr(pat, 'write') and 'w' in mode:
269 if hasattr(pat, 'write') and 'w' in mode:
270 return pat
270 return pat
271 if hasattr(pat, 'read') and 'r' in mode:
271 if hasattr(pat, 'read') and 'r' in mode:
272 return pat
272 return pat
273 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
273 return open(make_filename(repo, r, pat, node, total, seqno, revwidth,
274 pathname),
274 pathname),
275 mode)
275 mode)
276
276
277 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
277 def dodiff(fp, ui, repo, node1, node2, files=None, match=util.always,
278 changes=None, text=False, opts={}):
278 changes=None, text=False, opts={}):
279 if node1:
279 if not node1:
280 # reading the data for node1 early allows it to play nicely
280 node1 = repo.dirstate.parents()[0]
281 # with repo.changes and the revlog cache.
281 # reading the data for node1 early allows it to play nicely
282 change = repo.changelog.read(node1)
282 # with repo.changes and the revlog cache.
283 mmap = repo.manifest.read(change[0])
283 change = repo.changelog.read(node1)
284 date1 = util.datestr(change[2])
284 mmap = repo.manifest.read(change[0])
285 date1 = util.datestr(change[2])
285
286
286 if not changes:
287 if not changes:
287 changes = repo.changes(node1, node2, files, match=match)
288 changes = repo.changes(node1, node2, files, match=match)
288 modified, added, removed, deleted, unknown = changes
289 modified, added, removed, deleted, unknown = changes
289 if files:
290 if files:
290 modified, added, removed = map(lambda x: filterfiles(files, x),
291 modified, added, removed = map(lambda x: filterfiles(files, x),
291 (modified, added, removed))
292 (modified, added, removed))
292
293
293 if not modified and not added and not removed:
294 if not modified and not added and not removed:
294 return
295 return
295
296
296 if node2:
297 if node2:
297 change = repo.changelog.read(node2)
298 change = repo.changelog.read(node2)
298 mmap2 = repo.manifest.read(change[0])
299 mmap2 = repo.manifest.read(change[0])
299 date2 = util.datestr(change[2])
300 date2 = util.datestr(change[2])
300 def read(f):
301 def read(f):
301 return repo.file(f).read(mmap2[f])
302 return repo.file(f).read(mmap2[f])
302 else:
303 else:
303 date2 = util.datestr()
304 date2 = util.datestr()
304 if not node1:
305 node1 = repo.dirstate.parents()[0]
306 change = repo.changelog.read(node1)
307 mmap = repo.manifest.read(change[0])
308 date1 = util.datestr(change[2])
309 def read(f):
305 def read(f):
310 return repo.wread(f)
306 return repo.wread(f)
311
307
312 if ui.quiet:
308 if ui.quiet:
313 r = None
309 r = None
314 else:
310 else:
315 hexfunc = ui.verbose and hex or short
311 hexfunc = ui.verbose and hex or short
316 r = [hexfunc(node) for node in [node1, node2] if node]
312 r = [hexfunc(node) for node in [node1, node2] if node]
317
313
318 diffopts = ui.diffopts()
314 diffopts = ui.diffopts()
319 showfunc = opts.get('show_function') or diffopts['showfunc']
315 showfunc = opts.get('show_function') or diffopts['showfunc']
320 ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
316 ignorews = opts.get('ignore_all_space') or diffopts['ignorews']
321 for f in modified:
317 for f in modified:
322 to = None
318 to = None
323 if f in mmap:
319 if f in mmap:
324 to = repo.file(f).read(mmap[f])
320 to = repo.file(f).read(mmap[f])
325 tn = read(f)
321 tn = read(f)
326 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
322 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
327 showfunc=showfunc, ignorews=ignorews))
323 showfunc=showfunc, ignorews=ignorews))
328 for f in added:
324 for f in added:
329 to = None
325 to = None
330 tn = read(f)
326 tn = read(f)
331 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
327 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
332 showfunc=showfunc, ignorews=ignorews))
328 showfunc=showfunc, ignorews=ignorews))
333 for f in removed:
329 for f in removed:
334 to = repo.file(f).read(mmap[f])
330 to = repo.file(f).read(mmap[f])
335 tn = None
331 tn = None
336 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
332 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text,
337 showfunc=showfunc, ignorews=ignorews))
333 showfunc=showfunc, ignorews=ignorews))
338
334
339 def trimuser(ui, name, rev, revcache):
335 def trimuser(ui, name, rev, revcache):
340 """trim the name of the user who committed a change"""
336 """trim the name of the user who committed a change"""
341 user = revcache.get(rev)
337 user = revcache.get(rev)
342 if user is None:
338 if user is None:
343 user = revcache[rev] = ui.shortuser(name)
339 user = revcache[rev] = ui.shortuser(name)
344 return user
340 return user
345
341
346 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
342 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
347 """show a single changeset or file revision"""
343 """show a single changeset or file revision"""
348 log = repo.changelog
344 log = repo.changelog
349 if changenode is None:
345 if changenode is None:
350 changenode = log.node(rev)
346 changenode = log.node(rev)
351 elif not rev:
347 elif not rev:
352 rev = log.rev(changenode)
348 rev = log.rev(changenode)
353
349
354 if ui.quiet:
350 if ui.quiet:
355 ui.write("%d:%s\n" % (rev, short(changenode)))
351 ui.write("%d:%s\n" % (rev, short(changenode)))
356 return
352 return
357
353
358 changes = log.read(changenode)
354 changes = log.read(changenode)
359 date = util.datestr(changes[2])
355 date = util.datestr(changes[2])
360
356
361 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
357 parents = [(log.rev(p), ui.verbose and hex(p) or short(p))
362 for p in log.parents(changenode)
358 for p in log.parents(changenode)
363 if ui.debugflag or p != nullid]
359 if ui.debugflag or p != nullid]
364 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
360 if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
365 parents = []
361 parents = []
366
362
367 if ui.verbose:
363 if ui.verbose:
368 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
364 ui.write(_("changeset: %d:%s\n") % (rev, hex(changenode)))
369 else:
365 else:
370 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
366 ui.write(_("changeset: %d:%s\n") % (rev, short(changenode)))
371
367
372 for tag in repo.nodetags(changenode):
368 for tag in repo.nodetags(changenode):
373 ui.status(_("tag: %s\n") % tag)
369 ui.status(_("tag: %s\n") % tag)
374 for parent in parents:
370 for parent in parents:
375 ui.write(_("parent: %d:%s\n") % parent)
371 ui.write(_("parent: %d:%s\n") % parent)
376
372
377 if brinfo and changenode in brinfo:
373 if brinfo and changenode in brinfo:
378 br = brinfo[changenode]
374 br = brinfo[changenode]
379 ui.write(_("branch: %s\n") % " ".join(br))
375 ui.write(_("branch: %s\n") % " ".join(br))
380
376
381 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
377 ui.debug(_("manifest: %d:%s\n") % (repo.manifest.rev(changes[0]),
382 hex(changes[0])))
378 hex(changes[0])))
383 ui.status(_("user: %s\n") % changes[1])
379 ui.status(_("user: %s\n") % changes[1])
384 ui.status(_("date: %s\n") % date)
380 ui.status(_("date: %s\n") % date)
385
381
386 if ui.debugflag:
382 if ui.debugflag:
387 files = repo.changes(log.parents(changenode)[0], changenode)
383 files = repo.changes(log.parents(changenode)[0], changenode)
388 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
384 for key, value in zip([_("files:"), _("files+:"), _("files-:")], files):
389 if value:
385 if value:
390 ui.note("%-12s %s\n" % (key, " ".join(value)))
386 ui.note("%-12s %s\n" % (key, " ".join(value)))
391 else:
387 else:
392 ui.note(_("files: %s\n") % " ".join(changes[3]))
388 ui.note(_("files: %s\n") % " ".join(changes[3]))
393
389
394 description = changes[4].strip()
390 description = changes[4].strip()
395 if description:
391 if description:
396 if ui.verbose:
392 if ui.verbose:
397 ui.status(_("description:\n"))
393 ui.status(_("description:\n"))
398 ui.status(description)
394 ui.status(description)
399 ui.status("\n\n")
395 ui.status("\n\n")
400 else:
396 else:
401 ui.status(_("summary: %s\n") % description.splitlines()[0])
397 ui.status(_("summary: %s\n") % description.splitlines()[0])
402 ui.status("\n")
398 ui.status("\n")
403
399
404 def show_version(ui):
400 def show_version(ui):
405 """output version and copyright information"""
401 """output version and copyright information"""
406 ui.write(_("Mercurial Distributed SCM (version %s)\n")
402 ui.write(_("Mercurial Distributed SCM (version %s)\n")
407 % version.get_version())
403 % version.get_version())
408 ui.status(_(
404 ui.status(_(
409 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
405 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
410 "This is free software; see the source for copying conditions. "
406 "This is free software; see the source for copying conditions. "
411 "There is NO\nwarranty; "
407 "There is NO\nwarranty; "
412 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
408 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
413 ))
409 ))
414
410
415 def help_(ui, cmd=None, with_version=False):
411 def help_(ui, cmd=None, with_version=False):
416 """show help for a given command or all commands"""
412 """show help for a given command or all commands"""
417 option_lists = []
413 option_lists = []
418 if cmd and cmd != 'shortlist':
414 if cmd and cmd != 'shortlist':
419 if with_version:
415 if with_version:
420 show_version(ui)
416 show_version(ui)
421 ui.write('\n')
417 ui.write('\n')
422 aliases, i = find(cmd)
418 aliases, i = find(cmd)
423 # synopsis
419 # synopsis
424 ui.write("%s\n\n" % i[2])
420 ui.write("%s\n\n" % i[2])
425
421
426 # description
422 # description
427 doc = i[0].__doc__
423 doc = i[0].__doc__
428 if not doc:
424 if not doc:
429 doc = _("(No help text available)")
425 doc = _("(No help text available)")
430 if ui.quiet:
426 if ui.quiet:
431 doc = doc.splitlines(0)[0]
427 doc = doc.splitlines(0)[0]
432 ui.write("%s\n" % doc.rstrip())
428 ui.write("%s\n" % doc.rstrip())
433
429
434 if not ui.quiet:
430 if not ui.quiet:
435 # aliases
431 # aliases
436 if len(aliases) > 1:
432 if len(aliases) > 1:
437 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
433 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
438
434
439 # options
435 # options
440 if i[1]:
436 if i[1]:
441 option_lists.append(("options", i[1]))
437 option_lists.append(("options", i[1]))
442
438
443 else:
439 else:
444 # program name
440 # program name
445 if ui.verbose or with_version:
441 if ui.verbose or with_version:
446 show_version(ui)
442 show_version(ui)
447 else:
443 else:
448 ui.status(_("Mercurial Distributed SCM\n"))
444 ui.status(_("Mercurial Distributed SCM\n"))
449 ui.status('\n')
445 ui.status('\n')
450
446
451 # list of commands
447 # list of commands
452 if cmd == "shortlist":
448 if cmd == "shortlist":
453 ui.status(_('basic commands (use "hg help" '
449 ui.status(_('basic commands (use "hg help" '
454 'for the full list or option "-v" for details):\n\n'))
450 'for the full list or option "-v" for details):\n\n'))
455 elif ui.verbose:
451 elif ui.verbose:
456 ui.status(_('list of commands:\n\n'))
452 ui.status(_('list of commands:\n\n'))
457 else:
453 else:
458 ui.status(_('list of commands (use "hg help -v" '
454 ui.status(_('list of commands (use "hg help -v" '
459 'to show aliases and global options):\n\n'))
455 'to show aliases and global options):\n\n'))
460
456
461 h = {}
457 h = {}
462 cmds = {}
458 cmds = {}
463 for c, e in table.items():
459 for c, e in table.items():
464 f = c.split("|")[0]
460 f = c.split("|")[0]
465 if cmd == "shortlist" and not f.startswith("^"):
461 if cmd == "shortlist" and not f.startswith("^"):
466 continue
462 continue
467 f = f.lstrip("^")
463 f = f.lstrip("^")
468 if not ui.debugflag and f.startswith("debug"):
464 if not ui.debugflag and f.startswith("debug"):
469 continue
465 continue
470 doc = e[0].__doc__
466 doc = e[0].__doc__
471 if not doc:
467 if not doc:
472 doc = _("(No help text available)")
468 doc = _("(No help text available)")
473 h[f] = doc.splitlines(0)[0].rstrip()
469 h[f] = doc.splitlines(0)[0].rstrip()
474 cmds[f] = c.lstrip("^")
470 cmds[f] = c.lstrip("^")
475
471
476 fns = h.keys()
472 fns = h.keys()
477 fns.sort()
473 fns.sort()
478 m = max(map(len, fns))
474 m = max(map(len, fns))
479 for f in fns:
475 for f in fns:
480 if ui.verbose:
476 if ui.verbose:
481 commands = cmds[f].replace("|",", ")
477 commands = cmds[f].replace("|",", ")
482 ui.write(" %s:\n %s\n"%(commands, h[f]))
478 ui.write(" %s:\n %s\n"%(commands, h[f]))
483 else:
479 else:
484 ui.write(' %-*s %s\n' % (m, f, h[f]))
480 ui.write(' %-*s %s\n' % (m, f, h[f]))
485
481
486 # global options
482 # global options
487 if ui.verbose:
483 if ui.verbose:
488 option_lists.append(("global options", globalopts))
484 option_lists.append(("global options", globalopts))
489
485
490 # list all option lists
486 # list all option lists
491 opt_output = []
487 opt_output = []
492 for title, options in option_lists:
488 for title, options in option_lists:
493 opt_output.append(("\n%s:\n" % title, None))
489 opt_output.append(("\n%s:\n" % title, None))
494 for shortopt, longopt, default, desc in options:
490 for shortopt, longopt, default, desc in options:
495 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
491 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
496 longopt and " --%s" % longopt),
492 longopt and " --%s" % longopt),
497 "%s%s" % (desc,
493 "%s%s" % (desc,
498 default
494 default
499 and _(" (default: %s)") % default
495 and _(" (default: %s)") % default
500 or "")))
496 or "")))
501
497
502 if opt_output:
498 if opt_output:
503 opts_len = max([len(line[0]) for line in opt_output if line[1]])
499 opts_len = max([len(line[0]) for line in opt_output if line[1]])
504 for first, second in opt_output:
500 for first, second in opt_output:
505 if second:
501 if second:
506 ui.write(" %-*s %s\n" % (opts_len, first, second))
502 ui.write(" %-*s %s\n" % (opts_len, first, second))
507 else:
503 else:
508 ui.write("%s\n" % first)
504 ui.write("%s\n" % first)
509
505
510 # Commands start here, listed alphabetically
506 # Commands start here, listed alphabetically
511
507
512 def add(ui, repo, *pats, **opts):
508 def add(ui, repo, *pats, **opts):
513 """add the specified files on the next commit
509 """add the specified files on the next commit
514
510
515 Schedule files to be version controlled and added to the repository.
511 Schedule files to be version controlled and added to the repository.
516
512
517 The files will be added to the repository at the next commit.
513 The files will be added to the repository at the next commit.
518
514
519 If no names are given, add all files in the repository.
515 If no names are given, add all files in the repository.
520 """
516 """
521
517
522 names = []
518 names = []
523 for src, abs, rel, exact in walk(repo, pats, opts):
519 for src, abs, rel, exact in walk(repo, pats, opts):
524 if exact:
520 if exact:
525 if ui.verbose:
521 if ui.verbose:
526 ui.status(_('adding %s\n') % rel)
522 ui.status(_('adding %s\n') % rel)
527 names.append(abs)
523 names.append(abs)
528 elif repo.dirstate.state(abs) == '?':
524 elif repo.dirstate.state(abs) == '?':
529 ui.status(_('adding %s\n') % rel)
525 ui.status(_('adding %s\n') % rel)
530 names.append(abs)
526 names.append(abs)
531 repo.add(names)
527 repo.add(names)
532
528
533 def addremove(ui, repo, *pats, **opts):
529 def addremove(ui, repo, *pats, **opts):
534 """add all new files, delete all missing files
530 """add all new files, delete all missing files
535
531
536 Add all new files and remove all missing files from the repository.
532 Add all new files and remove all missing files from the repository.
537
533
538 New files are ignored if they match any of the patterns in .hgignore. As
534 New files are ignored if they match any of the patterns in .hgignore. As
539 with add, these changes take effect at the next commit.
535 with add, these changes take effect at the next commit.
540 """
536 """
541 return addremove_lock(ui, repo, pats, opts)
537 return addremove_lock(ui, repo, pats, opts)
542
538
543 def addremove_lock(ui, repo, pats, opts, wlock=None):
539 def addremove_lock(ui, repo, pats, opts, wlock=None):
544 add, remove = [], []
540 add, remove = [], []
545 for src, abs, rel, exact in walk(repo, pats, opts):
541 for src, abs, rel, exact in walk(repo, pats, opts):
546 if src == 'f' and repo.dirstate.state(abs) == '?':
542 if src == 'f' and repo.dirstate.state(abs) == '?':
547 add.append(abs)
543 add.append(abs)
548 if ui.verbose or not exact:
544 if ui.verbose or not exact:
549 ui.status(_('adding %s\n') % ((pats and rel) or abs))
545 ui.status(_('adding %s\n') % ((pats and rel) or abs))
550 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
546 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
551 remove.append(abs)
547 remove.append(abs)
552 if ui.verbose or not exact:
548 if ui.verbose or not exact:
553 ui.status(_('removing %s\n') % ((pats and rel) or abs))
549 ui.status(_('removing %s\n') % ((pats and rel) or abs))
554 repo.add(add, wlock=wlock)
550 repo.add(add, wlock=wlock)
555 repo.remove(remove, wlock=wlock)
551 repo.remove(remove, wlock=wlock)
556
552
557 def annotate(ui, repo, *pats, **opts):
553 def annotate(ui, repo, *pats, **opts):
558 """show changeset information per file line
554 """show changeset information per file line
559
555
560 List changes in files, showing the revision id responsible for each line
556 List changes in files, showing the revision id responsible for each line
561
557
562 This command is useful to discover who did a change or when a change took
558 This command is useful to discover who did a change or when a change took
563 place.
559 place.
564
560
565 Without the -a option, annotate will avoid processing files it
561 Without the -a option, annotate will avoid processing files it
566 detects as binary. With -a, annotate will generate an annotation
562 detects as binary. With -a, annotate will generate an annotation
567 anyway, probably with undesirable results.
563 anyway, probably with undesirable results.
568 """
564 """
569 def getnode(rev):
565 def getnode(rev):
570 return short(repo.changelog.node(rev))
566 return short(repo.changelog.node(rev))
571
567
572 ucache = {}
568 ucache = {}
573 def getname(rev):
569 def getname(rev):
574 cl = repo.changelog.read(repo.changelog.node(rev))
570 cl = repo.changelog.read(repo.changelog.node(rev))
575 return trimuser(ui, cl[1], rev, ucache)
571 return trimuser(ui, cl[1], rev, ucache)
576
572
577 dcache = {}
573 dcache = {}
578 def getdate(rev):
574 def getdate(rev):
579 datestr = dcache.get(rev)
575 datestr = dcache.get(rev)
580 if datestr is None:
576 if datestr is None:
581 cl = repo.changelog.read(repo.changelog.node(rev))
577 cl = repo.changelog.read(repo.changelog.node(rev))
582 datestr = dcache[rev] = util.datestr(cl[2])
578 datestr = dcache[rev] = util.datestr(cl[2])
583 return datestr
579 return datestr
584
580
585 if not pats:
581 if not pats:
586 raise util.Abort(_('at least one file name or pattern required'))
582 raise util.Abort(_('at least one file name or pattern required'))
587
583
588 opmap = [['user', getname], ['number', str], ['changeset', getnode],
584 opmap = [['user', getname], ['number', str], ['changeset', getnode],
589 ['date', getdate]]
585 ['date', getdate]]
590 if not opts['user'] and not opts['changeset'] and not opts['date']:
586 if not opts['user'] and not opts['changeset'] and not opts['date']:
591 opts['number'] = 1
587 opts['number'] = 1
592
588
593 if opts['rev']:
589 if opts['rev']:
594 node = repo.changelog.lookup(opts['rev'])
590 node = repo.changelog.lookup(opts['rev'])
595 else:
591 else:
596 node = repo.dirstate.parents()[0]
592 node = repo.dirstate.parents()[0]
597 change = repo.changelog.read(node)
593 change = repo.changelog.read(node)
598 mmap = repo.manifest.read(change[0])
594 mmap = repo.manifest.read(change[0])
599
595
600 for src, abs, rel, exact in walk(repo, pats, opts):
596 for src, abs, rel, exact in walk(repo, pats, opts):
601 if abs not in mmap:
597 if abs not in mmap:
602 ui.warn(_("warning: %s is not in the repository!\n") %
598 ui.warn(_("warning: %s is not in the repository!\n") %
603 ((pats and rel) or abs))
599 ((pats and rel) or abs))
604 continue
600 continue
605
601
606 f = repo.file(abs)
602 f = repo.file(abs)
607 if not opts['text'] and util.binary(f.read(mmap[abs])):
603 if not opts['text'] and util.binary(f.read(mmap[abs])):
608 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
604 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
609 continue
605 continue
610
606
611 lines = f.annotate(mmap[abs])
607 lines = f.annotate(mmap[abs])
612 pieces = []
608 pieces = []
613
609
614 for o, f in opmap:
610 for o, f in opmap:
615 if opts[o]:
611 if opts[o]:
616 l = [f(n) for n, dummy in lines]
612 l = [f(n) for n, dummy in lines]
617 if l:
613 if l:
618 m = max(map(len, l))
614 m = max(map(len, l))
619 pieces.append(["%*s" % (m, x) for x in l])
615 pieces.append(["%*s" % (m, x) for x in l])
620
616
621 if pieces:
617 if pieces:
622 for p, l in zip(zip(*pieces), lines):
618 for p, l in zip(zip(*pieces), lines):
623 ui.write("%s: %s" % (" ".join(p), l[1]))
619 ui.write("%s: %s" % (" ".join(p), l[1]))
624
620
625 def bundle(ui, repo, fname, dest="default-push", **opts):
621 def bundle(ui, repo, fname, dest="default-push", **opts):
626 """create a changegroup file
622 """create a changegroup file
627
623
628 Generate a compressed changegroup file collecting all changesets
624 Generate a compressed changegroup file collecting all changesets
629 not found in the other repository.
625 not found in the other repository.
630
626
631 This file can then be transferred using conventional means and
627 This file can then be transferred using conventional means and
632 applied to another repository with the unbundle command. This is
628 applied to another repository with the unbundle command. This is
633 useful when native push and pull are not available or when
629 useful when native push and pull are not available or when
634 exporting an entire repository is undesirable. The standard file
630 exporting an entire repository is undesirable. The standard file
635 extension is ".hg".
631 extension is ".hg".
636
632
637 Unlike import/export, this exactly preserves all changeset
633 Unlike import/export, this exactly preserves all changeset
638 contents including permissions, rename data, and revision history.
634 contents including permissions, rename data, and revision history.
639 """
635 """
640 f = open(fname, "wb")
636 f = open(fname, "wb")
641 dest = ui.expandpath(dest, repo.root)
637 dest = ui.expandpath(dest, repo.root)
642 other = hg.repository(ui, dest)
638 other = hg.repository(ui, dest)
643 o = repo.findoutgoing(other)
639 o = repo.findoutgoing(other)
644 cg = repo.changegroup(o, 'bundle')
640 cg = repo.changegroup(o, 'bundle')
645
641
646 try:
642 try:
647 f.write("HG10")
643 f.write("HG10")
648 z = bz2.BZ2Compressor(9)
644 z = bz2.BZ2Compressor(9)
649 while 1:
645 while 1:
650 chunk = cg.read(4096)
646 chunk = cg.read(4096)
651 if not chunk:
647 if not chunk:
652 break
648 break
653 f.write(z.compress(chunk))
649 f.write(z.compress(chunk))
654 f.write(z.flush())
650 f.write(z.flush())
655 except:
651 except:
656 os.unlink(fname)
652 os.unlink(fname)
657 raise
653 raise
658
654
659 def cat(ui, repo, file1, *pats, **opts):
655 def cat(ui, repo, file1, *pats, **opts):
660 """output the latest or given revisions of files
656 """output the latest or given revisions of files
661
657
662 Print the specified files as they were at the given revision.
658 Print the specified files as they were at the given revision.
663 If no revision is given then the tip is used.
659 If no revision is given then the tip is used.
664
660
665 Output may be to a file, in which case the name of the file is
661 Output may be to a file, in which case the name of the file is
666 given using a format string. The formatting rules are the same as
662 given using a format string. The formatting rules are the same as
667 for the export command, with the following additions:
663 for the export command, with the following additions:
668
664
669 %s basename of file being printed
665 %s basename of file being printed
670 %d dirname of file being printed, or '.' if in repo root
666 %d dirname of file being printed, or '.' if in repo root
671 %p root-relative path name of file being printed
667 %p root-relative path name of file being printed
672 """
668 """
673 mf = {}
669 mf = {}
674 rev = opts['rev']
670 rev = opts['rev']
675 if rev:
671 if rev:
676 node = repo.lookup(rev)
672 node = repo.lookup(rev)
677 else:
673 else:
678 node = repo.changelog.tip()
674 node = repo.changelog.tip()
679 change = repo.changelog.read(node)
675 change = repo.changelog.read(node)
680 mf = repo.manifest.read(change[0])
676 mf = repo.manifest.read(change[0])
681 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, node):
677 for src, abs, rel, exact in walk(repo, (file1,) + pats, opts, node):
682 r = repo.file(abs)
678 r = repo.file(abs)
683 n = mf[abs]
679 n = mf[abs]
684 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
680 fp = make_file(repo, r, opts['output'], node=n, pathname=abs)
685 fp.write(r.read(n))
681 fp.write(r.read(n))
686
682
687 def clone(ui, source, dest=None, **opts):
683 def clone(ui, source, dest=None, **opts):
688 """make a copy of an existing repository
684 """make a copy of an existing repository
689
685
690 Create a copy of an existing repository in a new directory.
686 Create a copy of an existing repository in a new directory.
691
687
692 If no destination directory name is specified, it defaults to the
688 If no destination directory name is specified, it defaults to the
693 basename of the source.
689 basename of the source.
694
690
695 The location of the source is added to the new repository's
691 The location of the source is added to the new repository's
696 .hg/hgrc file, as the default to be used for future pulls.
692 .hg/hgrc file, as the default to be used for future pulls.
697
693
698 For efficiency, hardlinks are used for cloning whenever the source
694 For efficiency, hardlinks are used for cloning whenever the source
699 and destination are on the same filesystem. Some filesystems,
695 and destination are on the same filesystem. Some filesystems,
700 such as AFS, implement hardlinking incorrectly, but do not report
696 such as AFS, implement hardlinking incorrectly, but do not report
701 errors. In these cases, use the --pull option to avoid
697 errors. In these cases, use the --pull option to avoid
702 hardlinking.
698 hardlinking.
703 """
699 """
704 if dest is None:
700 if dest is None:
705 dest = os.path.basename(os.path.normpath(source))
701 dest = os.path.basename(os.path.normpath(source))
706
702
707 if os.path.exists(dest):
703 if os.path.exists(dest):
708 raise util.Abort(_("destination '%s' already exists"), dest)
704 raise util.Abort(_("destination '%s' already exists"), dest)
709
705
710 dest = os.path.realpath(dest)
706 dest = os.path.realpath(dest)
711
707
712 class Dircleanup(object):
708 class Dircleanup(object):
713 def __init__(self, dir_):
709 def __init__(self, dir_):
714 self.rmtree = shutil.rmtree
710 self.rmtree = shutil.rmtree
715 self.dir_ = dir_
711 self.dir_ = dir_
716 os.mkdir(dir_)
712 os.mkdir(dir_)
717 def close(self):
713 def close(self):
718 self.dir_ = None
714 self.dir_ = None
719 def __del__(self):
715 def __del__(self):
720 if self.dir_:
716 if self.dir_:
721 self.rmtree(self.dir_, True)
717 self.rmtree(self.dir_, True)
722
718
723 if opts['ssh']:
719 if opts['ssh']:
724 ui.setconfig("ui", "ssh", opts['ssh'])
720 ui.setconfig("ui", "ssh", opts['ssh'])
725 if opts['remotecmd']:
721 if opts['remotecmd']:
726 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
722 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
727
723
728 if not os.path.exists(source):
724 if not os.path.exists(source):
729 source = ui.expandpath(source)
725 source = ui.expandpath(source)
730
726
731 d = Dircleanup(dest)
727 d = Dircleanup(dest)
732 abspath = source
728 abspath = source
733 other = hg.repository(ui, source)
729 other = hg.repository(ui, source)
734
730
735 copy = False
731 copy = False
736 if other.dev() != -1:
732 if other.dev() != -1:
737 abspath = os.path.abspath(source)
733 abspath = os.path.abspath(source)
738 if not opts['pull'] and not opts['rev']:
734 if not opts['pull'] and not opts['rev']:
739 copy = True
735 copy = True
740
736
741 if copy:
737 if copy:
742 try:
738 try:
743 # we use a lock here because if we race with commit, we
739 # we use a lock here because if we race with commit, we
744 # can end up with extra data in the cloned revlogs that's
740 # can end up with extra data in the cloned revlogs that's
745 # not pointed to by changesets, thus causing verify to
741 # not pointed to by changesets, thus causing verify to
746 # fail
742 # fail
747 l1 = other.lock()
743 l1 = other.lock()
748 except lock.LockException:
744 except lock.LockException:
749 copy = False
745 copy = False
750
746
751 if copy:
747 if copy:
752 # we lock here to avoid premature writing to the target
748 # we lock here to avoid premature writing to the target
753 os.mkdir(os.path.join(dest, ".hg"))
749 os.mkdir(os.path.join(dest, ".hg"))
754 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
750 l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
755
751
756 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
752 files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
757 for f in files.split():
753 for f in files.split():
758 src = os.path.join(source, ".hg", f)
754 src = os.path.join(source, ".hg", f)
759 dst = os.path.join(dest, ".hg", f)
755 dst = os.path.join(dest, ".hg", f)
760 try:
756 try:
761 util.copyfiles(src, dst)
757 util.copyfiles(src, dst)
762 except OSError, inst:
758 except OSError, inst:
763 if inst.errno != errno.ENOENT:
759 if inst.errno != errno.ENOENT:
764 raise
760 raise
765
761
766 repo = hg.repository(ui, dest)
762 repo = hg.repository(ui, dest)
767
763
768 else:
764 else:
769 revs = None
765 revs = None
770 if opts['rev']:
766 if opts['rev']:
771 if not other.local():
767 if not other.local():
772 error = _("clone -r not supported yet for remote repositories.")
768 error = _("clone -r not supported yet for remote repositories.")
773 raise util.Abort(error)
769 raise util.Abort(error)
774 else:
770 else:
775 revs = [other.lookup(rev) for rev in opts['rev']]
771 revs = [other.lookup(rev) for rev in opts['rev']]
776 repo = hg.repository(ui, dest, create=1)
772 repo = hg.repository(ui, dest, create=1)
777 repo.pull(other, heads = revs)
773 repo.pull(other, heads = revs)
778
774
779 f = repo.opener("hgrc", "w", text=True)
775 f = repo.opener("hgrc", "w", text=True)
780 f.write("[paths]\n")
776 f.write("[paths]\n")
781 f.write("default = %s\n" % abspath)
777 f.write("default = %s\n" % abspath)
782 f.close()
778 f.close()
783
779
784 if not opts['noupdate']:
780 if not opts['noupdate']:
785 update(ui, repo)
781 update(ui, repo)
786
782
787 d.close()
783 d.close()
788
784
789 def commit(ui, repo, *pats, **opts):
785 def commit(ui, repo, *pats, **opts):
790 """commit the specified files or all outstanding changes
786 """commit the specified files or all outstanding changes
791
787
792 Commit changes to the given files into the repository.
788 Commit changes to the given files into the repository.
793
789
794 If a list of files is omitted, all changes reported by "hg status"
790 If a list of files is omitted, all changes reported by "hg status"
795 will be commited.
791 will be commited.
796
792
797 The HGEDITOR or EDITOR environment variables are used to start an
793 The HGEDITOR or EDITOR environment variables are used to start an
798 editor to add a commit comment.
794 editor to add a commit comment.
799 """
795 """
800 message = opts['message']
796 message = opts['message']
801 logfile = opts['logfile']
797 logfile = opts['logfile']
802
798
803 if message and logfile:
799 if message and logfile:
804 raise util.Abort(_('options --message and --logfile are mutually '
800 raise util.Abort(_('options --message and --logfile are mutually '
805 'exclusive'))
801 'exclusive'))
806 if not message and logfile:
802 if not message and logfile:
807 try:
803 try:
808 if logfile == '-':
804 if logfile == '-':
809 message = sys.stdin.read()
805 message = sys.stdin.read()
810 else:
806 else:
811 message = open(logfile).read()
807 message = open(logfile).read()
812 except IOError, inst:
808 except IOError, inst:
813 raise util.Abort(_("can't read commit message '%s': %s") %
809 raise util.Abort(_("can't read commit message '%s': %s") %
814 (logfile, inst.strerror))
810 (logfile, inst.strerror))
815
811
816 if opts['addremove']:
812 if opts['addremove']:
817 addremove(ui, repo, *pats, **opts)
813 addremove(ui, repo, *pats, **opts)
818 fns, match, anypats = matchpats(repo, pats, opts)
814 fns, match, anypats = matchpats(repo, pats, opts)
819 if pats:
815 if pats:
820 modified, added, removed, deleted, unknown = (
816 modified, added, removed, deleted, unknown = (
821 repo.changes(files=fns, match=match))
817 repo.changes(files=fns, match=match))
822 files = modified + added + removed
818 files = modified + added + removed
823 else:
819 else:
824 files = []
820 files = []
825 try:
821 try:
826 repo.commit(files, message, opts['user'], opts['date'], match)
822 repo.commit(files, message, opts['user'], opts['date'], match)
827 except ValueError, inst:
823 except ValueError, inst:
828 raise util.Abort(str(inst))
824 raise util.Abort(str(inst))
829
825
830 def docopy(ui, repo, pats, opts):
826 def docopy(ui, repo, pats, opts):
831 cwd = repo.getcwd()
827 cwd = repo.getcwd()
832 errors = 0
828 errors = 0
833 copied = []
829 copied = []
834 targets = {}
830 targets = {}
835
831
836 def okaytocopy(abs, rel, exact):
832 def okaytocopy(abs, rel, exact):
837 reasons = {'?': _('is not managed'),
833 reasons = {'?': _('is not managed'),
838 'a': _('has been marked for add'),
834 'a': _('has been marked for add'),
839 'r': _('has been marked for remove')}
835 'r': _('has been marked for remove')}
840 state = repo.dirstate.state(abs)
836 state = repo.dirstate.state(abs)
841 reason = reasons.get(state)
837 reason = reasons.get(state)
842 if reason:
838 if reason:
843 if state == 'a':
839 if state == 'a':
844 origsrc = repo.dirstate.copied(abs)
840 origsrc = repo.dirstate.copied(abs)
845 if origsrc is not None:
841 if origsrc is not None:
846 return origsrc
842 return origsrc
847 if exact:
843 if exact:
848 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
844 ui.warn(_('%s: not copying - file %s\n') % (rel, reason))
849 else:
845 else:
850 return abs
846 return abs
851
847
852 def copy(origsrc, abssrc, relsrc, target, exact):
848 def copy(origsrc, abssrc, relsrc, target, exact):
853 abstarget = util.canonpath(repo.root, cwd, target)
849 abstarget = util.canonpath(repo.root, cwd, target)
854 reltarget = util.pathto(cwd, abstarget)
850 reltarget = util.pathto(cwd, abstarget)
855 prevsrc = targets.get(abstarget)
851 prevsrc = targets.get(abstarget)
856 if prevsrc is not None:
852 if prevsrc is not None:
857 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
853 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
858 (reltarget, abssrc, prevsrc))
854 (reltarget, abssrc, prevsrc))
859 return
855 return
860 if (not opts['after'] and os.path.exists(reltarget) or
856 if (not opts['after'] and os.path.exists(reltarget) or
861 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
857 opts['after'] and repo.dirstate.state(abstarget) not in '?r'):
862 if not opts['force']:
858 if not opts['force']:
863 ui.warn(_('%s: not overwriting - file exists\n') %
859 ui.warn(_('%s: not overwriting - file exists\n') %
864 reltarget)
860 reltarget)
865 return
861 return
866 if not opts['after']:
862 if not opts['after']:
867 os.unlink(reltarget)
863 os.unlink(reltarget)
868 if opts['after']:
864 if opts['after']:
869 if not os.path.exists(reltarget):
865 if not os.path.exists(reltarget):
870 return
866 return
871 else:
867 else:
872 targetdir = os.path.dirname(reltarget) or '.'
868 targetdir = os.path.dirname(reltarget) or '.'
873 if not os.path.isdir(targetdir):
869 if not os.path.isdir(targetdir):
874 os.makedirs(targetdir)
870 os.makedirs(targetdir)
875 try:
871 try:
876 shutil.copyfile(relsrc, reltarget)
872 shutil.copyfile(relsrc, reltarget)
877 shutil.copymode(relsrc, reltarget)
873 shutil.copymode(relsrc, reltarget)
878 except shutil.Error, inst:
874 except shutil.Error, inst:
879 raise util.Abort(str(inst))
875 raise util.Abort(str(inst))
880 except IOError, inst:
876 except IOError, inst:
881 if inst.errno == errno.ENOENT:
877 if inst.errno == errno.ENOENT:
882 ui.warn(_('%s: deleted in working copy\n') % relsrc)
878 ui.warn(_('%s: deleted in working copy\n') % relsrc)
883 else:
879 else:
884 ui.warn(_('%s: cannot copy - %s\n') %
880 ui.warn(_('%s: cannot copy - %s\n') %
885 (relsrc, inst.strerror))
881 (relsrc, inst.strerror))
886 errors += 1
882 errors += 1
887 return
883 return
888 if ui.verbose or not exact:
884 if ui.verbose or not exact:
889 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
885 ui.status(_('copying %s to %s\n') % (relsrc, reltarget))
890 targets[abstarget] = abssrc
886 targets[abstarget] = abssrc
891 repo.copy(origsrc, abstarget)
887 repo.copy(origsrc, abstarget)
892 copied.append((abssrc, relsrc, exact))
888 copied.append((abssrc, relsrc, exact))
893
889
894 def targetpathfn(pat, dest, srcs):
890 def targetpathfn(pat, dest, srcs):
895 if os.path.isdir(pat):
891 if os.path.isdir(pat):
896 abspfx = util.canonpath(repo.root, cwd, pat)
892 abspfx = util.canonpath(repo.root, cwd, pat)
897 if destdirexists:
893 if destdirexists:
898 striplen = len(os.path.split(abspfx)[0])
894 striplen = len(os.path.split(abspfx)[0])
899 else:
895 else:
900 striplen = len(abspfx)
896 striplen = len(abspfx)
901 if striplen:
897 if striplen:
902 striplen += len(os.sep)
898 striplen += len(os.sep)
903 res = lambda p: os.path.join(dest, p[striplen:])
899 res = lambda p: os.path.join(dest, p[striplen:])
904 elif destdirexists:
900 elif destdirexists:
905 res = lambda p: os.path.join(dest, os.path.basename(p))
901 res = lambda p: os.path.join(dest, os.path.basename(p))
906 else:
902 else:
907 res = lambda p: dest
903 res = lambda p: dest
908 return res
904 return res
909
905
910 def targetpathafterfn(pat, dest, srcs):
906 def targetpathafterfn(pat, dest, srcs):
911 if util.patkind(pat, None)[0]:
907 if util.patkind(pat, None)[0]:
912 # a mercurial pattern
908 # a mercurial pattern
913 res = lambda p: os.path.join(dest, os.path.basename(p))
909 res = lambda p: os.path.join(dest, os.path.basename(p))
914 else:
910 else:
915 abspfx = util.canonpath(repo.root, cwd, pat)
911 abspfx = util.canonpath(repo.root, cwd, pat)
916 if len(abspfx) < len(srcs[0][0]):
912 if len(abspfx) < len(srcs[0][0]):
917 # A directory. Either the target path contains the last
913 # A directory. Either the target path contains the last
918 # component of the source path or it does not.
914 # component of the source path or it does not.
919 def evalpath(striplen):
915 def evalpath(striplen):
920 score = 0
916 score = 0
921 for s in srcs:
917 for s in srcs:
922 t = os.path.join(dest, s[0][striplen:])
918 t = os.path.join(dest, s[0][striplen:])
923 if os.path.exists(t):
919 if os.path.exists(t):
924 score += 1
920 score += 1
925 return score
921 return score
926
922
927 striplen = len(abspfx)
923 striplen = len(abspfx)
928 if striplen:
924 if striplen:
929 striplen += len(os.sep)
925 striplen += len(os.sep)
930 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
926 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
931 score = evalpath(striplen)
927 score = evalpath(striplen)
932 striplen1 = len(os.path.split(abspfx)[0])
928 striplen1 = len(os.path.split(abspfx)[0])
933 if striplen1:
929 if striplen1:
934 striplen1 += len(os.sep)
930 striplen1 += len(os.sep)
935 if evalpath(striplen1) > score:
931 if evalpath(striplen1) > score:
936 striplen = striplen1
932 striplen = striplen1
937 res = lambda p: os.path.join(dest, p[striplen:])
933 res = lambda p: os.path.join(dest, p[striplen:])
938 else:
934 else:
939 # a file
935 # a file
940 if destdirexists:
936 if destdirexists:
941 res = lambda p: os.path.join(dest, os.path.basename(p))
937 res = lambda p: os.path.join(dest, os.path.basename(p))
942 else:
938 else:
943 res = lambda p: dest
939 res = lambda p: dest
944 return res
940 return res
945
941
946
942
947 pats = list(pats)
943 pats = list(pats)
948 if not pats:
944 if not pats:
949 raise util.Abort(_('no source or destination specified'))
945 raise util.Abort(_('no source or destination specified'))
950 if len(pats) == 1:
946 if len(pats) == 1:
951 raise util.Abort(_('no destination specified'))
947 raise util.Abort(_('no destination specified'))
952 dest = pats.pop()
948 dest = pats.pop()
953 destdirexists = os.path.isdir(dest)
949 destdirexists = os.path.isdir(dest)
954 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
950 if (len(pats) > 1 or util.patkind(pats[0], None)[0]) and not destdirexists:
955 raise util.Abort(_('with multiple sources, destination must be an '
951 raise util.Abort(_('with multiple sources, destination must be an '
956 'existing directory'))
952 'existing directory'))
957 if opts['after']:
953 if opts['after']:
958 tfn = targetpathafterfn
954 tfn = targetpathafterfn
959 else:
955 else:
960 tfn = targetpathfn
956 tfn = targetpathfn
961 copylist = []
957 copylist = []
962 for pat in pats:
958 for pat in pats:
963 srcs = []
959 srcs = []
964 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
960 for tag, abssrc, relsrc, exact in walk(repo, [pat], opts):
965 origsrc = okaytocopy(abssrc, relsrc, exact)
961 origsrc = okaytocopy(abssrc, relsrc, exact)
966 if origsrc:
962 if origsrc:
967 srcs.append((origsrc, abssrc, relsrc, exact))
963 srcs.append((origsrc, abssrc, relsrc, exact))
968 if not srcs:
964 if not srcs:
969 continue
965 continue
970 copylist.append((tfn(pat, dest, srcs), srcs))
966 copylist.append((tfn(pat, dest, srcs), srcs))
971 if not copylist:
967 if not copylist:
972 raise util.Abort(_('no files to copy'))
968 raise util.Abort(_('no files to copy'))
973
969
974 for targetpath, srcs in copylist:
970 for targetpath, srcs in copylist:
975 for origsrc, abssrc, relsrc, exact in srcs:
971 for origsrc, abssrc, relsrc, exact in srcs:
976 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
972 copy(origsrc, abssrc, relsrc, targetpath(abssrc), exact)
977
973
978 if errors:
974 if errors:
979 ui.warn(_('(consider using --after)\n'))
975 ui.warn(_('(consider using --after)\n'))
980 return errors, copied
976 return errors, copied
981
977
982 def copy(ui, repo, *pats, **opts):
978 def copy(ui, repo, *pats, **opts):
983 """mark files as copied for the next commit
979 """mark files as copied for the next commit
984
980
985 Mark dest as having copies of source files. If dest is a
981 Mark dest as having copies of source files. If dest is a
986 directory, copies are put in that directory. If dest is a file,
982 directory, copies are put in that directory. If dest is a file,
987 there can only be one source.
983 there can only be one source.
988
984
989 By default, this command copies the contents of files as they
985 By default, this command copies the contents of files as they
990 stand in the working directory. If invoked with --after, the
986 stand in the working directory. If invoked with --after, the
991 operation is recorded, but no copying is performed.
987 operation is recorded, but no copying is performed.
992
988
993 This command takes effect in the next commit.
989 This command takes effect in the next commit.
994
990
995 NOTE: This command should be treated as experimental. While it
991 NOTE: This command should be treated as experimental. While it
996 should properly record copied files, this information is not yet
992 should properly record copied files, this information is not yet
997 fully used by merge, nor fully reported by log.
993 fully used by merge, nor fully reported by log.
998 """
994 """
999 errs, copied = docopy(ui, repo, pats, opts)
995 errs, copied = docopy(ui, repo, pats, opts)
1000 return errs
996 return errs
1001
997
1002 def debugancestor(ui, index, rev1, rev2):
998 def debugancestor(ui, index, rev1, rev2):
1003 """find the ancestor revision of two revisions in a given index"""
999 """find the ancestor revision of two revisions in a given index"""
1004 r = revlog.revlog(util.opener(os.getcwd()), index, "")
1000 r = revlog.revlog(util.opener(os.getcwd()), index, "")
1005 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1001 a = r.ancestor(r.lookup(rev1), r.lookup(rev2))
1006 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1002 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1007
1003
1008 def debugrebuildstate(ui, repo, rev=None):
1004 def debugrebuildstate(ui, repo, rev=None):
1009 """rebuild the dirstate as it would look like for the given revision"""
1005 """rebuild the dirstate as it would look like for the given revision"""
1010 if not rev:
1006 if not rev:
1011 rev = repo.changelog.tip()
1007 rev = repo.changelog.tip()
1012 else:
1008 else:
1013 rev = repo.lookup(rev)
1009 rev = repo.lookup(rev)
1014 change = repo.changelog.read(rev)
1010 change = repo.changelog.read(rev)
1015 n = change[0]
1011 n = change[0]
1016 files = repo.manifest.readflags(n)
1012 files = repo.manifest.readflags(n)
1017 wlock = repo.wlock()
1013 wlock = repo.wlock()
1018 repo.dirstate.rebuild(rev, files.iteritems())
1014 repo.dirstate.rebuild(rev, files.iteritems())
1019
1015
1020 def debugcheckstate(ui, repo):
1016 def debugcheckstate(ui, repo):
1021 """validate the correctness of the current dirstate"""
1017 """validate the correctness of the current dirstate"""
1022 parent1, parent2 = repo.dirstate.parents()
1018 parent1, parent2 = repo.dirstate.parents()
1023 repo.dirstate.read()
1019 repo.dirstate.read()
1024 dc = repo.dirstate.map
1020 dc = repo.dirstate.map
1025 keys = dc.keys()
1021 keys = dc.keys()
1026 keys.sort()
1022 keys.sort()
1027 m1n = repo.changelog.read(parent1)[0]
1023 m1n = repo.changelog.read(parent1)[0]
1028 m2n = repo.changelog.read(parent2)[0]
1024 m2n = repo.changelog.read(parent2)[0]
1029 m1 = repo.manifest.read(m1n)
1025 m1 = repo.manifest.read(m1n)
1030 m2 = repo.manifest.read(m2n)
1026 m2 = repo.manifest.read(m2n)
1031 errors = 0
1027 errors = 0
1032 for f in dc:
1028 for f in dc:
1033 state = repo.dirstate.state(f)
1029 state = repo.dirstate.state(f)
1034 if state in "nr" and f not in m1:
1030 if state in "nr" and f not in m1:
1035 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1031 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1036 errors += 1
1032 errors += 1
1037 if state in "a" and f in m1:
1033 if state in "a" and f in m1:
1038 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1034 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1039 errors += 1
1035 errors += 1
1040 if state in "m" and f not in m1 and f not in m2:
1036 if state in "m" and f not in m1 and f not in m2:
1041 ui.warn(_("%s in state %s, but not in either manifest\n") %
1037 ui.warn(_("%s in state %s, but not in either manifest\n") %
1042 (f, state))
1038 (f, state))
1043 errors += 1
1039 errors += 1
1044 for f in m1:
1040 for f in m1:
1045 state = repo.dirstate.state(f)
1041 state = repo.dirstate.state(f)
1046 if state not in "nrm":
1042 if state not in "nrm":
1047 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1043 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1048 errors += 1
1044 errors += 1
1049 if errors:
1045 if errors:
1050 error = _(".hg/dirstate inconsistent with current parent's manifest")
1046 error = _(".hg/dirstate inconsistent with current parent's manifest")
1051 raise util.Abort(error)
1047 raise util.Abort(error)
1052
1048
1053 def debugconfig(ui):
1049 def debugconfig(ui):
1054 """show combined config settings from all hgrc files"""
1050 """show combined config settings from all hgrc files"""
1055 try:
1051 try:
1056 repo = hg.repository(ui)
1052 repo = hg.repository(ui)
1057 except hg.RepoError:
1053 except hg.RepoError:
1058 pass
1054 pass
1059 for section, name, value in ui.walkconfig():
1055 for section, name, value in ui.walkconfig():
1060 ui.write('%s.%s=%s\n' % (section, name, value))
1056 ui.write('%s.%s=%s\n' % (section, name, value))
1061
1057
1062 def debugsetparents(ui, repo, rev1, rev2=None):
1058 def debugsetparents(ui, repo, rev1, rev2=None):
1063 """manually set the parents of the current working directory
1059 """manually set the parents of the current working directory
1064
1060
1065 This is useful for writing repository conversion tools, but should
1061 This is useful for writing repository conversion tools, but should
1066 be used with care.
1062 be used with care.
1067 """
1063 """
1068
1064
1069 if not rev2:
1065 if not rev2:
1070 rev2 = hex(nullid)
1066 rev2 = hex(nullid)
1071
1067
1072 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1068 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
1073
1069
1074 def debugstate(ui, repo):
1070 def debugstate(ui, repo):
1075 """show the contents of the current dirstate"""
1071 """show the contents of the current dirstate"""
1076 repo.dirstate.read()
1072 repo.dirstate.read()
1077 dc = repo.dirstate.map
1073 dc = repo.dirstate.map
1078 keys = dc.keys()
1074 keys = dc.keys()
1079 keys.sort()
1075 keys.sort()
1080 for file_ in keys:
1076 for file_ in keys:
1081 ui.write("%c %3o %10d %s %s\n"
1077 ui.write("%c %3o %10d %s %s\n"
1082 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1078 % (dc[file_][0], dc[file_][1] & 0777, dc[file_][2],
1083 time.strftime("%x %X",
1079 time.strftime("%x %X",
1084 time.localtime(dc[file_][3])), file_))
1080 time.localtime(dc[file_][3])), file_))
1085 for f in repo.dirstate.copies:
1081 for f in repo.dirstate.copies:
1086 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1082 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copies[f], f))
1087
1083
1088 def debugdata(ui, file_, rev):
1084 def debugdata(ui, file_, rev):
1089 """dump the contents of an data file revision"""
1085 """dump the contents of an data file revision"""
1090 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
1086 r = revlog.revlog(util.opener(os.getcwd()), file_[:-2] + ".i", file_)
1091 try:
1087 try:
1092 ui.write(r.revision(r.lookup(rev)))
1088 ui.write(r.revision(r.lookup(rev)))
1093 except KeyError:
1089 except KeyError:
1094 raise util.Abort(_('invalid revision identifier %s'), rev)
1090 raise util.Abort(_('invalid revision identifier %s'), rev)
1095
1091
1096 def debugindex(ui, file_):
1092 def debugindex(ui, file_):
1097 """dump the contents of an index file"""
1093 """dump the contents of an index file"""
1098 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1094 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1099 ui.write(" rev offset length base linkrev" +
1095 ui.write(" rev offset length base linkrev" +
1100 " nodeid p1 p2\n")
1096 " nodeid p1 p2\n")
1101 for i in range(r.count()):
1097 for i in range(r.count()):
1102 e = r.index[i]
1098 e = r.index[i]
1103 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1099 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1104 i, e[0], e[1], e[2], e[3],
1100 i, e[0], e[1], e[2], e[3],
1105 short(e[6]), short(e[4]), short(e[5])))
1101 short(e[6]), short(e[4]), short(e[5])))
1106
1102
1107 def debugindexdot(ui, file_):
1103 def debugindexdot(ui, file_):
1108 """dump an index DAG as a .dot file"""
1104 """dump an index DAG as a .dot file"""
1109 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1105 r = revlog.revlog(util.opener(os.getcwd()), file_, "")
1110 ui.write("digraph G {\n")
1106 ui.write("digraph G {\n")
1111 for i in range(r.count()):
1107 for i in range(r.count()):
1112 e = r.index[i]
1108 e = r.index[i]
1113 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1109 ui.write("\t%d -> %d\n" % (r.rev(e[4]), i))
1114 if e[5] != nullid:
1110 if e[5] != nullid:
1115 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1111 ui.write("\t%d -> %d\n" % (r.rev(e[5]), i))
1116 ui.write("}\n")
1112 ui.write("}\n")
1117
1113
1118 def debugrename(ui, repo, file, rev=None):
1114 def debugrename(ui, repo, file, rev=None):
1119 """dump rename information"""
1115 """dump rename information"""
1120 r = repo.file(relpath(repo, [file])[0])
1116 r = repo.file(relpath(repo, [file])[0])
1121 if rev:
1117 if rev:
1122 try:
1118 try:
1123 # assume all revision numbers are for changesets
1119 # assume all revision numbers are for changesets
1124 n = repo.lookup(rev)
1120 n = repo.lookup(rev)
1125 change = repo.changelog.read(n)
1121 change = repo.changelog.read(n)
1126 m = repo.manifest.read(change[0])
1122 m = repo.manifest.read(change[0])
1127 n = m[relpath(repo, [file])[0]]
1123 n = m[relpath(repo, [file])[0]]
1128 except (hg.RepoError, KeyError):
1124 except (hg.RepoError, KeyError):
1129 n = r.lookup(rev)
1125 n = r.lookup(rev)
1130 else:
1126 else:
1131 n = r.tip()
1127 n = r.tip()
1132 m = r.renamed(n)
1128 m = r.renamed(n)
1133 if m:
1129 if m:
1134 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1130 ui.write(_("renamed from %s:%s\n") % (m[0], hex(m[1])))
1135 else:
1131 else:
1136 ui.write(_("not renamed\n"))
1132 ui.write(_("not renamed\n"))
1137
1133
1138 def debugwalk(ui, repo, *pats, **opts):
1134 def debugwalk(ui, repo, *pats, **opts):
1139 """show how files match on given patterns"""
1135 """show how files match on given patterns"""
1140 items = list(walk(repo, pats, opts))
1136 items = list(walk(repo, pats, opts))
1141 if not items:
1137 if not items:
1142 return
1138 return
1143 fmt = '%%s %%-%ds %%-%ds %%s' % (
1139 fmt = '%%s %%-%ds %%-%ds %%s' % (
1144 max([len(abs) for (src, abs, rel, exact) in items]),
1140 max([len(abs) for (src, abs, rel, exact) in items]),
1145 max([len(rel) for (src, abs, rel, exact) in items]))
1141 max([len(rel) for (src, abs, rel, exact) in items]))
1146 for src, abs, rel, exact in items:
1142 for src, abs, rel, exact in items:
1147 line = fmt % (src, abs, rel, exact and 'exact' or '')
1143 line = fmt % (src, abs, rel, exact and 'exact' or '')
1148 ui.write("%s\n" % line.rstrip())
1144 ui.write("%s\n" % line.rstrip())
1149
1145
1150 def diff(ui, repo, *pats, **opts):
1146 def diff(ui, repo, *pats, **opts):
1151 """diff repository (or selected files)
1147 """diff repository (or selected files)
1152
1148
1153 Show differences between revisions for the specified files.
1149 Show differences between revisions for the specified files.
1154
1150
1155 Differences between files are shown using the unified diff format.
1151 Differences between files are shown using the unified diff format.
1156
1152
1157 When two revision arguments are given, then changes are shown
1153 When two revision arguments are given, then changes are shown
1158 between those revisions. If only one revision is specified then
1154 between those revisions. If only one revision is specified then
1159 that revision is compared to the working directory, and, when no
1155 that revision is compared to the working directory, and, when no
1160 revisions are specified, the working directory files are compared
1156 revisions are specified, the working directory files are compared
1161 to its parent.
1157 to its parent.
1162
1158
1163 Without the -a option, diff will avoid generating diffs of files
1159 Without the -a option, diff will avoid generating diffs of files
1164 it detects as binary. With -a, diff will generate a diff anyway,
1160 it detects as binary. With -a, diff will generate a diff anyway,
1165 probably with undesirable results.
1161 probably with undesirable results.
1166 """
1162 """
1167 node1, node2 = None, None
1163 node1, node2 = None, None
1168 revs = [repo.lookup(x) for x in opts['rev']]
1164 revs = [repo.lookup(x) for x in opts['rev']]
1169
1165
1170 if len(revs) > 0:
1166 if len(revs) > 0:
1171 node1 = revs[0]
1167 node1 = revs[0]
1172 if len(revs) > 1:
1168 if len(revs) > 1:
1173 node2 = revs[1]
1169 node2 = revs[1]
1174 if len(revs) > 2:
1170 if len(revs) > 2:
1175 raise util.Abort(_("too many revisions to diff"))
1171 raise util.Abort(_("too many revisions to diff"))
1176
1172
1177 fns, matchfn, anypats = matchpats(repo, pats, opts)
1173 fns, matchfn, anypats = matchpats(repo, pats, opts)
1178
1174
1179 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1175 dodiff(sys.stdout, ui, repo, node1, node2, fns, match=matchfn,
1180 text=opts['text'], opts=opts)
1176 text=opts['text'], opts=opts)
1181
1177
1182 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1178 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
1183 node = repo.lookup(changeset)
1179 node = repo.lookup(changeset)
1184 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1180 parents = [p for p in repo.changelog.parents(node) if p != nullid]
1185 if opts['switch_parent']:
1181 if opts['switch_parent']:
1186 parents.reverse()
1182 parents.reverse()
1187 prev = (parents and parents[0]) or nullid
1183 prev = (parents and parents[0]) or nullid
1188 change = repo.changelog.read(node)
1184 change = repo.changelog.read(node)
1189
1185
1190 fp = make_file(repo, repo.changelog, opts['output'],
1186 fp = make_file(repo, repo.changelog, opts['output'],
1191 node=node, total=total, seqno=seqno,
1187 node=node, total=total, seqno=seqno,
1192 revwidth=revwidth)
1188 revwidth=revwidth)
1193 if fp != sys.stdout:
1189 if fp != sys.stdout:
1194 ui.note("%s\n" % fp.name)
1190 ui.note("%s\n" % fp.name)
1195
1191
1196 fp.write("# HG changeset patch\n")
1192 fp.write("# HG changeset patch\n")
1197 fp.write("# User %s\n" % change[1])
1193 fp.write("# User %s\n" % change[1])
1198 fp.write("# Node ID %s\n" % hex(node))
1194 fp.write("# Node ID %s\n" % hex(node))
1199 fp.write("# Parent %s\n" % hex(prev))
1195 fp.write("# Parent %s\n" % hex(prev))
1200 if len(parents) > 1:
1196 if len(parents) > 1:
1201 fp.write("# Parent %s\n" % hex(parents[1]))
1197 fp.write("# Parent %s\n" % hex(parents[1]))
1202 fp.write(change[4].rstrip())
1198 fp.write(change[4].rstrip())
1203 fp.write("\n\n")
1199 fp.write("\n\n")
1204
1200
1205 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1201 dodiff(fp, ui, repo, prev, node, text=opts['text'])
1206 if fp != sys.stdout:
1202 if fp != sys.stdout:
1207 fp.close()
1203 fp.close()
1208
1204
1209 def export(ui, repo, *changesets, **opts):
1205 def export(ui, repo, *changesets, **opts):
1210 """dump the header and diffs for one or more changesets
1206 """dump the header and diffs for one or more changesets
1211
1207
1212 Print the changeset header and diffs for one or more revisions.
1208 Print the changeset header and diffs for one or more revisions.
1213
1209
1214 The information shown in the changeset header is: author,
1210 The information shown in the changeset header is: author,
1215 changeset hash, parent and commit comment.
1211 changeset hash, parent and commit comment.
1216
1212
1217 Output may be to a file, in which case the name of the file is
1213 Output may be to a file, in which case the name of the file is
1218 given using a format string. The formatting rules are as follows:
1214 given using a format string. The formatting rules are as follows:
1219
1215
1220 %% literal "%" character
1216 %% literal "%" character
1221 %H changeset hash (40 bytes of hexadecimal)
1217 %H changeset hash (40 bytes of hexadecimal)
1222 %N number of patches being generated
1218 %N number of patches being generated
1223 %R changeset revision number
1219 %R changeset revision number
1224 %b basename of the exporting repository
1220 %b basename of the exporting repository
1225 %h short-form changeset hash (12 bytes of hexadecimal)
1221 %h short-form changeset hash (12 bytes of hexadecimal)
1226 %n zero-padded sequence number, starting at 1
1222 %n zero-padded sequence number, starting at 1
1227 %r zero-padded changeset revision number
1223 %r zero-padded changeset revision number
1228
1224
1229 Without the -a option, export will avoid generating diffs of files
1225 Without the -a option, export will avoid generating diffs of files
1230 it detects as binary. With -a, export will generate a diff anyway,
1226 it detects as binary. With -a, export will generate a diff anyway,
1231 probably with undesirable results.
1227 probably with undesirable results.
1232
1228
1233 With the --switch-parent option, the diff will be against the second
1229 With the --switch-parent option, the diff will be against the second
1234 parent. It can be useful to review a merge.
1230 parent. It can be useful to review a merge.
1235 """
1231 """
1236 if not changesets:
1232 if not changesets:
1237 raise util.Abort(_("export requires at least one changeset"))
1233 raise util.Abort(_("export requires at least one changeset"))
1238 seqno = 0
1234 seqno = 0
1239 revs = list(revrange(ui, repo, changesets))
1235 revs = list(revrange(ui, repo, changesets))
1240 total = len(revs)
1236 total = len(revs)
1241 revwidth = max(map(len, revs))
1237 revwidth = max(map(len, revs))
1242 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1238 msg = len(revs) > 1 and _("Exporting patches:\n") or _("Exporting patch:\n")
1243 ui.note(msg)
1239 ui.note(msg)
1244 for cset in revs:
1240 for cset in revs:
1245 seqno += 1
1241 seqno += 1
1246 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1242 doexport(ui, repo, cset, seqno, total, revwidth, opts)
1247
1243
1248 def forget(ui, repo, *pats, **opts):
1244 def forget(ui, repo, *pats, **opts):
1249 """don't add the specified files on the next commit
1245 """don't add the specified files on the next commit
1250
1246
1251 Undo an 'hg add' scheduled for the next commit.
1247 Undo an 'hg add' scheduled for the next commit.
1252 """
1248 """
1253 forget = []
1249 forget = []
1254 for src, abs, rel, exact in walk(repo, pats, opts):
1250 for src, abs, rel, exact in walk(repo, pats, opts):
1255 if repo.dirstate.state(abs) == 'a':
1251 if repo.dirstate.state(abs) == 'a':
1256 forget.append(abs)
1252 forget.append(abs)
1257 if ui.verbose or not exact:
1253 if ui.verbose or not exact:
1258 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1254 ui.status(_('forgetting %s\n') % ((pats and rel) or abs))
1259 repo.forget(forget)
1255 repo.forget(forget)
1260
1256
1261 def grep(ui, repo, pattern, *pats, **opts):
1257 def grep(ui, repo, pattern, *pats, **opts):
1262 """search for a pattern in specified files and revisions
1258 """search for a pattern in specified files and revisions
1263
1259
1264 Search revisions of files for a regular expression.
1260 Search revisions of files for a regular expression.
1265
1261
1266 This command behaves differently than Unix grep. It only accepts
1262 This command behaves differently than Unix grep. It only accepts
1267 Python/Perl regexps. It searches repository history, not the
1263 Python/Perl regexps. It searches repository history, not the
1268 working directory. It always prints the revision number in which
1264 working directory. It always prints the revision number in which
1269 a match appears.
1265 a match appears.
1270
1266
1271 By default, grep only prints output for the first revision of a
1267 By default, grep only prints output for the first revision of a
1272 file in which it finds a match. To get it to print every revision
1268 file in which it finds a match. To get it to print every revision
1273 that contains a change in match status ("-" for a match that
1269 that contains a change in match status ("-" for a match that
1274 becomes a non-match, or "+" for a non-match that becomes a match),
1270 becomes a non-match, or "+" for a non-match that becomes a match),
1275 use the --all flag.
1271 use the --all flag.
1276 """
1272 """
1277 reflags = 0
1273 reflags = 0
1278 if opts['ignore_case']:
1274 if opts['ignore_case']:
1279 reflags |= re.I
1275 reflags |= re.I
1280 regexp = re.compile(pattern, reflags)
1276 regexp = re.compile(pattern, reflags)
1281 sep, eol = ':', '\n'
1277 sep, eol = ':', '\n'
1282 if opts['print0']:
1278 if opts['print0']:
1283 sep = eol = '\0'
1279 sep = eol = '\0'
1284
1280
1285 fcache = {}
1281 fcache = {}
1286 def getfile(fn):
1282 def getfile(fn):
1287 if fn not in fcache:
1283 if fn not in fcache:
1288 fcache[fn] = repo.file(fn)
1284 fcache[fn] = repo.file(fn)
1289 return fcache[fn]
1285 return fcache[fn]
1290
1286
1291 def matchlines(body):
1287 def matchlines(body):
1292 begin = 0
1288 begin = 0
1293 linenum = 0
1289 linenum = 0
1294 while True:
1290 while True:
1295 match = regexp.search(body, begin)
1291 match = regexp.search(body, begin)
1296 if not match:
1292 if not match:
1297 break
1293 break
1298 mstart, mend = match.span()
1294 mstart, mend = match.span()
1299 linenum += body.count('\n', begin, mstart) + 1
1295 linenum += body.count('\n', begin, mstart) + 1
1300 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1296 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1301 lend = body.find('\n', mend)
1297 lend = body.find('\n', mend)
1302 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1298 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1303 begin = lend + 1
1299 begin = lend + 1
1304
1300
1305 class linestate(object):
1301 class linestate(object):
1306 def __init__(self, line, linenum, colstart, colend):
1302 def __init__(self, line, linenum, colstart, colend):
1307 self.line = line
1303 self.line = line
1308 self.linenum = linenum
1304 self.linenum = linenum
1309 self.colstart = colstart
1305 self.colstart = colstart
1310 self.colend = colend
1306 self.colend = colend
1311 def __eq__(self, other):
1307 def __eq__(self, other):
1312 return self.line == other.line
1308 return self.line == other.line
1313 def __hash__(self):
1309 def __hash__(self):
1314 return hash(self.line)
1310 return hash(self.line)
1315
1311
1316 matches = {}
1312 matches = {}
1317 def grepbody(fn, rev, body):
1313 def grepbody(fn, rev, body):
1318 matches[rev].setdefault(fn, {})
1314 matches[rev].setdefault(fn, {})
1319 m = matches[rev][fn]
1315 m = matches[rev][fn]
1320 for lnum, cstart, cend, line in matchlines(body):
1316 for lnum, cstart, cend, line in matchlines(body):
1321 s = linestate(line, lnum, cstart, cend)
1317 s = linestate(line, lnum, cstart, cend)
1322 m[s] = s
1318 m[s] = s
1323
1319
1324 # FIXME: prev isn't used, why ?
1320 # FIXME: prev isn't used, why ?
1325 prev = {}
1321 prev = {}
1326 ucache = {}
1322 ucache = {}
1327 def display(fn, rev, states, prevstates):
1323 def display(fn, rev, states, prevstates):
1328 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1324 diff = list(sets.Set(states).symmetric_difference(sets.Set(prevstates)))
1329 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1325 diff.sort(lambda x, y: cmp(x.linenum, y.linenum))
1330 counts = {'-': 0, '+': 0}
1326 counts = {'-': 0, '+': 0}
1331 filerevmatches = {}
1327 filerevmatches = {}
1332 for l in diff:
1328 for l in diff:
1333 if incrementing or not opts['all']:
1329 if incrementing or not opts['all']:
1334 change = ((l in prevstates) and '-') or '+'
1330 change = ((l in prevstates) and '-') or '+'
1335 r = rev
1331 r = rev
1336 else:
1332 else:
1337 change = ((l in states) and '-') or '+'
1333 change = ((l in states) and '-') or '+'
1338 r = prev[fn]
1334 r = prev[fn]
1339 cols = [fn, str(rev)]
1335 cols = [fn, str(rev)]
1340 if opts['line_number']:
1336 if opts['line_number']:
1341 cols.append(str(l.linenum))
1337 cols.append(str(l.linenum))
1342 if opts['all']:
1338 if opts['all']:
1343 cols.append(change)
1339 cols.append(change)
1344 if opts['user']:
1340 if opts['user']:
1345 cols.append(trimuser(ui, getchange(rev)[1], rev,
1341 cols.append(trimuser(ui, getchange(rev)[1], rev,
1346 ucache))
1342 ucache))
1347 if opts['files_with_matches']:
1343 if opts['files_with_matches']:
1348 c = (fn, rev)
1344 c = (fn, rev)
1349 if c in filerevmatches:
1345 if c in filerevmatches:
1350 continue
1346 continue
1351 filerevmatches[c] = 1
1347 filerevmatches[c] = 1
1352 else:
1348 else:
1353 cols.append(l.line)
1349 cols.append(l.line)
1354 ui.write(sep.join(cols), eol)
1350 ui.write(sep.join(cols), eol)
1355 counts[change] += 1
1351 counts[change] += 1
1356 return counts['+'], counts['-']
1352 return counts['+'], counts['-']
1357
1353
1358 fstate = {}
1354 fstate = {}
1359 skip = {}
1355 skip = {}
1360 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1356 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1361 count = 0
1357 count = 0
1362 incrementing = False
1358 incrementing = False
1363 for st, rev, fns in changeiter:
1359 for st, rev, fns in changeiter:
1364 if st == 'window':
1360 if st == 'window':
1365 incrementing = rev
1361 incrementing = rev
1366 matches.clear()
1362 matches.clear()
1367 elif st == 'add':
1363 elif st == 'add':
1368 change = repo.changelog.read(repo.lookup(str(rev)))
1364 change = repo.changelog.read(repo.lookup(str(rev)))
1369 mf = repo.manifest.read(change[0])
1365 mf = repo.manifest.read(change[0])
1370 matches[rev] = {}
1366 matches[rev] = {}
1371 for fn in fns:
1367 for fn in fns:
1372 if fn in skip:
1368 if fn in skip:
1373 continue
1369 continue
1374 fstate.setdefault(fn, {})
1370 fstate.setdefault(fn, {})
1375 try:
1371 try:
1376 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1372 grepbody(fn, rev, getfile(fn).read(mf[fn]))
1377 except KeyError:
1373 except KeyError:
1378 pass
1374 pass
1379 elif st == 'iter':
1375 elif st == 'iter':
1380 states = matches[rev].items()
1376 states = matches[rev].items()
1381 states.sort()
1377 states.sort()
1382 for fn, m in states:
1378 for fn, m in states:
1383 if fn in skip:
1379 if fn in skip:
1384 continue
1380 continue
1385 if incrementing or not opts['all'] or fstate[fn]:
1381 if incrementing or not opts['all'] or fstate[fn]:
1386 pos, neg = display(fn, rev, m, fstate[fn])
1382 pos, neg = display(fn, rev, m, fstate[fn])
1387 count += pos + neg
1383 count += pos + neg
1388 if pos and not opts['all']:
1384 if pos and not opts['all']:
1389 skip[fn] = True
1385 skip[fn] = True
1390 fstate[fn] = m
1386 fstate[fn] = m
1391 prev[fn] = rev
1387 prev[fn] = rev
1392
1388
1393 if not incrementing:
1389 if not incrementing:
1394 fstate = fstate.items()
1390 fstate = fstate.items()
1395 fstate.sort()
1391 fstate.sort()
1396 for fn, state in fstate:
1392 for fn, state in fstate:
1397 if fn in skip:
1393 if fn in skip:
1398 continue
1394 continue
1399 display(fn, rev, {}, state)
1395 display(fn, rev, {}, state)
1400 return (count == 0 and 1) or 0
1396 return (count == 0 and 1) or 0
1401
1397
1402 def heads(ui, repo, **opts):
1398 def heads(ui, repo, **opts):
1403 """show current repository heads
1399 """show current repository heads
1404
1400
1405 Show all repository head changesets.
1401 Show all repository head changesets.
1406
1402
1407 Repository "heads" are changesets that don't have children
1403 Repository "heads" are changesets that don't have children
1408 changesets. They are where development generally takes place and
1404 changesets. They are where development generally takes place and
1409 are the usual targets for update and merge operations.
1405 are the usual targets for update and merge operations.
1410 """
1406 """
1411 if opts['rev']:
1407 if opts['rev']:
1412 heads = repo.heads(repo.lookup(opts['rev']))
1408 heads = repo.heads(repo.lookup(opts['rev']))
1413 else:
1409 else:
1414 heads = repo.heads()
1410 heads = repo.heads()
1415 br = None
1411 br = None
1416 if opts['branches']:
1412 if opts['branches']:
1417 br = repo.branchlookup(heads)
1413 br = repo.branchlookup(heads)
1418 for n in heads:
1414 for n in heads:
1419 show_changeset(ui, repo, changenode=n, brinfo=br)
1415 show_changeset(ui, repo, changenode=n, brinfo=br)
1420
1416
1421 def identify(ui, repo):
1417 def identify(ui, repo):
1422 """print information about the working copy
1418 """print information about the working copy
1423
1419
1424 Print a short summary of the current state of the repo.
1420 Print a short summary of the current state of the repo.
1425
1421
1426 This summary identifies the repository state using one or two parent
1422 This summary identifies the repository state using one or two parent
1427 hash identifiers, followed by a "+" if there are uncommitted changes
1423 hash identifiers, followed by a "+" if there are uncommitted changes
1428 in the working directory, followed by a list of tags for this revision.
1424 in the working directory, followed by a list of tags for this revision.
1429 """
1425 """
1430 parents = [p for p in repo.dirstate.parents() if p != nullid]
1426 parents = [p for p in repo.dirstate.parents() if p != nullid]
1431 if not parents:
1427 if not parents:
1432 ui.write(_("unknown\n"))
1428 ui.write(_("unknown\n"))
1433 return
1429 return
1434
1430
1435 hexfunc = ui.verbose and hex or short
1431 hexfunc = ui.verbose and hex or short
1436 modified, added, removed, deleted, unknown = repo.changes()
1432 modified, added, removed, deleted, unknown = repo.changes()
1437 output = ["%s%s" %
1433 output = ["%s%s" %
1438 ('+'.join([hexfunc(parent) for parent in parents]),
1434 ('+'.join([hexfunc(parent) for parent in parents]),
1439 (modified or added or removed or deleted) and "+" or "")]
1435 (modified or added or removed or deleted) and "+" or "")]
1440
1436
1441 if not ui.quiet:
1437 if not ui.quiet:
1442 # multiple tags for a single parent separated by '/'
1438 # multiple tags for a single parent separated by '/'
1443 parenttags = ['/'.join(tags)
1439 parenttags = ['/'.join(tags)
1444 for tags in map(repo.nodetags, parents) if tags]
1440 for tags in map(repo.nodetags, parents) if tags]
1445 # tags for multiple parents separated by ' + '
1441 # tags for multiple parents separated by ' + '
1446 if parenttags:
1442 if parenttags:
1447 output.append(' + '.join(parenttags))
1443 output.append(' + '.join(parenttags))
1448
1444
1449 ui.write("%s\n" % ' '.join(output))
1445 ui.write("%s\n" % ' '.join(output))
1450
1446
1451 def import_(ui, repo, patch1, *patches, **opts):
1447 def import_(ui, repo, patch1, *patches, **opts):
1452 """import an ordered set of patches
1448 """import an ordered set of patches
1453
1449
1454 Import a list of patches and commit them individually.
1450 Import a list of patches and commit them individually.
1455
1451
1456 If there are outstanding changes in the working directory, import
1452 If there are outstanding changes in the working directory, import
1457 will abort unless given the -f flag.
1453 will abort unless given the -f flag.
1458
1454
1459 If a patch looks like a mail message (its first line starts with
1455 If a patch looks like a mail message (its first line starts with
1460 "From " or looks like an RFC822 header), it will not be applied
1456 "From " or looks like an RFC822 header), it will not be applied
1461 unless the -f option is used. The importer neither parses nor
1457 unless the -f option is used. The importer neither parses nor
1462 discards mail headers, so use -f only to override the "mailness"
1458 discards mail headers, so use -f only to override the "mailness"
1463 safety check, not to import a real mail message.
1459 safety check, not to import a real mail message.
1464 """
1460 """
1465 patches = (patch1,) + patches
1461 patches = (patch1,) + patches
1466
1462
1467 if not opts['force']:
1463 if not opts['force']:
1468 modified, added, removed, deleted, unknown = repo.changes()
1464 modified, added, removed, deleted, unknown = repo.changes()
1469 if modified or added or removed or deleted:
1465 if modified or added or removed or deleted:
1470 raise util.Abort(_("outstanding uncommitted changes"))
1466 raise util.Abort(_("outstanding uncommitted changes"))
1471
1467
1472 d = opts["base"]
1468 d = opts["base"]
1473 strip = opts["strip"]
1469 strip = opts["strip"]
1474
1470
1475 mailre = re.compile(r'(?:From |[\w-]+:)')
1471 mailre = re.compile(r'(?:From |[\w-]+:)')
1476
1472
1477 # attempt to detect the start of a patch
1473 # attempt to detect the start of a patch
1478 # (this heuristic is borrowed from quilt)
1474 # (this heuristic is borrowed from quilt)
1479 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1475 diffre = re.compile(r'(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1480 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1476 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1481 '(---|\*\*\*)[ \t])')
1477 '(---|\*\*\*)[ \t])')
1482
1478
1483 for patch in patches:
1479 for patch in patches:
1484 ui.status(_("applying %s\n") % patch)
1480 ui.status(_("applying %s\n") % patch)
1485 pf = os.path.join(d, patch)
1481 pf = os.path.join(d, patch)
1486
1482
1487 message = []
1483 message = []
1488 user = None
1484 user = None
1489 hgpatch = False
1485 hgpatch = False
1490 for line in file(pf):
1486 for line in file(pf):
1491 line = line.rstrip()
1487 line = line.rstrip()
1492 if (not message and not hgpatch and
1488 if (not message and not hgpatch and
1493 mailre.match(line) and not opts['force']):
1489 mailre.match(line) and not opts['force']):
1494 if len(line) > 35:
1490 if len(line) > 35:
1495 line = line[:32] + '...'
1491 line = line[:32] + '...'
1496 raise util.Abort(_('first line looks like a '
1492 raise util.Abort(_('first line looks like a '
1497 'mail header: ') + line)
1493 'mail header: ') + line)
1498 if diffre.match(line):
1494 if diffre.match(line):
1499 break
1495 break
1500 elif hgpatch:
1496 elif hgpatch:
1501 # parse values when importing the result of an hg export
1497 # parse values when importing the result of an hg export
1502 if line.startswith("# User "):
1498 if line.startswith("# User "):
1503 user = line[7:]
1499 user = line[7:]
1504 ui.debug(_('User: %s\n') % user)
1500 ui.debug(_('User: %s\n') % user)
1505 elif not line.startswith("# ") and line:
1501 elif not line.startswith("# ") and line:
1506 message.append(line)
1502 message.append(line)
1507 hgpatch = False
1503 hgpatch = False
1508 elif line == '# HG changeset patch':
1504 elif line == '# HG changeset patch':
1509 hgpatch = True
1505 hgpatch = True
1510 message = [] # We may have collected garbage
1506 message = [] # We may have collected garbage
1511 else:
1507 else:
1512 message.append(line)
1508 message.append(line)
1513
1509
1514 # make sure message isn't empty
1510 # make sure message isn't empty
1515 if not message:
1511 if not message:
1516 message = _("imported patch %s\n") % patch
1512 message = _("imported patch %s\n") % patch
1517 else:
1513 else:
1518 message = "%s\n" % '\n'.join(message)
1514 message = "%s\n" % '\n'.join(message)
1519 ui.debug(_('message:\n%s\n') % message)
1515 ui.debug(_('message:\n%s\n') % message)
1520
1516
1521 files = util.patch(strip, pf, ui)
1517 files = util.patch(strip, pf, ui)
1522
1518
1523 if len(files) > 0:
1519 if len(files) > 0:
1524 addremove(ui, repo, *files)
1520 addremove(ui, repo, *files)
1525 repo.commit(files, message, user)
1521 repo.commit(files, message, user)
1526
1522
1527 def incoming(ui, repo, source="default", **opts):
1523 def incoming(ui, repo, source="default", **opts):
1528 """show new changesets found in source
1524 """show new changesets found in source
1529
1525
1530 Show new changesets found in the specified repo or the default
1526 Show new changesets found in the specified repo or the default
1531 pull repo. These are the changesets that would be pulled if a pull
1527 pull repo. These are the changesets that would be pulled if a pull
1532 was requested.
1528 was requested.
1533
1529
1534 Currently only local repositories are supported.
1530 Currently only local repositories are supported.
1535 """
1531 """
1536 source = ui.expandpath(source, repo.root)
1532 source = ui.expandpath(source, repo.root)
1537 other = hg.repository(ui, source)
1533 other = hg.repository(ui, source)
1538 if not other.local():
1534 if not other.local():
1539 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1535 raise util.Abort(_("incoming doesn't work for remote repositories yet"))
1540 o = repo.findincoming(other)
1536 o = repo.findincoming(other)
1541 if not o:
1537 if not o:
1542 return
1538 return
1543 o = other.changelog.nodesbetween(o)[0]
1539 o = other.changelog.nodesbetween(o)[0]
1544 if opts['newest_first']:
1540 if opts['newest_first']:
1545 o.reverse()
1541 o.reverse()
1546 for n in o:
1542 for n in o:
1547 parents = [p for p in other.changelog.parents(n) if p != nullid]
1543 parents = [p for p in other.changelog.parents(n) if p != nullid]
1548 if opts['no_merges'] and len(parents) == 2:
1544 if opts['no_merges'] and len(parents) == 2:
1549 continue
1545 continue
1550 show_changeset(ui, other, changenode=n)
1546 show_changeset(ui, other, changenode=n)
1551 if opts['patch']:
1547 if opts['patch']:
1552 prev = (parents and parents[0]) or nullid
1548 prev = (parents and parents[0]) or nullid
1553 dodiff(ui, ui, other, prev, n)
1549 dodiff(ui, ui, other, prev, n)
1554 ui.write("\n")
1550 ui.write("\n")
1555
1551
1556 def init(ui, dest="."):
1552 def init(ui, dest="."):
1557 """create a new repository in the given directory
1553 """create a new repository in the given directory
1558
1554
1559 Initialize a new repository in the given directory. If the given
1555 Initialize a new repository in the given directory. If the given
1560 directory does not exist, it is created.
1556 directory does not exist, it is created.
1561
1557
1562 If no directory is given, the current directory is used.
1558 If no directory is given, the current directory is used.
1563 """
1559 """
1564 if not os.path.exists(dest):
1560 if not os.path.exists(dest):
1565 os.mkdir(dest)
1561 os.mkdir(dest)
1566 hg.repository(ui, dest, create=1)
1562 hg.repository(ui, dest, create=1)
1567
1563
1568 def locate(ui, repo, *pats, **opts):
1564 def locate(ui, repo, *pats, **opts):
1569 """locate files matching specific patterns
1565 """locate files matching specific patterns
1570
1566
1571 Print all files under Mercurial control whose names match the
1567 Print all files under Mercurial control whose names match the
1572 given patterns.
1568 given patterns.
1573
1569
1574 This command searches the current directory and its
1570 This command searches the current directory and its
1575 subdirectories. To search an entire repository, move to the root
1571 subdirectories. To search an entire repository, move to the root
1576 of the repository.
1572 of the repository.
1577
1573
1578 If no patterns are given to match, this command prints all file
1574 If no patterns are given to match, this command prints all file
1579 names.
1575 names.
1580
1576
1581 If you want to feed the output of this command into the "xargs"
1577 If you want to feed the output of this command into the "xargs"
1582 command, use the "-0" option to both this command and "xargs".
1578 command, use the "-0" option to both this command and "xargs".
1583 This will avoid the problem of "xargs" treating single filenames
1579 This will avoid the problem of "xargs" treating single filenames
1584 that contain white space as multiple filenames.
1580 that contain white space as multiple filenames.
1585 """
1581 """
1586 end = opts['print0'] and '\0' or '\n'
1582 end = opts['print0'] and '\0' or '\n'
1587 rev = opts['rev']
1583 rev = opts['rev']
1588 if rev:
1584 if rev:
1589 node = repo.lookup(rev)
1585 node = repo.lookup(rev)
1590 else:
1586 else:
1591 node = None
1587 node = None
1592
1588
1593 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1589 for src, abs, rel, exact in walk(repo, pats, opts, node=node,
1594 head='(?:.*/|)'):
1590 head='(?:.*/|)'):
1595 if not node and repo.dirstate.state(abs) == '?':
1591 if not node and repo.dirstate.state(abs) == '?':
1596 continue
1592 continue
1597 if opts['fullpath']:
1593 if opts['fullpath']:
1598 ui.write(os.path.join(repo.root, abs), end)
1594 ui.write(os.path.join(repo.root, abs), end)
1599 else:
1595 else:
1600 ui.write(((pats and rel) or abs), end)
1596 ui.write(((pats and rel) or abs), end)
1601
1597
1602 def log(ui, repo, *pats, **opts):
1598 def log(ui, repo, *pats, **opts):
1603 """show revision history of entire repository or files
1599 """show revision history of entire repository or files
1604
1600
1605 Print the revision history of the specified files or the entire project.
1601 Print the revision history of the specified files or the entire project.
1606
1602
1607 By default this command outputs: changeset id and hash, tags,
1603 By default this command outputs: changeset id and hash, tags,
1608 non-trivial parents, user, date and time, and a summary for each
1604 non-trivial parents, user, date and time, and a summary for each
1609 commit. When the -v/--verbose switch is used, the list of changed
1605 commit. When the -v/--verbose switch is used, the list of changed
1610 files and full commit message is shown.
1606 files and full commit message is shown.
1611 """
1607 """
1612 class dui(object):
1608 class dui(object):
1613 # Implement and delegate some ui protocol. Save hunks of
1609 # Implement and delegate some ui protocol. Save hunks of
1614 # output for later display in the desired order.
1610 # output for later display in the desired order.
1615 def __init__(self, ui):
1611 def __init__(self, ui):
1616 self.ui = ui
1612 self.ui = ui
1617 self.hunk = {}
1613 self.hunk = {}
1618 def bump(self, rev):
1614 def bump(self, rev):
1619 self.rev = rev
1615 self.rev = rev
1620 self.hunk[rev] = []
1616 self.hunk[rev] = []
1621 def note(self, *args):
1617 def note(self, *args):
1622 if self.verbose:
1618 if self.verbose:
1623 self.write(*args)
1619 self.write(*args)
1624 def status(self, *args):
1620 def status(self, *args):
1625 if not self.quiet:
1621 if not self.quiet:
1626 self.write(*args)
1622 self.write(*args)
1627 def write(self, *args):
1623 def write(self, *args):
1628 self.hunk[self.rev].append(args)
1624 self.hunk[self.rev].append(args)
1629 def debug(self, *args):
1625 def debug(self, *args):
1630 if self.debugflag:
1626 if self.debugflag:
1631 self.write(*args)
1627 self.write(*args)
1632 def __getattr__(self, key):
1628 def __getattr__(self, key):
1633 return getattr(self.ui, key)
1629 return getattr(self.ui, key)
1634
1630
1635 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1631 changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
1636
1632
1637 if opts['limit']:
1633 if opts['limit']:
1638 try:
1634 try:
1639 limit = int(opts['limit'])
1635 limit = int(opts['limit'])
1640 except ValueError:
1636 except ValueError:
1641 raise util.Abort(_('limit must be a positive integer'))
1637 raise util.Abort(_('limit must be a positive integer'))
1642 if limit <= 0: raise util.Abort(_('limit must be positive'))
1638 if limit <= 0: raise util.Abort(_('limit must be positive'))
1643 else:
1639 else:
1644 limit = sys.maxint
1640 limit = sys.maxint
1645 count = 0
1641 count = 0
1646
1642
1647 for st, rev, fns in changeiter:
1643 for st, rev, fns in changeiter:
1648 if st == 'window':
1644 if st == 'window':
1649 du = dui(ui)
1645 du = dui(ui)
1650 elif st == 'add':
1646 elif st == 'add':
1651 du.bump(rev)
1647 du.bump(rev)
1652 changenode = repo.changelog.node(rev)
1648 changenode = repo.changelog.node(rev)
1653 parents = [p for p in repo.changelog.parents(changenode)
1649 parents = [p for p in repo.changelog.parents(changenode)
1654 if p != nullid]
1650 if p != nullid]
1655 if opts['no_merges'] and len(parents) == 2:
1651 if opts['no_merges'] and len(parents) == 2:
1656 continue
1652 continue
1657 if opts['only_merges'] and len(parents) != 2:
1653 if opts['only_merges'] and len(parents) != 2:
1658 continue
1654 continue
1659
1655
1660 if opts['keyword']:
1656 if opts['keyword']:
1661 changes = getchange(rev)
1657 changes = getchange(rev)
1662 miss = 0
1658 miss = 0
1663 for k in [kw.lower() for kw in opts['keyword']]:
1659 for k in [kw.lower() for kw in opts['keyword']]:
1664 if not (k in changes[1].lower() or
1660 if not (k in changes[1].lower() or
1665 k in changes[4].lower() or
1661 k in changes[4].lower() or
1666 k in " ".join(changes[3][:20]).lower()):
1662 k in " ".join(changes[3][:20]).lower()):
1667 miss = 1
1663 miss = 1
1668 break
1664 break
1669 if miss:
1665 if miss:
1670 continue
1666 continue
1671
1667
1672 br = None
1668 br = None
1673 if opts['branches']:
1669 if opts['branches']:
1674 br = repo.branchlookup([repo.changelog.node(rev)])
1670 br = repo.branchlookup([repo.changelog.node(rev)])
1675
1671
1676 show_changeset(du, repo, rev, brinfo=br)
1672 show_changeset(du, repo, rev, brinfo=br)
1677 if opts['patch']:
1673 if opts['patch']:
1678 prev = (parents and parents[0]) or nullid
1674 prev = (parents and parents[0]) or nullid
1679 dodiff(du, du, repo, prev, changenode, match=matchfn)
1675 dodiff(du, du, repo, prev, changenode, match=matchfn)
1680 du.write("\n\n")
1676 du.write("\n\n")
1681 elif st == 'iter':
1677 elif st == 'iter':
1682 if count == limit: break
1678 if count == limit: break
1683 if du.hunk[rev]:
1679 if du.hunk[rev]:
1684 count += 1
1680 count += 1
1685 for args in du.hunk[rev]:
1681 for args in du.hunk[rev]:
1686 ui.write(*args)
1682 ui.write(*args)
1687
1683
1688 def manifest(ui, repo, rev=None):
1684 def manifest(ui, repo, rev=None):
1689 """output the latest or given revision of the project manifest
1685 """output the latest or given revision of the project manifest
1690
1686
1691 Print a list of version controlled files for the given revision.
1687 Print a list of version controlled files for the given revision.
1692
1688
1693 The manifest is the list of files being version controlled. If no revision
1689 The manifest is the list of files being version controlled. If no revision
1694 is given then the tip is used.
1690 is given then the tip is used.
1695 """
1691 """
1696 if rev:
1692 if rev:
1697 try:
1693 try:
1698 # assume all revision numbers are for changesets
1694 # assume all revision numbers are for changesets
1699 n = repo.lookup(rev)
1695 n = repo.lookup(rev)
1700 change = repo.changelog.read(n)
1696 change = repo.changelog.read(n)
1701 n = change[0]
1697 n = change[0]
1702 except hg.RepoError:
1698 except hg.RepoError:
1703 n = repo.manifest.lookup(rev)
1699 n = repo.manifest.lookup(rev)
1704 else:
1700 else:
1705 n = repo.manifest.tip()
1701 n = repo.manifest.tip()
1706 m = repo.manifest.read(n)
1702 m = repo.manifest.read(n)
1707 mf = repo.manifest.readflags(n)
1703 mf = repo.manifest.readflags(n)
1708 files = m.keys()
1704 files = m.keys()
1709 files.sort()
1705 files.sort()
1710
1706
1711 for f in files:
1707 for f in files:
1712 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1708 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
1713
1709
1714 def outgoing(ui, repo, dest="default-push", **opts):
1710 def outgoing(ui, repo, dest="default-push", **opts):
1715 """show changesets not found in destination
1711 """show changesets not found in destination
1716
1712
1717 Show changesets not found in the specified destination repo or the
1713 Show changesets not found in the specified destination repo or the
1718 default push repo. These are the changesets that would be pushed
1714 default push repo. These are the changesets that would be pushed
1719 if a push was requested.
1715 if a push was requested.
1720 """
1716 """
1721 dest = ui.expandpath(dest, repo.root)
1717 dest = ui.expandpath(dest, repo.root)
1722 other = hg.repository(ui, dest)
1718 other = hg.repository(ui, dest)
1723 o = repo.findoutgoing(other)
1719 o = repo.findoutgoing(other)
1724 o = repo.changelog.nodesbetween(o)[0]
1720 o = repo.changelog.nodesbetween(o)[0]
1725 if opts['newest_first']:
1721 if opts['newest_first']:
1726 o.reverse()
1722 o.reverse()
1727 for n in o:
1723 for n in o:
1728 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1724 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1729 if opts['no_merges'] and len(parents) == 2:
1725 if opts['no_merges'] and len(parents) == 2:
1730 continue
1726 continue
1731 show_changeset(ui, repo, changenode=n)
1727 show_changeset(ui, repo, changenode=n)
1732 if opts['patch']:
1728 if opts['patch']:
1733 prev = (parents and parents[0]) or nullid
1729 prev = (parents and parents[0]) or nullid
1734 dodiff(ui, ui, repo, prev, n)
1730 dodiff(ui, ui, repo, prev, n)
1735 ui.write("\n")
1731 ui.write("\n")
1736
1732
1737 def parents(ui, repo, rev=None, branches=None):
1733 def parents(ui, repo, rev=None, branches=None):
1738 """show the parents of the working dir or revision
1734 """show the parents of the working dir or revision
1739
1735
1740 Print the working directory's parent revisions.
1736 Print the working directory's parent revisions.
1741 """
1737 """
1742 if rev:
1738 if rev:
1743 p = repo.changelog.parents(repo.lookup(rev))
1739 p = repo.changelog.parents(repo.lookup(rev))
1744 else:
1740 else:
1745 p = repo.dirstate.parents()
1741 p = repo.dirstate.parents()
1746
1742
1747 br = None
1743 br = None
1748 if branches is not None:
1744 if branches is not None:
1749 br = repo.branchlookup(p)
1745 br = repo.branchlookup(p)
1750 for n in p:
1746 for n in p:
1751 if n != nullid:
1747 if n != nullid:
1752 show_changeset(ui, repo, changenode=n, brinfo=br)
1748 show_changeset(ui, repo, changenode=n, brinfo=br)
1753
1749
1754 def paths(ui, search=None):
1750 def paths(ui, search=None):
1755 """show definition of symbolic path names
1751 """show definition of symbolic path names
1756
1752
1757 Show definition of symbolic path name NAME. If no name is given, show
1753 Show definition of symbolic path name NAME. If no name is given, show
1758 definition of available names.
1754 definition of available names.
1759
1755
1760 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1756 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1761 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1757 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1762 """
1758 """
1763 try:
1759 try:
1764 repo = hg.repository(ui=ui)
1760 repo = hg.repository(ui=ui)
1765 except hg.RepoError:
1761 except hg.RepoError:
1766 pass
1762 pass
1767
1763
1768 if search:
1764 if search:
1769 for name, path in ui.configitems("paths"):
1765 for name, path in ui.configitems("paths"):
1770 if name == search:
1766 if name == search:
1771 ui.write("%s\n" % path)
1767 ui.write("%s\n" % path)
1772 return
1768 return
1773 ui.warn(_("not found!\n"))
1769 ui.warn(_("not found!\n"))
1774 return 1
1770 return 1
1775 else:
1771 else:
1776 for name, path in ui.configitems("paths"):
1772 for name, path in ui.configitems("paths"):
1777 ui.write("%s = %s\n" % (name, path))
1773 ui.write("%s = %s\n" % (name, path))
1778
1774
1779 def pull(ui, repo, source="default", **opts):
1775 def pull(ui, repo, source="default", **opts):
1780 """pull changes from the specified source
1776 """pull changes from the specified source
1781
1777
1782 Pull changes from a remote repository to a local one.
1778 Pull changes from a remote repository to a local one.
1783
1779
1784 This finds all changes from the repository at the specified path
1780 This finds all changes from the repository at the specified path
1785 or URL and adds them to the local repository. By default, this
1781 or URL and adds them to the local repository. By default, this
1786 does not update the copy of the project in the working directory.
1782 does not update the copy of the project in the working directory.
1787
1783
1788 Valid URLs are of the form:
1784 Valid URLs are of the form:
1789
1785
1790 local/filesystem/path
1786 local/filesystem/path
1791 http://[user@]host[:port][/path]
1787 http://[user@]host[:port][/path]
1792 https://[user@]host[:port][/path]
1788 https://[user@]host[:port][/path]
1793 ssh://[user@]host[:port][/path]
1789 ssh://[user@]host[:port][/path]
1794
1790
1795 SSH requires an accessible shell account on the destination machine
1791 SSH requires an accessible shell account on the destination machine
1796 and a copy of hg in the remote path. With SSH, paths are relative
1792 and a copy of hg in the remote path. With SSH, paths are relative
1797 to the remote user's home directory by default; use two slashes at
1793 to the remote user's home directory by default; use two slashes at
1798 the start of a path to specify it as relative to the filesystem root.
1794 the start of a path to specify it as relative to the filesystem root.
1799 """
1795 """
1800 source = ui.expandpath(source, repo.root)
1796 source = ui.expandpath(source, repo.root)
1801 ui.status(_('pulling from %s\n') % (source))
1797 ui.status(_('pulling from %s\n') % (source))
1802
1798
1803 if opts['ssh']:
1799 if opts['ssh']:
1804 ui.setconfig("ui", "ssh", opts['ssh'])
1800 ui.setconfig("ui", "ssh", opts['ssh'])
1805 if opts['remotecmd']:
1801 if opts['remotecmd']:
1806 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1802 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1807
1803
1808 other = hg.repository(ui, source)
1804 other = hg.repository(ui, source)
1809 revs = None
1805 revs = None
1810 if opts['rev'] and not other.local():
1806 if opts['rev'] and not other.local():
1811 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
1807 raise util.Abort(_("pull -r doesn't work for remote repositories yet"))
1812 elif opts['rev']:
1808 elif opts['rev']:
1813 revs = [other.lookup(rev) for rev in opts['rev']]
1809 revs = [other.lookup(rev) for rev in opts['rev']]
1814 r = repo.pull(other, heads=revs)
1810 r = repo.pull(other, heads=revs)
1815 if not r:
1811 if not r:
1816 if opts['update']:
1812 if opts['update']:
1817 return update(ui, repo)
1813 return update(ui, repo)
1818 else:
1814 else:
1819 ui.status(_("(run 'hg update' to get a working copy)\n"))
1815 ui.status(_("(run 'hg update' to get a working copy)\n"))
1820
1816
1821 return r
1817 return r
1822
1818
1823 def push(ui, repo, dest="default-push", **opts):
1819 def push(ui, repo, dest="default-push", **opts):
1824 """push changes to the specified destination
1820 """push changes to the specified destination
1825
1821
1826 Push changes from the local repository to the given destination.
1822 Push changes from the local repository to the given destination.
1827
1823
1828 This is the symmetrical operation for pull. It helps to move
1824 This is the symmetrical operation for pull. It helps to move
1829 changes from the current repository to a different one. If the
1825 changes from the current repository to a different one. If the
1830 destination is local this is identical to a pull in that directory
1826 destination is local this is identical to a pull in that directory
1831 from the current one.
1827 from the current one.
1832
1828
1833 By default, push will refuse to run if it detects the result would
1829 By default, push will refuse to run if it detects the result would
1834 increase the number of remote heads. This generally indicates the
1830 increase the number of remote heads. This generally indicates the
1835 the client has forgotten to sync and merge before pushing.
1831 the client has forgotten to sync and merge before pushing.
1836
1832
1837 Valid URLs are of the form:
1833 Valid URLs are of the form:
1838
1834
1839 local/filesystem/path
1835 local/filesystem/path
1840 ssh://[user@]host[:port][/path]
1836 ssh://[user@]host[:port][/path]
1841
1837
1842 SSH requires an accessible shell account on the destination
1838 SSH requires an accessible shell account on the destination
1843 machine and a copy of hg in the remote path.
1839 machine and a copy of hg in the remote path.
1844 """
1840 """
1845 dest = ui.expandpath(dest, repo.root)
1841 dest = ui.expandpath(dest, repo.root)
1846 ui.status('pushing to %s\n' % (dest))
1842 ui.status('pushing to %s\n' % (dest))
1847
1843
1848 if opts['ssh']:
1844 if opts['ssh']:
1849 ui.setconfig("ui", "ssh", opts['ssh'])
1845 ui.setconfig("ui", "ssh", opts['ssh'])
1850 if opts['remotecmd']:
1846 if opts['remotecmd']:
1851 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1847 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
1852
1848
1853 other = hg.repository(ui, dest)
1849 other = hg.repository(ui, dest)
1854 revs = None
1850 revs = None
1855 if opts['rev']:
1851 if opts['rev']:
1856 revs = [repo.lookup(rev) for rev in opts['rev']]
1852 revs = [repo.lookup(rev) for rev in opts['rev']]
1857 r = repo.push(other, opts['force'], revs=revs)
1853 r = repo.push(other, opts['force'], revs=revs)
1858 return r
1854 return r
1859
1855
1860 def rawcommit(ui, repo, *flist, **rc):
1856 def rawcommit(ui, repo, *flist, **rc):
1861 """raw commit interface (DEPRECATED)
1857 """raw commit interface (DEPRECATED)
1862
1858
1863 Lowlevel commit, for use in helper scripts.
1859 Lowlevel commit, for use in helper scripts.
1864
1860
1865 This command is not intended to be used by normal users, as it is
1861 This command is not intended to be used by normal users, as it is
1866 primarily useful for importing from other SCMs.
1862 primarily useful for importing from other SCMs.
1867
1863
1868 This command is now deprecated and will be removed in a future
1864 This command is now deprecated and will be removed in a future
1869 release, please use debugsetparents and commit instead.
1865 release, please use debugsetparents and commit instead.
1870 """
1866 """
1871
1867
1872 ui.warn(_("(the rawcommit command is deprecated)\n"))
1868 ui.warn(_("(the rawcommit command is deprecated)\n"))
1873
1869
1874 message = rc['message']
1870 message = rc['message']
1875 if not message and rc['logfile']:
1871 if not message and rc['logfile']:
1876 try:
1872 try:
1877 message = open(rc['logfile']).read()
1873 message = open(rc['logfile']).read()
1878 except IOError:
1874 except IOError:
1879 pass
1875 pass
1880 if not message and not rc['logfile']:
1876 if not message and not rc['logfile']:
1881 raise util.Abort(_("missing commit message"))
1877 raise util.Abort(_("missing commit message"))
1882
1878
1883 files = relpath(repo, list(flist))
1879 files = relpath(repo, list(flist))
1884 if rc['files']:
1880 if rc['files']:
1885 files += open(rc['files']).read().splitlines()
1881 files += open(rc['files']).read().splitlines()
1886
1882
1887 rc['parent'] = map(repo.lookup, rc['parent'])
1883 rc['parent'] = map(repo.lookup, rc['parent'])
1888
1884
1889 try:
1885 try:
1890 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1886 repo.rawcommit(files, message, rc['user'], rc['date'], *rc['parent'])
1891 except ValueError, inst:
1887 except ValueError, inst:
1892 raise util.Abort(str(inst))
1888 raise util.Abort(str(inst))
1893
1889
1894 def recover(ui, repo):
1890 def recover(ui, repo):
1895 """roll back an interrupted transaction
1891 """roll back an interrupted transaction
1896
1892
1897 Recover from an interrupted commit or pull.
1893 Recover from an interrupted commit or pull.
1898
1894
1899 This command tries to fix the repository status after an interrupted
1895 This command tries to fix the repository status after an interrupted
1900 operation. It should only be necessary when Mercurial suggests it.
1896 operation. It should only be necessary when Mercurial suggests it.
1901 """
1897 """
1902 if repo.recover():
1898 if repo.recover():
1903 return repo.verify()
1899 return repo.verify()
1904 return False
1900 return False
1905
1901
1906 def remove(ui, repo, pat, *pats, **opts):
1902 def remove(ui, repo, pat, *pats, **opts):
1907 """remove the specified files on the next commit
1903 """remove the specified files on the next commit
1908
1904
1909 Schedule the indicated files for removal from the repository.
1905 Schedule the indicated files for removal from the repository.
1910
1906
1911 This command schedules the files to be removed at the next commit.
1907 This command schedules the files to be removed at the next commit.
1912 This only removes files from the current branch, not from the
1908 This only removes files from the current branch, not from the
1913 entire project history. If the files still exist in the working
1909 entire project history. If the files still exist in the working
1914 directory, they will be deleted from it.
1910 directory, they will be deleted from it.
1915 """
1911 """
1916 names = []
1912 names = []
1917 def okaytoremove(abs, rel, exact):
1913 def okaytoremove(abs, rel, exact):
1918 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
1914 modified, added, removed, deleted, unknown = repo.changes(files=[abs])
1919 reason = None
1915 reason = None
1920 if modified:
1916 if modified:
1921 reason = _('is modified')
1917 reason = _('is modified')
1922 elif added:
1918 elif added:
1923 reason = _('has been marked for add')
1919 reason = _('has been marked for add')
1924 elif unknown:
1920 elif unknown:
1925 reason = _('is not managed')
1921 reason = _('is not managed')
1926 if reason:
1922 if reason:
1927 if exact:
1923 if exact:
1928 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1924 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
1929 else:
1925 else:
1930 return True
1926 return True
1931 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1927 for src, abs, rel, exact in walk(repo, (pat,) + pats, opts):
1932 if okaytoremove(abs, rel, exact):
1928 if okaytoremove(abs, rel, exact):
1933 if ui.verbose or not exact:
1929 if ui.verbose or not exact:
1934 ui.status(_('removing %s\n') % rel)
1930 ui.status(_('removing %s\n') % rel)
1935 names.append(abs)
1931 names.append(abs)
1936 repo.remove(names, unlink=True)
1932 repo.remove(names, unlink=True)
1937
1933
1938 def rename(ui, repo, *pats, **opts):
1934 def rename(ui, repo, *pats, **opts):
1939 """rename files; equivalent of copy + remove
1935 """rename files; equivalent of copy + remove
1940
1936
1941 Mark dest as copies of sources; mark sources for deletion. If
1937 Mark dest as copies of sources; mark sources for deletion. If
1942 dest is a directory, copies are put in that directory. If dest is
1938 dest is a directory, copies are put in that directory. If dest is
1943 a file, there can only be one source.
1939 a file, there can only be one source.
1944
1940
1945 By default, this command copies the contents of files as they
1941 By default, this command copies the contents of files as they
1946 stand in the working directory. If invoked with --after, the
1942 stand in the working directory. If invoked with --after, the
1947 operation is recorded, but no copying is performed.
1943 operation is recorded, but no copying is performed.
1948
1944
1949 This command takes effect in the next commit.
1945 This command takes effect in the next commit.
1950
1946
1951 NOTE: This command should be treated as experimental. While it
1947 NOTE: This command should be treated as experimental. While it
1952 should properly record rename files, this information is not yet
1948 should properly record rename files, this information is not yet
1953 fully used by merge, nor fully reported by log.
1949 fully used by merge, nor fully reported by log.
1954 """
1950 """
1955 errs, copied = docopy(ui, repo, pats, opts)
1951 errs, copied = docopy(ui, repo, pats, opts)
1956 names = []
1952 names = []
1957 for abs, rel, exact in copied:
1953 for abs, rel, exact in copied:
1958 if ui.verbose or not exact:
1954 if ui.verbose or not exact:
1959 ui.status(_('removing %s\n') % rel)
1955 ui.status(_('removing %s\n') % rel)
1960 names.append(abs)
1956 names.append(abs)
1961 repo.remove(names, unlink=True)
1957 repo.remove(names, unlink=True)
1962 return errs
1958 return errs
1963
1959
1964 def revert(ui, repo, *pats, **opts):
1960 def revert(ui, repo, *pats, **opts):
1965 """revert modified files or dirs back to their unmodified states
1961 """revert modified files or dirs back to their unmodified states
1966
1962
1967 Revert any uncommitted modifications made to the named files or
1963 Revert any uncommitted modifications made to the named files or
1968 directories. This restores the contents of the affected files to
1964 directories. This restores the contents of the affected files to
1969 an unmodified state.
1965 an unmodified state.
1970
1966
1971 If a file has been deleted, it is recreated. If the executable
1967 If a file has been deleted, it is recreated. If the executable
1972 mode of a file was changed, it is reset.
1968 mode of a file was changed, it is reset.
1973
1969
1974 If names are given, all files matching the names are reverted.
1970 If names are given, all files matching the names are reverted.
1975
1971
1976 If no arguments are given, all files in the repository are reverted.
1972 If no arguments are given, all files in the repository are reverted.
1977 """
1973 """
1978 node = opts['rev'] and repo.lookup(opts['rev']) or \
1974 node = opts['rev'] and repo.lookup(opts['rev']) or \
1979 repo.dirstate.parents()[0]
1975 repo.dirstate.parents()[0]
1980
1976
1981 files, choose, anypats = matchpats(repo, pats, opts)
1977 files, choose, anypats = matchpats(repo, pats, opts)
1982 modified, added, removed, deleted, unknown = repo.changes(match=choose)
1978 modified, added, removed, deleted, unknown = repo.changes(match=choose)
1983 repo.forget(added)
1979 repo.forget(added)
1984 repo.undelete(removed)
1980 repo.undelete(removed)
1985
1981
1986 return repo.update(node, False, True, choose, False)
1982 return repo.update(node, False, True, choose, False)
1987
1983
1988 def root(ui, repo):
1984 def root(ui, repo):
1989 """print the root (top) of the current working dir
1985 """print the root (top) of the current working dir
1990
1986
1991 Print the root directory of the current repository.
1987 Print the root directory of the current repository.
1992 """
1988 """
1993 ui.write(repo.root + "\n")
1989 ui.write(repo.root + "\n")
1994
1990
1995 def serve(ui, repo, **opts):
1991 def serve(ui, repo, **opts):
1996 """export the repository via HTTP
1992 """export the repository via HTTP
1997
1993
1998 Start a local HTTP repository browser and pull server.
1994 Start a local HTTP repository browser and pull server.
1999
1995
2000 By default, the server logs accesses to stdout and errors to
1996 By default, the server logs accesses to stdout and errors to
2001 stderr. Use the "-A" and "-E" options to log to files.
1997 stderr. Use the "-A" and "-E" options to log to files.
2002 """
1998 """
2003
1999
2004 if opts["stdio"]:
2000 if opts["stdio"]:
2005 fin, fout = sys.stdin, sys.stdout
2001 fin, fout = sys.stdin, sys.stdout
2006 sys.stdout = sys.stderr
2002 sys.stdout = sys.stderr
2007
2003
2008 # Prevent insertion/deletion of CRs
2004 # Prevent insertion/deletion of CRs
2009 util.set_binary(fin)
2005 util.set_binary(fin)
2010 util.set_binary(fout)
2006 util.set_binary(fout)
2011
2007
2012 def getarg():
2008 def getarg():
2013 argline = fin.readline()[:-1]
2009 argline = fin.readline()[:-1]
2014 arg, l = argline.split()
2010 arg, l = argline.split()
2015 val = fin.read(int(l))
2011 val = fin.read(int(l))
2016 return arg, val
2012 return arg, val
2017 def respond(v):
2013 def respond(v):
2018 fout.write("%d\n" % len(v))
2014 fout.write("%d\n" % len(v))
2019 fout.write(v)
2015 fout.write(v)
2020 fout.flush()
2016 fout.flush()
2021
2017
2022 lock = None
2018 lock = None
2023
2019
2024 while 1:
2020 while 1:
2025 cmd = fin.readline()[:-1]
2021 cmd = fin.readline()[:-1]
2026 if cmd == '':
2022 if cmd == '':
2027 return
2023 return
2028 if cmd == "heads":
2024 if cmd == "heads":
2029 h = repo.heads()
2025 h = repo.heads()
2030 respond(" ".join(map(hex, h)) + "\n")
2026 respond(" ".join(map(hex, h)) + "\n")
2031 if cmd == "lock":
2027 if cmd == "lock":
2032 lock = repo.lock()
2028 lock = repo.lock()
2033 respond("")
2029 respond("")
2034 if cmd == "unlock":
2030 if cmd == "unlock":
2035 if lock:
2031 if lock:
2036 lock.release()
2032 lock.release()
2037 lock = None
2033 lock = None
2038 respond("")
2034 respond("")
2039 elif cmd == "branches":
2035 elif cmd == "branches":
2040 arg, nodes = getarg()
2036 arg, nodes = getarg()
2041 nodes = map(bin, nodes.split(" "))
2037 nodes = map(bin, nodes.split(" "))
2042 r = []
2038 r = []
2043 for b in repo.branches(nodes):
2039 for b in repo.branches(nodes):
2044 r.append(" ".join(map(hex, b)) + "\n")
2040 r.append(" ".join(map(hex, b)) + "\n")
2045 respond("".join(r))
2041 respond("".join(r))
2046 elif cmd == "between":
2042 elif cmd == "between":
2047 arg, pairs = getarg()
2043 arg, pairs = getarg()
2048 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2044 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
2049 r = []
2045 r = []
2050 for b in repo.between(pairs):
2046 for b in repo.between(pairs):
2051 r.append(" ".join(map(hex, b)) + "\n")
2047 r.append(" ".join(map(hex, b)) + "\n")
2052 respond("".join(r))
2048 respond("".join(r))
2053 elif cmd == "changegroup":
2049 elif cmd == "changegroup":
2054 nodes = []
2050 nodes = []
2055 arg, roots = getarg()
2051 arg, roots = getarg()
2056 nodes = map(bin, roots.split(" "))
2052 nodes = map(bin, roots.split(" "))
2057
2053
2058 cg = repo.changegroup(nodes, 'serve')
2054 cg = repo.changegroup(nodes, 'serve')
2059 while 1:
2055 while 1:
2060 d = cg.read(4096)
2056 d = cg.read(4096)
2061 if not d:
2057 if not d:
2062 break
2058 break
2063 fout.write(d)
2059 fout.write(d)
2064
2060
2065 fout.flush()
2061 fout.flush()
2066
2062
2067 elif cmd == "addchangegroup":
2063 elif cmd == "addchangegroup":
2068 if not lock:
2064 if not lock:
2069 respond("not locked")
2065 respond("not locked")
2070 continue
2066 continue
2071 respond("")
2067 respond("")
2072
2068
2073 r = repo.addchangegroup(fin)
2069 r = repo.addchangegroup(fin)
2074 respond("")
2070 respond("")
2075
2071
2076 optlist = "name templates style address port ipv6 accesslog errorlog"
2072 optlist = "name templates style address port ipv6 accesslog errorlog"
2077 for o in optlist.split():
2073 for o in optlist.split():
2078 if opts[o]:
2074 if opts[o]:
2079 ui.setconfig("web", o, opts[o])
2075 ui.setconfig("web", o, opts[o])
2080
2076
2081 if opts['daemon'] and not opts['daemon_pipefds']:
2077 if opts['daemon'] and not opts['daemon_pipefds']:
2082 rfd, wfd = os.pipe()
2078 rfd, wfd = os.pipe()
2083 args = sys.argv[:]
2079 args = sys.argv[:]
2084 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2080 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
2085 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2081 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
2086 args[0], args)
2082 args[0], args)
2087 os.close(wfd)
2083 os.close(wfd)
2088 os.read(rfd, 1)
2084 os.read(rfd, 1)
2089 os._exit(0)
2085 os._exit(0)
2090
2086
2091 try:
2087 try:
2092 httpd = hgweb.create_server(repo)
2088 httpd = hgweb.create_server(repo)
2093 except socket.error, inst:
2089 except socket.error, inst:
2094 raise util.Abort(_('cannot start server: ') + inst.args[1])
2090 raise util.Abort(_('cannot start server: ') + inst.args[1])
2095
2091
2096 if ui.verbose:
2092 if ui.verbose:
2097 addr, port = httpd.socket.getsockname()
2093 addr, port = httpd.socket.getsockname()
2098 if addr == '0.0.0.0':
2094 if addr == '0.0.0.0':
2099 addr = socket.gethostname()
2095 addr = socket.gethostname()
2100 else:
2096 else:
2101 try:
2097 try:
2102 addr = socket.gethostbyaddr(addr)[0]
2098 addr = socket.gethostbyaddr(addr)[0]
2103 except socket.error:
2099 except socket.error:
2104 pass
2100 pass
2105 if port != 80:
2101 if port != 80:
2106 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2102 ui.status(_('listening at http://%s:%d/\n') % (addr, port))
2107 else:
2103 else:
2108 ui.status(_('listening at http://%s/\n') % addr)
2104 ui.status(_('listening at http://%s/\n') % addr)
2109
2105
2110 if opts['pid_file']:
2106 if opts['pid_file']:
2111 fp = open(opts['pid_file'], 'w')
2107 fp = open(opts['pid_file'], 'w')
2112 fp.write(str(os.getpid()))
2108 fp.write(str(os.getpid()))
2113 fp.close()
2109 fp.close()
2114
2110
2115 if opts['daemon_pipefds']:
2111 if opts['daemon_pipefds']:
2116 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2112 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
2117 os.close(rfd)
2113 os.close(rfd)
2118 os.write(wfd, 'y')
2114 os.write(wfd, 'y')
2119 os.close(wfd)
2115 os.close(wfd)
2120 sys.stdout.flush()
2116 sys.stdout.flush()
2121 sys.stderr.flush()
2117 sys.stderr.flush()
2122 fd = os.open(util.nulldev, os.O_RDWR)
2118 fd = os.open(util.nulldev, os.O_RDWR)
2123 if fd != 0: os.dup2(fd, 0)
2119 if fd != 0: os.dup2(fd, 0)
2124 if fd != 1: os.dup2(fd, 1)
2120 if fd != 1: os.dup2(fd, 1)
2125 if fd != 2: os.dup2(fd, 2)
2121 if fd != 2: os.dup2(fd, 2)
2126 if fd not in (0, 1, 2): os.close(fd)
2122 if fd not in (0, 1, 2): os.close(fd)
2127
2123
2128 httpd.serve_forever()
2124 httpd.serve_forever()
2129
2125
2130 def status(ui, repo, *pats, **opts):
2126 def status(ui, repo, *pats, **opts):
2131 """show changed files in the working directory
2127 """show changed files in the working directory
2132
2128
2133 Show changed files in the repository. If names are
2129 Show changed files in the repository. If names are
2134 given, only files that match are shown.
2130 given, only files that match are shown.
2135
2131
2136 The codes used to show the status of files are:
2132 The codes used to show the status of files are:
2137 M = modified
2133 M = modified
2138 A = added
2134 A = added
2139 R = removed
2135 R = removed
2140 ! = deleted, but still tracked
2136 ! = deleted, but still tracked
2141 ? = not tracked
2137 ? = not tracked
2142 """
2138 """
2143
2139
2144 files, matchfn, anypats = matchpats(repo, pats, opts)
2140 files, matchfn, anypats = matchpats(repo, pats, opts)
2145 cwd = (pats and repo.getcwd()) or ''
2141 cwd = (pats and repo.getcwd()) or ''
2146 modified, added, removed, deleted, unknown = [
2142 modified, added, removed, deleted, unknown = [
2147 [util.pathto(cwd, x) for x in n]
2143 [util.pathto(cwd, x) for x in n]
2148 for n in repo.changes(files=files, match=matchfn)]
2144 for n in repo.changes(files=files, match=matchfn)]
2149
2145
2150 changetypes = [(_('modified'), 'M', modified),
2146 changetypes = [(_('modified'), 'M', modified),
2151 (_('added'), 'A', added),
2147 (_('added'), 'A', added),
2152 (_('removed'), 'R', removed),
2148 (_('removed'), 'R', removed),
2153 (_('deleted'), '!', deleted),
2149 (_('deleted'), '!', deleted),
2154 (_('unknown'), '?', unknown)]
2150 (_('unknown'), '?', unknown)]
2155
2151
2156 end = opts['print0'] and '\0' or '\n'
2152 end = opts['print0'] and '\0' or '\n'
2157
2153
2158 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2154 for opt, char, changes in ([ct for ct in changetypes if opts[ct[0]]]
2159 or changetypes):
2155 or changetypes):
2160 if opts['no_status']:
2156 if opts['no_status']:
2161 format = "%%s%s" % end
2157 format = "%%s%s" % end
2162 else:
2158 else:
2163 format = "%s %%s%s" % (char, end);
2159 format = "%s %%s%s" % (char, end);
2164
2160
2165 for f in changes:
2161 for f in changes:
2166 ui.write(format % f)
2162 ui.write(format % f)
2167
2163
2168 def tag(ui, repo, name, rev_=None, **opts):
2164 def tag(ui, repo, name, rev_=None, **opts):
2169 """add a tag for the current tip or a given revision
2165 """add a tag for the current tip or a given revision
2170
2166
2171 Name a particular revision using <name>.
2167 Name a particular revision using <name>.
2172
2168
2173 Tags are used to name particular revisions of the repository and are
2169 Tags are used to name particular revisions of the repository and are
2174 very useful to compare different revision, to go back to significant
2170 very useful to compare different revision, to go back to significant
2175 earlier versions or to mark branch points as releases, etc.
2171 earlier versions or to mark branch points as releases, etc.
2176
2172
2177 If no revision is given, the tip is used.
2173 If no revision is given, the tip is used.
2178
2174
2179 To facilitate version control, distribution, and merging of tags,
2175 To facilitate version control, distribution, and merging of tags,
2180 they are stored as a file named ".hgtags" which is managed
2176 they are stored as a file named ".hgtags" which is managed
2181 similarly to other project files and can be hand-edited if
2177 similarly to other project files and can be hand-edited if
2182 necessary. The file '.hg/localtags' is used for local tags (not
2178 necessary. The file '.hg/localtags' is used for local tags (not
2183 shared among repositories).
2179 shared among repositories).
2184 """
2180 """
2185 if name == "tip":
2181 if name == "tip":
2186 raise util.Abort(_("the name 'tip' is reserved"))
2182 raise util.Abort(_("the name 'tip' is reserved"))
2187 if rev_ is not None:
2183 if rev_ is not None:
2188 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2184 ui.warn(_("use of 'hg tag NAME [REV]' is deprecated, "
2189 "please use 'hg tag [-r REV] NAME' instead\n"))
2185 "please use 'hg tag [-r REV] NAME' instead\n"))
2190 if opts['rev']:
2186 if opts['rev']:
2191 raise util.Abort(_("use only one form to specify the revision"))
2187 raise util.Abort(_("use only one form to specify the revision"))
2192 if opts['rev']:
2188 if opts['rev']:
2193 rev_ = opts['rev']
2189 rev_ = opts['rev']
2194 if rev_:
2190 if rev_:
2195 r = hex(repo.lookup(rev_))
2191 r = hex(repo.lookup(rev_))
2196 else:
2192 else:
2197 r = hex(repo.changelog.tip())
2193 r = hex(repo.changelog.tip())
2198
2194
2199 disallowed = (revrangesep, '\r', '\n')
2195 disallowed = (revrangesep, '\r', '\n')
2200 for c in disallowed:
2196 for c in disallowed:
2201 if name.find(c) >= 0:
2197 if name.find(c) >= 0:
2202 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2198 raise util.Abort(_("%s cannot be used in a tag name") % repr(c))
2203
2199
2204 repo.hook('pretag', throw=True, node=r, tag=name,
2200 repo.hook('pretag', throw=True, node=r, tag=name,
2205 local=int(not not opts['local']))
2201 local=int(not not opts['local']))
2206
2202
2207 if opts['local']:
2203 if opts['local']:
2208 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2204 repo.opener("localtags", "a").write("%s %s\n" % (r, name))
2209 repo.hook('tag', node=r, tag=name, local=1)
2205 repo.hook('tag', node=r, tag=name, local=1)
2210 return
2206 return
2211
2207
2212 for x in repo.changes():
2208 for x in repo.changes():
2213 if ".hgtags" in x:
2209 if ".hgtags" in x:
2214 raise util.Abort(_("working copy of .hgtags is changed "
2210 raise util.Abort(_("working copy of .hgtags is changed "
2215 "(please commit .hgtags manually)"))
2211 "(please commit .hgtags manually)"))
2216
2212
2217 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2213 repo.wfile(".hgtags", "ab").write("%s %s\n" % (r, name))
2218 if repo.dirstate.state(".hgtags") == '?':
2214 if repo.dirstate.state(".hgtags") == '?':
2219 repo.add([".hgtags"])
2215 repo.add([".hgtags"])
2220
2216
2221 message = (opts['message'] or
2217 message = (opts['message'] or
2222 _("Added tag %s for changeset %s") % (name, r))
2218 _("Added tag %s for changeset %s") % (name, r))
2223 try:
2219 try:
2224 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2220 repo.commit([".hgtags"], message, opts['user'], opts['date'])
2225 repo.hook('tag', node=r, tag=name, local=0)
2221 repo.hook('tag', node=r, tag=name, local=0)
2226 except ValueError, inst:
2222 except ValueError, inst:
2227 raise util.Abort(str(inst))
2223 raise util.Abort(str(inst))
2228
2224
2229 def tags(ui, repo):
2225 def tags(ui, repo):
2230 """list repository tags
2226 """list repository tags
2231
2227
2232 List the repository tags.
2228 List the repository tags.
2233
2229
2234 This lists both regular and local tags.
2230 This lists both regular and local tags.
2235 """
2231 """
2236
2232
2237 l = repo.tagslist()
2233 l = repo.tagslist()
2238 l.reverse()
2234 l.reverse()
2239 for t, n in l:
2235 for t, n in l:
2240 try:
2236 try:
2241 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2237 r = "%5d:%s" % (repo.changelog.rev(n), hex(n))
2242 except KeyError:
2238 except KeyError:
2243 r = " ?:?"
2239 r = " ?:?"
2244 ui.write("%-30s %s\n" % (t, r))
2240 ui.write("%-30s %s\n" % (t, r))
2245
2241
2246 def tip(ui, repo, **opts):
2242 def tip(ui, repo, **opts):
2247 """show the tip revision
2243 """show the tip revision
2248
2244
2249 Show the tip revision.
2245 Show the tip revision.
2250 """
2246 """
2251 n = repo.changelog.tip()
2247 n = repo.changelog.tip()
2252 br = None
2248 br = None
2253 if opts['branches']:
2249 if opts['branches']:
2254 br = repo.branchlookup([n])
2250 br = repo.branchlookup([n])
2255 show_changeset(ui, repo, changenode=n, brinfo=br)
2251 show_changeset(ui, repo, changenode=n, brinfo=br)
2256 if opts['patch']:
2252 if opts['patch']:
2257 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2253 dodiff(ui, ui, repo, repo.changelog.parents(n)[0], n)
2258
2254
2259 def unbundle(ui, repo, fname, **opts):
2255 def unbundle(ui, repo, fname, **opts):
2260 """apply a changegroup file
2256 """apply a changegroup file
2261
2257
2262 Apply a compressed changegroup file generated by the bundle
2258 Apply a compressed changegroup file generated by the bundle
2263 command.
2259 command.
2264 """
2260 """
2265 f = urllib.urlopen(fname)
2261 f = urllib.urlopen(fname)
2266
2262
2267 if f.read(4) != "HG10":
2263 if f.read(4) != "HG10":
2268 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2264 raise util.Abort(_("%s: not a Mercurial bundle file") % fname)
2269
2265
2270 def bzgenerator(f):
2266 def bzgenerator(f):
2271 zd = bz2.BZ2Decompressor()
2267 zd = bz2.BZ2Decompressor()
2272 for chunk in f:
2268 for chunk in f:
2273 yield zd.decompress(chunk)
2269 yield zd.decompress(chunk)
2274
2270
2275 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2271 bzgen = bzgenerator(util.filechunkiter(f, 4096))
2276 if repo.addchangegroup(util.chunkbuffer(bzgen)):
2272 if repo.addchangegroup(util.chunkbuffer(bzgen)):
2277 return 1
2273 return 1
2278
2274
2279 if opts['update']:
2275 if opts['update']:
2280 return update(ui, repo)
2276 return update(ui, repo)
2281 else:
2277 else:
2282 ui.status(_("(run 'hg update' to get a working copy)\n"))
2278 ui.status(_("(run 'hg update' to get a working copy)\n"))
2283
2279
2284 def undo(ui, repo):
2280 def undo(ui, repo):
2285 """undo the last commit or pull
2281 """undo the last commit or pull
2286
2282
2287 Roll back the last pull or commit transaction on the
2283 Roll back the last pull or commit transaction on the
2288 repository, restoring the project to its earlier state.
2284 repository, restoring the project to its earlier state.
2289
2285
2290 This command should be used with care. There is only one level of
2286 This command should be used with care. There is only one level of
2291 undo and there is no redo.
2287 undo and there is no redo.
2292
2288
2293 This command is not intended for use on public repositories. Once
2289 This command is not intended for use on public repositories. Once
2294 a change is visible for pull by other users, undoing it locally is
2290 a change is visible for pull by other users, undoing it locally is
2295 ineffective.
2291 ineffective.
2296 """
2292 """
2297 repo.undo()
2293 repo.undo()
2298
2294
2299 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2295 def update(ui, repo, node=None, merge=False, clean=False, force=None,
2300 branch=None):
2296 branch=None):
2301 """update or merge working directory
2297 """update or merge working directory
2302
2298
2303 Update the working directory to the specified revision.
2299 Update the working directory to the specified revision.
2304
2300
2305 If there are no outstanding changes in the working directory and
2301 If there are no outstanding changes in the working directory and
2306 there is a linear relationship between the current version and the
2302 there is a linear relationship between the current version and the
2307 requested version, the result is the requested version.
2303 requested version, the result is the requested version.
2308
2304
2309 Otherwise the result is a merge between the contents of the
2305 Otherwise the result is a merge between the contents of the
2310 current working directory and the requested version. Files that
2306 current working directory and the requested version. Files that
2311 changed between either parent are marked as changed for the next
2307 changed between either parent are marked as changed for the next
2312 commit and a commit must be performed before any further updates
2308 commit and a commit must be performed before any further updates
2313 are allowed.
2309 are allowed.
2314
2310
2315 By default, update will refuse to run if doing so would require
2311 By default, update will refuse to run if doing so would require
2316 merging or discarding local changes.
2312 merging or discarding local changes.
2317 """
2313 """
2318 if branch:
2314 if branch:
2319 br = repo.branchlookup(branch=branch)
2315 br = repo.branchlookup(branch=branch)
2320 found = []
2316 found = []
2321 for x in br:
2317 for x in br:
2322 if branch in br[x]:
2318 if branch in br[x]:
2323 found.append(x)
2319 found.append(x)
2324 if len(found) > 1:
2320 if len(found) > 1:
2325 ui.warn(_("Found multiple heads for %s\n") % branch)
2321 ui.warn(_("Found multiple heads for %s\n") % branch)
2326 for x in found:
2322 for x in found:
2327 show_changeset(ui, repo, changenode=x, brinfo=br)
2323 show_changeset(ui, repo, changenode=x, brinfo=br)
2328 return 1
2324 return 1
2329 if len(found) == 1:
2325 if len(found) == 1:
2330 node = found[0]
2326 node = found[0]
2331 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2327 ui.warn(_("Using head %s for branch %s\n") % (short(node), branch))
2332 else:
2328 else:
2333 ui.warn(_("branch %s not found\n") % (branch))
2329 ui.warn(_("branch %s not found\n") % (branch))
2334 return 1
2330 return 1
2335 else:
2331 else:
2336 node = node and repo.lookup(node) or repo.changelog.tip()
2332 node = node and repo.lookup(node) or repo.changelog.tip()
2337 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2333 return repo.update(node, allow=merge, force=clean, forcemerge=force)
2338
2334
2339 def verify(ui, repo):
2335 def verify(ui, repo):
2340 """verify the integrity of the repository
2336 """verify the integrity of the repository
2341
2337
2342 Verify the integrity of the current repository.
2338 Verify the integrity of the current repository.
2343
2339
2344 This will perform an extensive check of the repository's
2340 This will perform an extensive check of the repository's
2345 integrity, validating the hashes and checksums of each entry in
2341 integrity, validating the hashes and checksums of each entry in
2346 the changelog, manifest, and tracked files, as well as the
2342 the changelog, manifest, and tracked files, as well as the
2347 integrity of their crosslinks and indices.
2343 integrity of their crosslinks and indices.
2348 """
2344 """
2349 return repo.verify()
2345 return repo.verify()
2350
2346
2351 # Command options and aliases are listed here, alphabetically
2347 # Command options and aliases are listed here, alphabetically
2352
2348
2353 table = {
2349 table = {
2354 "^add":
2350 "^add":
2355 (add,
2351 (add,
2356 [('I', 'include', [], _('include names matching the given patterns')),
2352 [('I', 'include', [], _('include names matching the given patterns')),
2357 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2353 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2358 _('hg add [OPTION]... [FILE]...')),
2354 _('hg add [OPTION]... [FILE]...')),
2359 "addremove":
2355 "addremove":
2360 (addremove,
2356 (addremove,
2361 [('I', 'include', [], _('include names matching the given patterns')),
2357 [('I', 'include', [], _('include names matching the given patterns')),
2362 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2358 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2363 _('hg addremove [OPTION]... [FILE]...')),
2359 _('hg addremove [OPTION]... [FILE]...')),
2364 "^annotate":
2360 "^annotate":
2365 (annotate,
2361 (annotate,
2366 [('r', 'rev', '', _('annotate the specified revision')),
2362 [('r', 'rev', '', _('annotate the specified revision')),
2367 ('a', 'text', None, _('treat all files as text')),
2363 ('a', 'text', None, _('treat all files as text')),
2368 ('u', 'user', None, _('list the author')),
2364 ('u', 'user', None, _('list the author')),
2369 ('d', 'date', None, _('list the date')),
2365 ('d', 'date', None, _('list the date')),
2370 ('n', 'number', None, _('list the revision number (default)')),
2366 ('n', 'number', None, _('list the revision number (default)')),
2371 ('c', 'changeset', None, _('list the changeset')),
2367 ('c', 'changeset', None, _('list the changeset')),
2372 ('I', 'include', [], _('include names matching the given patterns')),
2368 ('I', 'include', [], _('include names matching the given patterns')),
2373 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2369 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2374 _('hg annotate [OPTION]... FILE...')),
2370 _('hg annotate [OPTION]... FILE...')),
2375 "bundle":
2371 "bundle":
2376 (bundle,
2372 (bundle,
2377 [],
2373 [],
2378 _('hg bundle FILE DEST')),
2374 _('hg bundle FILE DEST')),
2379 "cat":
2375 "cat":
2380 (cat,
2376 (cat,
2381 [('I', 'include', [], _('include names matching the given patterns')),
2377 [('I', 'include', [], _('include names matching the given patterns')),
2382 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2378 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2383 ('o', 'output', '', _('print output to file with formatted name')),
2379 ('o', 'output', '', _('print output to file with formatted name')),
2384 ('r', 'rev', '', _('print the given revision'))],
2380 ('r', 'rev', '', _('print the given revision'))],
2385 _('hg cat [OPTION]... FILE...')),
2381 _('hg cat [OPTION]... FILE...')),
2386 "^clone":
2382 "^clone":
2387 (clone,
2383 (clone,
2388 [('U', 'noupdate', None, _('do not update the new working directory')),
2384 [('U', 'noupdate', None, _('do not update the new working directory')),
2389 ('e', 'ssh', '', _('specify ssh command to use')),
2385 ('e', 'ssh', '', _('specify ssh command to use')),
2390 ('', 'pull', None, _('use pull protocol to copy metadata')),
2386 ('', 'pull', None, _('use pull protocol to copy metadata')),
2391 ('r', 'rev', [],
2387 ('r', 'rev', [],
2392 _('a changeset you would like to have after cloning')),
2388 _('a changeset you would like to have after cloning')),
2393 ('', 'remotecmd', '',
2389 ('', 'remotecmd', '',
2394 _('specify hg command to run on the remote side'))],
2390 _('specify hg command to run on the remote side'))],
2395 _('hg clone [OPTION]... SOURCE [DEST]')),
2391 _('hg clone [OPTION]... SOURCE [DEST]')),
2396 "^commit|ci":
2392 "^commit|ci":
2397 (commit,
2393 (commit,
2398 [('A', 'addremove', None, _('run addremove during commit')),
2394 [('A', 'addremove', None, _('run addremove during commit')),
2399 ('I', 'include', [], _('include names matching the given patterns')),
2395 ('I', 'include', [], _('include names matching the given patterns')),
2400 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2396 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2401 ('m', 'message', '', _('use <text> as commit message')),
2397 ('m', 'message', '', _('use <text> as commit message')),
2402 ('l', 'logfile', '', _('read the commit message from <file>')),
2398 ('l', 'logfile', '', _('read the commit message from <file>')),
2403 ('d', 'date', '', _('record datecode as commit date')),
2399 ('d', 'date', '', _('record datecode as commit date')),
2404 ('u', 'user', '', _('record user as commiter'))],
2400 ('u', 'user', '', _('record user as commiter'))],
2405 _('hg commit [OPTION]... [FILE]...')),
2401 _('hg commit [OPTION]... [FILE]...')),
2406 "copy|cp":
2402 "copy|cp":
2407 (copy,
2403 (copy,
2408 [('I', 'include', [], _('include names matching the given patterns')),
2404 [('I', 'include', [], _('include names matching the given patterns')),
2409 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2405 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2410 ('A', 'after', None, _('record a copy that has already occurred')),
2406 ('A', 'after', None, _('record a copy that has already occurred')),
2411 ('f', 'force', None,
2407 ('f', 'force', None,
2412 _('forcibly copy over an existing managed file'))],
2408 _('forcibly copy over an existing managed file'))],
2413 _('hg copy [OPTION]... [SOURCE]... DEST')),
2409 _('hg copy [OPTION]... [SOURCE]... DEST')),
2414 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2410 "debugancestor": (debugancestor, [], _('debugancestor INDEX REV1 REV2')),
2415 "debugrebuildstate":
2411 "debugrebuildstate":
2416 (debugrebuildstate,
2412 (debugrebuildstate,
2417 [('r', 'rev', "", _("revision to rebuild to"))],
2413 [('r', 'rev', "", _("revision to rebuild to"))],
2418 _('debugrebuildstate [-r REV] [REV]')),
2414 _('debugrebuildstate [-r REV] [REV]')),
2419 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2415 "debugcheckstate": (debugcheckstate, [], _('debugcheckstate')),
2420 "debugconfig": (debugconfig, [], _('debugconfig')),
2416 "debugconfig": (debugconfig, [], _('debugconfig')),
2421 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2417 "debugsetparents": (debugsetparents, [], _('debugsetparents REV1 [REV2]')),
2422 "debugstate": (debugstate, [], _('debugstate')),
2418 "debugstate": (debugstate, [], _('debugstate')),
2423 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2419 "debugdata": (debugdata, [], _('debugdata FILE REV')),
2424 "debugindex": (debugindex, [], _('debugindex FILE')),
2420 "debugindex": (debugindex, [], _('debugindex FILE')),
2425 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2421 "debugindexdot": (debugindexdot, [], _('debugindexdot FILE')),
2426 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2422 "debugrename": (debugrename, [], _('debugrename FILE [REV]')),
2427 "debugwalk":
2423 "debugwalk":
2428 (debugwalk,
2424 (debugwalk,
2429 [('I', 'include', [], _('include names matching the given patterns')),
2425 [('I', 'include', [], _('include names matching the given patterns')),
2430 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2426 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2431 _('debugwalk [OPTION]... [FILE]...')),
2427 _('debugwalk [OPTION]... [FILE]...')),
2432 "^diff":
2428 "^diff":
2433 (diff,
2429 (diff,
2434 [('r', 'rev', [], _('revision')),
2430 [('r', 'rev', [], _('revision')),
2435 ('a', 'text', None, _('treat all files as text')),
2431 ('a', 'text', None, _('treat all files as text')),
2436 ('I', 'include', [], _('include names matching the given patterns')),
2432 ('I', 'include', [], _('include names matching the given patterns')),
2437 ('p', 'show-function', None,
2433 ('p', 'show-function', None,
2438 _('show which function each change is in')),
2434 _('show which function each change is in')),
2439 ('w', 'ignore-all-space', None,
2435 ('w', 'ignore-all-space', None,
2440 _('ignore white space when comparing lines')),
2436 _('ignore white space when comparing lines')),
2441 ('X', 'exclude', [],
2437 ('X', 'exclude', [],
2442 _('exclude names matching the given patterns'))],
2438 _('exclude names matching the given patterns'))],
2443 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2439 _('hg diff [-a] [-I] [-X] [-r REV1 [-r REV2]] [FILE]...')),
2444 "^export":
2440 "^export":
2445 (export,
2441 (export,
2446 [('o', 'output', '', _('print output to file with formatted name')),
2442 [('o', 'output', '', _('print output to file with formatted name')),
2447 ('a', 'text', None, _('treat all files as text')),
2443 ('a', 'text', None, _('treat all files as text')),
2448 ('', 'switch-parent', None, _('diff against the second parent'))],
2444 ('', 'switch-parent', None, _('diff against the second parent'))],
2449 _('hg export [-a] [-o OUTFILE] REV...')),
2445 _('hg export [-a] [-o OUTFILE] REV...')),
2450 "forget":
2446 "forget":
2451 (forget,
2447 (forget,
2452 [('I', 'include', [], _('include names matching the given patterns')),
2448 [('I', 'include', [], _('include names matching the given patterns')),
2453 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2449 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2454 _('hg forget [OPTION]... FILE...')),
2450 _('hg forget [OPTION]... FILE...')),
2455 "grep":
2451 "grep":
2456 (grep,
2452 (grep,
2457 [('0', 'print0', None, _('end fields with NUL')),
2453 [('0', 'print0', None, _('end fields with NUL')),
2458 ('I', 'include', [], _('include names matching the given patterns')),
2454 ('I', 'include', [], _('include names matching the given patterns')),
2459 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2455 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2460 ('', 'all', None, _('print all revisions that match')),
2456 ('', 'all', None, _('print all revisions that match')),
2461 ('i', 'ignore-case', None, _('ignore case when matching')),
2457 ('i', 'ignore-case', None, _('ignore case when matching')),
2462 ('l', 'files-with-matches', None,
2458 ('l', 'files-with-matches', None,
2463 _('print only filenames and revs that match')),
2459 _('print only filenames and revs that match')),
2464 ('n', 'line-number', None, _('print matching line numbers')),
2460 ('n', 'line-number', None, _('print matching line numbers')),
2465 ('r', 'rev', [], _('search in given revision range')),
2461 ('r', 'rev', [], _('search in given revision range')),
2466 ('u', 'user', None, _('print user who committed change'))],
2462 ('u', 'user', None, _('print user who committed change'))],
2467 _('hg grep [OPTION]... PATTERN [FILE]...')),
2463 _('hg grep [OPTION]... PATTERN [FILE]...')),
2468 "heads":
2464 "heads":
2469 (heads,
2465 (heads,
2470 [('b', 'branches', None, _('show branches')),
2466 [('b', 'branches', None, _('show branches')),
2471 ('r', 'rev', '', _('show only heads which are descendants of rev'))],
2467 ('r', 'rev', '', _('show only heads which are descendants of rev'))],
2472 _('hg heads [-b] [-r <rev>]')),
2468 _('hg heads [-b] [-r <rev>]')),
2473 "help": (help_, [], _('hg help [COMMAND]')),
2469 "help": (help_, [], _('hg help [COMMAND]')),
2474 "identify|id": (identify, [], _('hg identify')),
2470 "identify|id": (identify, [], _('hg identify')),
2475 "import|patch":
2471 "import|patch":
2476 (import_,
2472 (import_,
2477 [('p', 'strip', 1,
2473 [('p', 'strip', 1,
2478 _('directory strip option for patch. This has the same\n') +
2474 _('directory strip option for patch. This has the same\n') +
2479 _('meaning as the corresponding patch option')),
2475 _('meaning as the corresponding patch option')),
2480 ('f', 'force', None,
2476 ('f', 'force', None,
2481 _('skip check for outstanding uncommitted changes')),
2477 _('skip check for outstanding uncommitted changes')),
2482 ('b', 'base', '', _('base path'))],
2478 ('b', 'base', '', _('base path'))],
2483 _('hg import [-f] [-p NUM] [-b BASE] PATCH...')),
2479 _('hg import [-f] [-p NUM] [-b BASE] PATCH...')),
2484 "incoming|in": (incoming,
2480 "incoming|in": (incoming,
2485 [('M', 'no-merges', None, _('do not show merges')),
2481 [('M', 'no-merges', None, _('do not show merges')),
2486 ('p', 'patch', None, _('show patch')),
2482 ('p', 'patch', None, _('show patch')),
2487 ('n', 'newest-first', None, _('show newest record first'))],
2483 ('n', 'newest-first', None, _('show newest record first'))],
2488 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2484 _('hg incoming [-p] [-n] [-M] [SOURCE]')),
2489 "^init": (init, [], _('hg init [DEST]')),
2485 "^init": (init, [], _('hg init [DEST]')),
2490 "locate":
2486 "locate":
2491 (locate,
2487 (locate,
2492 [('r', 'rev', '', _('search the repository as it stood at rev')),
2488 [('r', 'rev', '', _('search the repository as it stood at rev')),
2493 ('0', 'print0', None,
2489 ('0', 'print0', None,
2494 _('end filenames with NUL, for use with xargs')),
2490 _('end filenames with NUL, for use with xargs')),
2495 ('f', 'fullpath', None,
2491 ('f', 'fullpath', None,
2496 _('print complete paths from the filesystem root')),
2492 _('print complete paths from the filesystem root')),
2497 ('I', 'include', [], _('include names matching the given patterns')),
2493 ('I', 'include', [], _('include names matching the given patterns')),
2498 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2494 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2499 _('hg locate [OPTION]... [PATTERN]...')),
2495 _('hg locate [OPTION]... [PATTERN]...')),
2500 "^log|history":
2496 "^log|history":
2501 (log,
2497 (log,
2502 [('I', 'include', [], _('include names matching the given patterns')),
2498 [('I', 'include', [], _('include names matching the given patterns')),
2503 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2499 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2504 ('b', 'branches', None, _('show branches')),
2500 ('b', 'branches', None, _('show branches')),
2505 ('k', 'keyword', [], _('search for a keyword')),
2501 ('k', 'keyword', [], _('search for a keyword')),
2506 ('l', 'limit', '', _('limit number of changes displayed')),
2502 ('l', 'limit', '', _('limit number of changes displayed')),
2507 ('r', 'rev', [], _('show the specified revision or range')),
2503 ('r', 'rev', [], _('show the specified revision or range')),
2508 ('M', 'no-merges', None, _('do not show merges')),
2504 ('M', 'no-merges', None, _('do not show merges')),
2509 ('m', 'only-merges', None, _('show only merges')),
2505 ('m', 'only-merges', None, _('show only merges')),
2510 ('p', 'patch', None, _('show patch'))],
2506 ('p', 'patch', None, _('show patch'))],
2511 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2507 _('hg log [-I] [-X] [-r REV]... [-p] [FILE]')),
2512 "manifest": (manifest, [], _('hg manifest [REV]')),
2508 "manifest": (manifest, [], _('hg manifest [REV]')),
2513 "outgoing|out": (outgoing,
2509 "outgoing|out": (outgoing,
2514 [('M', 'no-merges', None, _('do not show merges')),
2510 [('M', 'no-merges', None, _('do not show merges')),
2515 ('p', 'patch', None, _('show patch')),
2511 ('p', 'patch', None, _('show patch')),
2516 ('n', 'newest-first', None, _('show newest record first'))],
2512 ('n', 'newest-first', None, _('show newest record first'))],
2517 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2513 _('hg outgoing [-p] [-n] [-M] [DEST]')),
2518 "^parents":
2514 "^parents":
2519 (parents,
2515 (parents,
2520 [('b', 'branches', None, _('show branches'))],
2516 [('b', 'branches', None, _('show branches'))],
2521 _('hg parents [-b] [REV]')),
2517 _('hg parents [-b] [REV]')),
2522 "paths": (paths, [], _('hg paths [NAME]')),
2518 "paths": (paths, [], _('hg paths [NAME]')),
2523 "^pull":
2519 "^pull":
2524 (pull,
2520 (pull,
2525 [('u', 'update', None,
2521 [('u', 'update', None,
2526 _('update the working directory to tip after pull')),
2522 _('update the working directory to tip after pull')),
2527 ('e', 'ssh', '', _('specify ssh command to use')),
2523 ('e', 'ssh', '', _('specify ssh command to use')),
2528 ('r', 'rev', [], _('a specific revision you would like to pull')),
2524 ('r', 'rev', [], _('a specific revision you would like to pull')),
2529 ('', 'remotecmd', '',
2525 ('', 'remotecmd', '',
2530 _('specify hg command to run on the remote side'))],
2526 _('specify hg command to run on the remote side'))],
2531 _('hg pull [-u] [-e FILE] [-r rev]... [--remotecmd FILE] [SOURCE]')),
2527 _('hg pull [-u] [-e FILE] [-r rev]... [--remotecmd FILE] [SOURCE]')),
2532 "^push":
2528 "^push":
2533 (push,
2529 (push,
2534 [('f', 'force', None, _('force push')),
2530 [('f', 'force', None, _('force push')),
2535 ('e', 'ssh', '', _('specify ssh command to use')),
2531 ('e', 'ssh', '', _('specify ssh command to use')),
2536 ('r', 'rev', [], _('a specific revision you would like to push')),
2532 ('r', 'rev', [], _('a specific revision you would like to push')),
2537 ('', 'remotecmd', '',
2533 ('', 'remotecmd', '',
2538 _('specify hg command to run on the remote side'))],
2534 _('specify hg command to run on the remote side'))],
2539 _('hg push [-f] [-e FILE] [-r rev]... [--remotecmd FILE] [DEST]')),
2535 _('hg push [-f] [-e FILE] [-r rev]... [--remotecmd FILE] [DEST]')),
2540 "rawcommit":
2536 "rawcommit":
2541 (rawcommit,
2537 (rawcommit,
2542 [('p', 'parent', [], _('parent')),
2538 [('p', 'parent', [], _('parent')),
2543 ('d', 'date', '', _('date code')),
2539 ('d', 'date', '', _('date code')),
2544 ('u', 'user', '', _('user')),
2540 ('u', 'user', '', _('user')),
2545 ('F', 'files', '', _('file list')),
2541 ('F', 'files', '', _('file list')),
2546 ('m', 'message', '', _('commit message')),
2542 ('m', 'message', '', _('commit message')),
2547 ('l', 'logfile', '', _('commit message file'))],
2543 ('l', 'logfile', '', _('commit message file'))],
2548 _('hg rawcommit [OPTION]... [FILE]...')),
2544 _('hg rawcommit [OPTION]... [FILE]...')),
2549 "recover": (recover, [], _('hg recover')),
2545 "recover": (recover, [], _('hg recover')),
2550 "^remove|rm":
2546 "^remove|rm":
2551 (remove,
2547 (remove,
2552 [('I', 'include', [], _('include names matching the given patterns')),
2548 [('I', 'include', [], _('include names matching the given patterns')),
2553 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2549 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2554 _('hg remove [OPTION]... FILE...')),
2550 _('hg remove [OPTION]... FILE...')),
2555 "rename|mv":
2551 "rename|mv":
2556 (rename,
2552 (rename,
2557 [('I', 'include', [], _('include names matching the given patterns')),
2553 [('I', 'include', [], _('include names matching the given patterns')),
2558 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2554 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2559 ('A', 'after', None, _('record a rename that has already occurred')),
2555 ('A', 'after', None, _('record a rename that has already occurred')),
2560 ('f', 'force', None,
2556 ('f', 'force', None,
2561 _('forcibly copy over an existing managed file'))],
2557 _('forcibly copy over an existing managed file'))],
2562 _('hg rename [OPTION]... [SOURCE]... DEST')),
2558 _('hg rename [OPTION]... [SOURCE]... DEST')),
2563 "^revert":
2559 "^revert":
2564 (revert,
2560 (revert,
2565 [('I', 'include', [], _('include names matching the given patterns')),
2561 [('I', 'include', [], _('include names matching the given patterns')),
2566 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2562 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2567 ('r', 'rev', '', _('revision to revert to'))],
2563 ('r', 'rev', '', _('revision to revert to'))],
2568 _('hg revert [-n] [-r REV] [NAME]...')),
2564 _('hg revert [-n] [-r REV] [NAME]...')),
2569 "root": (root, [], _('hg root')),
2565 "root": (root, [], _('hg root')),
2570 "^serve":
2566 "^serve":
2571 (serve,
2567 (serve,
2572 [('A', 'accesslog', '', _('name of access log file to write to')),
2568 [('A', 'accesslog', '', _('name of access log file to write to')),
2573 ('d', 'daemon', None, _('run server in background')),
2569 ('d', 'daemon', None, _('run server in background')),
2574 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2570 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
2575 ('E', 'errorlog', '', _('name of error log file to write to')),
2571 ('E', 'errorlog', '', _('name of error log file to write to')),
2576 ('p', 'port', 0, _('port to use (default: 8000)')),
2572 ('p', 'port', 0, _('port to use (default: 8000)')),
2577 ('a', 'address', '', _('address to use')),
2573 ('a', 'address', '', _('address to use')),
2578 ('n', 'name', '',
2574 ('n', 'name', '',
2579 _('name to show in web pages (default: working dir)')),
2575 _('name to show in web pages (default: working dir)')),
2580 ('', 'pid-file', '', _('name of file to write process ID to')),
2576 ('', 'pid-file', '', _('name of file to write process ID to')),
2581 ('', 'stdio', None, _('for remote clients')),
2577 ('', 'stdio', None, _('for remote clients')),
2582 ('t', 'templates', '', _('web templates to use')),
2578 ('t', 'templates', '', _('web templates to use')),
2583 ('', 'style', '', _('template style to use')),
2579 ('', 'style', '', _('template style to use')),
2584 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2580 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4'))],
2585 _('hg serve [OPTION]...')),
2581 _('hg serve [OPTION]...')),
2586 "^status|st":
2582 "^status|st":
2587 (status,
2583 (status,
2588 [('m', 'modified', None, _('show only modified files')),
2584 [('m', 'modified', None, _('show only modified files')),
2589 ('a', 'added', None, _('show only added files')),
2585 ('a', 'added', None, _('show only added files')),
2590 ('r', 'removed', None, _('show only removed files')),
2586 ('r', 'removed', None, _('show only removed files')),
2591 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2587 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
2592 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2588 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
2593 ('n', 'no-status', None, _('hide status prefix')),
2589 ('n', 'no-status', None, _('hide status prefix')),
2594 ('0', 'print0', None,
2590 ('0', 'print0', None,
2595 _('end filenames with NUL, for use with xargs')),
2591 _('end filenames with NUL, for use with xargs')),
2596 ('I', 'include', [], _('include names matching the given patterns')),
2592 ('I', 'include', [], _('include names matching the given patterns')),
2597 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2593 ('X', 'exclude', [], _('exclude names matching the given patterns'))],
2598 _('hg status [OPTION]... [FILE]...')),
2594 _('hg status [OPTION]... [FILE]...')),
2599 "tag":
2595 "tag":
2600 (tag,
2596 (tag,
2601 [('l', 'local', None, _('make the tag local')),
2597 [('l', 'local', None, _('make the tag local')),
2602 ('m', 'message', '', _('message for tag commit log entry')),
2598 ('m', 'message', '', _('message for tag commit log entry')),
2603 ('d', 'date', '', _('record datecode as commit date')),
2599 ('d', 'date', '', _('record datecode as commit date')),
2604 ('u', 'user', '', _('record user as commiter')),
2600 ('u', 'user', '', _('record user as commiter')),
2605 ('r', 'rev', '', _('revision to tag'))],
2601 ('r', 'rev', '', _('revision to tag'))],
2606 _('hg tag [-r REV] [OPTION]... NAME')),
2602 _('hg tag [-r REV] [OPTION]... NAME')),
2607 "tags": (tags, [], _('hg tags')),
2603 "tags": (tags, [], _('hg tags')),
2608 "tip":
2604 "tip":
2609 (tip,
2605 (tip,
2610 [('b', 'branches', None, _('show branches')),
2606 [('b', 'branches', None, _('show branches')),
2611 ('p', 'patch', None, _('show patch'))],
2607 ('p', 'patch', None, _('show patch'))],
2612 _('hg [-b] [-p] tip')),
2608 _('hg [-b] [-p] tip')),
2613 "unbundle":
2609 "unbundle":
2614 (unbundle,
2610 (unbundle,
2615 [('u', 'update', None,
2611 [('u', 'update', None,
2616 _('update the working directory to tip after unbundle'))],
2612 _('update the working directory to tip after unbundle'))],
2617 _('hg unbundle [-u] FILE')),
2613 _('hg unbundle [-u] FILE')),
2618 "undo": (undo, [], _('hg undo')),
2614 "undo": (undo, [], _('hg undo')),
2619 "^update|up|checkout|co":
2615 "^update|up|checkout|co":
2620 (update,
2616 (update,
2621 [('b', 'branch', '', _('checkout the head of a specific branch')),
2617 [('b', 'branch', '', _('checkout the head of a specific branch')),
2622 ('m', 'merge', None, _('allow merging of branches')),
2618 ('m', 'merge', None, _('allow merging of branches')),
2623 ('C', 'clean', None, _('overwrite locally modified files')),
2619 ('C', 'clean', None, _('overwrite locally modified files')),
2624 ('f', 'force', None, _('force a merge with outstanding changes'))],
2620 ('f', 'force', None, _('force a merge with outstanding changes'))],
2625 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
2621 _('hg update [-b TAG] [-m] [-C] [-f] [REV]')),
2626 "verify": (verify, [], _('hg verify')),
2622 "verify": (verify, [], _('hg verify')),
2627 "version": (show_version, [], _('hg version')),
2623 "version": (show_version, [], _('hg version')),
2628 }
2624 }
2629
2625
2630 globalopts = [
2626 globalopts = [
2631 ('R', 'repository', '', _('repository root directory')),
2627 ('R', 'repository', '', _('repository root directory')),
2632 ('', 'cwd', '', _('change working directory')),
2628 ('', 'cwd', '', _('change working directory')),
2633 ('y', 'noninteractive', None,
2629 ('y', 'noninteractive', None,
2634 _('do not prompt, assume \'yes\' for any required answers')),
2630 _('do not prompt, assume \'yes\' for any required answers')),
2635 ('q', 'quiet', None, _('suppress output')),
2631 ('q', 'quiet', None, _('suppress output')),
2636 ('v', 'verbose', None, _('enable additional output')),
2632 ('v', 'verbose', None, _('enable additional output')),
2637 ('', 'debug', None, _('enable debugging output')),
2633 ('', 'debug', None, _('enable debugging output')),
2638 ('', 'debugger', None, _('start debugger')),
2634 ('', 'debugger', None, _('start debugger')),
2639 ('', 'traceback', None, _('print traceback on exception')),
2635 ('', 'traceback', None, _('print traceback on exception')),
2640 ('', 'time', None, _('time how long the command takes')),
2636 ('', 'time', None, _('time how long the command takes')),
2641 ('', 'profile', None, _('print command execution profile')),
2637 ('', 'profile', None, _('print command execution profile')),
2642 ('', 'version', None, _('output version information and exit')),
2638 ('', 'version', None, _('output version information and exit')),
2643 ('h', 'help', None, _('display help and exit')),
2639 ('h', 'help', None, _('display help and exit')),
2644 ]
2640 ]
2645
2641
2646 norepo = ("clone init version help debugancestor debugconfig debugdata"
2642 norepo = ("clone init version help debugancestor debugconfig debugdata"
2647 " debugindex debugindexdot paths")
2643 " debugindex debugindexdot paths")
2648
2644
2649 def find(cmd):
2645 def find(cmd):
2650 """Return (aliases, command table entry) for command string."""
2646 """Return (aliases, command table entry) for command string."""
2651 choice = None
2647 choice = None
2652 count = 0
2648 count = 0
2653 for e in table.keys():
2649 for e in table.keys():
2654 aliases = e.lstrip("^").split("|")
2650 aliases = e.lstrip("^").split("|")
2655 if cmd in aliases:
2651 if cmd in aliases:
2656 return aliases, table[e]
2652 return aliases, table[e]
2657 for a in aliases:
2653 for a in aliases:
2658 if a.startswith(cmd):
2654 if a.startswith(cmd):
2659 count += 1
2655 count += 1
2660 choice = aliases, table[e]
2656 choice = aliases, table[e]
2661 break
2657 break
2662
2658
2663 if count > 1:
2659 if count > 1:
2664 raise AmbiguousCommand(cmd)
2660 raise AmbiguousCommand(cmd)
2665
2661
2666 if choice:
2662 if choice:
2667 return choice
2663 return choice
2668
2664
2669 raise UnknownCommand(cmd)
2665 raise UnknownCommand(cmd)
2670
2666
2671 class SignalInterrupt(Exception):
2667 class SignalInterrupt(Exception):
2672 """Exception raised on SIGTERM and SIGHUP."""
2668 """Exception raised on SIGTERM and SIGHUP."""
2673
2669
2674 def catchterm(*args):
2670 def catchterm(*args):
2675 raise SignalInterrupt
2671 raise SignalInterrupt
2676
2672
2677 def run():
2673 def run():
2678 sys.exit(dispatch(sys.argv[1:]))
2674 sys.exit(dispatch(sys.argv[1:]))
2679
2675
2680 class ParseError(Exception):
2676 class ParseError(Exception):
2681 """Exception raised on errors in parsing the command line."""
2677 """Exception raised on errors in parsing the command line."""
2682
2678
2683 def parse(ui, args):
2679 def parse(ui, args):
2684 options = {}
2680 options = {}
2685 cmdoptions = {}
2681 cmdoptions = {}
2686
2682
2687 try:
2683 try:
2688 args = fancyopts.fancyopts(args, globalopts, options)
2684 args = fancyopts.fancyopts(args, globalopts, options)
2689 except fancyopts.getopt.GetoptError, inst:
2685 except fancyopts.getopt.GetoptError, inst:
2690 raise ParseError(None, inst)
2686 raise ParseError(None, inst)
2691
2687
2692 if args:
2688 if args:
2693 cmd, args = args[0], args[1:]
2689 cmd, args = args[0], args[1:]
2694 aliases, i = find(cmd)
2690 aliases, i = find(cmd)
2695 cmd = aliases[0]
2691 cmd = aliases[0]
2696 defaults = ui.config("defaults", cmd)
2692 defaults = ui.config("defaults", cmd)
2697 if defaults:
2693 if defaults:
2698 args = defaults.split() + args
2694 args = defaults.split() + args
2699 c = list(i[1])
2695 c = list(i[1])
2700 else:
2696 else:
2701 cmd = None
2697 cmd = None
2702 c = []
2698 c = []
2703
2699
2704 # combine global options into local
2700 # combine global options into local
2705 for o in globalopts:
2701 for o in globalopts:
2706 c.append((o[0], o[1], options[o[1]], o[3]))
2702 c.append((o[0], o[1], options[o[1]], o[3]))
2707
2703
2708 try:
2704 try:
2709 args = fancyopts.fancyopts(args, c, cmdoptions)
2705 args = fancyopts.fancyopts(args, c, cmdoptions)
2710 except fancyopts.getopt.GetoptError, inst:
2706 except fancyopts.getopt.GetoptError, inst:
2711 raise ParseError(cmd, inst)
2707 raise ParseError(cmd, inst)
2712
2708
2713 # separate global options back out
2709 # separate global options back out
2714 for o in globalopts:
2710 for o in globalopts:
2715 n = o[1]
2711 n = o[1]
2716 options[n] = cmdoptions[n]
2712 options[n] = cmdoptions[n]
2717 del cmdoptions[n]
2713 del cmdoptions[n]
2718
2714
2719 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2715 return (cmd, cmd and i[0] or None, args, options, cmdoptions)
2720
2716
2721 def dispatch(args):
2717 def dispatch(args):
2722 signal.signal(signal.SIGTERM, catchterm)
2718 signal.signal(signal.SIGTERM, catchterm)
2723 try:
2719 try:
2724 signal.signal(signal.SIGHUP, catchterm)
2720 signal.signal(signal.SIGHUP, catchterm)
2725 except AttributeError:
2721 except AttributeError:
2726 pass
2722 pass
2727
2723
2728 try:
2724 try:
2729 u = ui.ui()
2725 u = ui.ui()
2730 except util.Abort, inst:
2726 except util.Abort, inst:
2731 sys.stderr.write(_("abort: %s\n") % inst)
2727 sys.stderr.write(_("abort: %s\n") % inst)
2732 sys.exit(1)
2728 sys.exit(1)
2733
2729
2734 external = []
2730 external = []
2735 for x in u.extensions():
2731 for x in u.extensions():
2736 def on_exception(exc, inst):
2732 def on_exception(exc, inst):
2737 u.warn(_("*** failed to import extension %s\n") % x[1])
2733 u.warn(_("*** failed to import extension %s\n") % x[1])
2738 u.warn("%s\n" % inst)
2734 u.warn("%s\n" % inst)
2739 if "--traceback" in sys.argv[1:]:
2735 if "--traceback" in sys.argv[1:]:
2740 traceback.print_exc()
2736 traceback.print_exc()
2741 if x[1]:
2737 if x[1]:
2742 try:
2738 try:
2743 mod = imp.load_source(x[0], x[1])
2739 mod = imp.load_source(x[0], x[1])
2744 except Exception, inst:
2740 except Exception, inst:
2745 on_exception(Exception, inst)
2741 on_exception(Exception, inst)
2746 continue
2742 continue
2747 else:
2743 else:
2748 def importh(name):
2744 def importh(name):
2749 mod = __import__(name)
2745 mod = __import__(name)
2750 components = name.split('.')
2746 components = name.split('.')
2751 for comp in components[1:]:
2747 for comp in components[1:]:
2752 mod = getattr(mod, comp)
2748 mod = getattr(mod, comp)
2753 return mod
2749 return mod
2754 try:
2750 try:
2755 mod = importh(x[0])
2751 mod = importh(x[0])
2756 except Exception, inst:
2752 except Exception, inst:
2757 on_exception(Exception, inst)
2753 on_exception(Exception, inst)
2758 continue
2754 continue
2759
2755
2760 external.append(mod)
2756 external.append(mod)
2761 for x in external:
2757 for x in external:
2762 cmdtable = getattr(x, 'cmdtable', {})
2758 cmdtable = getattr(x, 'cmdtable', {})
2763 for t in cmdtable:
2759 for t in cmdtable:
2764 if t in table:
2760 if t in table:
2765 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2761 u.warn(_("module %s overrides %s\n") % (x.__name__, t))
2766 table.update(cmdtable)
2762 table.update(cmdtable)
2767
2763
2768 try:
2764 try:
2769 cmd, func, args, options, cmdoptions = parse(u, args)
2765 cmd, func, args, options, cmdoptions = parse(u, args)
2770 except ParseError, inst:
2766 except ParseError, inst:
2771 if inst.args[0]:
2767 if inst.args[0]:
2772 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2768 u.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
2773 help_(u, inst.args[0])
2769 help_(u, inst.args[0])
2774 else:
2770 else:
2775 u.warn(_("hg: %s\n") % inst.args[1])
2771 u.warn(_("hg: %s\n") % inst.args[1])
2776 help_(u, 'shortlist')
2772 help_(u, 'shortlist')
2777 sys.exit(-1)
2773 sys.exit(-1)
2778 except AmbiguousCommand, inst:
2774 except AmbiguousCommand, inst:
2779 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2775 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2780 sys.exit(1)
2776 sys.exit(1)
2781 except UnknownCommand, inst:
2777 except UnknownCommand, inst:
2782 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2778 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2783 help_(u, 'shortlist')
2779 help_(u, 'shortlist')
2784 sys.exit(1)
2780 sys.exit(1)
2785
2781
2786 if options["time"]:
2782 if options["time"]:
2787 def get_times():
2783 def get_times():
2788 t = os.times()
2784 t = os.times()
2789 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2785 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
2790 t = (t[0], t[1], t[2], t[3], time.clock())
2786 t = (t[0], t[1], t[2], t[3], time.clock())
2791 return t
2787 return t
2792 s = get_times()
2788 s = get_times()
2793 def print_time():
2789 def print_time():
2794 t = get_times()
2790 t = get_times()
2795 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2791 u.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
2796 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2792 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
2797 atexit.register(print_time)
2793 atexit.register(print_time)
2798
2794
2799 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2795 u.updateopts(options["verbose"], options["debug"], options["quiet"],
2800 not options["noninteractive"])
2796 not options["noninteractive"])
2801
2797
2802 # enter the debugger before command execution
2798 # enter the debugger before command execution
2803 if options['debugger']:
2799 if options['debugger']:
2804 pdb.set_trace()
2800 pdb.set_trace()
2805
2801
2806 try:
2802 try:
2807 try:
2803 try:
2808 if options['help']:
2804 if options['help']:
2809 help_(u, cmd, options['version'])
2805 help_(u, cmd, options['version'])
2810 sys.exit(0)
2806 sys.exit(0)
2811 elif options['version']:
2807 elif options['version']:
2812 show_version(u)
2808 show_version(u)
2813 sys.exit(0)
2809 sys.exit(0)
2814 elif not cmd:
2810 elif not cmd:
2815 help_(u, 'shortlist')
2811 help_(u, 'shortlist')
2816 sys.exit(0)
2812 sys.exit(0)
2817
2813
2818 if options['cwd']:
2814 if options['cwd']:
2819 try:
2815 try:
2820 os.chdir(options['cwd'])
2816 os.chdir(options['cwd'])
2821 except OSError, inst:
2817 except OSError, inst:
2822 raise util.Abort('%s: %s' %
2818 raise util.Abort('%s: %s' %
2823 (options['cwd'], inst.strerror))
2819 (options['cwd'], inst.strerror))
2824
2820
2825 if cmd not in norepo.split():
2821 if cmd not in norepo.split():
2826 path = options["repository"] or ""
2822 path = options["repository"] or ""
2827 repo = hg.repository(ui=u, path=path)
2823 repo = hg.repository(ui=u, path=path)
2828 for x in external:
2824 for x in external:
2829 if hasattr(x, 'reposetup'):
2825 if hasattr(x, 'reposetup'):
2830 x.reposetup(u, repo)
2826 x.reposetup(u, repo)
2831 d = lambda: func(u, repo, *args, **cmdoptions)
2827 d = lambda: func(u, repo, *args, **cmdoptions)
2832 else:
2828 else:
2833 d = lambda: func(u, *args, **cmdoptions)
2829 d = lambda: func(u, *args, **cmdoptions)
2834
2830
2835 if options['profile']:
2831 if options['profile']:
2836 import hotshot, hotshot.stats
2832 import hotshot, hotshot.stats
2837 prof = hotshot.Profile("hg.prof")
2833 prof = hotshot.Profile("hg.prof")
2838 r = prof.runcall(d)
2834 r = prof.runcall(d)
2839 prof.close()
2835 prof.close()
2840 stats = hotshot.stats.load("hg.prof")
2836 stats = hotshot.stats.load("hg.prof")
2841 stats.strip_dirs()
2837 stats.strip_dirs()
2842 stats.sort_stats('time', 'calls')
2838 stats.sort_stats('time', 'calls')
2843 stats.print_stats(40)
2839 stats.print_stats(40)
2844 return r
2840 return r
2845 else:
2841 else:
2846 return d()
2842 return d()
2847 except:
2843 except:
2848 # enter the debugger when we hit an exception
2844 # enter the debugger when we hit an exception
2849 if options['debugger']:
2845 if options['debugger']:
2850 pdb.post_mortem(sys.exc_info()[2])
2846 pdb.post_mortem(sys.exc_info()[2])
2851 if options['traceback']:
2847 if options['traceback']:
2852 traceback.print_exc()
2848 traceback.print_exc()
2853 raise
2849 raise
2854 except hg.RepoError, inst:
2850 except hg.RepoError, inst:
2855 u.warn(_("abort: "), inst, "!\n")
2851 u.warn(_("abort: "), inst, "!\n")
2856 except revlog.RevlogError, inst:
2852 except revlog.RevlogError, inst:
2857 u.warn(_("abort: "), inst, "!\n")
2853 u.warn(_("abort: "), inst, "!\n")
2858 except SignalInterrupt:
2854 except SignalInterrupt:
2859 u.warn(_("killed!\n"))
2855 u.warn(_("killed!\n"))
2860 except KeyboardInterrupt:
2856 except KeyboardInterrupt:
2861 try:
2857 try:
2862 u.warn(_("interrupted!\n"))
2858 u.warn(_("interrupted!\n"))
2863 except IOError, inst:
2859 except IOError, inst:
2864 if inst.errno == errno.EPIPE:
2860 if inst.errno == errno.EPIPE:
2865 if u.debugflag:
2861 if u.debugflag:
2866 u.warn(_("\nbroken pipe\n"))
2862 u.warn(_("\nbroken pipe\n"))
2867 else:
2863 else:
2868 raise
2864 raise
2869 except IOError, inst:
2865 except IOError, inst:
2870 if hasattr(inst, "code"):
2866 if hasattr(inst, "code"):
2871 u.warn(_("abort: %s\n") % inst)
2867 u.warn(_("abort: %s\n") % inst)
2872 elif hasattr(inst, "reason"):
2868 elif hasattr(inst, "reason"):
2873 u.warn(_("abort: error: %s\n") % inst.reason[1])
2869 u.warn(_("abort: error: %s\n") % inst.reason[1])
2874 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2870 elif hasattr(inst, "args") and inst[0] == errno.EPIPE:
2875 if u.debugflag:
2871 if u.debugflag:
2876 u.warn(_("broken pipe\n"))
2872 u.warn(_("broken pipe\n"))
2877 elif getattr(inst, "strerror", None):
2873 elif getattr(inst, "strerror", None):
2878 if getattr(inst, "filename", None):
2874 if getattr(inst, "filename", None):
2879 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2875 u.warn(_("abort: %s - %s\n") % (inst.strerror, inst.filename))
2880 else:
2876 else:
2881 u.warn(_("abort: %s\n") % inst.strerror)
2877 u.warn(_("abort: %s\n") % inst.strerror)
2882 else:
2878 else:
2883 raise
2879 raise
2884 except OSError, inst:
2880 except OSError, inst:
2885 if hasattr(inst, "filename"):
2881 if hasattr(inst, "filename"):
2886 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2882 u.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
2887 else:
2883 else:
2888 u.warn(_("abort: %s\n") % inst.strerror)
2884 u.warn(_("abort: %s\n") % inst.strerror)
2889 except util.Abort, inst:
2885 except util.Abort, inst:
2890 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2886 u.warn(_('abort: '), inst.args[0] % inst.args[1:], '\n')
2891 sys.exit(1)
2887 sys.exit(1)
2892 except TypeError, inst:
2888 except TypeError, inst:
2893 # was this an argument error?
2889 # was this an argument error?
2894 tb = traceback.extract_tb(sys.exc_info()[2])
2890 tb = traceback.extract_tb(sys.exc_info()[2])
2895 if len(tb) > 2: # no
2891 if len(tb) > 2: # no
2896 raise
2892 raise
2897 u.debug(inst, "\n")
2893 u.debug(inst, "\n")
2898 u.warn(_("%s: invalid arguments\n") % cmd)
2894 u.warn(_("%s: invalid arguments\n") % cmd)
2899 help_(u, cmd)
2895 help_(u, cmd)
2900 except AmbiguousCommand, inst:
2896 except AmbiguousCommand, inst:
2901 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2897 u.warn(_("hg: command '%s' is ambiguous.\n") % inst.args[0])
2902 help_(u, 'shortlist')
2898 help_(u, 'shortlist')
2903 except UnknownCommand, inst:
2899 except UnknownCommand, inst:
2904 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2900 u.warn(_("hg: unknown command '%s'\n") % inst.args[0])
2905 help_(u, 'shortlist')
2901 help_(u, 'shortlist')
2906 except SystemExit:
2902 except SystemExit:
2907 # don't catch this in the catch-all below
2903 # don't catch this in the catch-all below
2908 raise
2904 raise
2909 except:
2905 except:
2910 u.warn(_("** unknown exception encountered, details follow\n"))
2906 u.warn(_("** unknown exception encountered, details follow\n"))
2911 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2907 u.warn(_("** report bug details to mercurial@selenic.com\n"))
2912 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2908 u.warn(_("** Mercurial Distributed SCM (version %s)\n")
2913 % version.get_version())
2909 % version.get_version())
2914 raise
2910 raise
2915
2911
2916 sys.exit(-1)
2912 sys.exit(-1)
General Comments 0
You need to be logged in to leave comments. Login now