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