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