comparison mercurial/context.py @ 3239:6d98149d70fe

contexts: add working dir and working file contexts add workingctx add workingfilectx extend filectx.annotate for rev=None extend filectx.ancestor
author Matt Mackall <mpm@selenic.com>
date Mon, 02 Oct 2006 22:03:14 -0500
parents d865390c1781
children 8d4855fd9d7b
comparison
equal deleted inserted replaced
3238:d865390c1781 3239:6d98149d70fe
224 getctx = util.cachefunc(getctx) 224 getctx = util.cachefunc(getctx)
225 225
226 def parents(f): 226 def parents(f):
227 # we want to reuse filectx objects as much as possible 227 # we want to reuse filectx objects as much as possible
228 p = f._path 228 p = f._path
229 pl = [ (p, f._filelog.rev(n)) for n in f._filelog.parents(f._filenode) ] 229 if f._filerev is None: # working dir
230 pl = [ (n.path(), n.filerev()) for n in f.parents() ]
231 else:
232 pl = [ (p, n) for n in f._filelog.parentrevs(f._filerev) ]
230 233
231 if follow: 234 if follow:
232 r = f.renamed() 235 r = f.renamed()
233 if r: 236 if r:
234 pl[0] = (r[0], getlog(r[0]).rev(r[1])) 237 pl[0] = (r[0], getlog(r[0]).rev(r[1]))
235 238
236 return [ getctx(p, n) for p, n in pl if n != -1 ] 239 return [ getctx(p, n) for p, n in pl if n != -1 ]
237 240
238 # find all ancestors 241 # find all ancestors
239 needed = {self: 1} 242 needed = {self: 1}
240 visit = [self] 243 visit = [self]
241 files = [self._path] 244 files = [self._path]
242 while visit: 245 while visit:
277 """ 280 """
278 find the common ancestor file context, if any, of self, and fc2 281 find the common ancestor file context, if any, of self, and fc2
279 """ 282 """
280 283
281 acache = {} 284 acache = {}
285
286 # prime the ancestor cache for the working directory
287 for c in (self, fc2):
288 if c._filerev == None:
289 pl = [ (n.path(), n.filenode()) for n in c.parents() ]
290 acache[(c._path, None)] = pl
291
282 flcache = {self._path:self._filelog, fc2._path:fc2._filelog} 292 flcache = {self._path:self._filelog, fc2._path:fc2._filelog}
283 def parents(vertex): 293 def parents(vertex):
284 if vertex in acache: 294 if vertex in acache:
285 return acache[vertex] 295 return acache[vertex]
286 f, n = vertex 296 f, n = vertex
299 if v: 309 if v:
300 f,n = v 310 f,n = v
301 return filectx(self._repo, f, fileid=n, filelog=flcache[f]) 311 return filectx(self._repo, f, fileid=n, filelog=flcache[f])
302 312
303 return None 313 return None
314
315 class workingctx(changectx):
316 """A workingctx object makes access to data related to
317 the current working directory convenient."""
318 def __init__(self, repo):
319 self._repo = repo
320 self._rev = None
321 self._node = None
322
323 def __str__(self):
324 return "."
325
326 def __nonzero__(self):
327 return True
328
329 def __getattr__(self, name):
330 if name == '_parents':
331 self._parents = self._repo.parents()
332 return self._parents
333 if name == '_status':
334 self._status = self._repo.status()
335 return self._status
336 if name == '_manifest':
337 self._buildmanifest()
338 return self._manifest
339 else:
340 raise AttributeError, name
341
342 def _buildmanifest(self):
343 """generate a manifest corresponding to the working directory"""
344
345 man = self._parents[0].manifest().coy()
346 copied = self._repo.dirstate.copies()
347 modified, added, removed, deleted, unknown = self._status[:5]
348 for i,l in (("a", added), ("m", modified), ("u", unknown)):
349 for f in l:
350 man[f] = man.get(copied.get(f, f), nullid) + i
351 man.set(f, util.is_exec(self._repo.wjoin(f), man.execf(f)))
352
353 for f in deleted + removed:
354 del man[f]
355
356 self._manifest = man
357
358 def manifest(self): return self._manifest
359
360 def user(self): return self._repo.ui.username()
361 def date(self): return util.makedate()
362 def description(self): return ""
363 def files(self):
364 f = self.modified() + self.added() + self.removed()
365 f.sort()
366 return f
367
368 def modified(self): return self._status[0]
369 def added(self): return self._status[1]
370 def removed(self): return self._status[2]
371 def deleted(self): return self._status[3]
372 def unknown(self): return self._status[4]
373 def clean(self): return self._status[5]
374
375 def parents(self):
376 """return contexts for each parent changeset"""
377 return self._parents
378
379 def children(self):
380 return []
381
382 def filectx(self, path):
383 """get a file context from the working directory"""
384 return workingfilectx(self._repo, path, workingctx=self)
385
386 def ancestor(self, c2):
387 """return the ancestor context of self and c2"""
388 return self._parents[0].ancestor(c2) # punt on two parents for now
389
390 class workingfilectx(filectx):
391 """A workingfilectx object makes access to data related to a particular
392 file in the working directory convenient."""
393 def __init__(self, repo, path, filelog=None, workingctx=None):
394 """changeid can be a changeset revision, node, or tag.
395 fileid can be a file revision or node."""
396 self._repo = repo
397 self._path = path
398 self._changeid = None
399 self._filerev = self._filenode = None
400
401 if filelog:
402 self._filelog = filelog
403 if workingctx:
404 self._changectx = workingctx
405
406 def __getattr__(self, name):
407 if name == '_changectx':
408 self._changectx = workingctx(repo)
409 return self._changectx
410 elif name == '_repopath':
411 self._repopath = self._repo.dirstate.copied(p) or self._path
412 elif name == '_filelog':
413 self._filelog = self._repo.file(self._repopath)
414 return self._filelog
415 else:
416 raise AttributeError, name
417
418 def __nonzero__(self):
419 return True
420
421 def __str__(self):
422 return "%s@." % self.path()
423
424 def filectx(self, fileid):
425 '''opens an arbitrary revision of the file without
426 opening a new filelog'''
427 return filectx(self._repo, self._repopath, fileid=fileid,
428 filelog=self._filelog)
429
430 def rev(self):
431 if hasattr(self, "_changectx"):
432 return self._changectx.rev()
433 return self._filelog.linkrev(self._filenode)
434
435 def data(self): return self._repo.wread(self._path)
436 def renamed(self):
437 rp = self._repopath
438 if rp == self._path:
439 return None
440 return rp, self._workingctx._parents._manifest.get(rp, nullid)
441
442 def parents(self):
443 '''return parent filectxs, following copies if necessary'''
444 p = self._path
445 rp = self._repopath
446 pcl = self._workingctx._parents
447 fl = self._filelog
448 pl = [ (rp, pcl[0]._manifest.get(rp, nullid), fl) ]
449 if len(pcl) > 1:
450 if rp != p:
451 fl = None
452 pl.append((p, pcl[1]._manifest.get(p, nullid), fl))
453
454 return [ filectx(self._repo, p, fileid=n, filelog=l)
455 for p,n,l in pl if n != nullid ]
456
457 def children(self):
458 return []
459