search/search.py

124 lines
3.8 KiB
Python
Raw Normal View History

"""
Search
======
A Pelican plugin to generate an index for static site searches.
Copyright (c) Justin Mayer
"""
from codecs import open
from inspect import cleandoc
from json import dumps
import logging
import os.path
from shutil import which
import subprocess
from jinja2.filters import do_striptags as striptags
from pelican import signals
logger = logging.getLogger(__name__)
class SearchSettingsGenerator:
def __init__(self, context, settings, path, theme, output_path, *null):
self.output_path = output_path
self.context = context
self.content = settings.get("PATH")
self.tpages = settings.get("TEMPLATE_PAGES")
self.search_mode = settings.get("SEARCH_MODE", "output")
self.html_selector = settings.get("SEARCH_HTML_SELECTOR", "main")
def build_search_index(self, search_settings_path):
if not which("stork"):
raise Exception("Stork must be installed and available on $PATH.")
try:
output = subprocess.run(
[
"stork",
"build",
"--input",
search_settings_path,
"--output",
f"{self.output_path}/search-index.st",
],
capture_output=True,
encoding="utf-8",
check=True,
)
except subprocess.CalledProcessError as e:
raise Exception("".join(["Search plugin reported ", e.stdout, e.stderr]))
return output.stdout
def generate_output(self, writer):
search_settings_path = os.path.join(self.output_path, "search.toml")
pages = self.context["pages"] + self.context["articles"]
for article in self.context["articles"]:
pages += article.translations
input_files = ""
# Generate list of articles and pages to index
for page in pages:
if self.search_mode == "output":
page_to_index = page.save_as
if self.search_mode == "source":
page_to_index = page.relative_source_path
input_file = f"""
[[input.files]]
path = "{page_to_index}"
url = "/{page.url}"
title = {dumps(striptags(page.title))}
"""
input_files = "".join([input_files, input_file])
# Generate list of *template* pages to index (if any)
for tpage in self.tpages:
if self.search_mode == "output":
tpage_to_index = self.tpages[tpage]
if self.search_mode == "source":
tpage_to_index = tpage
input_file = f"""
[[input.files]]
path = "{tpage_to_index}"
url = "{self.tpages[tpage]}"
title = ""
"""
input_files = "".join([input_files, input_file])
# Assemble the search settings file
if self.search_mode == "output":
base_dir = self.output_path
if self.search_mode == "source":
base_dir = self.content
search_settings = cleandoc(
f"""
[input]
base_directory = "{base_dir}"
html_selector = "{self.html_selector}"
{input_files}
"""
)
# Write the search settings file to disk
with open(search_settings_path, "w", encoding="utf-8") as fd:
fd.write(search_settings)
# Build the search index
build_log = self.build_search_index(search_settings_path)
build_log = "".join(["Search plugin reported ", build_log])
logger.error(build_log) if "error" in build_log else logger.debug(build_log)
def get_generators(generators):
return SearchSettingsGenerator
def register():
signals.get_generators.connect(get_generators)