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