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