From 90058697439ee3f048f0f42b61ca5ea677e9b5cc Mon Sep 17 00:00:00 2001 From: Starfall Date: Tue, 5 Dec 2023 09:59:19 -0600 Subject: strike: merge as subdir --- strike/CONTRIBUTING | 10 +++++ strike/README | 56 +++++++++++++++++++++++++ strike/sample/blog/also-exclude.html | 1 + strike/sample/blog/empty.html | 0 strike/sample/blog/exclude.html | 1 + strike/sample/blog/happy.html | 1 + strike/sample/blog/subdir/index.html | 1 + strike/sample/blog/with-frontmatter.html | 6 +++ strike/sample/html/empty.html | 14 +++++++ strike/sample/html/happy.html | 15 +++++++ strike/sample/html/subdir/index.html | 15 +++++++ strike/sample/html/with-frontmatter.html | 17 ++++++++ strike/sample/strike.ini | 19 +++++++++ strike/sample/template.html | 14 +++++++ strike/strike.py | 70 ++++++++++++++++++++++++++++++++ 15 files changed, 240 insertions(+) create mode 100644 strike/CONTRIBUTING create mode 100644 strike/README create mode 100644 strike/sample/blog/also-exclude.html create mode 100644 strike/sample/blog/empty.html create mode 100644 strike/sample/blog/exclude.html create mode 100644 strike/sample/blog/happy.html create mode 100644 strike/sample/blog/subdir/index.html create mode 100644 strike/sample/blog/with-frontmatter.html create mode 100644 strike/sample/html/empty.html create mode 100644 strike/sample/html/happy.html create mode 100644 strike/sample/html/subdir/index.html create mode 100644 strike/sample/html/with-frontmatter.html create mode 100644 strike/sample/strike.ini create mode 100644 strike/sample/template.html create mode 100644 strike/strike.py (limited to 'strike') diff --git a/strike/CONTRIBUTING b/strike/CONTRIBUTING new file mode 100644 index 0000000..2f2508f --- /dev/null +++ b/strike/CONTRIBUTING @@ -0,0 +1,10 @@ +Patches are accepted via email or Matrix DM (check https://starfall.systems/contact for the latest information). + +If anyone actually contributes, feel free to suggest a license change with the first patch. Check https://git.starfall.systems/www-starfall-systems/tree/COPYING.md for our thoughts - AGPL or MPL is probably fine. + +PATCH CHECKLIST +--------------- +* Code style matches everything else (PEP8 compliance is suggested but not required as I've already decided to indent with tabs, feel free to go to 90-110 character lines as appropriate) +* Documentation updated to describe new behavior +* Example case(s) written in sample/blog +* `./strike.py sample` run and output in sample/html looks as expected (you can use `git diff` to verify nothing except last-modified lines are changed) diff --git a/strike/README b/strike/README new file mode 100644 index 0000000..dd6448e --- /dev/null +++ b/strike/README @@ -0,0 +1,56 @@ + _____ __ _ __ + / ___// /______(_) /_____ + \__ \/ __/ ___/ / //_/ _ \ + ___/ / /_/ / / / ,< / __/ +/____/\__/_/ /_/_/|_|\___/ +============================ + +A static site generator that does exactly what we need it to and no more. + +(c) 2021 Starfall , all rights reserved until I decide it's in a good enough state for others to use. + +Strike has simple goals: +1. Read HTML page contents from files in the source folder +2. Add boilerplate (head, header, footer, etc) +3. Save to output folder + +And some stretch goals: + * Create an extra page listing all generated pages in order of creation date (newest first) + * As above, but as an RSS feed + * Add links to next & previous generated pages + * Turn the extra page into a flexible component that can be added into any other page + * Use different templates on different files + * Markup parsing (see below) + * More robust created/modified date handling - needs more specification (markup changes vs. template changes, caching original creation date because posix systems don't actually provide that, etc.) + +strike.ini file +--------------- + +Strike should be passed the location of a .ini file or a directory containing a file named strike.ini. This is a text file in Python's configparser format (for now). You can see an example config file with all supported options at sample/strike.ini. + +Markup +------ + +TBD. No markup is used at the moment. + +reStructuredText fulfills most of our desires: https://docutils.sourceforge.io/rst.html +It generates
s and has specific markup for page titles. + +Templating +---------- + +TBD. + +Right now, templates are just passed to Python's str.format(). You can use these variables by default: + +{content} : Complete file contents. +{meta[title]} : Filename, with extension dropped. +{meta[date]} : File modification date, in HTTP header format (e.g. "Sat, 23 Oct 2021 18:28:37 GMT") + +Front matter +------------ + +* Front matter is indicated by starting a file with a line that contains exactly three dashes and nothing else ("---\n"). +* Front matter is closed by another line that containts exactly three dashes and nothing else. +* Every line between the opening and closing line should be key=value pairs. +* Front matter is stored into the 'meta' dict, so you can overwrite meta[title] or meta[date] if you want to. diff --git a/strike/sample/blog/also-exclude.html b/strike/sample/blog/also-exclude.html new file mode 100644 index 0000000..6ce0fb1 --- /dev/null +++ b/strike/sample/blog/also-exclude.html @@ -0,0 +1 @@ +This file shouldn't be processed by Strike either. diff --git a/strike/sample/blog/empty.html b/strike/sample/blog/empty.html new file mode 100644 index 0000000..e69de29 diff --git a/strike/sample/blog/exclude.html b/strike/sample/blog/exclude.html new file mode 100644 index 0000000..d881dce --- /dev/null +++ b/strike/sample/blog/exclude.html @@ -0,0 +1 @@ +This file should be excluded from processing when Strike is processed using strike.ini diff --git a/strike/sample/blog/happy.html b/strike/sample/blog/happy.html new file mode 100644 index 0000000..af5626b --- /dev/null +++ b/strike/sample/blog/happy.html @@ -0,0 +1 @@ +Hello, world! diff --git a/strike/sample/blog/subdir/index.html b/strike/sample/blog/subdir/index.html new file mode 100644 index 0000000..b66efd5 --- /dev/null +++ b/strike/sample/blog/subdir/index.html @@ -0,0 +1 @@ +This file in a subdirectory of the input directory should also be processed. diff --git a/strike/sample/blog/with-frontmatter.html b/strike/sample/blog/with-frontmatter.html new file mode 100644 index 0000000..5195292 --- /dev/null +++ b/strike/sample/blog/with-frontmatter.html @@ -0,0 +1,6 @@ +--- +title=Custom Title +--- +Things before this line should not appear in the output. +--- +Including the delimiter in body content shouldn't be an issue. diff --git a/strike/sample/html/empty.html b/strike/sample/html/empty.html new file mode 100644 index 0000000..b1a01ea --- /dev/null +++ b/strike/sample/html/empty.html @@ -0,0 +1,14 @@ + + +empty + + + + + +
+ +
+
+

This page was generated by Strike. +

diff --git a/strike/sample/html/happy.html b/strike/sample/html/happy.html new file mode 100644 index 0000000..9f4b32f --- /dev/null +++ b/strike/sample/html/happy.html @@ -0,0 +1,15 @@ + + +happy + + + + + +
+ Hello, world! + +
+
+

This page was generated by Strike. +

diff --git a/strike/sample/html/subdir/index.html b/strike/sample/html/subdir/index.html new file mode 100644 index 0000000..bdeaad0 --- /dev/null +++ b/strike/sample/html/subdir/index.html @@ -0,0 +1,15 @@ + + +index + + + + + +
+ This file in a subdirectory of the input directory should also be processed. + +
+
+

This page was generated by Strike. +

diff --git a/strike/sample/html/with-frontmatter.html b/strike/sample/html/with-frontmatter.html new file mode 100644 index 0000000..99627a1 --- /dev/null +++ b/strike/sample/html/with-frontmatter.html @@ -0,0 +1,17 @@ + + +Custom Title + + + + + +
+ Things before this line should not appear in the output. +--- +Including the delimiter in body content shouldn't be an issue. + +
+
+

This page was generated by Strike. +

diff --git a/strike/sample/strike.ini b/strike/sample/strike.ini new file mode 100644 index 0000000..86bc8c3 --- /dev/null +++ b/strike/sample/strike.ini @@ -0,0 +1,19 @@ +[Input] +# Directory with all of the markup files that you want Strike to process. +# Location should be relative to this config file. +directory = blog +# Files in the input directory to exclude. +# Location should be relative to the default input directory. +excludes = exclude.html + also-exclude.html + +[Templates] +# For now, Strike only supports using a single template, named default. +default = template.html + +[Output] +# Directory to put the output into. +directory = html + +# That's all for now. In the future, we hope to allow the use of multiple templates, +# letting you choose individual directories and files for each template. diff --git a/strike/sample/template.html b/strike/sample/template.html new file mode 100644 index 0000000..2552906 --- /dev/null +++ b/strike/sample/template.html @@ -0,0 +1,14 @@ + + +{meta[title]} + + + + + +
+ {content} +
+ diff --git a/strike/strike.py b/strike/strike.py new file mode 100644 index 0000000..03d991e --- /dev/null +++ b/strike/strike.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +import os +from time import gmtime, strftime +from argparse import ArgumentParser +from configparser import ConfigParser +from pathlib import Path + +def handle_args(): + parser = ArgumentParser() + parser.add_argument('config', help='location of strike.ini file (or a directory containing it)') + return parser.parse_args() + +def read_config(location): + location = Path(location) + config = ConfigParser() + if location.is_dir(): + location = location/'strike.ini' + if not location.exists(): + raise FileNotFoundError(f'Config file not found at {location}.') + config.read(location) + return location.resolve().parent, config + +def handle_file(file): + meta = dict( + title = file.stem, + date = strftime('%a, %d %b %Y %H:%M:%S GMT', gmtime(file.stat().st_mtime)) + ) + contents = file.read_text() + delim = '---\n' + if contents.startswith(delim): + parts = contents.split(delim, maxsplit=2) + meta.update(dict((key.strip(), value.strip()) + for key, value in (line.split('=') for line in parts[1].splitlines()) + )) + contents = parts[2] + return contents, meta + +def apply_template(content, meta, template="{content}"): + return template.format( + content = content, + meta = meta + ) + +def main(): + args = handle_args() + basedir, config = read_config(args.config) + + input_dir = basedir/config['Input']['directory'] + + try: exclusions = config['Input']['excludes'].splitlines() + except KeyError: exclusions = {} + + default_template = basedir/config['Templates']['default'] + template = default_template.read_text() + + output_dir = basedir/config['Output']['directory'] + + for path, _, files in os.walk(input_dir): + loc = os.path.relpath(path, input_dir) + (output_dir/loc).mkdir(parents=True, exist_ok=True) + for file in files: + if file in exclusions: + continue + contents, meta = handle_file(input_dir/loc/file) + output = apply_template(contents, meta, template) + (output_dir/loc/file).write_text(output) + +if __name__ == '__main__': + import sys + sys.exit(main()) -- cgit