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