##// END OF EJS Templates
Make filectx lazier - some users never use filenode
Brendan Cully -
r3144:8342ad5a default
parent child Browse files
Show More
@@ -1,186 +1,187
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")
10 demandload(globals(), "ancestor")
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 # if given a changeset id, go ahead and look up the file
106 self._changeid = changeid
105 self._changeid = changeid
107 self._changectx = self.changectx()
108 self._filenode = self._changectx.filenode(self._path)
109 else:
106 else:
110 # else delay changectx creation
111 self._filenode = self._filelog.lookup(fileid)
107 self._filenode = self._filelog.lookup(fileid)
112 self._changeid = self._filelog.linkrev(self._filenode)
108 self._changeid = self._filelog.linkrev(self._filenode)
113 self._filerev = self._filelog.rev(self._filenode)
114
109
115 def changectx(self):
110 def __getattr__(self, name):
116 try:
111 if name == '_changectx':
117 return self._changectx
118 except AttributeError:
119 self._changectx = changectx(self._repo, self._changeid)
112 self._changectx = changectx(self._repo, self._changeid)
120 return self._changectx
113 return self._changectx
114 elif name == '_filenode':
115 self._filenode = self._changectx.filenode(self._path)
116 return self._filenode
117 elif name == '_filerev':
118 self._filerev = self._filelog.rev(self._filenode)
119 return self._filerev
120 else:
121 raise AttributeError, name
121
122
122 def filerev(self): return self._filerev
123 def filerev(self): return self._filerev
123 def filenode(self): return self._filenode
124 def filenode(self): return self._filenode
124 def filelog(self): return self._filelog
125 def filelog(self): return self._filelog
125
126
126 def rev(self): return self.changectx().rev()
127 def rev(self): return self._changectx.rev()
127 def node(self): return self.changectx().node()
128 def node(self): return self._changectx.node()
128 def user(self): return self.changectx().user()
129 def user(self): return self._changectx.user()
129 def date(self): return self.changectx().date()
130 def date(self): return self._changectx.date()
130 def files(self): return self.changectx().files()
131 def files(self): return self._changectx.files()
131 def description(self): return self.changectx().description()
132 def description(self): return self._changectx.description()
132 def manifest(self): return self.changectx().manifest()
133 def manifest(self): return self._changectx.manifest()
133
134
134 def data(self): return self._filelog.read(self._filenode)
135 def data(self): return self._filelog.read(self._filenode)
135 def renamed(self): return self._filelog.renamed(self._filenode)
136 def renamed(self): return self._filelog.renamed(self._filenode)
136 def path(self): return self._path
137 def path(self): return self._path
137
138
138 def parents(self):
139 def parents(self):
139 p = self._path
140 p = self._path
140 fl = self._filelog
141 fl = self._filelog
141 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
142 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
142
143
143 r = self.renamed()
144 r = self.renamed()
144 if r:
145 if r:
145 pl[0] = (r[0], r[1], None)
146 pl[0] = (r[0], r[1], None)
146
147
147 return [ filectx(self._repo, p, fileid=n, filelog=l)
148 return [ filectx(self._repo, p, fileid=n, filelog=l)
148 for p,n,l in pl if n != nullid ]
149 for p,n,l in pl if n != nullid ]
149
150
150 def children(self):
151 def children(self):
151 # hard for renames
152 # hard for renames
152 c = self._filelog.children(self._filenode)
153 c = self._filelog.children(self._filenode)
153 return [ filectx(self._repo, self._path, fileid=x,
154 return [ filectx(self._repo, self._path, fileid=x,
154 filelog=self._filelog) for x in c ]
155 filelog=self._filelog) for x in c ]
155
156
156 def annotate(self):
157 def annotate(self):
157 return self._filelog.annotate(self._filenode)
158 return self._filelog.annotate(self._filenode)
158
159
159 def ancestor(self, fc2):
160 def ancestor(self, fc2):
160 """
161 """
161 find the common ancestor file context, if any, of self, and fc2
162 find the common ancestor file context, if any, of self, and fc2
162 """
163 """
163
164
164 acache = {}
165 acache = {}
165 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
166 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
166 def parents(vertex):
167 def parents(vertex):
167 if vertex in acache:
168 if vertex in acache:
168 return acache[vertex]
169 return acache[vertex]
169 f, n = vertex
170 f, n = vertex
170 if f not in flcache:
171 if f not in flcache:
171 flcache[f] = self._repo.file(f)
172 flcache[f] = self._repo.file(f)
172 fl = flcache[f]
173 fl = flcache[f]
173 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
174 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
174 re = fl.renamed(n)
175 re = fl.renamed(n)
175 if re:
176 if re:
176 pl.append(re)
177 pl.append(re)
177 acache[vertex]=pl
178 acache[vertex]=pl
178 return pl
179 return pl
179
180
180 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
181 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
181 v = ancestor.ancestor(a, b, parents)
182 v = ancestor.ancestor(a, b, parents)
182 if v:
183 if v:
183 f,n = v
184 f,n = v
184 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
185 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
185
186
186 return None
187 return None
General Comments 0
You need to be logged in to leave comments. Login now