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