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