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