summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Métaireau <alexis@notmyidea.org>2013-09-25 23:35:36 +0200
committerAlexis Métaireau <alexis@notmyidea.org>2013-09-25 23:35:36 +0200
commit2b87eb7af63b856862d65e289fefe3f295409bda (patch)
tree0d6f3f76a548390b3da03e179e78d7d097f4d798
parentdbbf95b1845661fd8ea4b183bd421ad8e8cc3f20 (diff)
downloadpelican-cache-readers.tar.gz
Add a caching mechnismcache-readers
-rw-r--r--pelican/__init__.py23
-rw-r--r--pelican/cache.py37
-rw-r--r--pelican/readers.py7
-rw-r--r--pelican/settings.py4
4 files changed, 66 insertions, 5 deletions
diff --git a/pelican/__init__.py b/pelican/__init__.py
index b3ffe21a..6057a31c 100644
--- a/pelican/__init__.py
+++ b/pelican/__init__.py
@@ -13,13 +13,16 @@ import collections
from pelican import signals
-from pelican.generators import (ArticlesGenerator, PagesGenerator,
- StaticGenerator, SourceFileGenerator,
- TemplatePagesGenerator)
+from pelican.generators import (
+ ArticlesGenerator, PagesGenerator, StaticGenerator, SourceFileGenerator,
+ TemplatePagesGenerator
+)
from pelican.log import init
from pelican.readers import Readers
from pelican.settings import read_settings
-from pelican.utils import clean_output_dir, folder_watcher, file_watcher
+from pelican.utils import (
+ clean_output_dir, folder_watcher, file_watcher, mkdir_p
+)
from pelican.writers import Writer
__version__ = "3.3.1.dev"
@@ -48,10 +51,17 @@ class Pelican(object):
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
self.output_retention = settings['OUTPUT_RETENTION']
+ self.init_filesystem()
self.init_path()
self.init_plugins()
signals.initialized.send(self)
+ def init_filesystem(self):
+ cache_dir = self.settings['CACHE_PATH']
+ if self.settings['USE_CACHE'] and not os.path.exists(cache_dir):
+ logger.debug('Creating directory {0}'.format(cache_dir))
+ mkdir_p(cache_dir)
+
def init_path(self):
if not any(p in sys.path for p in ['', os.curdir]):
logger.debug("Adding current directory to system path")
@@ -261,6 +271,9 @@ def parse_arguments():
action='store_true',
help="Relaunch pelican each time a modification occurs"
" on the content files.")
+
+ parser.add_argument('--cache', dest='use_cache', action='store_true',
+ help='Cache the file rendering between runs')
return parser.parse_args()
@@ -276,6 +289,8 @@ def get_config(args):
config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme
if args.delete_outputdir is not None:
config['DELETE_OUTPUT_DIRECTORY'] = args.delete_outputdir
+ if args.use_cache:
+ config['USE_CACHE'] = True
# argparse returns bytes in Py2. There is no definite answer as to which
# encoding argparse (or sys.argv) uses.
diff --git a/pelican/cache.py b/pelican/cache.py
new file mode 100644
index 00000000..8b78c6f6
--- /dev/null
+++ b/pelican/cache.py
@@ -0,0 +1,37 @@
+import os.path
+import hashlib
+import pickle
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+class CachedReader(object):
+
+ def __init__(self, reader, cache_path):
+ self._reader = reader
+ self._cache_path = cache_path
+
+ def process_metadata(self, *args, **kwargs):
+ return self._reader.process_metadata(*args, **kwargs)
+
+ def read(self, path):
+ mtime = os.stat(path).st_mtime
+
+ m = hashlib.md5()
+ # We want to hash path + mtime
+ m.update(path)
+ m.update(str(mtime))
+ hash_ = m.hexdigest()
+
+ cache_file = os.path.join(self._cache_path, hash_)
+ if os.path.exists(cache_file):
+ logger.debug('reading {0} from cache'.format(path))
+ with open(cache_file) as f:
+ content, metadata = pickle.load(f)
+ else:
+ content, metadata = self._reader.read(path)
+ with open(cache_file, 'w+') as f:
+ pickle.dump((content, metadata), f)
+ logger.debug('stored {0} in the cache'.format(path))
+ return content, metadata
diff --git a/pelican/readers.py b/pelican/readers.py
index 067bbb85..f632eec8 100644
--- a/pelican/readers.py
+++ b/pelican/readers.py
@@ -35,6 +35,7 @@ except ImportError:
from HTMLParser import HTMLParser
from pelican import signals
+from pelican.cache import CachedReader
from pelican.contents import Page, Category, Tag, Author
from pelican.utils import get_date, pelican_open
@@ -435,6 +436,12 @@ class Readers(object):
reader = self.readers[fmt]
+ if self.settings['USE_CACHE']:
+ # If we are using a cache, then the reader class should be a cached
+ # one.
+ reader = CachedReader(reader=reader,
+ cache_path=self.settings['CACHE_PATH'])
+
metadata = default_metadata(
settings=self.settings, process=reader.process_metadata)
metadata.update(path_metadata(
diff --git a/pelican/settings.py b/pelican/settings.py
index 99828935..f472ba74 100644
--- a/pelican/settings.py
+++ b/pelican/settings.py
@@ -112,6 +112,8 @@ DEFAULT_CONFIG = {
'IGNORE_FILES': ['.#*'],
'SLUG_SUBSTITUTIONS': (),
'INTRASITE_LINK_REGEX': '[{|](?P<what>.*?)[|}]',
+ 'CACHE_PATH': '_pelican_cache',
+ 'USE_CACHE': False,
}
PYGMENTS_RST_OPTIONS = None
@@ -121,7 +123,7 @@ def read_settings(path=None, override=None):
if path:
local_settings = get_settings_from_file(path)
# Make the paths relative to the settings file
- for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'PLUGIN_PATH']:
+ for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'PLUGIN_PATH', 'CACHE_PATH']:
if p in local_settings and local_settings[p] is not None \
and not isabs(local_settings[p]):
absp = os.path.abspath(os.path.normpath(os.path.join(