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