1247 |
1247 |
1248 On first access, the files defined as arguments are stat()ed and the |
1248 On first access, the files defined as arguments are stat()ed and the |
1249 results cached. The decorated function is called. The results are stashed |
1249 results cached. The decorated function is called. The results are stashed |
1250 away in a ``_filecache`` dict on the object whose method is decorated. |
1250 away in a ``_filecache`` dict on the object whose method is decorated. |
1251 |
1251 |
1252 On subsequent access, the cached result is returned. |
1252 On subsequent access, the cached result is used as it is set to the |
1253 |
1253 instance dictionary. |
1254 On external property set operations, stat() calls are performed and the new |
1254 |
1255 value is cached. |
1255 On external property set/delete operations, the caller must update the |
1256 |
1256 corresponding _filecache entry appropriately. Use __class__.<attr>.set() |
1257 On property delete operations, cached data is removed. |
1257 instead of directly setting <attr>. |
1258 |
1258 |
1259 When using the property API, cached data is always returned, if available: |
1259 When using the property API, the cached data is always used if available. |
1260 no stat() is performed to check if the file has changed and if the function |
1260 No stat() is performed to check if the file has changed. |
1261 needs to be called to reflect file changes. |
|
1262 |
1261 |
1263 Others can muck about with the state of the ``_filecache`` dict. e.g. they |
1262 Others can muck about with the state of the ``_filecache`` dict. e.g. they |
1264 can populate an entry before the property's getter is called. In this case, |
1263 can populate an entry before the property's getter is called. In this case, |
1265 entries in ``_filecache`` will be used during property operations, |
1264 entries in ``_filecache`` will be used during property operations, |
1266 if available. If the underlying file changes, it is up to external callers |
1265 if available. If the underlying file changes, it is up to external callers |
1289 |
1288 |
1290 def __get__(self, obj, type=None): |
1289 def __get__(self, obj, type=None): |
1291 # if accessed on the class, return the descriptor itself. |
1290 # if accessed on the class, return the descriptor itself. |
1292 if obj is None: |
1291 if obj is None: |
1293 return self |
1292 return self |
1294 # do we need to check if the file changed? |
1293 |
1295 try: |
1294 assert self.sname not in obj.__dict__ |
1296 return obj.__dict__[self.sname] |
|
1297 except KeyError: |
|
1298 pass |
|
1299 |
1295 |
1300 entry = obj._filecache.get(self.name) |
1296 entry = obj._filecache.get(self.name) |
1301 |
1297 |
1302 if entry: |
1298 if entry: |
1303 if entry.changed(): |
1299 if entry.changed(): |
1313 obj._filecache[self.name] = entry |
1309 obj._filecache[self.name] = entry |
1314 |
1310 |
1315 obj.__dict__[self.sname] = entry.obj |
1311 obj.__dict__[self.sname] = entry.obj |
1316 return entry.obj |
1312 return entry.obj |
1317 |
1313 |
1318 def __set__(self, obj, value): |
1314 # don't implement __set__(), which would make __dict__ lookup as slow as |
|
1315 # function call. |
|
1316 |
|
1317 def set(self, obj, value): |
1319 if self.name not in obj._filecache: |
1318 if self.name not in obj._filecache: |
1320 # we add an entry for the missing value because X in __dict__ |
1319 # we add an entry for the missing value because X in __dict__ |
1321 # implies X in _filecache |
1320 # implies X in _filecache |
1322 paths = [self.join(obj, path) for path in self.paths] |
1321 paths = [self.join(obj, path) for path in self.paths] |
1323 ce = filecacheentry(paths, False) |
1322 ce = filecacheentry(paths, False) |
1325 else: |
1324 else: |
1326 ce = obj._filecache[self.name] |
1325 ce = obj._filecache[self.name] |
1327 |
1326 |
1328 ce.obj = value # update cached copy |
1327 ce.obj = value # update cached copy |
1329 obj.__dict__[self.sname] = value # update copy returned by obj.x |
1328 obj.__dict__[self.sname] = value # update copy returned by obj.x |
1330 |
|
1331 def __delete__(self, obj): |
|
1332 try: |
|
1333 del obj.__dict__[self.sname] |
|
1334 except KeyError: |
|
1335 raise AttributeError(self.sname) |
|
1336 |
1329 |
1337 def extdatasource(repo, source): |
1330 def extdatasource(repo, source): |
1338 """Gather a map of rev -> value dict from the specified source |
1331 """Gather a map of rev -> value dict from the specified source |
1339 |
1332 |
1340 A source spec is treated as a URL, with a special case shell: type |
1333 A source spec is treated as a URL, with a special case shell: type |