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