##// END OF EJS Templates
filectx: lazy linkrev usage
Matt Mackall -
r3150:a5e4c817 default
parent child Browse files
Show More
@@ -1,193 +1,197
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from node import *
8 from node import *
9 from demandload import demandload
9 from demandload import demandload
10 demandload(globals(), "ancestor util")
10 demandload(globals(), "ancestor util")
11
11
12 class changectx(object):
12 class changectx(object):
13 """A changecontext object makes access to data related to a particular
13 """A changecontext object makes access to data related to a particular
14 changeset convenient."""
14 changeset convenient."""
15 def __init__(self, repo, changeid=None):
15 def __init__(self, repo, changeid=None):
16 """changeid is a revision number, node, or tag"""
16 """changeid is a revision number, node, or tag"""
17 self._repo = repo
17 self._repo = repo
18
18
19 if not changeid and changeid != 0:
19 if not changeid and changeid != 0:
20 p1, p2 = self._repo.dirstate.parents()
20 p1, p2 = self._repo.dirstate.parents()
21 self._rev = self._repo.changelog.rev(p1)
21 self._rev = self._repo.changelog.rev(p1)
22 if self._rev == -1:
22 if self._rev == -1:
23 changeid = 'tip'
23 changeid = 'tip'
24 else:
24 else:
25 self._node = p1
25 self._node = p1
26 return
26 return
27
27
28 self._node = self._repo.lookup(changeid)
28 self._node = self._repo.lookup(changeid)
29 self._rev = self._repo.changelog.rev(self._node)
29 self._rev = self._repo.changelog.rev(self._node)
30
30
31 def changeset(self):
31 def changeset(self):
32 try:
32 try:
33 return self._changeset
33 return self._changeset
34 except AttributeError:
34 except AttributeError:
35 self._changeset = self._repo.changelog.read(self.node())
35 self._changeset = self._repo.changelog.read(self.node())
36 return self._changeset
36 return self._changeset
37
37
38 def manifest(self):
38 def manifest(self):
39 try:
39 try:
40 return self._manifest
40 return self._manifest
41 except AttributeError:
41 except AttributeError:
42 self._manifest = self._repo.manifest.read(self.changeset()[0])
42 self._manifest = self._repo.manifest.read(self.changeset()[0])
43 return self._manifest
43 return self._manifest
44
44
45 def rev(self): return self._rev
45 def rev(self): return self._rev
46 def node(self): return self._node
46 def node(self): return self._node
47 def user(self): return self.changeset()[1]
47 def user(self): return self.changeset()[1]
48 def date(self): return self.changeset()[2]
48 def date(self): return self.changeset()[2]
49 def files(self): return self.changeset()[3]
49 def files(self): return self.changeset()[3]
50 def description(self): return self.changeset()[4]
50 def description(self): return self.changeset()[4]
51
51
52 def parents(self):
52 def parents(self):
53 """return contexts for each parent changeset"""
53 """return contexts for each parent changeset"""
54 p = self._repo.changelog.parents(self._node)
54 p = self._repo.changelog.parents(self._node)
55 return [ changectx(self._repo, x) for x in p ]
55 return [ changectx(self._repo, x) for x in p ]
56
56
57 def children(self):
57 def children(self):
58 """return contexts for each child changeset"""
58 """return contexts for each child changeset"""
59 c = self._repo.changelog.children(self._node)
59 c = self._repo.changelog.children(self._node)
60 return [ changectx(self._repo, x) for x in c ]
60 return [ changectx(self._repo, x) for x in c ]
61
61
62 def filenode(self, path):
62 def filenode(self, path):
63 node, flag = self._repo.manifest.find(self.changeset()[0], path)
63 node, flag = self._repo.manifest.find(self.changeset()[0], path)
64 return node
64 return node
65
65
66 def filectx(self, path, fileid=None):
66 def filectx(self, path, fileid=None):
67 """get a file context from this changeset"""
67 """get a file context from this changeset"""
68 if fileid is None:
68 if fileid is None:
69 fileid = self.filenode(path)
69 fileid = self.filenode(path)
70 return filectx(self._repo, path, fileid=fileid)
70 return filectx(self._repo, path, fileid=fileid)
71
71
72 def filectxs(self):
72 def filectxs(self):
73 """generate a file context for each file in this changeset's
73 """generate a file context for each file in this changeset's
74 manifest"""
74 manifest"""
75 mf = self.manifest()
75 mf = self.manifest()
76 m = mf.keys()
76 m = mf.keys()
77 m.sort()
77 m.sort()
78 for f in m:
78 for f in m:
79 yield self.filectx(f, fileid=mf[f])
79 yield self.filectx(f, fileid=mf[f])
80
80
81 def ancestor(self, c2):
81 def ancestor(self, c2):
82 """
82 """
83 return the ancestor context of self and c2
83 return the ancestor context of self and c2
84 """
84 """
85 n = self._repo.changelog.ancestor(self._node, c2._node)
85 n = self._repo.changelog.ancestor(self._node, c2._node)
86 return changectx(self._repo, n)
86 return changectx(self._repo, n)
87
87
88 class filectx(object):
88 class filectx(object):
89 """A filecontext object makes access to data related to a particular
89 """A filecontext object makes access to data related to a particular
90 filerevision convenient."""
90 filerevision convenient."""
91 def __init__(self, repo, path, changeid=None, fileid=None, filelog=None):
91 def __init__(self, repo, path, changeid=None, fileid=None, filelog=None):
92 """changeid can be a changeset revision, node, or tag.
92 """changeid can be a changeset revision, node, or tag.
93 fileid can be a file revision or node."""
93 fileid can be a file revision or node."""
94 self._repo = repo
94 self._repo = repo
95 self._path = path
95 self._path = path
96
96
97 assert changeid is not None or fileid is not None
97 assert changeid is not None or fileid is not None
98
98
99 if filelog:
99 if filelog:
100 self._filelog = filelog
100 self._filelog = filelog
101 else:
101 else:
102 self._filelog = self._repo.file(self._path)
102 self._filelog = self._repo.file(self._path)
103
103
104 if fileid is None:
104 if fileid is None:
105 self._changeid = changeid
105 self._changeid = changeid
106 else:
106 else:
107 self._filenode = self._filelog.lookup(fileid)
107 self._filenode = self._filelog.lookup(fileid)
108 self._changeid = self._filelog.linkrev(self._filenode)
108 self._changeid = self._filelog.linkrev(self._filenode)
109
109
110 def __getattr__(self, name):
110 def __getattr__(self, name):
111 if name == '_changectx':
111 if name == '_changectx':
112 self._changectx = changectx(self._repo, self._changeid)
112 self._changectx = changectx(self._repo, self._changeid)
113 return self._changectx
113 return self._changectx
114 elif name == '_filenode':
114 elif name == '_filenode':
115 self._filenode = self._changectx.filenode(self._path)
115 self._filenode = self._changectx.filenode(self._path)
116 return self._filenode
116 return self._filenode
117 elif name == '_filerev':
117 elif name == '_filerev':
118 self._filerev = self._filelog.rev(self._filenode)
118 self._filerev = self._filelog.rev(self._filenode)
119 return self._filerev
119 return self._filerev
120 else:
120 else:
121 raise AttributeError, name
121 raise AttributeError, name
122
122
123 def filerev(self): return self._filerev
123 def filerev(self): return self._filerev
124 def filenode(self): return self._filenode
124 def filenode(self): return self._filenode
125 def filelog(self): return self._filelog
125 def filelog(self): return self._filelog
126
126
127 def rev(self): return self._changectx.rev()
127 def rev(self):
128 if hasattr(self, "_changectx"):
129 return self._changectx.rev()
130 return self._filelog.linkrev(self._filenode)
131
128 def node(self): return self._changectx.node()
132 def node(self): return self._changectx.node()
129 def user(self): return self._changectx.user()
133 def user(self): return self._changectx.user()
130 def date(self): return self._changectx.date()
134 def date(self): return self._changectx.date()
131 def files(self): return self._changectx.files()
135 def files(self): return self._changectx.files()
132 def description(self): return self._changectx.description()
136 def description(self): return self._changectx.description()
133 def manifest(self): return self._changectx.manifest()
137 def manifest(self): return self._changectx.manifest()
134 def changectx(self): return self._changectx
138 def changectx(self): return self._changectx
135
139
136 def data(self): return self._filelog.read(self._filenode)
140 def data(self): return self._filelog.read(self._filenode)
137 def renamed(self): return self._filelog.renamed(self._filenode)
141 def renamed(self): return self._filelog.renamed(self._filenode)
138 def path(self): return self._path
142 def path(self): return self._path
139
143
140 def parents(self):
144 def parents(self):
141 p = self._path
145 p = self._path
142 fl = self._filelog
146 fl = self._filelog
143 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
147 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
144
148
145 r = self.renamed()
149 r = self.renamed()
146 if r:
150 if r:
147 pl[0] = (r[0], r[1], None)
151 pl[0] = (r[0], r[1], None)
148
152
149 return [ filectx(self._repo, p, fileid=n, filelog=l)
153 return [ filectx(self._repo, p, fileid=n, filelog=l)
150 for p,n,l in pl if n != nullid ]
154 for p,n,l in pl if n != nullid ]
151
155
152 def children(self):
156 def children(self):
153 # hard for renames
157 # hard for renames
154 c = self._filelog.children(self._filenode)
158 c = self._filelog.children(self._filenode)
155 return [ filectx(self._repo, self._path, fileid=x,
159 return [ filectx(self._repo, self._path, fileid=x,
156 filelog=self._filelog) for x in c ]
160 filelog=self._filelog) for x in c ]
157
161
158 def annotate(self):
162 def annotate(self):
159 getctx = util.cachefunc(lambda x: filectx(self._repo, self._path,
163 getctx = util.cachefunc(lambda x: filectx(self._repo, self._path,
160 changeid=x,
164 changeid=x,
161 filelog=self._filelog))
165 filelog=self._filelog))
162 hist = self._filelog.annotate(self._filenode)
166 hist = self._filelog.annotate(self._filenode)
163
167
164 return [(getctx(rev), line) for rev, line in hist]
168 return [(getctx(rev), line) for rev, line in hist]
165
169
166 def ancestor(self, fc2):
170 def ancestor(self, fc2):
167 """
171 """
168 find the common ancestor file context, if any, of self, and fc2
172 find the common ancestor file context, if any, of self, and fc2
169 """
173 """
170
174
171 acache = {}
175 acache = {}
172 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
176 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
173 def parents(vertex):
177 def parents(vertex):
174 if vertex in acache:
178 if vertex in acache:
175 return acache[vertex]
179 return acache[vertex]
176 f, n = vertex
180 f, n = vertex
177 if f not in flcache:
181 if f not in flcache:
178 flcache[f] = self._repo.file(f)
182 flcache[f] = self._repo.file(f)
179 fl = flcache[f]
183 fl = flcache[f]
180 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
184 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
181 re = fl.renamed(n)
185 re = fl.renamed(n)
182 if re:
186 if re:
183 pl.append(re)
187 pl.append(re)
184 acache[vertex]=pl
188 acache[vertex]=pl
185 return pl
189 return pl
186
190
187 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
191 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
188 v = ancestor.ancestor(a, b, parents)
192 v = ancestor.ancestor(a, b, parents)
189 if v:
193 if v:
190 f,n = v
194 f,n = v
191 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
195 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
192
196
193 return None
197 return None
General Comments 0
You need to be logged in to leave comments. Login now