Mercurial > piecrust2
diff piecrust/sources/fs.py @ 852:4850f8c21b6e
core: Start of the big refactor for PieCrust 3.0.
* Everything is a `ContentSource`, including assets directories.
* Most content sources are subclasses of the base file-system source.
* A source is processed by a "pipeline", and there are 2 built-in pipelines,
one for assets and one for pages. The asset pipeline is vaguely functional,
but the page pipeline is completely broken right now.
* Rewrite the baking process as just running appropriate pipelines on each
content item. This should allow for better parallelization.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Wed, 17 May 2017 00:11:48 -0700 |
parents | |
children | f070a4fc033c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piecrust/sources/fs.py Wed May 17 00:11:48 2017 -0700 @@ -0,0 +1,111 @@ +import os.path +import logging +from piecrust import osutil +from piecrust.routing import RouteParameter +from piecrust.sources.base import ContentItem, ContentGroup, ContentSource + + +logger = logging.getLogger(__name__) + + +class InvalidFileSystemEndpointError(Exception): + def __init__(self, source_name, fs_endpoint): + super(InvalidFileSystemEndpointError, self).__init__( + "Invalid file-system endpoint for source '%s': %s" % + (source_name, fs_endpoint)) + + +def _filter_crap_files(f): + return (f[-1] != '~' and # Vim temp files and what-not + f not in ['.DS_Store', 'Thumbs.db']) # OSX and Windows bullshit + + +class FSContentSourceBase(ContentSource): + """ Implements some basic stuff for a `ContentSource` that stores its + items as files on disk. + """ + def __init__(self, app, name, config): + super().__init__(app, name, config) + self.fs_endpoint = config.get('fs_endpoint', name) + self.fs_endpoint_path = os.path.join(self.root_dir, self.fs_endpoint) + self._fs_filter = None + + def _checkFSEndpoint(self): + if not os.path.isdir(self.fs_endpoint_path): + if self.config.get('ignore_missing_dir'): + return False + raise InvalidFileSystemEndpointError(self.name, + self.fs_endpoint_path) + return True + + def openItem(self, item, mode='r'): + for m in 'wxa+': + if m in mode: + # If opening the file for writing, let's make sure the + # directory exists. + dirname = os.path.dirname(item.spec) + if not os.path.exists(dirname): + os.makedirs(dirname, 0o755) + break + return open(item.spec, mode) + + def getItemMtime(self, item): + return os.path.getmtime(item.spec) + + +class FSContentSource(FSContentSourceBase): + """ Implements a `ContentSource` that simply returns files on disk + under a given root directory. + """ + SOURCE_NAME = 'fs' + + def getContents(self, group): + logger.debug("Scanning for content in: %s" % self.fs_endpoint_path) + if not self._checkFSEndpoint(): + return None + + parent_path = self.fs_endpoint_path + if group is not None: + parent_path = group.spec + + names = filter(_filter_crap_files, osutil.listdir(parent_path)) + if self._fs_filter is not None: + names = filter(self._fs_filter, names) + + items = [] + groups = [] + for name in names: + path = os.path.join(parent_path, name) + if os.path.isdir(path): + metadata = self._createGroupMetadata(path) + groups.append(ContentGroup(path, metadata)) + else: + metadata = self._createItemMetadata(path) + items.append(ContentItem(path, metadata)) + self._finalizeContent(group, items, groups) + return items + groups + + def _createGroupMetadata(self, path): + return {} + + def _createItemMetadata(self, path): + return {} + + def _finalizeContent(self, parent_group, items, groups): + pass + + def getRelatedContents(self, item, relationship): + return None + + def findContent(self, route_params): + rel_path = route_params['path'] + path = os.path.join(self.fs_endpoint_path, rel_path) + metadata = self._createItemMetadata(path) + return ContentItem(path, metadata) + + def getSupportedRouteParameters(self): + return [ + RouteParameter('path', RouteParameter.TYPE_PATH)] + + def describe(self): + return {'endpoint_path': self.fs_endpoint_path}