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