Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | """Maintain a cache of stat() information on files. |
2 | ||
3 | There are functions to reset the cache or to selectively remove items. | |
4 | """ | |
5 | ||
6 | import warnings | |
7 | warnings.warn("The statcache module is obsolete. Use os.stat() instead.", | |
8 | DeprecationWarning) | |
9 | del warnings | |
10 | ||
11 | import os as _os | |
12 | from stat import * | |
13 | ||
14 | __all__ = ["stat","reset","forget","forget_prefix","forget_dir", | |
15 | "forget_except_prefix","isdir"] | |
16 | ||
17 | # The cache. Keys are pathnames, values are os.stat outcomes. | |
18 | # Remember that multiple threads may be calling this! So, e.g., that | |
19 | # path in cache returns 1 doesn't mean the cache will still contain | |
20 | # path on the next line. Code defensively. | |
21 | ||
22 | cache = {} | |
23 | ||
24 | def stat(path): | |
25 | """Stat a file, possibly out of the cache.""" | |
26 | ret = cache.get(path, None) | |
27 | if ret is None: | |
28 | cache[path] = ret = _os.stat(path) | |
29 | return ret | |
30 | ||
31 | def reset(): | |
32 | """Clear the cache.""" | |
33 | cache.clear() | |
34 | ||
35 | # For thread saftey, always use forget() internally too. | |
36 | def forget(path): | |
37 | """Remove a given item from the cache, if it exists.""" | |
38 | try: | |
39 | del cache[path] | |
40 | except KeyError: | |
41 | pass | |
42 | ||
43 | def forget_prefix(prefix): | |
44 | """Remove all pathnames with a given prefix.""" | |
45 | for path in cache.keys(): | |
46 | if path.startswith(prefix): | |
47 | forget(path) | |
48 | ||
49 | def forget_dir(prefix): | |
50 | """Forget a directory and all entries except for entries in subdirs.""" | |
51 | ||
52 | # Remove trailing separator, if any. This is tricky to do in a | |
53 | # x-platform way. For example, Windows accepts both / and \ as | |
54 | # separators, and if there's nothing *but* a separator we want to | |
55 | # preserve that this is the root. Only os.path has the platform | |
56 | # knowledge we need. | |
57 | from os.path import split, join | |
58 | prefix = split(join(prefix, "xxx"))[0] | |
59 | forget(prefix) | |
60 | for path in cache.keys(): | |
61 | # First check that the path at least starts with the prefix, so | |
62 | # that when it doesn't we can avoid paying for split(). | |
63 | if path.startswith(prefix) and split(path)[0] == prefix: | |
64 | forget(path) | |
65 | ||
66 | def forget_except_prefix(prefix): | |
67 | """Remove all pathnames except with a given prefix. | |
68 | ||
69 | Normally used with prefix = '/' after a chdir(). | |
70 | """ | |
71 | ||
72 | for path in cache.keys(): | |
73 | if not path.startswith(prefix): | |
74 | forget(path) | |
75 | ||
76 | def isdir(path): | |
77 | """Return True if directory, else False.""" | |
78 | try: | |
79 | st = stat(path) | |
80 | except _os.error: | |
81 | return False | |
82 | return S_ISDIR(st.st_mode) |