Skip to content

Commit

Permalink
Putting theme paths and not just names into site.THEMES. Removing exp…
Browse files Browse the repository at this point in the history
…licit passing of themes_dirs in several places except where handling theme names is necessary.
  • Loading branch information
felixfontein committed Aug 7, 2016
1 parent 78c59a3 commit 5f61a63
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 47 deletions.
2 changes: 1 addition & 1 deletion docs/extending.txt
Expand Up @@ -351,7 +351,7 @@ And the ``task_copy_assets.py`` file, in its entirety:

tasks = {}
for theme_name in kw['themes']:
src = os.path.join(utils.get_theme_path(theme_name, self.site.themes_dirs), 'assets')
src = os.path.join(utils.get_theme_path(theme_name), 'assets')
dst = os.path.join(kw['output_folder'], 'assets')
for task in utils.copy_tree(src, dst):
if task['name'] in tasks:
Expand Down
5 changes: 5 additions & 0 deletions nikola/conf.py.in
Expand Up @@ -1100,6 +1100,11 @@ UNSLUGIFY_TITLES = True
# repository.
# EXTRA_PLUGINS_DIRS = []

# Add the absolute paths to directories containing themes to use them.
# For example, the `v7` directory of your clone of the Nikola themes
# repository.
# EXTRA_THEMES_DIRS = []

# List of regular expressions, links matching them will always be considered
# valid by "nikola check -l"
# LINK_CHECK_WHITELIST = []
Expand Down
13 changes: 6 additions & 7 deletions nikola/nikola.py
Expand Up @@ -1127,7 +1127,7 @@ def _get_themes(self):
# Check consistency of USE_CDN and the current THEME (Issue #386)
if self.config['USE_CDN'] and self.config['USE_CDN_WARNING']:
bootstrap_path = utils.get_asset_path(os.path.join(
'assets', 'css', 'bootstrap.min.css'), self._THEMES, themes_dirs=self.themes_dirs)
'assets', 'css', 'bootstrap.min.css'), self._THEMES)
if bootstrap_path and bootstrap_path.split(os.sep)[-4] not in ['bootstrap', 'bootstrap3']:
utils.LOGGER.warn('The USE_CDN option may be incompatible with your theme, because it uses a hosted version of bootstrap.')

Expand Down Expand Up @@ -1158,8 +1158,7 @@ def _get_global_context(self):
custom_css_path = utils.get_asset_path(
'assets/css/custom.css',
self.THEMES,
self.config['FILES_FOLDERS'],
themes_dirs=self.themes_dirs
self.config['FILES_FOLDERS']
)
if custom_css_path and self.file_exists(custom_css_path, not_empty=True):
self._GLOBAL_CONTEXT['has_custom_css'] = True
Expand All @@ -1173,15 +1172,15 @@ def _get_global_context(self):
def _get_template_system(self):
if self._template_system is None:
# Load template plugin
template_sys_name = utils.get_template_engine(self.THEMES, self.themes_dirs)
template_sys_name = utils.get_template_engine(self.THEMES)
pi = self.plugin_manager.getPluginByName(
template_sys_name, "TemplateSystem")
if pi is None:
sys.stderr.write("Error loading {0} template system "
"plugin\n".format(template_sys_name))
sys.exit(1)
self._template_system = pi.plugin_object
lookup_dirs = ['templates'] + [os.path.join(utils.get_theme_path(name, self.themes_dirs), "templates")
lookup_dirs = ['templates'] + [os.path.join(utils.get_theme_path(name), "templates")
for name in self.THEMES]
self._template_system.set_directories(lookup_dirs,
self.config['CACHE_FOLDER'])
Expand Down Expand Up @@ -1422,7 +1421,7 @@ def _register_templated_shortcodes(self):
"""Register shortcodes provided by templates in shortcodes/ folders."""
builtin_sc_dir = resource_filename(
'nikola',
os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES, self.themes_dirs)))
os.path.join('data', 'shortcodes', utils.get_template_engine(self.THEMES)))

for sc_dir in [builtin_sc_dir, 'shortcodes']:
if not os.path.isdir(sc_dir):
Expand Down Expand Up @@ -1906,7 +1905,7 @@ def generic_page_renderer(self, lang, post, filters, context=None):
context = context.copy() if context else {}
deps = post.deps(lang) + \
self.template_system.template_deps(post.template_name)
deps.extend(utils.get_asset_path(x, self.THEMES, themes_dirs=self.themes_dirs) for x in ('bundles', 'parent', 'engine'))
deps.extend(utils.get_asset_path(x, self.THEMES) for x in ('bundles', 'parent', 'engine'))
deps = list(filter(None, deps))
context['post'] = post
context['lang'] = lang
Expand Down
2 changes: 1 addition & 1 deletion nikola/plugins/command/auto/__init__.py
Expand Up @@ -158,7 +158,7 @@ def _execute(self, options, args):
# Do not duplicate entries -- otherwise, multiple rebuilds are triggered
watched = set([
'templates/'
] + [get_theme_path(name, self.site.themes_dirs) for name in self.site.THEMES])
] + [get_theme_path(name) for name in self.site.THEMES])
for item in self.site.config['post_pages']:
watched.add(os.path.dirname(item[0]))
for item in self.site.config['FILES_FOLDERS']:
Expand Down
13 changes: 10 additions & 3 deletions nikola/plugins/command/bootswatch_theme.py
Expand Up @@ -36,6 +36,13 @@
LOGGER = utils.get_logger('bootswatch_theme', utils.STDERR_HANDLER)


def _check_for_theme(theme, themes):
for t in themes:
if t.endswith(os.sep + theme):
return True
return False


class CommandBootswatchTheme(Command):
"""Given a swatch name from bootswatch.com and a parent theme, creates a custom theme."""

Expand Down Expand Up @@ -80,11 +87,11 @@ def _execute(self, options, args):

# See if we need bootswatch for bootstrap v2 or v3
themes = utils.get_theme_chain(parent, self.site.themes_dirs)
if 'bootstrap3' not in themes and 'bootstrap3-jinja' not in themes:
if not _check_for_theme('bootstrap3', themes) and not _check_for_theme('bootstrap3-jinja', themes):
version = '2'
elif 'bootstrap' not in themes and 'bootstrap-jinja' not in themes:
elif not _check_for_theme('bootstrap', themes) and not _check_for_theme('bootstrap-jinja', themes):
LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')
elif 'bootstrap3-gradients' in themes or 'bootstrap3-gradients-jinja' in themes:
elif _check_for_theme('bootstrap3-gradients', themes) or _check_for_theme('bootstrap3-gradients-jinja', themes):
LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family')

LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
Expand Down
2 changes: 1 addition & 1 deletion nikola/plugins/command/init.py
Expand Up @@ -360,7 +360,7 @@ def lhandler(default, toconf, show_header=True):
# Assuming that base contains all the locales, and that base does
# not inherit from anywhere.
try:
messages = load_messages(['base'], tr, default)
messages = load_messages(['base'], tr, default, themes_dirs=['themes'])
SAMPLE_CONF['NAVIGATION_LINKS'] = format_navigation_links(langs, default, messages, SAMPLE_CONF['STRIP_INDEXES'])
except nikola.utils.LanguageNotFoundError as e:
print(" ERROR: the language '{0}' is not supported.".format(e.lang))
Expand Down
14 changes: 7 additions & 7 deletions nikola/plugins/command/theme.py
Expand Up @@ -170,11 +170,11 @@ def do_install_deps(self, url, name):
installstatus = self.do_install(name, data)
# See if the theme's parent is available. If not, install it
while True:
parent_name = utils.get_parent_theme_name(name, self.site.themes_dirs)
parent_name = utils.get_parent_theme_name(utils.get_theme_path_real(name, self.site.themes_dirs))
if parent_name is None:
break
try:
utils.get_theme_path(parent_name, self.site.themes_dirs)
utils.get_theme_path_real(parent_name, self.site.themes_dirs)
break
except: # Not available
self.do_install(parent_name, data)
Expand Down Expand Up @@ -204,7 +204,7 @@ def do_install(self, name, data):
else:
dest_path = os.path.join(self.output_dir, name)
try:
theme_path = utils.get_theme_path(name, self.site.themes_dirs)
theme_path = utils.get_theme_path_real(name, self.site.themes_dirs)
LOGGER.error("Theme '{0}' is already installed in {1}".format(name, theme_path))
except Exception:
LOGGER.error("Can't find theme {0}".format(name))
Expand All @@ -227,7 +227,7 @@ def do_install(self, name, data):
def do_uninstall(self, name):
"""Uninstall a theme."""
try:
path = utils.get_theme_path(name, self.site.themes_dirs)
path = utils.get_theme_path_real(name, self.site.themes_dirs)
except Exception:
LOGGER.error('Unknown theme: {0}'.format(name))
return 1
Expand All @@ -243,7 +243,7 @@ def do_uninstall(self, name):
def get_path(self, name):
"""Get path for an installed theme."""
try:
path = utils.get_theme_path(name, self.site.themes_dirs)
path = utils.get_theme_path_real(name, self.site.themes_dirs)
print(path)
except Exception:
print("not installed")
Expand All @@ -268,7 +268,7 @@ def copy_template(self, template):

# Figure out where to put it.
# Check if a local theme exists.
theme_path = utils.get_theme_path(self.site.THEMES[0], self.site.themes_dirs)
theme_path = utils.get_theme_path(self.site.THEMES[0])
if theme_path.startswith('themes' + os.sep):
# Theme in local themes/ directory
base = os.path.join(theme_path, 'templates')
Expand Down Expand Up @@ -297,7 +297,7 @@ def new_theme(self, name, engine, parent):
LOGGER.info("Created directory {0}".format(base))

# Check if engine and parent match
engine_file = utils.get_asset_path('engine', utils.get_theme_chain(parent, self.site.themes_dirs), themes_dirs=self.site.themes_dirs)
engine_file = utils.get_asset_path('engine', utils.get_theme_chain(parent, self.site.themes_dirs))
with io.open(engine_file, 'r', encoding='utf-8') as fh:
parent_engine = fh.read().strip()

Expand Down
7 changes: 3 additions & 4 deletions nikola/plugins/task/bundles.py
Expand Up @@ -60,7 +60,7 @@ def gen_tasks(self):
'filters': self.site.config['FILTERS'],
'output_folder': self.site.config['OUTPUT_FOLDER'],
'cache_folder': self.site.config['CACHE_FOLDER'],
'theme_bundles': get_theme_bundles(self.site.THEMES, self.site.themes_dirs),
'theme_bundles': get_theme_bundles(self.site.THEMES),
'themes': self.site.THEMES,
'files_folders': self.site.config['FILES_FOLDERS'],
'code_color_scheme': self.site.config['CODE_COLOR_SCHEME'],
Expand Down Expand Up @@ -104,7 +104,6 @@ def build_bundle(output, inputs):
fname,
self.site.THEMES,
self.site.config['FILES_FOLDERS'],
themes_dirs=self.site.themes_dirs,
output_dir=kw['output_folder']) or fname == os.path.join('assets', 'css', 'code.css')]
# code.css will be generated by us if it does not exist in
# FILES_FOLDERS or theme assets. It is guaranteed that the
Expand All @@ -126,12 +125,12 @@ def build_bundle(output, inputs):
yield utils.apply_filters(task, kw['filters'])


def get_theme_bundles(themes, themes_dirs):
def get_theme_bundles(themes):
"""Given a theme chain, return the bundle definitions."""
bundles = {}
for theme_name in themes:
bundles_path = os.path.join(
utils.get_theme_path(theme_name, themes_dirs), 'bundles')
utils.get_theme_path(theme_name), 'bundles')
if os.path.isfile(bundles_path):
with open(bundles_path) as fd:
for line in fd:
Expand Down
5 changes: 2 additions & 3 deletions nikola/plugins/task/copy_assets.py
Expand Up @@ -60,12 +60,11 @@ def gen_tasks(self):
code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
code_css_input = utils.get_asset_path('assets/css/code.css',
themes=kw['themes'],
files_folders=kw['files_folders'],
themes_dirs=self.site.themes_dirs, output_dir=None)
files_folders=kw['files_folders'], output_dir=None)
yield self.group_task()

for theme_name in kw['themes']:
src = os.path.join(utils.get_theme_path(theme_name, self.site.themes_dirs), 'assets')
src = os.path.join(utils.get_theme_path(theme_name), 'assets')
dst = os.path.join(kw['output_folder'], 'assets')
for task in utils.copy_tree(src, dst):
if task['name'] in tasks:
Expand Down
2 changes: 1 addition & 1 deletion nikola/plugins/task/robots.py
Expand Up @@ -71,7 +71,7 @@ def write_robots():

yield self.group_task()

if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"], themes_dirs=self.site.themes_dirs, output_dir=False):
if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"], output_dir=False):
yield utils.apply_filters({
"basename": self.name,
"name": robots_path,
Expand Down
43 changes: 24 additions & 19 deletions nikola/utils.py
Expand Up @@ -69,7 +69,7 @@

from nikola import DEBUG

__all__ = ('CustomEncoder', 'get_theme_path', 'get_theme_chain', 'load_messages', 'copy_tree',
__all__ = ('CustomEncoder', 'get_theme_path', 'get_theme_path_real', 'get_theme_chain', 'load_messages', 'copy_tree',
'copy_file', 'slugify', 'unslugify', 'to_datetime', 'apply_filters',
'config_changed', 'get_crumbs', 'get_tzname', 'get_asset_path',
'_reload', 'unicode_str', 'bytes_str', 'unichr', 'Functionary',
Expand Down Expand Up @@ -572,7 +572,7 @@ def __repr__(self):
sort_keys=True))


def get_theme_path(theme, themes_dirs=['themes']):
def get_theme_path_real(theme, themes_dirs):
"""Return the path where the given theme's files are located.
Looks in ./themes and in the place where themes go when installed.
Expand All @@ -587,32 +587,40 @@ def get_theme_path(theme, themes_dirs=['themes']):
raise Exception("Can't find theme '{0}'".format(theme))


def get_template_engine(themes, themes_dirs=['themes']):
def get_theme_path(theme):
"""Return the theme's path, which equals the theme's name."""
return theme


def get_template_engine(themes):
"""Get template engine used by a given theme."""
for theme_name in themes:
engine_path = os.path.join(get_theme_path(theme_name, themes_dirs), 'engine')
engine_path = os.path.join(theme_name, 'engine')
if os.path.isfile(engine_path):
with open(engine_path) as fd:
return fd.readlines()[0].strip()
# default
return 'mako'


def get_parent_theme_name(theme_name, themes_dirs=['themes']):
def get_parent_theme_name(theme_name, themes_dirs=None):
"""Get name of parent theme."""
parent_path = os.path.join(get_theme_path(theme_name, themes_dirs), 'parent')
parent_path = os.path.join(theme_name, 'parent')
if os.path.isfile(parent_path):
with open(parent_path) as fd:
return fd.readlines()[0].strip()
parent = fd.readlines()[0].strip()
if themes_dirs:
return get_theme_path_real(parent, themes_dirs)
return parent
return None


def get_theme_chain(theme, themes_dirs=['themes']):
"""Create the full theme inheritance chain."""
themes = [theme]
def get_theme_chain(theme, themes_dirs):
"""Create the full theme inheritance chain including paths."""
themes = [get_theme_path_real(theme, themes_dirs)]

while True:
parent = get_parent_theme_name(themes[-1], themes_dirs)
parent = get_parent_theme_name(themes[-1], themes_dirs=themes_dirs)
# Avoid silly loops
if parent is None or parent in themes:
break
Expand All @@ -636,7 +644,7 @@ def __str__(self):
return 'cannot find language {0}'.format(self.lang)


def load_messages(themes, translations, default_lang, themes_dirs=['themes']):
def load_messages(themes, translations, default_lang, themes_dirs):
"""Load theme's messages into context.
All the messages from parent themes are loaded,
Expand All @@ -645,8 +653,8 @@ def load_messages(themes, translations, default_lang, themes_dirs=['themes']):
messages = Functionary(dict, default_lang)
oldpath = list(sys.path)
for theme_name in themes[::-1]:
msg_folder = os.path.join(get_theme_path(theme_name, themes_dirs), 'messages')
default_folder = os.path.join(get_theme_path('base', themes_dirs), 'messages')
msg_folder = os.path.join(get_theme_path(theme_name), 'messages')
default_folder = os.path.join(get_theme_path_real('base', themes_dirs), 'messages')
sys.path.insert(0, default_folder)
sys.path.insert(0, msg_folder)
english = __import__('messages_en')
Expand Down Expand Up @@ -979,7 +987,7 @@ def get_crumbs(path, is_file=False, index_folder=None, lang=None):
return list(reversed(_crumbs))


def get_asset_path(path, themes, files_folders={'files': ''}, themes_dirs=['themes'], output_dir='output'):
def get_asset_path(path, themes, files_folders={'files': ''}, output_dir='output'):
"""Return the "real", absolute path to the asset.
By default, it checks which theme provides the asset.
Expand All @@ -1005,10 +1013,7 @@ def get_asset_path(path, themes, files_folders={'files': ''}, themes_dirs=['them
"""
for theme_name in themes:
candidate = os.path.join(
get_theme_path(theme_name, themes_dirs),
path
)
candidate = os.path.join(get_theme_path(theme_name), path)
if os.path.isfile(candidate):
return candidate
for src, rel_dst in files_folders.items():
Expand Down

0 comments on commit 5f61a63

Please sign in to comment.