From d88466f28e7d603a0c61e6e20c62d7ee05238320 Mon Sep 17 00:00:00 2001 From: gurkenhabicht Date: Tue, 23 Dec 2025 01:42:46 +0100 Subject: [PATCH] changed to package --- Dockerfile | 20 +--- freezer.py | 30 ++++- pyproject.toml | 4 +- scripts/patch_flask_frozen.py | 5 +- start_site.py => start_site.bkp | 0 start_site/__init__.py | 189 ++++++++++++++++++++++++++++++++ 6 files changed, 224 insertions(+), 24 deletions(-) rename start_site.py => start_site.bkp (100%) create mode 100644 start_site/__init__.py diff --git a/Dockerfile b/Dockerfile index f000b86..97781f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,11 +4,7 @@ FROM python:3.11.0-alpine AS builder RUN apk add --no-cache \ - # python3 \ - # py3-pip \ - git \ - # build-base \ - # curl + git ENV POETRY_VERSION=2.2.0 RUN pip install --no-cache-dir "poetry==$POETRY_VERSION" # --break-system-packages is not needed @@ -18,24 +14,18 @@ ENV POETRY_NO_INTERACTION=1 WORKDIR /app RUN git clone https://git.stefan.works/stefan/website.git . -RUN poetry install --only main ## --no-root +RUN poetry install --only main # --no-root + +RUN poetry run python -m scripts.patch_flask_frozen -# RUN poetry run python -m scripts/patch_flask_frozen -RUN poetry run patch-frozen RUN poetry run python freezer.py # ---------------------------- # Runtime stage # ---------------------------- -FROM alpine:3.20 - -RUN apk add --no-cache nginx - -RUN rm -rf /usr/share/nginx/html/* \ - && mkdir -p /run/nginx +FROM nginx:alpine COPY --from=builder /app/build /usr/share/nginx/html -COPY container-nginx.conf /etc/nginx/nginx.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] diff --git a/freezer.py b/freezer.py index 382997f..69942c9 100755 --- a/freezer.py +++ b/freezer.py @@ -1,13 +1,31 @@ -from flask_frozen import Freezer from start_site import app -freezer = Freezer(app) +# Runtime patch for Flask >= 2.3 -#@freezer.register_generator -#def errorhandler(): -# yield "/404" +import flask_frozen + +if not hasattr(flask_frozen.Freezer, "_original_generate_all_urls"): + flask_frozen.Freezer._original_generate_all_urls = flask_frozen.Freezer._generate_all_urls + + def _patched_generate_all_urls(self): + if not hasattr(self.app.url_map, "charset"): + setattr(self.app.url_map, "charset", "utf-8") + + return self._original_generate_all_urls() + + flask_frozen.Freezer._generate_all_urls = _patched_generate_all_urls + + +from flask_frozen import Freezer +# from start_site import app + +freezer = Freezer(app) + +# @freezer.register_generator +# def errorhandler(): +# yield "/404" if __name__ == '__main__': freezer.freeze() - #freezer.run(debug=True) +# #freezer.run(debug=True) diff --git a/pyproject.toml b/pyproject.toml index 397fb79..08ee23d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,9 @@ [tool.poetry] name = "website" version = "0.1.0" +packages = [ + { include = "start_site" } +] description = "Stefan's Blog" authors = ["stefan "] readme = "README.md" @@ -17,7 +20,6 @@ Pygments = "^2.12.0" python-markdown-math = "*" toml = "*" - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/scripts/patch_flask_frozen.py b/scripts/patch_flask_frozen.py index f27141e..6197cff 100644 --- a/scripts/patch_flask_frozen.py +++ b/scripts/patch_flask_frozen.py @@ -1,6 +1,5 @@ from pathlib import Path - def patch_flask_frozen(): try: import flask_frozen @@ -23,7 +22,8 @@ def patch_flask_frozen(): for i, line in enumerate(lines): if "url_encoding = self.app.url_map.charset" in line: - lines[i] = " url_encoding = 'utf-8' # patched charset\n" + indent = line[: len(line) - len(line.lstrip())] + lines[i] = f"{indent}url_encoding = getattr(self.app.url_map, 'charset', 'utf-8') # patched\n" changed = True if changed: @@ -36,3 +36,4 @@ def patch_flask_frozen(): if __name__ == "__main__": patch_flask_frozen() + diff --git a/start_site.py b/start_site.bkp similarity index 100% rename from start_site.py rename to start_site.bkp diff --git a/start_site/__init__.py b/start_site/__init__.py new file mode 100644 index 0000000..a10971c --- /dev/null +++ b/start_site/__init__.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python + +import os +import toml +from datetime import datetime +import pytz +from flask import Flask, url_for, render_template, send_from_directory +from flask import make_response +from feedgen.feed import FeedGenerator +from flaskext.markdown import Markdown +import markdown +import markdown.extensions.fenced_code +import markdown.extensions.codehilite +import markdown.extensions.toc +from markdown.extensions.toc import TocExtension +from pygments.formatters import HtmlFormatter + +app = Flask(__name__) +Markdown(app) + +meta_data = { + root[len("./blog/") :]: datetime.strptime( + open(os.path.join(root, "index.md"), encoding="UTF-8").readline().rstrip(), + "%Y-%m-%d", + ) + + for root, dirs, files in os.walk("./blog") + + if "index.md" in files +} + + +app.config["blog"] = toml.load("settings.toml") +content_path = app.config["blog"]["content"]["path"] +highlight_style = app.config["blog"]["content"]["style"] +STYLESHEET = "stylesheet.css" +STYLESHEET_AUTO_COMPLETE = "auto-complete.css" +project_name = app.config["blog"]["project"]["name"] +project_title = app.config["blog"]["project"]["title"] + +app.config["blog"]["style"] = toml.load("style.toml") +colors = app.config["blog"]["style"][highlight_style] + + +@app.route("/") +def index(_paths=meta_data): + """Main Site.""" + sorted_meta_data = dict( + sorted(meta_data.items(), reverse=True, key=lambda item: item[1]) + ) + + return render_template("index.html", colors=colors, _paths=sorted_meta_data) + + +@app.route("/blog//index.html") +def blog(blog_item, _date=meta_data): + """Blog Pages.""" + md_file_path = os.path.join(f"blog/{blog_item}/index.md") + with open(md_file_path, "r") as _f: + md_file = _f.read() + md_extensions = [ + "toc", + TocExtension(toc_class="", title=""), + "fenced_code", + "codehilite", + "tables", + "mdx_math", + ] + + md_configs = {"mdx_math": {"enable_dollar_delimiter": True}} + md = markdown.Markdown(extensions=md_extensions, extension_configs=md_configs) + + html = md.convert(md_file) + + formatter = HtmlFormatter(style=highlight_style, full=True, cssclass="codehilite") + css_string = formatter.get_style_defs() + md_css_string = "" + md_template = md_css_string + html + res = render_template( + "blog.html", + # toc=md.toc, + md_doc=md_template, + colors=colors, + stylesheet=STYLESHEET, + # stylesheet_auto_complete=STYLESHEET_AUTO_COMPLETE, + project_name=project_name, + project_title=project_title, + # tree=cut_path_tree( + # #rem_readme(content_path, make_tree(content_path)), + # make_tree(content_path), + # content_path, + # ".md" # ) + _date=meta_data[blog_item], + ) + response = make_response(res) + response.headers["Content-Type"] = "text/html; charset=utf-8" + + return response + + # return render_template( + # f"blog/{blog_item}/index.html", + # _date=meta_data[blog_item] + # ) + + +@app.route("/about.html") +def about(): + """About Page.""" + + return render_template("about.html", colors=colors) + + +@app.route("/contact.html") +def contact(): + """Contact Page.""" + + return render_template("contact.html", colors=colors) + + +@app.route("/rss.xml") +def rss(_items=meta_data): + """RSS Feed. + Generates RSS feed as XML + """ + # rss_feed = [] + _tz = pytz.timezone("Europe/Berlin") + _fg = FeedGenerator() + _fg.title("Website of Stefan Friese") + _fg.description("test") + _fg.language("en-us") + # _fg.author({'name': "Stefan Friese", 'email': 'stefan@stefan.works'}) + _fg.link(href="https://stefan.works", rel="self") + + for key in meta_data.keys(): + _fe = _fg.add_entry() + _fe.id(f"https://stefan.works/blog/{key}/index.html") + _fe.title(key) + # _fe.description("test") + # _fe.author({'name': "Stefan Friese", 'email': 'stefan@stefan.works'}) + _fe.link(href=f"https://stefan.works/blog/{key}/index.html") + _fe.pubDate(pubDate=_tz.localize(meta_data[key])) + _fg.rss_str(pretty=True) + _fg.rss_file("./static/rss.xml") + + return send_from_directory(os.path.join(app.root_path, "static"), "rss.xml") + + +@app.route("/favicon.ico") +def favicon(): + """Provides favicon.""" + + return send_from_directory(os.path.join(app.root_path, "static"), "favicon.ico") + + +@app.errorhandler(404) +def page_not_found(_error): + """Error Handling. + Error 404 + """ + + return render_template("/status_code/404.html", colors=colors), 404 + + +@app.errorhandler(400) +def bad_request(_error): + """Error Handling. + Error 400 + """ + + return render_template("/status_code/400.html", colors=colors), 400 + + +@app.errorhandler(500) +def internal_server_error(_error): + """Error Handling. + Error 500 + """ + + return render_template("/status_code/500.html", colors=colors), 500 + + +with app.test_request_context(): + print(url_for("index")) + # print(url_for("about")) + # print(url_for("contact")) + # print(url_for("rss")) + # print(url_for("static", filename="stylesheet.css")) + # print(meta_data) + # print(url_for("blog", blog_item="first_blog"))