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