##// END OF EJS Templates
context: change workingctx str() from . to <node>+
Matt Mackall -
r3313:6c68bc1e default
parent child Browse files
Show More
@@ -1,473 +1,473 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 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 def size(self): return self._filelog.size(self._filerev)
194 def size(self): return self._filelog.size(self._filerev)
195
195
196 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
196 def cmp(self, text): return self._filelog.cmp(self._filenode, text)
197
197
198 def parents(self):
198 def parents(self):
199 p = self._path
199 p = self._path
200 fl = self._filelog
200 fl = self._filelog
201 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
201 pl = [ (p, n, fl) for n in self._filelog.parents(self._filenode) ]
202
202
203 r = self.renamed()
203 r = self.renamed()
204 if r:
204 if r:
205 pl[0] = (r[0], r[1], None)
205 pl[0] = (r[0], r[1], None)
206
206
207 return [ filectx(self._repo, p, fileid=n, filelog=l)
207 return [ filectx(self._repo, p, fileid=n, filelog=l)
208 for p,n,l in pl if n != nullid ]
208 for p,n,l in pl if n != nullid ]
209
209
210 def children(self):
210 def children(self):
211 # hard for renames
211 # hard for renames
212 c = self._filelog.children(self._filenode)
212 c = self._filelog.children(self._filenode)
213 return [ filectx(self._repo, self._path, fileid=x,
213 return [ filectx(self._repo, self._path, fileid=x,
214 filelog=self._filelog) for x in c ]
214 filelog=self._filelog) for x in c ]
215
215
216 def annotate(self, follow=False):
216 def annotate(self, follow=False):
217 '''returns a list of tuples of (ctx, line) for each line
217 '''returns a list of tuples of (ctx, line) for each line
218 in the file, where ctx is the filectx of the node where
218 in the file, where ctx is the filectx of the node where
219 that line was last changed'''
219 that line was last changed'''
220
220
221 def decorate(text, rev):
221 def decorate(text, rev):
222 return ([rev] * len(text.splitlines()), text)
222 return ([rev] * len(text.splitlines()), text)
223
223
224 def pair(parent, child):
224 def pair(parent, child):
225 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
225 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
226 child[0][b1:b2] = parent[0][a1:a2]
226 child[0][b1:b2] = parent[0][a1:a2]
227 return child
227 return child
228
228
229 getlog = util.cachefunc(lambda x: self._repo.file(x))
229 getlog = util.cachefunc(lambda x: self._repo.file(x))
230 def getctx(path, fileid):
230 def getctx(path, fileid):
231 log = path == self._path and self._filelog or getlog(path)
231 log = path == self._path and self._filelog or getlog(path)
232 return filectx(self._repo, path, fileid=fileid, filelog=log)
232 return filectx(self._repo, path, fileid=fileid, filelog=log)
233 getctx = util.cachefunc(getctx)
233 getctx = util.cachefunc(getctx)
234
234
235 def parents(f):
235 def parents(f):
236 # we want to reuse filectx objects as much as possible
236 # we want to reuse filectx objects as much as possible
237 p = f._path
237 p = f._path
238 if f._filerev is None: # working dir
238 if f._filerev is None: # working dir
239 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
239 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
240 else:
240 else:
241 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
241 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
242
242
243 if follow:
243 if follow:
244 r = f.renamed()
244 r = f.renamed()
245 if r:
245 if r:
246 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
246 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
247
247
248 return [ getctx(p, n) for p, n in pl if n != -1 ]
248 return [ getctx(p, n) for p, n in pl if n != -1 ]
249
249
250 # find all ancestors
250 # find all ancestors
251 needed = {self: 1}
251 needed = {self: 1}
252 visit = [self]
252 visit = [self]
253 files = [self._path]
253 files = [self._path]
254 while visit:
254 while visit:
255 f = visit.pop(0)
255 f = visit.pop(0)
256 for p in parents(f):
256 for p in parents(f):
257 if p not in needed:
257 if p not in needed:
258 needed[p] = 1
258 needed[p] = 1
259 visit.append(p)
259 visit.append(p)
260 if p._path not in files:
260 if p._path not in files:
261 files.append(p._path)
261 files.append(p._path)
262 else:
262 else:
263 # count how many times we'll use this
263 # count how many times we'll use this
264 needed[p] += 1
264 needed[p] += 1
265
265
266 # sort by revision (per file) which is a topological order
266 # sort by revision (per file) which is a topological order
267 visit = []
267 visit = []
268 files.reverse()
268 files.reverse()
269 for f in files:
269 for f in files:
270 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
270 fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
271 fn.sort()
271 fn.sort()
272 visit.extend(fn)
272 visit.extend(fn)
273 hist = {}
273 hist = {}
274
274
275 for r, f in visit:
275 for r, f in visit:
276 curr = decorate(f.data(), f)
276 curr = decorate(f.data(), f)
277 for p in parents(f):
277 for p in parents(f):
278 if p != nullid:
278 if p != nullid:
279 curr = pair(hist[p], curr)
279 curr = pair(hist[p], curr)
280 # trim the history of unneeded revs
280 # trim the history of unneeded revs
281 needed[p] -= 1
281 needed[p] -= 1
282 if not needed[p]:
282 if not needed[p]:
283 del hist[p]
283 del hist[p]
284 hist[f] = curr
284 hist[f] = curr
285
285
286 return zip(hist[f][0], hist[f][1].splitlines(1))
286 return zip(hist[f][0], hist[f][1].splitlines(1))
287
287
288 def ancestor(self, fc2):
288 def ancestor(self, fc2):
289 """
289 """
290 find the common ancestor file context, if any, of self, and fc2
290 find the common ancestor file context, if any, of self, and fc2
291 """
291 """
292
292
293 acache = {}
293 acache = {}
294
294
295 # prime the ancestor cache for the working directory
295 # prime the ancestor cache for the working directory
296 for c in (self, fc2):
296 for c in (self, fc2):
297 if c._filerev == None:
297 if c._filerev == None:
298 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
298 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
299 acache[(c._path, None)] = pl
299 acache[(c._path, None)] = pl
300
300
301 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
301 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
302 def parents(vertex):
302 def parents(vertex):
303 if vertex in acache:
303 if vertex in acache:
304 return acache[vertex]
304 return acache[vertex]
305 f, n = vertex
305 f, n = vertex
306 if f not in flcache:
306 if f not in flcache:
307 flcache[f] = self._repo.file(f)
307 flcache[f] = self._repo.file(f)
308 fl = flcache[f]
308 fl = flcache[f]
309 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
309 pl = [ (f,p) for p in fl.parents(n) if p != nullid ]
310 re = fl.renamed(n)
310 re = fl.renamed(n)
311 if re:
311 if re:
312 pl.append(re)
312 pl.append(re)
313 acache[vertex]=pl
313 acache[vertex]=pl
314 return pl
314 return pl
315
315
316 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
316 a, b = (self._path, self._filenode), (fc2._path, fc2._filenode)
317 v = ancestor.ancestor(a, b, parents)
317 v = ancestor.ancestor(a, b, parents)
318 if v:
318 if v:
319 f,n = v
319 f,n = v
320 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
320 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
321
321
322 return None
322 return None
323
323
324 class workingctx(changectx):
324 class workingctx(changectx):
325 """A workingctx object makes access to data related to
325 """A workingctx object makes access to data related to
326 the current working directory convenient."""
326 the current working directory convenient."""
327 def __init__(self, repo):
327 def __init__(self, repo):
328 self._repo = repo
328 self._repo = repo
329 self._rev = None
329 self._rev = None
330 self._node = None
330 self._node = None
331
331
332 def __str__(self):
332 def __str__(self):
333 return "."
333 return str(self._parents[0]) + "+"
334
334
335 def __nonzero__(self):
335 def __nonzero__(self):
336 return True
336 return True
337
337
338 def __getattr__(self, name):
338 def __getattr__(self, name):
339 if name == '_parents':
339 if name == '_parents':
340 self._parents = self._repo.parents()
340 self._parents = self._repo.parents()
341 return self._parents
341 return self._parents
342 if name == '_status':
342 if name == '_status':
343 self._status = self._repo.status()
343 self._status = self._repo.status()
344 return self._status
344 return self._status
345 if name == '_manifest':
345 if name == '_manifest':
346 self._buildmanifest()
346 self._buildmanifest()
347 return self._manifest
347 return self._manifest
348 else:
348 else:
349 raise AttributeError, name
349 raise AttributeError, name
350
350
351 def _buildmanifest(self):
351 def _buildmanifest(self):
352 """generate a manifest corresponding to the working directory"""
352 """generate a manifest corresponding to the working directory"""
353
353
354 man = self._parents[0].manifest().copy()
354 man = self._parents[0].manifest().copy()
355 copied = self._repo.dirstate.copies()
355 copied = self._repo.dirstate.copies()
356 modified, added, removed, deleted, unknown = self._status[:5]
356 modified, added, removed, deleted, unknown = self._status[:5]
357 for i,l in (("a", added), ("m", modified), ("u", unknown)):
357 for i,l in (("a", added), ("m", modified), ("u", unknown)):
358 for f in l:
358 for f in l:
359 man[f] = man.get(copied.get(f, f), nullid) + i
359 man[f] = man.get(copied.get(f, f), nullid) + i
360 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
360 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
361
361
362 for f in deleted + removed:
362 for f in deleted + removed:
363 del man[f]
363 del man[f]
364
364
365 self._manifest = man
365 self._manifest = man
366
366
367 def manifest(self): return self._manifest
367 def manifest(self): return self._manifest
368
368
369 def user(self): return self._repo.ui.username()
369 def user(self): return self._repo.ui.username()
370 def date(self): return util.makedate()
370 def date(self): return util.makedate()
371 def description(self): return ""
371 def description(self): return ""
372 def files(self):
372 def files(self):
373 f = self.modified() + self.added() + self.removed()
373 f = self.modified() + self.added() + self.removed()
374 f.sort()
374 f.sort()
375 return f
375 return f
376
376
377 def modified(self): return self._status[0]
377 def modified(self): return self._status[0]
378 def added(self): return self._status[1]
378 def added(self): return self._status[1]
379 def removed(self): return self._status[2]
379 def removed(self): return self._status[2]
380 def deleted(self): return self._status[3]
380 def deleted(self): return self._status[3]
381 def unknown(self): return self._status[4]
381 def unknown(self): return self._status[4]
382 def clean(self): return self._status[5]
382 def clean(self): return self._status[5]
383
383
384 def parents(self):
384 def parents(self):
385 """return contexts for each parent changeset"""
385 """return contexts for each parent changeset"""
386 return self._parents
386 return self._parents
387
387
388 def children(self):
388 def children(self):
389 return []
389 return []
390
390
391 def filectx(self, path):
391 def filectx(self, path):
392 """get a file context from the working directory"""
392 """get a file context from the working directory"""
393 return workingfilectx(self._repo, path, workingctx=self)
393 return workingfilectx(self._repo, path, workingctx=self)
394
394
395 def ancestor(self, c2):
395 def ancestor(self, c2):
396 """return the ancestor context of self and c2"""
396 """return the ancestor context of self and c2"""
397 return self._parents[0].ancestor(c2) # punt on two parents for now
397 return self._parents[0].ancestor(c2) # punt on two parents for now
398
398
399 class workingfilectx(filectx):
399 class workingfilectx(filectx):
400 """A workingfilectx object makes access to data related to a particular
400 """A workingfilectx object makes access to data related to a particular
401 file in the working directory convenient."""
401 file in the working directory convenient."""
402 def __init__(self, repo, path, filelog=None, workingctx=None):
402 def __init__(self, repo, path, filelog=None, workingctx=None):
403 """changeid can be a changeset revision, node, or tag.
403 """changeid can be a changeset revision, node, or tag.
404 fileid can be a file revision or node."""
404 fileid can be a file revision or node."""
405 self._repo = repo
405 self._repo = repo
406 self._path = path
406 self._path = path
407 self._changeid = None
407 self._changeid = None
408 self._filerev = self._filenode = None
408 self._filerev = self._filenode = None
409
409
410 if filelog:
410 if filelog:
411 self._filelog = filelog
411 self._filelog = filelog
412 if workingctx:
412 if workingctx:
413 self._changectx = workingctx
413 self._changectx = workingctx
414
414
415 def __getattr__(self, name):
415 def __getattr__(self, name):
416 if name == '_changectx':
416 if name == '_changectx':
417 self._changectx = workingctx(repo)
417 self._changectx = workingctx(repo)
418 return self._changectx
418 return self._changectx
419 elif name == '_repopath':
419 elif name == '_repopath':
420 self._repopath = (self._repo.dirstate.copied(self._path)
420 self._repopath = (self._repo.dirstate.copied(self._path)
421 or self._path)
421 or self._path)
422 return self._repopath
422 return self._repopath
423 elif name == '_filelog':
423 elif name == '_filelog':
424 self._filelog = self._repo.file(self._repopath)
424 self._filelog = self._repo.file(self._repopath)
425 return self._filelog
425 return self._filelog
426 else:
426 else:
427 raise AttributeError, name
427 raise AttributeError, name
428
428
429 def __nonzero__(self):
429 def __nonzero__(self):
430 return True
430 return True
431
431
432 def __str__(self):
432 def __str__(self):
433 return "%s@." % self.path()
433 return "%s@%s" % (self.path(), self._changectx)
434
434
435 def filectx(self, fileid):
435 def filectx(self, fileid):
436 '''opens an arbitrary revision of the file without
436 '''opens an arbitrary revision of the file without
437 opening a new filelog'''
437 opening a new filelog'''
438 return filectx(self._repo, self._repopath, fileid=fileid,
438 return filectx(self._repo, self._repopath, fileid=fileid,
439 filelog=self._filelog)
439 filelog=self._filelog)
440
440
441 def rev(self):
441 def rev(self):
442 if hasattr(self, "_changectx"):
442 if hasattr(self, "_changectx"):
443 return self._changectx.rev()
443 return self._changectx.rev()
444 return self._filelog.linkrev(self._filenode)
444 return self._filelog.linkrev(self._filenode)
445
445
446 def data(self): return self._repo.wread(self._path)
446 def data(self): return self._repo.wread(self._path)
447 def renamed(self):
447 def renamed(self):
448 rp = self._repopath
448 rp = self._repopath
449 if rp == self._path:
449 if rp == self._path:
450 return None
450 return None
451 return rp, self._workingctx._parents._manifest.get(rp, nullid)
451 return rp, self._workingctx._parents._manifest.get(rp, nullid)
452
452
453 def parents(self):
453 def parents(self):
454 '''return parent filectxs, following copies if necessary'''
454 '''return parent filectxs, following copies if necessary'''
455 p = self._path
455 p = self._path
456 rp = self._repopath
456 rp = self._repopath
457 pcl = self._changectx._parents
457 pcl = self._changectx._parents
458 fl = self._filelog
458 fl = self._filelog
459 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
459 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
460 if len(pcl) > 1:
460 if len(pcl) > 1:
461 if rp != p:
461 if rp != p:
462 fl = None
462 fl = None
463 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
463 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
464
464
465 return [ filectx(self._repo, p, fileid=n, filelog=l)
465 return [ filectx(self._repo, p, fileid=n, filelog=l)
466 for p,n,l in pl if n != nullid ]
466 for p,n,l in pl if n != nullid ]
467
467
468 def children(self):
468 def children(self):
469 return []
469 return []
470
470
471 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
471 def size(self): return os.stat(self._repo.wjoin(self._path)).st_size
472
472
473 def cmp(self, text): return self._repo.wread(self._path) == text
473 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