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