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