Files
libkiwix/scripts/kiwix-resources
Veloman Yunkan 3b9f28b2b5 Applied cache-id to search_results.css
The story of search_results.css

static/skin/search_results.css was extracted from
static/templates/no_search_result.html before the latter was dropped.

static/templates/no_search_result.html in turn seems to be a copied and
edited version of static/templates/search_result.html.

In the context of exploratory work on the internationalization of
kiwix-serve (PR #679) I noticed duplication of inline CSS across those
two templates and intended to eliminated it. That goal was not fully
accomplished (static/templates/search_result.html remained untouched)
because by that time PR #679 grew too big and the efforts were diverted
into splitting it into smaller ones. Thus search_results.css slipped
into one of those small PRs, without making much sense because nothing
really justifies preserving custom CSS in the "Fulltext search unavailable"
error page.

At the same time, it served as the only case where a link to a cacheable
resource is generated in C++ code (rather than found in a template).
This poses certain problems to the handling of cache-ids. A workaround
is to expel the URL into a template so that it is processed by
`kiwix-resources`. This commit merely demonstrates that solution. But
whether it should be preserved (or rather the "Fulltext search
unavailable" page should be deprived of CSS) is questionable.
2022-05-02 20:37:22 +04:00

117 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
'''
Copyright 2022 Veloman Yunkan <veloman.yunkan@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or any
later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
'''
import argparse
import hashlib
import os.path
import re
def read_resource_file(resource_file_path):
with open(resource_file_path, 'r') as f:
return [line.strip() for line in f]
def list_resources(resource_file_path):
for resource_path in read_resource_file(resource_file_path):
print(resource_path)
def get_resource_revision(base_dir, resource_path):
with open(os.path.join(base_dir, resource_path), 'rb') as f:
return hashlib.sha1(f.read()).hexdigest()[:8]
resource_revisions = {}
def fill_resource_revisions(resource_file_path):
base_dir = os.path.dirname(os.path.realpath(resource_file_path))
for resource in read_resource_file(resource_file_path):
resource_revisions[resource] = get_resource_revision(base_dir, resource)
RESOURCE_WITH_CACHEID_URL_PATTERN=r'([^"?]+)\?KIWIXCACHEID([^"]*)'
def set_cacheid(resource_matchobj):
path = resource_matchobj.group(1)
resource = path
root_prefix = '{{root}}/'
if resource.startswith(root_prefix):
resource = resource[len(root_prefix):]
extra_query = resource_matchobj.group(2)
cacheid = 'cacheid=' + resource_revisions[resource]
return f'{path}?{cacheid}{extra_query}'
def preprocess_line(line):
if 'KIWIXCACHEID' in line:
line = re.sub(RESOURCE_WITH_CACHEID_URL_PATTERN, set_cacheid, line)
assert not 'KIWIXCACHEID' in line
return line
def preprocess_template(srcpath, dstpath):
preprocessed_lines = []
with open(srcpath, 'r') as source:
for line in source:
preprocessed_lines.append(preprocess_line(line))
with open(dstpath, 'w') as target:
print("".join(preprocessed_lines), end='', file=target)
def symlink_resource(src, resource_path):
if os.path.exists(resource_path):
if os.path.islink(resource_path) and os.readlink(resource_path) == src:
return
os.remove(resource_path)
os.symlink(src, resource_path)
def preprocess_resource(srcdir, resource_path, outdir):
resource_dir = os.path.dirname(resource_path)
if resource_dir != '':
os.makedirs(os.path.join(outdir, resource_dir), exist_ok=True)
srcpath = os.path.join(srcdir, resource_path)
outpath = os.path.join(outdir, resource_path)
if resource_path.startswith('templates/'):
preprocess_template(srcpath, outpath)
else:
symlink_resource(srcpath, outpath)
def copy_file(src_path, dst_path):
with open(src_path, 'rb') as src:
with open(dst_path, 'wb') as dst:
dst.write(src.read())
def preprocess_resources(resource_file_path, outdir):
base_dir = os.path.dirname(os.path.realpath(resource_file_path))
resource_filename = os.path.basename(resource_file_path)
for resource in read_resource_file(resource_file_path):
preprocess_resource(base_dir, resource, outdir)
copy_file(resource_file_path, os.path.join(outdir, resource_filename))
if __name__ == "__main__":
parser = argparse.ArgumentParser()
commands = parser.add_mutually_exclusive_group()
commands.add_argument('--list-all', action='store_true')
commands.add_argument('--preprocess', action='store_true')
parser.add_argument('--outdir')
parser.add_argument('resource_file')
args = parser.parse_args()
if args.list_all:
list_resources(args.resource_file)
elif args.preprocess:
fill_resource_revisions(args.resource_file)
preprocess_resources(args.resource_file, args.outdir)