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