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