view piecrust/data/builder.py @ 113:de257cc40ce1

Re-enable proper caching of rendered segments in server. The server keeps records on files that are processed while the server is running. Disk caching is simply disabled for files that are known to use other pages -- because unlike the baker, there's no cheap way to know which files are up to date or not, and rendering is faster enough anyway.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 19 Oct 2014 00:30:44 -0700
parents a643b14a59a3
children 4fc1d306046b
line wrap: on
line source

import re
import time
import logging
from piecrust import APP_VERSION
from piecrust.configuration import merge_dicts
from piecrust.data.assetor import Assetor
from piecrust.data.debug import build_debug_info
from piecrust.data.linker import Linker
from piecrust.data.paginator import Paginator
from piecrust.uriutil import get_slug, get_first_sub_uri


logger = logging.getLogger(__name__)


class DataBuildingContext(object):
    def __init__(self, page, uri, page_num=1):
        self.page = page
        self.uri = uri
        self.page_num = page_num
        self.pagination_source = None
        self.pagination_filter = None

    @property
    def slug(self):
        return get_slug(self.page.app, self.uri)


def build_page_data(ctx):
    page = ctx.page
    app = page.app
    first_uri = get_first_sub_uri(app, ctx.uri)

    pc_data = PieCrustData()
    pgn_source = ctx.pagination_source or get_default_pagination_source(page)
    paginator = Paginator(page, pgn_source, first_uri, ctx.page_num,
            ctx.pagination_filter)
    assetor = Assetor(page, first_uri)
    linker = Linker(page)
    data = {
            'piecrust': pc_data,
            'page': dict(page.config.get()),
            'assets': assetor,
            'pagination': paginator,
            'siblings': linker,
            'family': linker
            }
    page_data = data['page']
    page_data['url'] = ctx.uri
    page_data['slug'] = ctx.slug
    page_data['timestamp'] = time.mktime(page.datetime.timetuple())
    date_format = app.config.get('site/date_format')
    if date_format:
        page_data['date'] = page.datetime.strftime(date_format)

    #TODO: handle slugified taxonomy terms.

    site_data = build_site_data(page)
    merge_dicts(data, site_data)

    # Do this at the end because we want all the data to be ready to be
    # displayed in the debugger window.
    if (app.debug and app.config.get('site/enable_debug_info') and
            not app.config.get('baker/is_baking')):
        pc_data._enableDebugInfo(page, data)

    return data


def build_layout_data(page, page_data, contents):
    data = dict(page_data)
    for name, txt in contents.items():
        if name in data:
            logger.warning("Content segment '%s' will hide existing data." %
                    name)
        data[name] = txt
    return data


class PieCrustData(object):
    debug_render = ['version', 'url', 'branding', 'debug_info']
    debug_render_invoke = ['version', 'url', 'branding', 'debug_info']
    debug_render_redirect = {'debug_info': '_debugRenderDebugInfo'}

    def __init__(self):
        self.version = APP_VERSION
        self.url = 'http://bolt80.com/piecrust/'
        self.branding = 'Baked with <em><a href="%s">PieCrust</a> %s</em>.' % (
                'http://bolt80.com/piecrust/', APP_VERSION)
        self._page = None
        self._data = None

    @property
    def debug_info(self):
        if self._page is not None and self._data is not None:
            return build_debug_info(self._page, self._data)
        return ''

    def _enableDebugInfo(self, page, data):
        self._page = page
        self._data = data

    def _debugRenderDebugInfo(self):
        return "The very thing you're looking at!"


re_endpoint_sep = re.compile(r'[\/\.]')


def build_site_data(page):
    app = page.app
    data = dict(app.config.get())
    for source in app.sources:
        endpoint_bits = re_endpoint_sep.split(source.data_endpoint)
        endpoint = data
        for e in endpoint_bits[:-1]:
            if e not in endpoint:
                endpoint[e] = {}
            endpoint = endpoint[e]
        user_data = endpoint.get(endpoint_bits[-1])
        provider = source.buildDataProvider(page, user_data)
        if endpoint_bits[-1] in endpoint:
            provider.user_data = endpoint[endpoint_bits[-1]]
        endpoint[endpoint_bits[-1]] = provider
    return data


def get_default_pagination_source(page):
    app = page.app
    source_name = page.config.get('source') or page.config.get('blog')
    if source_name is None:
        blog_names = app.config.get('site/blogs')
        if blog_names is not None:
            source_name = blog_names[0]
        else:
            source_name = app.sources[0].name
    source = app.getSource(source_name)
    return source