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