##// END OF EJS Templates
Make changectx.filenode raise repo.LookupError on failure
Brendan Cully -
r3242:1539f788 default
parent child Browse files
Show More
@@ -1,459 +1,465 b''
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 i18n import gettext as _
9 from i18n import gettext as _
10 from demandload import demandload
10 from demandload import demandload
11 demandload(globals(), "ancestor bdiff repo revlog util")
11 demandload(globals(), "ancestor bdiff repo revlog util")
12
12
13 class changectx(object):
13 class changectx(object):
14 """A changecontext object makes access to data related to a particular
14 """A changecontext object makes access to data related to a particular
15 changeset convenient."""
15 changeset convenient."""
16 def __init__(self, repo, changeid=None):
16 def __init__(self, repo, changeid=None):
17 """changeid is a revision number, node, or tag"""
17 """changeid is a revision number, node, or tag"""
18 self._repo = repo
18 self._repo = repo
19
19
20 if not changeid and changeid != 0:
20 if not changeid and changeid != 0:
21 p1, p2 = self._repo.dirstate.parents()
21 p1, p2 = self._repo.dirstate.parents()
22 self._rev = self._repo.changelog.rev(p1)
22 self._rev = self._repo.changelog.rev(p1)
23 if self._rev == -1:
23 if self._rev == -1:
24 changeid = 'tip'
24 changeid = 'tip'
25 else:
25 else:
26 self._node = p1
26 self._node = p1
27 return
27 return
28
28
29 self._node = self._repo.lookup(changeid)
29 self._node = self._repo.lookup(changeid)
30 self._rev = self._repo.changelog.rev(self._node)
30 self._rev = self._repo.changelog.rev(self._node)
31
31
32 def __str__(self):
32 def __str__(self):
33 return short(self.node())
33 return short(self.node())
34
34
35 def __repr__(self):
35 def __repr__(self):
36 return "<changectx %s>" % str(self)
36 return "<changectx %s>" % str(self)
37
37
38 def __eq__(self, other):
38 def __eq__(self, other):
39 return self._rev == other._rev
39 return self._rev == other._rev
40
40
41 def __nonzero__(self):
41 def __nonzero__(self):
42 return self._rev != -1
42 return self._rev != -1
43
43
44 def __getattr__(self, name):
44 def __getattr__(self, name):
45 if name == '_changeset':
45 if name == '_changeset':
46 self._changeset = self._repo.changelog.read(self.node())
46 self._changeset = self._repo.changelog.read(self.node())
47 return self._changeset
47 return self._changeset
48 elif name == '_manifest':
48 elif name == '_manifest':
49 self._manifest = self._repo.manifest.read(self._changeset[0])
49 self._manifest = self._repo.manifest.read(self._changeset[0])
50 return self._manifest
50 return self._manifest
51 else:
51 else:
52 raise AttributeError, name
52 raise AttributeError, name
53
53
54 def changeset(self): return self._changeset
54 def changeset(self): return self._changeset
55 def manifest(self): return self._manifest
55 def manifest(self): return self._manifest
56
56
57 def rev(self): return self._rev
57 def rev(self): return self._rev
58 def node(self): return self._node
58 def node(self): return self._node
59 def user(self): return self._changeset[1]
59 def user(self): return self._changeset[1]
60 def date(self): return self._changeset[2]
60 def date(self): return self._changeset[2]
61 def files(self): return self._changeset[3]
61 def files(self): return self._changeset[3]
62 def description(self): return self._changeset[4]
62 def description(self): return self._changeset[4]
63
63
64 def parents(self):
64 def parents(self):
65 """return contexts for each parent changeset"""
65 """return contexts for each parent changeset"""
66 p = self._repo.changelog.parents(self._node)
66 p = self._repo.changelog.parents(self._node)
67 return [ changectx(self._repo, x) for x in p ]
67 return [ changectx(self._repo, x) for x in p ]
68
68
69 def children(self):
69 def children(self):
70 """return contexts for each child changeset"""
70 """return contexts for each child changeset"""
71 c = self._repo.changelog.children(self._node)
71 c = self._repo.changelog.children(self._node)
72 return [ changectx(self._repo, x) for x in c ]
72 return [ changectx(self._repo, x) for x in c ]
73
73
74 def filenode(self, path):
74 def filenode(self, path):
75 if hasattr(self, "_manifest"):
75 if hasattr(self, "_manifest"):
76 return self._manifest[path]
76 try:
77 return self._manifest[path]
78 except KeyError:
79 raise repo.LookupError(_("'%s' not found in manifest") % path)
77 node, flag = self._repo.manifest.find(self._changeset[0], path)
80 node, flag = self._repo.manifest.find(self._changeset[0], path)
81 if not node:
82 raise repo.LookupError(_("'%s' not found in manifest") % path)
83
78 return node
84 return node
79
85
80 def filectx(self, path, fileid=None):
86 def filectx(self, path, fileid=None):
81 """get a file context from this changeset"""
87 """get a file context from this changeset"""
82 if fileid is None:
88 if fileid is None:
83 fileid = self.filenode(path)
89 fileid = self.filenode(path)
84 return filectx(self._repo, path, fileid=fileid, changectx=self)
90 return filectx(self._repo, path, fileid=fileid, changectx=self)
85
91
86 def filectxs(self):
92 def filectxs(self):
87 """generate a file context for each file in this changeset's
93 """generate a file context for each file in this changeset's
88 manifest"""
94 manifest"""
89 mf = self.manifest()
95 mf = self.manifest()
90 m = mf.keys()
96 m = mf.keys()
91 m.sort()
97 m.sort()
92 for f in m:
98 for f in m:
93 yield self.filectx(f, fileid=mf[f])
99 yield self.filectx(f, fileid=mf[f])
94
100
95 def ancestor(self, c2):
101 def ancestor(self, c2):
96 """
102 """
97 return the ancestor context of self and c2
103 return the ancestor context of self and c2
98 """
104 """
99 n = self._repo.changelog.ancestor(self._node, c2._node)
105 n = self._repo.changelog.ancestor(self._node, c2._node)
100 return changectx(self._repo, n)
106 return changectx(self._repo, n)
101
107
102 class filectx(object):
108 class filectx(object):
103 """A filecontext object makes access to data related to a particular
109 """A filecontext object makes access to data related to a particular
104 filerevision convenient."""
110 filerevision convenient."""
105 def __init__(self, repo, path, changeid=None, fileid=None,
111 def __init__(self, repo, path, changeid=None, fileid=None,
106 filelog=None, changectx=None):
112 filelog=None, changectx=None):
107 """changeid can be a changeset revision, node, or tag.
113 """changeid can be a changeset revision, node, or tag.
108 fileid can be a file revision or node."""
114 fileid can be a file revision or node."""
109 self._repo = repo
115 self._repo = repo
110 self._path = path
116 self._path = path
111
117
112 assert changeid is not None or fileid is not None
118 assert changeid is not None or fileid is not None
113
119
114 if filelog:
120 if filelog:
115 self._filelog = filelog
121 self._filelog = filelog
116 if changectx:
122 if changectx:
117 self._changectx = changectx
123 self._changectx = changectx
118 self._changeid = changectx.node()
124 self._changeid = changectx.node()
119
125
120 if fileid is None:
126 if fileid is None:
121 self._changeid = changeid
127 self._changeid = changeid
122 else:
128 else:
123 self._fileid = fileid
129 self._fileid = fileid
124
130
125 def __getattr__(self, name):
131 def __getattr__(self, name):
126 if name == '_changectx':
132 if name == '_changectx':
127 self._changectx = changectx(self._repo, self._changeid)
133 self._changectx = changectx(self._repo, self._changeid)
128 return self._changectx
134 return self._changectx
129 elif name == '_filelog':
135 elif name == '_filelog':
130 self._filelog = self._repo.file(self._path)
136 self._filelog = self._repo.file(self._path)
131 return self._filelog
137 return self._filelog
132 elif name == '_changeid':
138 elif name == '_changeid':
133 self._changeid = self._filelog.linkrev(self._filenode)
139 self._changeid = self._filelog.linkrev(self._filenode)
134 return self._changeid
140 return self._changeid
135 elif name == '_filenode':
141 elif name == '_filenode':
136 try:
142 try:
137 if hasattr(self, "_fileid"):
143 if hasattr(self, "_fileid"):
138 self._filenode = self._filelog.lookup(self._fileid)
144 self._filenode = self._filelog.lookup(self._fileid)
139 else:
145 else:
140 self._filenode = self._changectx.filenode(self._path)
146 self._filenode = self._changectx.filenode(self._path)
141 except revlog.RevlogError, inst:
147 except revlog.RevlogError, inst:
142 raise repo.LookupError(str(inst))
148 raise repo.LookupError(str(inst))
143 return self._filenode
149 return self._filenode
144 elif name == '_filerev':
150 elif name == '_filerev':
145 self._filerev = self._filelog.rev(self._filenode)
151 self._filerev = self._filelog.rev(self._filenode)
146 return self._filerev
152 return self._filerev
147 else:
153 else:
148 raise AttributeError, name
154 raise AttributeError, name
149
155
150 def __nonzero__(self):
156 def __nonzero__(self):
151 return self._filerev != nullid
157 return self._filerev != nullid
152
158
153 def __str__(self):
159 def __str__(self):
154 return "%s@%s" % (self.path(), short(self.node()))
160 return "%s@%s" % (self.path(), short(self.node()))
155
161
156 def __repr__(self):
162 def __repr__(self):
157 return "<filectx %s>" % str(self)
163 return "<filectx %s>" % str(self)
158
164
159 def __eq__(self, other):
165 def __eq__(self, other):
160 return self._path == other._path and self._changeid == other._changeid
166 return self._path == other._path and self._changeid == other._changeid
161
167
162 def filectx(self, fileid):
168 def filectx(self, fileid):
163 '''opens an arbitrary revision of the file without
169 '''opens an arbitrary revision of the file without
164 opening a new filelog'''
170 opening a new filelog'''
165 return filectx(self._repo, self._path, fileid=fileid,
171 return filectx(self._repo, self._path, fileid=fileid,
166 filelog=self._filelog)
172 filelog=self._filelog)
167
173
168 def filerev(self): return self._filerev
174 def filerev(self): return self._filerev
169 def filenode(self): return self._filenode
175 def filenode(self): return self._filenode
170 def filelog(self): return self._filelog
176 def filelog(self): return self._filelog
171
177
172 def rev(self):
178 def rev(self):
173 if hasattr(self, "_changectx"):
179 if hasattr(self, "_changectx"):
174 return self._changectx.rev()
180 return self._changectx.rev()
175 return self._filelog.linkrev(self._filenode)
181 return self._filelog.linkrev(self._filenode)
176
182
177 def node(self): return self._changectx.node()
183 def node(self): return self._changectx.node()
178 def user(self): return self._changectx.user()
184 def user(self): return self._changectx.user()
179 def date(self): return self._changectx.date()
185 def date(self): return self._changectx.date()
180 def files(self): return self._changectx.files()
186 def files(self): return self._changectx.files()
181 def description(self): return self._changectx.description()
187 def description(self): return self._changectx.description()
182 def manifest(self): return self._changectx.manifest()
188 def manifest(self): return self._changectx.manifest()
183 def changectx(self): return self._changectx
189 def changectx(self): return self._changectx
184
190
185 def data(self): return self._filelog.read(self._filenode)
191 def data(self): return self._filelog.read(self._filenode)
186 def renamed(self): return self._filelog.renamed(self._filenode)
192 def renamed(self): return self._filelog.renamed(self._filenode)
187 def path(self): return self._path
193 def path(self): return self._path
188
194
189 def parents(self):
195 def parents(self):
190 p = self._path
196 p = self._path
191 fl = self._filelog
197 fl = self._filelog
192 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
198 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
193
199
194 r = self.renamed()
200 r = self.renamed()
195 if r:
201 if r:
196 pl[0] = (r[0], r[1], None)
202 pl[0] = (r[0], r[1], None)
197
203
198 return [ filectx(self._repo, p, fileid=n, filelog=l)
204 return [ filectx(self._repo, p, fileid=n, filelog=l)
199 for p,n,l in pl if n != nullid ]
205 for p,n,l in pl if n != nullid ]
200
206
201 def children(self):
207 def children(self):
202 # hard for renames
208 # hard for renames
203 c = self._filelog.children(self._filenode)
209 c = self._filelog.children(self._filenode)
204 return [ filectx(self._repo, self._path, fileid=x,
210 return [ filectx(self._repo, self._path, fileid=x,
205 filelog=self._filelog) for x in c ]
211 filelog=self._filelog) for x in c ]
206
212
207 def annotate(self, follow=False):
213 def annotate(self, follow=False):
208 '''returns a list of tuples of (ctx, line) for each line
214 '''returns a list of tuples of (ctx, line) for each line
209 in the file, where ctx is the filectx of the node where
215 in the file, where ctx is the filectx of the node where
210 that line was last changed'''
216 that line was last changed'''
211
217
212 def decorate(text, rev):
218 def decorate(text, rev):
213 return ([rev] * len(text.splitlines()), text)
219 return ([rev] * len(text.splitlines()), text)
214
220
215 def pair(parent, child):
221 def pair(parent, child):
216 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
222 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
217 child[0][b1:b2] = parent[0][a1:a2]
223 child[0][b1:b2] = parent[0][a1:a2]
218 return child
224 return child
219
225
220 getlog = util.cachefunc(lambda x: self._repo.file(x))
226 getlog = util.cachefunc(lambda x: self._repo.file(x))
221 def getctx(path, fileid):
227 def getctx(path, fileid):
222 log = path == self._path and self._filelog or getlog(path)
228 log = path == self._path and self._filelog or getlog(path)
223 return filectx(self._repo, path, fileid=fileid, filelog=log)
229 return filectx(self._repo, path, fileid=fileid, filelog=log)
224 getctx = util.cachefunc(getctx)
230 getctx = util.cachefunc(getctx)
225
231
226 def parents(f):
232 def parents(f):
227 # we want to reuse filectx objects as much as possible
233 # we want to reuse filectx objects as much as possible
228 p = f._path
234 p = f._path
229 if f._filerev is None: # working dir
235 if f._filerev is None: # working dir
230 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
236 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
231 else:
237 else:
232 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
238 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
233
239
234 if follow:
240 if follow:
235 r = f.renamed()
241 r = f.renamed()
236 if r:
242 if r:
237 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
243 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
238
244
239 return [ getctx(p, n) for p, n in pl if n != -1 ]
245 return [ getctx(p, n) for p, n in pl if n != -1 ]
240
246
241 # find all ancestors
247 # find all ancestors
242 needed = {self: 1}
248 needed = {self: 1}
243 visit = [self]
249 visit = [self]
244 files = [self._path]
250 files = [self._path]
245 while visit:
251 while visit:
246 f = visit.pop(0)
252 f = visit.pop(0)
247 for p in parents(f):
253 for p in parents(f):
248 if p not in needed:
254 if p not in needed:
249 needed[p] = 1
255 needed[p] = 1
250 visit.append(p)
256 visit.append(p)
251 if p._path not in files:
257 if p._path not in files:
252 files.append(p._path)
258 files.append(p._path)
253 else:
259 else:
254 # count how many times we'll use this
260 # count how many times we'll use this
255 needed[p] += 1
261 needed[p] += 1
256
262
257 # sort by revision (per file) which is a topological order
263 # sort by revision (per file) which is a topological order
258 visit = []
264 visit = []
259 files.reverse()
265 files.reverse()
260 for f in files:
266 for f in files:
261 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
267 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
262 fn.sort()
268 fn.sort()
263 visit.extend(fn)
269 visit.extend(fn)
264 hist = {}
270 hist = {}
265
271
266 for r, f in visit:
272 for r, f in visit:
267 curr = decorate(f.data(), f)
273 curr = decorate(f.data(), f)
268 for p in parents(f):
274 for p in parents(f):
269 if p != nullid:
275 if p != nullid:
270 curr = pair(hist[p], curr)
276 curr = pair(hist[p], curr)
271 # trim the history of unneeded revs
277 # trim the history of unneeded revs
272 needed[p] -= 1
278 needed[p] -= 1
273 if not needed[p]:
279 if not needed[p]:
274 del hist[p]
280 del hist[p]
275 hist[f] = curr
281 hist[f] = curr
276
282
277 return zip(hist[f][0], hist[f][1].splitlines(1))
283 return zip(hist[f][0], hist[f][1].splitlines(1))
278
284
279 def ancestor(self, fc2):
285 def ancestor(self, fc2):
280 """
286 """
281 find the common ancestor file context, if any, of self, and fc2
287 find the common ancestor file context, if any, of self, and fc2
282 """
288 """
283
289
284 acache = {}
290 acache = {}
285
291
286 # prime the ancestor cache for the working directory
292 # prime the ancestor cache for the working directory
287 for c in (self, fc2):
293 for c in (self, fc2):
288 if c._filerev == None:
294 if c._filerev == None:
289 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
295 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
290 acache[(c._path, None)] = pl
296 acache[(c._path, None)] = pl
291
297
292 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
298 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
293 def parents(vertex):
299 def parents(vertex):
294 if vertex in acache:
300 if vertex in acache:
295 return acache[vertex]
301 return acache[vertex]
296 f, n = vertex
302 f, n = vertex
297 if f not in flcache:
303 if f not in flcache:
298 flcache[f] = self._repo.file(f)
304 flcache[f] = self._repo.file(f)
299 fl = flcache[f]
305 fl = flcache[f]
300 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
306 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
301 re = fl.renamed(n)
307 re = fl.renamed(n)
302 if re:
308 if re:
303 pl.append(re)
309 pl.append(re)
304 acache[vertex]=pl
310 acache[vertex]=pl
305 return pl
311 return pl
306
312
307 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
313 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
308 v = ancestor.ancestor(a, b, parents)
314 v = ancestor.ancestor(a, b, parents)
309 if v:
315 if v:
310 f,n = v
316 f,n = v
311 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
317 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
312
318
313 return None
319 return None
314
320
315 class workingctx(changectx):
321 class workingctx(changectx):
316 """A workingctx object makes access to data related to
322 """A workingctx object makes access to data related to
317 the current working directory convenient."""
323 the current working directory convenient."""
318 def __init__(self, repo):
324 def __init__(self, repo):
319 self._repo = repo
325 self._repo = repo
320 self._rev = None
326 self._rev = None
321 self._node = None
327 self._node = None
322
328
323 def __str__(self):
329 def __str__(self):
324 return "."
330 return "."
325
331
326 def __nonzero__(self):
332 def __nonzero__(self):
327 return True
333 return True
328
334
329 def __getattr__(self, name):
335 def __getattr__(self, name):
330 if name == '_parents':
336 if name == '_parents':
331 self._parents = self._repo.parents()
337 self._parents = self._repo.parents()
332 return self._parents
338 return self._parents
333 if name == '_status':
339 if name == '_status':
334 self._status = self._repo.status()
340 self._status = self._repo.status()
335 return self._status
341 return self._status
336 if name == '_manifest':
342 if name == '_manifest':
337 self._buildmanifest()
343 self._buildmanifest()
338 return self._manifest
344 return self._manifest
339 else:
345 else:
340 raise AttributeError, name
346 raise AttributeError, name
341
347
342 def _buildmanifest(self):
348 def _buildmanifest(self):
343 """generate a manifest corresponding to the working directory"""
349 """generate a manifest corresponding to the working directory"""
344
350
345 man = self._parents[0].manifest().copy()
351 man = self._parents[0].manifest().copy()
346 copied = self._repo.dirstate.copies()
352 copied = self._repo.dirstate.copies()
347 modified, added, removed, deleted, unknown = self._status[:5]
353 modified, added, removed, deleted, unknown = self._status[:5]
348 for i,l in (("a", added), ("m", modified), ("u", unknown)):
354 for i,l in (("a", added), ("m", modified), ("u", unknown)):
349 for f in l:
355 for f in l:
350 man[f] = man.get(copied.get(f, f), nullid) + i
356 man[f] = man.get(copied.get(f, f), nullid) + i
351 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
357 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
352
358
353 for f in deleted + removed:
359 for f in deleted + removed:
354 del man[f]
360 del man[f]
355
361
356 self._manifest = man
362 self._manifest = man
357
363
358 def manifest(self): return self._manifest
364 def manifest(self): return self._manifest
359
365
360 def user(self): return self._repo.ui.username()
366 def user(self): return self._repo.ui.username()
361 def date(self): return util.makedate()
367 def date(self): return util.makedate()
362 def description(self): return ""
368 def description(self): return ""
363 def files(self):
369 def files(self):
364 f = self.modified() + self.added() + self.removed()
370 f = self.modified() + self.added() + self.removed()
365 f.sort()
371 f.sort()
366 return f
372 return f
367
373
368 def modified(self): return self._status[0]
374 def modified(self): return self._status[0]
369 def added(self): return self._status[1]
375 def added(self): return self._status[1]
370 def removed(self): return self._status[2]
376 def removed(self): return self._status[2]
371 def deleted(self): return self._status[3]
377 def deleted(self): return self._status[3]
372 def unknown(self): return self._status[4]
378 def unknown(self): return self._status[4]
373 def clean(self): return self._status[5]
379 def clean(self): return self._status[5]
374
380
375 def parents(self):
381 def parents(self):
376 """return contexts for each parent changeset"""
382 """return contexts for each parent changeset"""
377 return self._parents
383 return self._parents
378
384
379 def children(self):
385 def children(self):
380 return []
386 return []
381
387
382 def filectx(self, path):
388 def filectx(self, path):
383 """get a file context from the working directory"""
389 """get a file context from the working directory"""
384 return workingfilectx(self._repo, path, workingctx=self)
390 return workingfilectx(self._repo, path, workingctx=self)
385
391
386 def ancestor(self, c2):
392 def ancestor(self, c2):
387 """return the ancestor context of self and c2"""
393 """return the ancestor context of self and c2"""
388 return self._parents[0].ancestor(c2) # punt on two parents for now
394 return self._parents[0].ancestor(c2) # punt on two parents for now
389
395
390 class workingfilectx(filectx):
396 class workingfilectx(filectx):
391 """A workingfilectx object makes access to data related to a particular
397 """A workingfilectx object makes access to data related to a particular
392 file in the working directory convenient."""
398 file in the working directory convenient."""
393 def __init__(self, repo, path, filelog=None, workingctx=None):
399 def __init__(self, repo, path, filelog=None, workingctx=None):
394 """changeid can be a changeset revision, node, or tag.
400 """changeid can be a changeset revision, node, or tag.
395 fileid can be a file revision or node."""
401 fileid can be a file revision or node."""
396 self._repo = repo
402 self._repo = repo
397 self._path = path
403 self._path = path
398 self._changeid = None
404 self._changeid = None
399 self._filerev = self._filenode = None
405 self._filerev = self._filenode = None
400
406
401 if filelog:
407 if filelog:
402 self._filelog = filelog
408 self._filelog = filelog
403 if workingctx:
409 if workingctx:
404 self._changectx = workingctx
410 self._changectx = workingctx
405
411
406 def __getattr__(self, name):
412 def __getattr__(self, name):
407 if name == '_changectx':
413 if name == '_changectx':
408 self._changectx = workingctx(repo)
414 self._changectx = workingctx(repo)
409 return self._changectx
415 return self._changectx
410 elif name == '_repopath':
416 elif name == '_repopath':
411 self._repopath = self._repo.dirstate.copied(p) or self._path
417 self._repopath = self._repo.dirstate.copied(p) or self._path
412 elif name == '_filelog':
418 elif name == '_filelog':
413 self._filelog = self._repo.file(self._repopath)
419 self._filelog = self._repo.file(self._repopath)
414 return self._filelog
420 return self._filelog
415 else:
421 else:
416 raise AttributeError, name
422 raise AttributeError, name
417
423
418 def __nonzero__(self):
424 def __nonzero__(self):
419 return True
425 return True
420
426
421 def __str__(self):
427 def __str__(self):
422 return "%s@." % self.path()
428 return "%s@." % self.path()
423
429
424 def filectx(self, fileid):
430 def filectx(self, fileid):
425 '''opens an arbitrary revision of the file without
431 '''opens an arbitrary revision of the file without
426 opening a new filelog'''
432 opening a new filelog'''
427 return filectx(self._repo, self._repopath, fileid=fileid,
433 return filectx(self._repo, self._repopath, fileid=fileid,
428 filelog=self._filelog)
434 filelog=self._filelog)
429
435
430 def rev(self):
436 def rev(self):
431 if hasattr(self, "_changectx"):
437 if hasattr(self, "_changectx"):
432 return self._changectx.rev()
438 return self._changectx.rev()
433 return self._filelog.linkrev(self._filenode)
439 return self._filelog.linkrev(self._filenode)
434
440
435 def data(self): return self._repo.wread(self._path)
441 def data(self): return self._repo.wread(self._path)
436 def renamed(self):
442 def renamed(self):
437 rp = self._repopath
443 rp = self._repopath
438 if rp == self._path:
444 if rp == self._path:
439 return None
445 return None
440 return rp, self._workingctx._parents._manifest.get(rp, nullid)
446 return rp, self._workingctx._parents._manifest.get(rp, nullid)
441
447
442 def parents(self):
448 def parents(self):
443 '''return parent filectxs, following copies if necessary'''
449 '''return parent filectxs, following copies if necessary'''
444 p = self._path
450 p = self._path
445 rp = self._repopath
451 rp = self._repopath
446 pcl = self._workingctx._parents
452 pcl = self._workingctx._parents
447 fl = self._filelog
453 fl = self._filelog
448 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
454 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
449 if len(pcl) > 1:
455 if len(pcl) > 1:
450 if rp != p:
456 if rp != p:
451 fl = None
457 fl = None
452 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
458 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
453
459
454 return [ filectx(self._repo, p, fileid=n, filelog=l)
460 return [ filectx(self._repo, p, fileid=n, filelog=l)
455 for p,n,l in pl if n != nullid ]
461 for p,n,l in pl if n != nullid ]
456
462
457 def children(self):
463 def children(self):
458 return []
464 return []
459
465
General Comments 0
You need to be logged in to leave comments. Login now