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