123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- from __future__ import absolute_import
- from __future__ import division
- from __future__ import print_function
- from __future__ import unicode_literals
- import errno
- import glob
- import hashlib
- import os
- import shutil
- import sys
- import tempfile
- try:
- import cPickle as pickle
- except ImportError:
- import pickle
- import giscanner
- from . import utils
- _CACHE_VERSION_FILENAME = '.cache-version'
- def _get_versionhash():
- toplevel = os.path.dirname(giscanner.__file__)
- sources = glob.glob(os.path.join(toplevel, '*.py'))
- sources.append(sys.argv[0])
-
- mtimes = (str(os.stat(source).st_mtime) for source in sources)
-
- return hashlib.sha1(''.join(mtimes).encode('ascii')).hexdigest()
- class CacheStore(object):
- def __init__(self):
- self._directory = self._get_cachedir()
- self._check_cache_version()
- def _get_cachedir(self):
- if 'GI_SCANNER_DISABLE_CACHE' in os.environ:
- return None
- else:
- cachedir = utils.get_user_cache_dir('g-ir-scanner')
- return cachedir
- def _check_cache_version(self):
- if self._directory is None:
- return
- current_hash = _get_versionhash()
- version = os.path.join(self._directory, _CACHE_VERSION_FILENAME)
- try:
- with open(version, 'r') as version_file:
- cache_hash = version_file.read()
- except IOError as e:
-
- if e.errno == errno.ENOENT:
- cache_hash = 0
- else:
- raise
- if current_hash == cache_hash:
- return
- self._clean()
- tmp_fd, tmp_filename = tempfile.mkstemp(prefix='g-ir-scanner-cache-version-')
- try:
- with os.fdopen(tmp_fd, 'w') as tmp_file:
- tmp_file.write(current_hash)
-
-
- shutil.move(tmp_filename, version)
- except IOError as e:
-
- if e.errno == errno.EACCES:
- return
- else:
- raise
- def _get_filename(self, filename):
-
-
-
- if self._directory is None:
- return
-
-
- hexdigest = hashlib.sha1(filename.encode('utf-8')).hexdigest()
- return os.path.join(self._directory, hexdigest)
- def _cache_is_valid(self, store_filename, filename):
- return (os.stat(store_filename).st_mtime >=
- os.stat(filename).st_mtime)
- def _remove_filename(self, filename):
- try:
- os.unlink(filename)
- except IOError as e:
-
- if e.errno == errno.EACCES:
- return
- else:
- raise
- except OSError as e:
-
- if e.errno == errno.ENOENT:
- return
- else:
- raise
- def _clean(self):
- for filename in os.listdir(self._directory):
- if filename == _CACHE_VERSION_FILENAME:
- continue
- self._remove_filename(os.path.join(self._directory, filename))
- def store(self, filename, data):
- store_filename = self._get_filename(filename)
- if store_filename is None:
- return
- if (os.path.exists(store_filename) and self._cache_is_valid(store_filename, filename)):
- return None
- tmp_fd, tmp_filename = tempfile.mkstemp(prefix='g-ir-scanner-cache-')
- try:
- with os.fdopen(tmp_fd, 'wb') as tmp_file:
- pickle.dump(data, tmp_file)
- except IOError as e:
-
- if e.errno == errno.ENOSPC:
- self._remove_filename(tmp_filename)
- return
- else:
- raise
- try:
- shutil.move(tmp_filename, store_filename)
- except IOError as e:
-
- if e.errno == errno.EACCES:
- self._remove_filename(tmp_filename)
- else:
- raise
- def load(self, filename):
- store_filename = self._get_filename(filename)
- if store_filename is None:
- return
- try:
- fd = open(store_filename, 'rb')
- except IOError as e:
- if e.errno == errno.ENOENT:
- return None
- else:
- raise
- if not self._cache_is_valid(store_filename, filename):
- return None
- try:
- data = pickle.load(fd)
- except (AttributeError, EOFError, ValueError, pickle.BadPickleGet):
-
- self._remove_filename(store_filename)
- data = None
- return data
|