Merge pull request #1322 from smartass101/get_files_multiple_paths

move {ARTICLE,PAGE}_DIR -> {ARTICLE,PAGE}_PATHS and correlate with {ARTICLE,PAGE}_EXCLUDES
This commit is contained in:
Justin Mayer 2014-06-25 07:29:22 -07:00
commit 2432a22400
7 changed files with 92 additions and 60 deletions

View file

@ -21,10 +21,10 @@ Alternatively, another method is to import them and add them to the list::
PLUGINS = [myplugin,] PLUGINS = [myplugin,]
If your plugins are not in an importable path, you can specify a list of paths 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 via the ``PLUGIN_PATHS`` setting. As shown in the following example, paths in
the ``PLUGIN_PATH`` list can be absolute or relative to the settings file:: 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"] PLUGINS = ["assets", "liquid_tags", "sitemap"]
Where to find plugins Where to find plugins

View file

@ -111,10 +111,12 @@ Setting name (followed by default value, if any)
``PATH`` Path to content directory to be processed by Pelican. If undefined, ``PATH`` Path to content directory to be processed by Pelican. If undefined,
and content path is not specified via an argument to the ``pelican`` and content path is not specified via an argument to the ``pelican``
command, Pelican will use the current working directory. 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. ``PAGE_EXCLUDES = []`` A list of directories to exclude when looking for pages in addition
``ARTICLE_DIR = ''`` Directory to look at for articles, relative to ``PATH``. to ``ARTICLE_PATHS``.
``ARTICLE_EXCLUDES = ('pages',)`` A list of directories to exclude when looking for articles. ``ARTICLE_PATHS = ['']`` A list of directories to look at for articles, relative to ``PATH``.
``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 ``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 original format (e.g. Markdown or reStructuredText) to the
specified ``OUTPUT_PATH``. specified ``OUTPUT_PATH``.
@ -125,6 +127,7 @@ Setting name (followed by default value, if any)
not. Only set this to ``True`` when developing/testing and only not. Only set this to ``True`` when developing/testing and only
if you fully understand the effect it can have on links/feeds. if you fully understand the effect it can have on links/feeds.
``PLUGINS = []`` The list of plugins to load. See :ref:`plugins`. ``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 ``SITENAME = 'A Pelican Blog'`` Your site name
``SITEURL`` Base URL of your website. Not defined by default, ``SITEURL`` Base URL of your website. Not defined by default,
so it is best to specify your SITEURL; if you do not, feeds so it is best to specify your SITEURL; if you do not, feeds

View file

@ -63,9 +63,9 @@ class Pelican(object):
def init_plugins(self): def init_plugins(self):
self.plugins = [] self.plugins = []
logger.debug('Temporarily adding PLUGIN_PATH to system path') logger.debug('Temporarily adding PLUGIN_PATHS to system path')
_sys_path = sys.path[:] _sys_path = sys.path[:]
for pluginpath in self.settings['PLUGIN_PATH']: for pluginpath in self.settings['PLUGIN_PATHS']:
sys.path.insert(0, pluginpath) sys.path.insert(0, pluginpath)
for plugin in self.settings['PLUGINS']: for plugin in self.settings['PLUGINS']:
# if it's a string, then import it # if it's a string, then import it

View file

@ -110,29 +110,30 @@ class Generator(object):
return True return True
return False 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 """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 exclude: the list of path to exclude
:param extensions: the list of allowed extensions (if False, all :param extensions: the list of allowed extensions (if False, all
extensions are allowed) extensions are allowed)
""" """
files = [] files = []
root = os.path.join(self.path, path) for path in paths:
root = os.path.join(self.path, path)
if os.path.isdir(root): if os.path.isdir(root):
for dirpath, dirs, temp_files in os.walk(root, followlinks=True): for dirpath, dirs, temp_files in os.walk(root, followlinks=True):
for e in exclude: for e in exclude:
if e in dirs: if e in dirs:
dirs.remove(e) dirs.remove(e)
reldir = os.path.relpath(dirpath, self.path) reldir = os.path.relpath(dirpath, self.path)
for f in temp_files: for f in temp_files:
fp = os.path.join(reldir, f) fp = os.path.join(reldir, f)
if self._include_path(fp, extensions): if self._include_path(fp, extensions):
files.append(fp) files.append(fp)
elif os.path.exists(root) and self._include_path(path, extensions): elif os.path.exists(root) and self._include_path(path, extensions):
files.append(path) # can't walk non-directories files.append(path) # can't walk non-directories
return files return files
def add_source_path(self, content): def add_source_path(self, content):
@ -462,7 +463,7 @@ class ArticlesGenerator(CachingGenerator):
all_articles = [] all_articles = []
all_drafts = [] all_drafts = []
for f in self.get_files( for f in self.get_files(
self.settings['ARTICLE_DIR'], self.settings['ARTICLE_PATHS'],
exclude=self.settings['ARTICLE_EXCLUDES']): exclude=self.settings['ARTICLE_EXCLUDES']):
article = self.get_cached_data(f, None) article = self.get_cached_data(f, None)
if article is None: if article is None:
@ -586,7 +587,7 @@ class PagesGenerator(CachingGenerator):
all_pages = [] all_pages = []
hidden_pages = [] hidden_pages = []
for f in self.get_files( for f in self.get_files(
self.settings['PAGE_DIR'], self.settings['PAGE_PATHS'],
exclude=self.settings['PAGE_EXCLUDES']): exclude=self.settings['PAGE_EXCLUDES']):
page = self.get_cached_data(f, None) page = self.get_cached_data(f, None)
if page is None: if page is None:
@ -660,20 +661,17 @@ class StaticGenerator(Generator):
def generate_context(self): def generate_context(self):
self.staticfiles = [] self.staticfiles = []
for f in self.get_files(self.settings['STATIC_PATHS'],
# walk static paths extensions=False):
for static_path in self.settings['STATIC_PATHS']: static = self.readers.read_file(
for f in self.get_files( base_path=self.path, path=f, content_class=Static,
static_path, extensions=False): fmt='static', context=self.context,
static = self.readers.read_file( preread_signal=signals.static_generator_preread,
base_path=self.path, path=f, content_class=Static, preread_sender=self,
fmt='static', context=self.context, context_signal=signals.static_generator_context,
preread_signal=signals.static_generator_preread, context_sender=self)
preread_sender=self, self.staticfiles.append(static)
context_signal=signals.static_generator_context, self.add_source_path(static)
context_sender=self)
self.staticfiles.append(static)
self.add_source_path(static)
self._update_context(('staticfiles',)) self._update_context(('staticfiles',))
signals.static_generator_finalized.send(self) signals.static_generator_finalized.send(self)

View file

@ -29,10 +29,10 @@ DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'themes', 'notmyidea') 'themes', 'notmyidea')
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
'PATH': os.curdir, 'PATH': os.curdir,
'ARTICLE_DIR': '', 'ARTICLE_PATHS': [''],
'ARTICLE_EXCLUDES': ('pages',), 'ARTICLE_EXCLUDES': [],
'PAGE_DIR': 'pages', 'PAGE_PATHS': ['pages'],
'PAGE_EXCLUDES': (), 'PAGE_EXCLUDES': [],
'THEME': DEFAULT_THEME, 'THEME': DEFAULT_THEME,
'OUTPUT_PATH': 'output', 'OUTPUT_PATH': 'output',
'READERS': {}, 'READERS': {},
@ -113,7 +113,7 @@ DEFAULT_CONFIG = {
'ARTICLE_PERMALINK_STRUCTURE': '', 'ARTICLE_PERMALINK_STRUCTURE': '',
'TYPOGRIFY': False, 'TYPOGRIFY': False,
'SUMMARY_MAX_LENGTH': 50, 'SUMMARY_MAX_LENGTH': 50,
'PLUGIN_PATH': [], 'PLUGIN_PATHS': [],
'PLUGINS': [], 'PLUGINS': [],
'PYGMENTS_RST_OPTIONS': {}, 'PYGMENTS_RST_OPTIONS': {},
'TEMPLATE_PAGES': {}, 'TEMPLATE_PAGES': {},
@ -146,13 +146,17 @@ def read_settings(path=None, override=None):
if p not in ('THEME') or os.path.exists(absp): if p not in ('THEME') or os.path.exists(absp):
local_settings[p] = absp local_settings[p] = absp
if isinstance(local_settings['PLUGIN_PATH'], six.string_types): if 'PLUGIN_PATH' in local_settings:
logger.warning("Defining %s setting as string has been deprecated (should be a list)" % 'PLUGIN_PATH') logger.warning('PLUGIN_PATH setting has been replaced by '
local_settings['PLUGIN_PATH'] = [local_settings['PLUGIN_PATH']] 'PLUGIN_PATHS, moving it to the new setting name.')
else: local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH']
if 'PLUGIN_PATH' in local_settings and local_settings['PLUGIN_PATH'] is not None: del local_settings['PLUGIN_PATH']
local_settings['PLUGIN_PATH'] = [os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), pluginpath))) if isinstance(local_settings['PLUGIN_PATHS'], six.string_types):
if not isabs(pluginpath) else pluginpath for pluginpath in local_settings['PLUGIN_PATH']] 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: else:
local_settings = copy.deepcopy(DEFAULT_CONFIG) local_settings = copy.deepcopy(DEFAULT_CONFIG)
@ -310,6 +314,16 @@ def configure_settings(settings):
key=lambda r: r[0], 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 # Save people from accidentally setting a string rather than a list
path_keys = ( path_keys = (
'ARTICLE_EXCLUDES', 'ARTICLE_EXCLUDES',
@ -323,13 +337,27 @@ def configure_settings(settings):
'PLUGINS', 'PLUGINS',
'STATIC_PATHS', 'STATIC_PATHS',
'THEME_STATIC_PATHS', 'THEME_STATIC_PATHS',
'ARTICLE_PATHS',
'PAGE_PATHS',
) )
for PATH_KEY in filter(lambda k: k in settings, path_keys): for PATH_KEY in filter(lambda k: k in settings, path_keys):
if isinstance(settings[PATH_KEY], six.string_types): if isinstance(settings[PATH_KEY], six.string_types):
logger.warning("Detected misconfiguration with %s setting " logger.warning("Detected misconfiguration with %s setting "
"(must be a list), falling back to the default" "(must be a list), falling back to the default"
% PATH_KEY) % PATH_KEY)
settings[PATH_KEY] = DEFAULT_CONFIG[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 [ for old, new, doc in [
('LESS_GENERATOR', 'the Webassets plugin', None), ('LESS_GENERATOR', 'the Webassets plugin', None),

View file

@ -373,8 +373,8 @@ class TestPageGenerator(unittest.TestCase):
def test_generate_context(self): def test_generate_context(self):
settings = get_settings(filenames={}) settings = get_settings(filenames={})
settings['PAGE_DIR'] = 'TestPages' # relative to CUR_DIR
settings['CACHE_PATH'] = self.temp_cache settings['CACHE_PATH'] = self.temp_cache
settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR
settings['DEFAULT_DATE'] = (1970, 1, 1) settings['DEFAULT_DATE'] = (1970, 1, 1)
generator = PagesGenerator( generator = PagesGenerator(

View file

@ -43,7 +43,10 @@ class TestSettingsConfiguration(unittest.TestCase):
# Providing no file should return the default values. # Providing no file should return the default values.
settings = read_settings(None) settings = read_settings(None)
expected = copy.deepcopy(DEFAULT_CONFIG) 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.maxDiff = None
self.assertDictEqual(settings, expected) self.assertDictEqual(settings, expected)