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