Mercurial > piecrust2
comparison 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 |
comparison
equal
deleted
inserted
replaced
851:2c7e57d80bba | 852:4850f8c21b6e |
---|---|
1 import os.path | |
2 import logging | |
3 from piecrust import osutil | |
4 from piecrust.routing import RouteParameter | |
5 from piecrust.sources.base import ContentItem, ContentGroup, ContentSource | |
6 | |
7 | |
8 logger = logging.getLogger(__name__) | |
9 | |
10 | |
11 class InvalidFileSystemEndpointError(Exception): | |
12 def __init__(self, source_name, fs_endpoint): | |
13 super(InvalidFileSystemEndpointError, self).__init__( | |
14 "Invalid file-system endpoint for source '%s': %s" % | |
15 (source_name, fs_endpoint)) | |
16 | |
17 | |
18 def _filter_crap_files(f): | |
19 return (f[-1] != '~' and # Vim temp files and what-not | |
20 f not in ['.DS_Store', 'Thumbs.db']) # OSX and Windows bullshit | |
21 | |
22 | |
23 class FSContentSourceBase(ContentSource): | |
24 """ Implements some basic stuff for a `ContentSource` that stores its | |
25 items as files on disk. | |
26 """ | |
27 def __init__(self, app, name, config): | |
28 super().__init__(app, name, config) | |
29 self.fs_endpoint = config.get('fs_endpoint', name) | |
30 self.fs_endpoint_path = os.path.join(self.root_dir, self.fs_endpoint) | |
31 self._fs_filter = None | |
32 | |
33 def _checkFSEndpoint(self): | |
34 if not os.path.isdir(self.fs_endpoint_path): | |
35 if self.config.get('ignore_missing_dir'): | |
36 return False | |
37 raise InvalidFileSystemEndpointError(self.name, | |
38 self.fs_endpoint_path) | |
39 return True | |
40 | |
41 def openItem(self, item, mode='r'): | |
42 for m in 'wxa+': | |
43 if m in mode: | |
44 # If opening the file for writing, let's make sure the | |
45 # directory exists. | |
46 dirname = os.path.dirname(item.spec) | |
47 if not os.path.exists(dirname): | |
48 os.makedirs(dirname, 0o755) | |
49 break | |
50 return open(item.spec, mode) | |
51 | |
52 def getItemMtime(self, item): | |
53 return os.path.getmtime(item.spec) | |
54 | |
55 | |
56 class FSContentSource(FSContentSourceBase): | |
57 """ Implements a `ContentSource` that simply returns files on disk | |
58 under a given root directory. | |
59 """ | |
60 SOURCE_NAME = 'fs' | |
61 | |
62 def getContents(self, group): | |
63 logger.debug("Scanning for content in: %s" % self.fs_endpoint_path) | |
64 if not self._checkFSEndpoint(): | |
65 return None | |
66 | |
67 parent_path = self.fs_endpoint_path | |
68 if group is not None: | |
69 parent_path = group.spec | |
70 | |
71 names = filter(_filter_crap_files, osutil.listdir(parent_path)) | |
72 if self._fs_filter is not None: | |
73 names = filter(self._fs_filter, names) | |
74 | |
75 items = [] | |
76 groups = [] | |
77 for name in names: | |
78 path = os.path.join(parent_path, name) | |
79 if os.path.isdir(path): | |
80 metadata = self._createGroupMetadata(path) | |
81 groups.append(ContentGroup(path, metadata)) | |
82 else: | |
83 metadata = self._createItemMetadata(path) | |
84 items.append(ContentItem(path, metadata)) | |
85 self._finalizeContent(group, items, groups) | |
86 return items + groups | |
87 | |
88 def _createGroupMetadata(self, path): | |
89 return {} | |
90 | |
91 def _createItemMetadata(self, path): | |
92 return {} | |
93 | |
94 def _finalizeContent(self, parent_group, items, groups): | |
95 pass | |
96 | |
97 def getRelatedContents(self, item, relationship): | |
98 return None | |
99 | |
100 def findContent(self, route_params): | |
101 rel_path = route_params['path'] | |
102 path = os.path.join(self.fs_endpoint_path, rel_path) | |
103 metadata = self._createItemMetadata(path) | |
104 return ContentItem(path, metadata) | |
105 | |
106 def getSupportedRouteParameters(self): | |
107 return [ | |
108 RouteParameter('path', RouteParameter.TYPE_PATH)] | |
109 | |
110 def describe(self): | |
111 return {'endpoint_path': self.fs_endpoint_path} |