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