diff piecrust/sources/pageref.py @ 242:f130365568ff

internal: Code reorganization to put less stuff in `sources.base`. Interfaces that sources can implement are in `sources.interfaces`. The default page source is in `sources.default`. The `SimplePageSource` is gone since most subclasses only wanted to do *some* stuff the same, but *lots* of stuff slightly different. I may have to revisit the code to extract exactly the code that's in common.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 18 Feb 2015 18:35:03 -0800
parents
children dd25bd3ce1f9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/piecrust/sources/pageref.py	Wed Feb 18 18:35:03 2015 -0800
@@ -0,0 +1,99 @@
+import re
+import os.path
+
+
+page_ref_pattern = re.compile(r'(?P<src>[\w]+)\:(?P<path>.*?)(;|$)')
+
+
+class PageNotFoundError(Exception):
+    pass
+
+
+class PageRef(object):
+    """ A reference to a page, with support for looking a page in different
+        realms.
+    """
+    def __init__(self, app, page_ref):
+        self.app = app
+        self._page_ref = page_ref
+        self._paths = None
+        self._first_valid_path_index = -2
+        self._exts = list(app.config.get('site/auto_formats').keys())
+
+    @property
+    def exists(self):
+        try:
+            self._checkPaths()
+            return True
+        except PageNotFoundError:
+            return False
+
+    @property
+    def source_name(self):
+        self._checkPaths()
+        return self._paths[self._first_valid_path_index][0]
+
+    @property
+    def source(self):
+        return self.app.getSource(self.source_name)
+
+    @property
+    def rel_path(self):
+        self._checkPaths()
+        return self._paths[self._first_valid_path_index][1]
+
+    @property
+    def path(self):
+        self._checkPaths()
+        return self._paths[self._first_valid_path_index][2]
+
+    @property
+    def possible_rel_paths(self):
+        self._load()
+        return [p[1] for p in self._paths]
+
+    @property
+    def possible_paths(self):
+        self._load()
+        return [p[2] for p in self._paths]
+
+    def _load(self):
+        if self._paths is not None:
+            return
+
+        it = list(page_ref_pattern.finditer(self._page_ref))
+        if len(it) == 0:
+            raise Exception("Invalid page ref: %s" % self._page_ref)
+
+        self._paths = []
+        for m in it:
+            source_name = m.group('src')
+            source = self.app.getSource(source_name)
+            if source is None:
+                raise Exception("No such source: %s" % source_name)
+            rel_path = m.group('path')
+            path = source.resolveRef(rel_path)
+            if '%ext%' in rel_path:
+                for e in self._exts:
+                    self._paths.append(
+                            (source_name,
+                             rel_path.replace('%ext%', e),
+                             path.replace('%ext%', e)))
+            else:
+                self._paths.append((source_name, rel_path, path))
+
+    def _checkPaths(self):
+        if self._first_valid_path_index >= 0:
+            return
+        if self._first_valid_path_index == -1:
+            raise PageNotFoundError(
+                    "No valid paths were found for page reference: %s" %
+                    self._page_ref)
+
+        self._load()
+        self._first_valid_path_index = -1
+        for i, path_info in enumerate(self._paths):
+            if os.path.isfile(path_info[2]):
+                self._first_valid_path_index = i
+                break
+