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