mercurial/scmutil.py
changeset 14928 dca59d5be12d
parent 14861 6ed2a449cb5b
child 14961 5523529bd1af
equal deleted inserted replaced
14927:2aa3e07b2f07 14928:dca59d5be12d
   707     missings.sort()
   707     missings.sort()
   708     if missings:
   708     if missings:
   709         raise error.RequirementError(_("unknown repository format: "
   709         raise error.RequirementError(_("unknown repository format: "
   710             "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
   710             "requires features '%s' (upgrade Mercurial)") % "', '".join(missings))
   711     return requirements
   711     return requirements
       
   712 
       
   713 class filecacheentry(object):
       
   714     def __init__(self, path):
       
   715         self.path = path
       
   716         self.cachestat = filecacheentry.stat(self.path)
       
   717 
       
   718         if self.cachestat:
       
   719             self._cacheable = self.cachestat.cacheable()
       
   720         else:
       
   721             # None means we don't know yet
       
   722             self._cacheable = None
       
   723 
       
   724     def refresh(self):
       
   725         if self.cacheable():
       
   726             self.cachestat = filecacheentry.stat(self.path)
       
   727 
       
   728     def cacheable(self):
       
   729         if self._cacheable is not None:
       
   730             return self._cacheable
       
   731 
       
   732         # we don't know yet, assume it is for now
       
   733         return True
       
   734 
       
   735     def changed(self):
       
   736         # no point in going further if we can't cache it
       
   737         if not self.cacheable():
       
   738             return True
       
   739 
       
   740         newstat = filecacheentry.stat(self.path)
       
   741 
       
   742         # we may not know if it's cacheable yet, check again now
       
   743         if newstat and self._cacheable is None:
       
   744             self._cacheable = newstat.cacheable()
       
   745 
       
   746             # check again
       
   747             if not self._cacheable:
       
   748                 return True
       
   749 
       
   750         if self.cachestat != newstat:
       
   751             self.cachestat = newstat
       
   752             return True
       
   753         else:
       
   754             return False
       
   755 
       
   756     @staticmethod
       
   757     def stat(path):
       
   758         try:
       
   759             return util.cachestat(path)
       
   760         except OSError, e:
       
   761             if e.errno != errno.ENOENT:
       
   762                 raise
       
   763 
       
   764 class filecache(object):
       
   765     '''A property like decorator that tracks a file under .hg/ for updates.
       
   766 
       
   767     Records stat info when called in _filecache.
       
   768 
       
   769     On subsequent calls, compares old stat info with new info, and recreates
       
   770     the object when needed, updating the new stat info in _filecache.
       
   771 
       
   772     Mercurial either atomic renames or appends for files under .hg,
       
   773     so to ensure the cache is reliable we need the filesystem to be able
       
   774     to tell us if a file has been replaced. If it can't, we fallback to
       
   775     recreating the object on every call (essentially the same behaviour as
       
   776     propertycache).'''
       
   777     def __init__(self, path, instore=False):
       
   778         self.path = path
       
   779         self.instore = instore
       
   780 
       
   781     def __call__(self, func):
       
   782         self.func = func
       
   783         self.name = func.__name__
       
   784         return self
       
   785 
       
   786     def __get__(self, obj, type=None):
       
   787         entry = obj._filecache.get(self.name)
       
   788 
       
   789         if entry:
       
   790             if entry.changed():
       
   791                 entry.obj = self.func(obj)
       
   792         else:
       
   793             path = self.instore and obj.sjoin(self.path) or obj.join(self.path)
       
   794 
       
   795             # We stat -before- creating the object so our cache doesn't lie if
       
   796             # a writer modified between the time we read and stat
       
   797             entry = filecacheentry(path)
       
   798             entry.obj = self.func(obj)
       
   799 
       
   800             obj._filecache[self.name] = entry
       
   801 
       
   802         setattr(obj, self.name, entry.obj)
       
   803         return entry.obj