From d635a347d1a5bb7336edb712356237b141efb4d1 Mon Sep 17 00:00:00 2001 From: Ondrej Grover Date: Mon, 21 Apr 2014 11:36:17 +0200 Subject: [PATCH 1/3] move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS Instead of one path a list can be given. This is due to popular request. Should help people not wanting to use Pelican for blogging. Maintain backward compatibility though. Thanks to @ingwinlu for pointing out the change in StaticGenerator. --- docs/settings.rst | 4 +-- pelican/generators.py | 60 +++++++++++++++----------------- pelican/settings.py | 26 ++++++++++---- pelican/tests/test_generators.py | 2 +- 4 files changed, 51 insertions(+), 41 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 4701e92d..33117a7f 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -111,9 +111,9 @@ Setting name (followed by default value, if any) ``PATH`` Path to content directory to be processed by Pelican. If undefined, and content path is not specified via an argument to the ``pelican`` command, Pelican will use the current working directory. -``PAGE_DIR = 'pages'`` Directory to look at for pages, relative to ``PATH``. +``PAGE_PATHS = ['pages']`` A list of directories to look at for pages, relative to ``PATH``. ``PAGE_EXCLUDES = ()`` A list of directories to exclude when looking for pages. -``ARTICLE_DIR = ''`` Directory to look at for articles, relative to ``PATH``. +``ARTICLE_PATHS = ['']`` A list of directories to look at for articles, relative to ``PATH``. ``ARTICLE_EXCLUDES = ('pages',)`` A list of directories to exclude when looking for articles. ``OUTPUT_SOURCES = False`` Set to True if you want to copy the articles and pages in their original format (e.g. Markdown or reStructuredText) to the diff --git a/pelican/generators.py b/pelican/generators.py index 7c6ba66b..deb237a2 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -110,29 +110,30 @@ class Generator(object): return True return False - def get_files(self, path, exclude=[], extensions=None): + def get_files(self, paths, exclude=[], extensions=None): """Return a list of files to use, based on rules - :param path: the path to search (relative to self.path) + :param paths: the list pf paths to search (relative to self.path) :param exclude: the list of path to exclude :param extensions: the list of allowed extensions (if False, all extensions are allowed) """ files = [] - root = os.path.join(self.path, path) + for path in paths: + root = os.path.join(self.path, path) - if os.path.isdir(root): - for dirpath, dirs, temp_files in os.walk(root, followlinks=True): - for e in exclude: - if e in dirs: - dirs.remove(e) - reldir = os.path.relpath(dirpath, self.path) - for f in temp_files: - fp = os.path.join(reldir, f) - if self._include_path(fp, extensions): - files.append(fp) - elif os.path.exists(root) and self._include_path(path, extensions): - files.append(path) # can't walk non-directories + if os.path.isdir(root): + for dirpath, dirs, temp_files in os.walk(root, followlinks=True): + for e in exclude: + if e in dirs: + dirs.remove(e) + reldir = os.path.relpath(dirpath, self.path) + for f in temp_files: + fp = os.path.join(reldir, f) + if self._include_path(fp, extensions): + files.append(fp) + elif os.path.exists(root) and self._include_path(path, extensions): + files.append(path) # can't walk non-directories return files def add_source_path(self, content): @@ -462,7 +463,7 @@ class ArticlesGenerator(CachingGenerator): all_articles = [] all_drafts = [] for f in self.get_files( - self.settings['ARTICLE_DIR'], + self.settings['ARTICLE_PATHS'], exclude=self.settings['ARTICLE_EXCLUDES']): article = self.get_cached_data(f, None) if article is None: @@ -586,7 +587,7 @@ class PagesGenerator(CachingGenerator): all_pages = [] hidden_pages = [] for f in self.get_files( - self.settings['PAGE_DIR'], + self.settings['PAGE_PATHS'], exclude=self.settings['PAGE_EXCLUDES']): page = self.get_cached_data(f, None) if page is None: @@ -660,20 +661,17 @@ class StaticGenerator(Generator): def generate_context(self): self.staticfiles = [] - - # walk static paths - for static_path in self.settings['STATIC_PATHS']: - for f in self.get_files( - static_path, extensions=False): - static = self.readers.read_file( - base_path=self.path, path=f, content_class=Static, - fmt='static', context=self.context, - preread_signal=signals.static_generator_preread, - preread_sender=self, - context_signal=signals.static_generator_context, - context_sender=self) - self.staticfiles.append(static) - self.add_source_path(static) + for f in self.get_files(self.settings['STATIC_PATHS'], + extensions=False): + static = self.readers.read_file( + base_path=self.path, path=f, content_class=Static, + fmt='static', context=self.context, + preread_signal=signals.static_generator_preread, + preread_sender=self, + context_signal=signals.static_generator_context, + context_sender=self) + self.staticfiles.append(static) + self.add_source_path(static) self._update_context(('staticfiles',)) signals.static_generator_finalized.send(self) diff --git a/pelican/settings.py b/pelican/settings.py index f759ff9e..219ebbd0 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -29,9 +29,9 @@ DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'themes', 'notmyidea') DEFAULT_CONFIG = { 'PATH': os.curdir, - 'ARTICLE_DIR': '', + 'ARTICLE_PATHS': [''], 'ARTICLE_EXCLUDES': ('pages',), - 'PAGE_DIR': 'pages', + 'PAGE_PATHS': ['pages'], 'PAGE_EXCLUDES': (), 'THEME': DEFAULT_THEME, 'OUTPUT_PATH': 'output', @@ -311,6 +311,16 @@ def configure_settings(settings): key=lambda r: r[0], ) + # move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS + for key in ['ARTICLE', 'PAGE']: + old_key = key + '_DIR' + new_key = key + '_PATHS' + if old_key in settings: + logger.warning('Deprecated setting {}, moving it to {} list'.format( + old_key, new_key)) + settings[new_key] = [settings[old_key]] # also make a list + del settings[old_key] + # Save people from accidentally setting a string rather than a list path_keys = ( 'ARTICLE_EXCLUDES', @@ -324,13 +334,15 @@ def configure_settings(settings): 'PLUGINS', 'STATIC_PATHS', 'THEME_STATIC_PATHS', + 'ARTICLE_PATHS', + 'PAGE_PATHS', ) for PATH_KEY in filter(lambda k: k in settings, path_keys): - if isinstance(settings[PATH_KEY], six.string_types): - logger.warning("Detected misconfiguration with %s setting " - "(must be a list), falling back to the default" - % PATH_KEY) - settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] + if isinstance(settings[PATH_KEY], six.string_types): + logger.warning("Detected misconfiguration with %s setting " + "(must be a list), falling back to the default" + % PATH_KEY) + settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] for old, new, doc in [ ('LESS_GENERATOR', 'the Webassets plugin', None), diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py index 7b79e8f3..668a0093 100644 --- a/pelican/tests/test_generators.py +++ b/pelican/tests/test_generators.py @@ -372,8 +372,8 @@ class TestPageGenerator(unittest.TestCase): def test_generate_context(self): settings = get_settings(filenames={}) - settings['PAGE_DIR'] = 'TestPages' # relative to CUR_DIR settings['CACHE_PATH'] = self.temp_cache + settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR settings['DEFAULT_DATE'] = (1970, 1, 1) generator = PagesGenerator( From 21882fd4a00ffdcee7029d7d5ee5ed355ef34a94 Mon Sep 17 00:00:00 2001 From: Ondrej Grover Date: Wed, 14 May 2014 14:06:58 +0200 Subject: [PATCH 2/3] Fix #1344 move PLUGIN_PATH -> PLUGIN_PATHS Pelican uses *_PATHS names for settings that represent a list of paths. --- docs/plugins.rst | 6 +++--- docs/settings.rst | 1 + pelican/__init__.py | 4 ++-- pelican/settings.py | 20 ++++++++++++-------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index 717019a8..a13d9dce 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -21,10 +21,10 @@ Alternatively, another method is to import them and add them to the list:: PLUGINS = [myplugin,] If your plugins are not in an importable path, you can specify a list of paths -via the ``PLUGIN_PATH`` setting. As shown in the following example, paths in -the ``PLUGIN_PATH`` list can be absolute or relative to the settings file:: +via the ``PLUGIN_PATHS`` setting. As shown in the following example, paths in +the ``PLUGIN_PATHS`` list can be absolute or relative to the settings file:: - PLUGIN_PATH = ["plugins", "/srv/pelican/plugins"] + PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"] PLUGINS = ["assets", "liquid_tags", "sitemap"] Where to find plugins diff --git a/docs/settings.rst b/docs/settings.rst index 33117a7f..34245ff4 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -125,6 +125,7 @@ Setting name (followed by default value, if any) not. Only set this to ``True`` when developing/testing and only if you fully understand the effect it can have on links/feeds. ``PLUGINS = []`` The list of plugins to load. See :ref:`plugins`. +``PLUGIN_PATHS = []`` A list of directories where to look for plugins. See :ref:`plugins`. ``SITENAME = 'A Pelican Blog'`` Your site name ``SITEURL`` Base URL of your website. Not defined by default, so it is best to specify your SITEURL; if you do not, feeds diff --git a/pelican/__init__.py b/pelican/__init__.py index e9fef163..082e5a58 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -63,9 +63,9 @@ class Pelican(object): def init_plugins(self): self.plugins = [] - logger.debug('Temporarily adding PLUGIN_PATH to system path') + logger.debug('Temporarily adding PLUGIN_PATHS to system path') _sys_path = sys.path[:] - for pluginpath in self.settings['PLUGIN_PATH']: + for pluginpath in self.settings['PLUGIN_PATHS']: sys.path.insert(0, pluginpath) for plugin in self.settings['PLUGINS']: # if it's a string, then import it diff --git a/pelican/settings.py b/pelican/settings.py index 219ebbd0..c93050ad 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -114,7 +114,7 @@ DEFAULT_CONFIG = { 'ARTICLE_PERMALINK_STRUCTURE': '', 'TYPOGRIFY': False, 'SUMMARY_MAX_LENGTH': 50, - 'PLUGIN_PATH': [], + 'PLUGIN_PATHS': [], 'PLUGINS': [], 'PYGMENTS_RST_OPTIONS': {}, 'TEMPLATE_PAGES': {}, @@ -147,13 +147,17 @@ def read_settings(path=None, override=None): if p not in ('THEME') or os.path.exists(absp): local_settings[p] = absp - if isinstance(local_settings['PLUGIN_PATH'], six.string_types): - logger.warning("Defining %s setting as string has been deprecated (should be a list)" % 'PLUGIN_PATH') - local_settings['PLUGIN_PATH'] = [local_settings['PLUGIN_PATH']] - else: - if 'PLUGIN_PATH' in local_settings and local_settings['PLUGIN_PATH'] is not None: - local_settings['PLUGIN_PATH'] = [os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), pluginpath))) - if not isabs(pluginpath) else pluginpath for pluginpath in local_settings['PLUGIN_PATH']] + if 'PLUGIN_PATH' in local_settings: + logger.warning('PLUGIN_PATH setting has been replaced by ' + 'PLUGIN_PATHS, moving it to the new setting name.') + local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH'] + del local_settings['PLUGIN_PATH'] + if isinstance(local_settings['PLUGIN_PATHS'], six.string_types): + logger.warning("Defining %s setting as string has been deprecated (should be a list)" % 'PLUGIN_PATHS') + local_settings['PLUGIN_PATHS'] = [local_settings['PLUGIN_PATHS']] + elif local_settings['PLUGIN_PATHS'] is not None: + local_settings['PLUGIN_PATHS'] = [os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), pluginpath))) + if not isabs(pluginpath) else pluginpath for pluginpath in local_settings['PLUGIN_PATHS']] else: local_settings = copy.deepcopy(DEFAULT_CONFIG) From 6aa0e4346de498ada234f772163579e677cfd10b Mon Sep 17 00:00:00 2001 From: Ondrej Grover Date: Wed, 14 May 2014 14:30:21 +0200 Subject: [PATCH 3/3] Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES automatically This makes it easier for someone to change PAGE_PATHS without the need to change ARTICLE_EXCLUDES accordingly. --- docs/settings.rst | 6 ++++-- pelican/settings.py | 16 ++++++++++++++-- pelican/tests/test_settings.py | 5 ++++- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 34245ff4..fd5f488b 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -112,9 +112,11 @@ Setting name (followed by default value, if any) and content path is not specified via an argument to the ``pelican`` command, Pelican will use the current working directory. ``PAGE_PATHS = ['pages']`` A list of directories to look at for pages, relative to ``PATH``. -``PAGE_EXCLUDES = ()`` A list of directories to exclude when looking for pages. +``PAGE_EXCLUDES = []`` A list of directories to exclude when looking for pages in addition + to ``ARTICLE_PATHS``. ``ARTICLE_PATHS = ['']`` A list of directories to look at for articles, relative to ``PATH``. -``ARTICLE_EXCLUDES = ('pages',)`` A list of directories to exclude when looking for articles. +``ARTICLE_EXCLUDES = []`` A list of directories to exclude when looking for articles in addition + to ``PAGE_PATHS``. ``OUTPUT_SOURCES = False`` Set to True if you want to copy the articles and pages in their original format (e.g. Markdown or reStructuredText) to the specified ``OUTPUT_PATH``. diff --git a/pelican/settings.py b/pelican/settings.py index c93050ad..69ade05f 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -30,9 +30,9 @@ DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)), DEFAULT_CONFIG = { 'PATH': os.curdir, 'ARTICLE_PATHS': [''], - 'ARTICLE_EXCLUDES': ('pages',), + 'ARTICLE_EXCLUDES': [], 'PAGE_PATHS': ['pages'], - 'PAGE_EXCLUDES': (), + 'PAGE_EXCLUDES': [], 'THEME': DEFAULT_THEME, 'OUTPUT_PATH': 'output', 'READERS': {}, @@ -348,6 +348,18 @@ def configure_settings(settings): % PATH_KEY) settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY] + # Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES + mutually_exclusive = ('ARTICLE', 'PAGE') + for type_1, type_2 in [mutually_exclusive, mutually_exclusive[::-1]]: + try: + includes = settings[type_1 + '_PATHS'] + excludes = settings[type_2 + '_EXCLUDES'] + for path in includes: + if path not in excludes: + excludes.append(path) + except KeyError: + continue # setting not specified, nothing to do + for old, new, doc in [ ('LESS_GENERATOR', 'the Webassets plugin', None), ('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA', diff --git a/pelican/tests/test_settings.py b/pelican/tests/test_settings.py index 930e0fea..260eff05 100644 --- a/pelican/tests/test_settings.py +++ b/pelican/tests/test_settings.py @@ -43,7 +43,10 @@ class TestSettingsConfiguration(unittest.TestCase): # Providing no file should return the default values. settings = read_settings(None) expected = copy.deepcopy(DEFAULT_CONFIG) - expected['FEED_DOMAIN'] = '' # Added by configure settings + # Added by configure settings + expected['FEED_DOMAIN'] = '' + expected['ARTICLE_EXCLUDES'] = ['pages'] + expected['PAGE_EXCLUDES'] = [''] self.maxDiff = None self.assertDictEqual(settings, expected)