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