statcache.py 2.26 KB
Newer Older
1 2
"""Maintain a cache of stat() information on files.

3 4
There are functions to reset the cache or to selectively remove items.
"""
Guido van Rossum's avatar
Guido van Rossum committed
5

6
import os as _os
7
from stat import *
Guido van Rossum's avatar
Guido van Rossum committed
8

9 10 11
__all__ = ["stat","reset","forget","forget_prefix","forget_dir",
           "forget_except_prefix","isdir"]

12 13 14 15
# The cache.  Keys are pathnames, values are os.stat outcomes.
# Remember that multiple threads may be calling this!  So, e.g., that
# cache.has_key(path) returns 1 doesn't mean the cache will still contain
# path on the next line.  Code defensively.
Guido van Rossum's avatar
Guido van Rossum committed
16

17
cache = {}
Guido van Rossum's avatar
Guido van Rossum committed
18 19

def stat(path):
Tim Peters's avatar
Tim Peters committed
20
    """Stat a file, possibly out of the cache."""
21 22 23
    ret = cache.get(path, None)
    if ret is None:
        cache[path] = ret = _os.stat(path)
Tim Peters's avatar
Tim Peters committed
24
    return ret
Guido van Rossum's avatar
Guido van Rossum committed
25 26

def reset():
27 28
    """Clear the cache."""
    cache.clear()
Guido van Rossum's avatar
Guido van Rossum committed
29

30
# For thread saftey, always use forget() internally too.
Guido van Rossum's avatar
Guido van Rossum committed
31
def forget(path):
Tim Peters's avatar
Tim Peters committed
32
    """Remove a given item from the cache, if it exists."""
33
    try:
Tim Peters's avatar
Tim Peters committed
34
        del cache[path]
35 36
    except KeyError:
        pass
Guido van Rossum's avatar
Guido van Rossum committed
37 38

def forget_prefix(prefix):
Tim Peters's avatar
Tim Peters committed
39 40
    """Remove all pathnames with a given prefix."""
    for path in cache.keys():
41 42
        if path.startswith(prefix):
            forget(path)
Guido van Rossum's avatar
Guido van Rossum committed
43 44

def forget_dir(prefix):
45 46 47 48 49 50 51 52 53
    """Forget a directory and all entries except for entries in subdirs."""

    # Remove trailing separator, if any.  This is tricky to do in a
    # x-platform way.  For example, Windows accepts both / and \ as
    # separators, and if there's nothing *but* a separator we want to
    # preserve that this is the root.  Only os.path has the platform
    # knowledge we need.
    from os.path import split, join
    prefix = split(join(prefix, "xxx"))[0]
Tim Peters's avatar
Tim Peters committed
54 55
    forget(prefix)
    for path in cache.keys():
56 57 58 59
        # First check that the path at least starts with the prefix, so
        # that when it doesn't we can avoid paying for split().
        if path.startswith(prefix) and split(path)[0] == prefix:
            forget(path)
Guido van Rossum's avatar
Guido van Rossum committed
60 61

def forget_except_prefix(prefix):
Tim Peters's avatar
Tim Peters committed
62
    """Remove all pathnames except with a given prefix.
Guido van Rossum's avatar
Guido van Rossum committed
63

64 65 66 67 68 69
    Normally used with prefix = '/' after a chdir().
    """

    for path in cache.keys():
        if not path.startswith(prefix):
            forget(path)
Guido van Rossum's avatar
Guido van Rossum committed
70 71

def isdir(path):
72
    """Return 1 if directory, else 0."""
Tim Peters's avatar
Tim Peters committed
73 74
    try:
        st = stat(path)
75
    except _os.error:
Tim Peters's avatar
Tim Peters committed
76 77
        return 0
    return S_ISDIR(st[ST_MODE])