Mercurial > piecrust2
changeset 862:fddaf43424e2
refactor: Get the page assets to work again in the server.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Thu, 08 Jun 2017 23:09:34 -0700 |
parents | d214918d4d2c |
children | 01458d3b646b |
files | piecrust/data/assetor.py piecrust/data/linker.py piecrust/serving/server.py piecrust/serving/util.py piecrust/sources/base.py piecrust/sources/default.py piecrust/sources/fs.py piecrust/sources/mixins.py piecrust/sources/posts.py |
diffstat | 9 files changed, 104 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- a/piecrust/data/assetor.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/data/assetor.py Thu Jun 08 23:09:34 2017 -0700 @@ -2,6 +2,7 @@ import os.path import shutil import logging +import collections.abc from piecrust import ASSET_DIR_SUFFIX from piecrust.sources.base import REL_ASSETS from piecrust.uriutil import multi_replace @@ -14,26 +15,13 @@ pass -def build_base_url(app, uri, rel_assets_path): - base_url_format = app.config.get('site/base_asset_url_format') - rel_assets_path = rel_assets_path.replace('\\', '/') - - # Remove any extension since we'll be copying assets into the 1st - # sub-page's folder. - pretty = app.config.get('site/pretty_urls') - if not pretty: - uri, _ = os.path.splitext(uri) - - base_url = multi_replace( - base_url_format, - { - '%path%': rel_assets_path, - '%uri%': uri}) - - return base_url.rstrip('/') + '/' +class _AssetInfo: + def __init__(self, content_item, uri): + self.content_item = content_item + self.uri = uri -class Assetor: +class Assetor(collections.abc.Mapping): debug_render_doc = """Helps render URLs to files in the current page's asset folder.""" debug_render = [] @@ -46,21 +34,21 @@ def __getattr__(self, name): try: self._cacheAssets() - return self._cache[name][0] + return self._cache[name].uri except KeyError: raise AttributeError() def __getitem__(self, key): self._cacheAssets() - return self._cache[key][0] + return self._cache[key].uri def __iter__(self): self._cacheAssets() - return map(lambda i: i[0], self._cache.values()) + return self._cache.keys() - def allNames(self): + def __len__(self): self._cacheAssets() - return list(self._cache.keys()) + return len(self._cache) def _debugRenderAssetNames(self): self._cacheAssets() @@ -70,25 +58,52 @@ if self._cache is not None: return - self._cache = self.findAssets() or {} - - def findAssets(self): + source = self._page.source content_item = self._page.content_item - source = content_item.source - assets = source.getRelatedContent(content_item, REL_ASSETS) + + assets = source.getRelatedContents(content_item, REL_ASSETS) if assets is None: - return {} + self._cache = {} + return + + self._cache = {} app = source.app + root_dir = app.root_dir + asset_url_format = app.config.get('site/asset_url_format') + + page_uri = self._page.getUri() + pretty_urls = app.config.get('site/pretty_urls') + if not pretty_urls: + page_uri, _ = os.path.splitext(page_uri) + + uri_build_tokens = { + '%path%': None, + '%filename%': None, + '%page_uri%': page_uri + } + + for a in assets: + name = a.metadata['name'] + if name in self._cache: + raise UnsupportedAssetsError( + "An asset with name '%s' already exists for item '%s'. " + "Do you have multiple assets with colliding names?" % + (name, content_item.spec)) + + # TODO: this assumes a file-system source! + uri_build_tokens['%path%'] = ( + os.path.relpath(a.spec, root_dir).replace('\\', '/')) + uri_build_tokens['%filename%'] = a.metadata['filename'], + uri = multi_replace(asset_url_format, uri_build_tokens) + + self._cache[name] = _AssetInfo(a, uri) + stack = app.env.render_ctx_stack cur_ctx = stack.current_ctx if cur_ctx is not None: cur_ctx.current_pass_info.used_assets = True - # base_url = build_base_url(app, self._uri, rel_assets_dir) - - return assets - def copyAssets(self, dest_dir): page_pathname, _ = os.path.splitext(self._page.path) in_assets_dir = page_pathname + ASSET_DIR_SUFFIX
--- a/piecrust/data/linker.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/data/linker.py Thu Jun 08 23:09:34 2017 -0700 @@ -1,7 +1,7 @@ import logging from piecrust.data.paginationdata import PaginationData from piecrust.sources.base import ( - REL_PARENT_GROUP, REL_LOGICAL_PARENT_ITEM, REL_LOGICAl_CHILD_GROUP) + REL_LOGICAL_PARENT_ITEM, REL_LOGICAl_CHILD_GROUP) logger = logging.getLogger(__name__) @@ -67,8 +67,7 @@ def siblings(self): if self._siblings is None: self._siblings = [] - parent_group = self._source.getRelatedContents( - self._content_item, REL_PARENT_GROUP) + parent_group = self._source.getParentGroup(self._content_item) for i in self._source.getContents(parent_group): if not i.is_group: ipage = self._app.getPage(self._source, i)
--- a/piecrust/serving/server.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/serving/server.py Thu Jun 08 23:09:34 2017 -0700 @@ -107,10 +107,6 @@ '!debug' in request.args): app.config.set('site/show_debug_info', True) - # We'll serve page assets directly from where they are. - app.config.set('site/asset_url_format', - self.root_url + '_asset/%path%') - # Let's try to serve a page. try: response = self._try_serve_page(app, environ, request)
--- a/piecrust/serving/util.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/serving/util.py Thu Jun 08 23:09:34 2017 -0700 @@ -17,6 +17,8 @@ app = appfactory.create() app.config.set('site/root', root_url) app.config.set('server/is_serving', True) + # We'll serve page assets directly from where they are. + app.config.set('site/asset_url_format', root_url + '_asset/%path%') return app
--- a/piecrust/sources/base.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/sources/base.py Thu Jun 08 23:09:34 2017 -0700 @@ -13,9 +13,8 @@ # Types of relationships a content source can be asked for. -REL_PARENT_GROUP = 1 -REL_LOGICAL_PARENT_ITEM = 2 -REL_LOGICAl_CHILD_GROUP = 3 +REL_LOGICAL_PARENT_ITEM = 1 +REL_LOGICAl_CHILD_GROUP = 2 REL_ASSETS = 10 @@ -119,6 +118,9 @@ raise NotImplementedError("'%s' doesn't implement 'getContents'." % self.__class__) + def getParentGroup(self, item): + raise NotImplementedError() + def getRelatedContents(self, item, relationship): raise NotImplementedError()
--- a/piecrust/sources/default.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/sources/default.py Thu Jun 08 23:09:34 2017 -0700 @@ -31,8 +31,7 @@ return self._doCreateItemMetadata(path) def _finalizeContent(self, parent_group, items, groups): - SimpleAssetsSubDirMixin._onFinalizeContent( - self, parent_group, items, groups) + SimpleAssetsSubDirMixin._removeAssetGroups(groups) def _doCreateItemMetadata(self, path): slug = self._makeSlug(path) @@ -62,8 +61,9 @@ def getRelatedContents(self, item, relationship): if relationship == REL_ASSETS: - SimpleAssetsSubDirMixin._getRelatedAssetsContents(self, item) - raise NotImplementedError() + return SimpleAssetsSubDirMixin._getRelatedAssetsContents( + self, item) + return FSContentSource.getRelatedContents(self, item, relationship) def getSupportedRouteParameters(self): return [
--- a/piecrust/sources/fs.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/sources/fs.py Thu Jun 08 23:09:34 2017 -0700 @@ -7,7 +7,7 @@ from piecrust.routing import RouteParameter from piecrust.sources.base import ( ContentItem, ContentGroup, ContentSource, - REL_PARENT_GROUP, REL_LOGICAL_PARENT_ITEM, REL_LOGICAl_CHILD_GROUP) + REL_LOGICAL_PARENT_ITEM, REL_LOGICAl_CHILD_GROUP) logger = logging.getLogger(__name__) @@ -110,6 +110,16 @@ self._finalizeContent(group, items, groups) return items + groups + def getParentGroup(self, item): + parent_dir = os.path.dirname(item.spec) + if len(parent_dir) >= len(self.fs_endpoint_path): + metadata = self._createGroupMetadata(parent_dir) + return ContentGroup(parent_dir, metadata) + + # Don't return a group for paths that are outside of our + # endpoint directory. + return None + def _filterIgnored(self, path): rel_path = os.path.relpath(path, self.fs_endpoint_path) for g in self._ignore_globs: @@ -130,16 +140,6 @@ pass def getRelatedContents(self, item, relationship): - if relationship == REL_PARENT_GROUP: - parent_dir = os.path.dirname(item.spec) - if len(parent_dir) >= len(self.fs_endpoint_path): - metadata = self._createGroupMetadata(parent_dir) - return ContentGroup(parent_dir, metadata) - - # Don't return a group for paths that are outside of our - # endpoint directory. - return None - if relationship == REL_LOGICAL_PARENT_ITEM: # If we want the logical parent item of a folder, we find a # page file with the same name as the folder.
--- a/piecrust/sources/mixins.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/sources/mixins.py Thu Jun 08 23:09:34 2017 -0700 @@ -10,31 +10,34 @@ class SimpleAssetsSubDirMixin: - def _getRelatedAssetsContents(self, item, relationship): - if not item.metadata.get('__has_assets', False): + """ A content source mixin for sources that are file-system-based, + and have item assets stored in a sub-folder that is named after + the item. + + More specifically, assets are stored in a sub-folder named: + `<item_path>-assets` + """ + def _getRelatedAssetsContents(self, item): + spec_no_ext, _ = os.path.splitext(item.spec) + assets_dir = spec_no_ext + assets_suffix + try: + asset_files = osutil.listdir(assets_dir) + except OSError: return None - assets = {} - assets_dir = item.spec + assets_suffix - for f in osutil.listdir(assets_dir): + assets = [] + for f in asset_files: fpath = os.path.join(assets_dir, f) name, _ = os.path.splitext(f) - if name in assets: - raise Exception("Multiple assets are named '%s'." % - name) - assets[name] = ContentItem(fpath, {'__is_asset': True}) + assets.append(ContentItem( + fpath, + {'name': name, + 'filename': f, + '__is_asset': True})) return assets - def _onFinalizeContent(self, parent_group, items, groups): - assetsGroups = [] - for g in groups: - if not g.spec.endswith(assets_suffix): - continue - match = g.spec[:-len(assets_suffix)] - item = next(filter(lambda i: i.spec == match), None) - if item: - item.metadata['__has_assets'] = True - assetsGroups.append(g) - for g in assetsGroups: + def _removeAssetGroups(self, groups): + asset_groups = [g for g in groups + if g.spec.endswith(assets_suffix)] + for g in asset_groups: groups.remove(g) -
--- a/piecrust/sources/posts.py Thu Jun 08 08:52:45 2017 -0700 +++ b/piecrust/sources/posts.py Thu Jun 08 23:09:34 2017 -0700 @@ -36,14 +36,17 @@ def path_format(self): return self.__class__.PATH_FORMAT - def _finalizeContent(self, parent_group, items, groups): - SimpleAssetsSubDirMixin._onFinalizeContent( - parent_group, items, groups) + def _finalizeContent(self, groups): + SimpleAssetsSubDirMixin._removeAssetGroups(groups) + + def getParentGroup(self, item): + return None def getRelatedContents(self, item, relationship): if relationship == REL_ASSETS: - SimpleAssetsSubDirMixin._getRelatedAssetsContents(item) - raise NotImplementedError() + return SimpleAssetsSubDirMixin._getRelatedAssetsContents( + self, item) + return FSContentSource.getRelatedContents(self, item, relationship) def findContent(self, route_params): year = route_params.get('year')