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