about summary refs log tree commit diff
diff options
context:
space:
mode:
authoruser@node5.net <user@node5.net>2026-05-12 18:50:37 +0200
committeruser@node5.net <user@node5.net>2026-05-12 18:50:37 +0200
commit5a4bcbe84adb3aac980451259819f3029d7499c8 (patch)
tree16f7befb7f752abb41b923c44eaaa4247fe16b15
parent1d81f5dbf63d361c76744fcd759904c4bf616fcc (diff)
Nixify app: Add flake, load content from dynamic path
- Package with flake
- Load content from a path given with an environment variable, with the
  intention of loading this from a derivation
-rw-r--r--flake.lock46
-rw-r--r--flake.nix39
-rw-r--r--pyproject.toml19
-rw-r--r--src/article.py9
-rw-r--r--src/blog_node5_net.py27
5 files changed, 127 insertions, 13 deletions
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..846c7ed
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,46 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1778274207,
+        "narHash": "sha256-I4puXmX1iovcCHZlRmztO3vW0mAbbRvq4F8wgIMQ1MM=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "b3da656039dc7a6240f27b2ef8cc6a3ef3bccae7",
+        "type": "github"
+      },
+      "original": {
+        "id": "nixpkgs",
+        "type": "indirect"
+      }
+    },
+    "pyproject-nix": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1776715674,
+        "narHash": "sha256-Gs1VnEkCkkRZxJQAC/Dhz0Jbfi22mFXChbtNg9w/Ybg=",
+        "owner": "nix-community",
+        "repo": "pyproject.nix",
+        "rev": "69f57f27e52a87c54e28138a75ec741cd46663c9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "pyproject.nix",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs",
+        "pyproject-nix": "pyproject-nix"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..7996ee1
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,39 @@
+{
+  description = "A basic flake using pyproject.toml project metadata";
+
+  inputs = {
+    pyproject-nix = {
+      url = "github:nix-community/pyproject.nix";
+      inputs.nixpkgs.follows = "nixpkgs";
+    };
+  };
+
+  outputs = { nixpkgs, pyproject-nix, ... }:
+    let
+      inherit (nixpkgs) lib;
+
+      project = pyproject-nix.lib.project.loadPyproject {
+        # Read & unmarshal pyproject.toml relative to this project root.
+        # projectRoot is also used to set `src` for renderers such as buildPythonPackage.
+        projectRoot = ./.;
+      };
+
+      # This example is only using x86_64-linux
+      pkgs = nixpkgs.legacyPackages.x86_64-linux;
+
+      python = pkgs.python3;
+
+    in
+    {
+      # Build our package using `buildPythonPackage
+      packages.x86_64-linux.default =
+        let
+          # Returns an attribute set that can be passed to `buildPythonPackage`.
+          attrs = project.renderers.buildPythonPackage { inherit python; };
+        in
+        # Pass attributes to buildPythonPackage.
+        # Here is a good spot to add on any missing or custom attributes.
+        python.pkgs.buildPythonPackage (attrs // {
+        });
+    };
+}
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..7c5288c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,19 @@
+[project]
+name = "blog.node5.net"
+version = "0.1.0"
+description = "Flask project to host blog.node5.net, simple markdown parser "
+
+# define any Python dependencies
+dependencies = [
+  "Flask~=3.0",                 # Dynamic web server
+  "PyYAML~=6.0",                # For config fiels
+  "Markdown~=3.5",              # Convert markdown to HTML
+  "python-telegram-bot~=22.7",  # Notify when new comments are made
+  "pygments~=2.17",             # Use a newer version than in debain packages for python code snippet highlighting
+  "tabulate~=0.9",              # Format lists as ascii tables for comments
+]
+
+# define the CLI executable
+# Here, we define the entry point to be the 'main()' function in the module 'app/main.py'
+[project.scripts]
+cli = "blog_node5_net:main"
diff --git a/src/article.py b/src/article.py
index 0b437bc..a35b431 100644
--- a/src/article.py
+++ b/src/article.py
@@ -87,10 +87,9 @@ class ArticleGenerator:
         self.articles_path = articles_path
 
     def get_web_dir(self, path, name) -> tuple[str, ...]:
-        dir_structure = path.split(name)[0]
-        # Split into tuple, remove first part, assemble to path again, all to remove the first source dir agnostically
-        dir_structure_prefix_striped = pathlib.Path(dir_structure).parts[2:]
-        return dir_structure_prefix_striped
+        dir = path.split(name)[0]  # Get dir for one file articles and folder articles
+        web_path = pathlib.Path(dir).relative_to(pathlib.Path(self.articles_path))
+        return web_path.parts
 
     def parse_article_meta_data(self, source: str) -> typing.Tuple[str, MetaData]:
         if source.startswith('---'):
@@ -189,6 +188,6 @@ class ArticleGenerator:
         for article_path in articles_paths:
             article = self.get_article(article_path)
             logger.debug(article.pretty_print)
-            self.discover_folder_structure(articles=articles, article=article)
+            self.discover_folder_structure(article=article, articles=articles)
         self.sort_articles(articles)
         return articles
diff --git a/src/blog_node5_net.py b/src/blog_node5_net.py
index a8961d8..7da959c 100644
--- a/src/blog_node5_net.py
+++ b/src/blog_node5_net.py
@@ -5,6 +5,7 @@ import signal
 import sys
 import typing
 import urllib
+import pathlib
 
 import flask
 import markdown
@@ -50,10 +51,11 @@ stream_handler.setFormatter(CustomFormatter())
 logger.root.addHandler(stream_handler)
 logger.info(f"Debug: {'en' if debug else 'dis'}abled")
 
-with open(os.path.join('configs', 'config.yml'), 'r') as file:
-    config = yaml.safe_load(file.read())
+content_root_path = os.environ.get("CONTENT_ROOT_PATH")
+if not content_root_path:
+    sys.exit("ERROR: required environment variable CONTENT_ROOT_PATH is not set")
 
-article_generator = article.ArticleGenerator(os.path.join(config['site_root_folder_path'], 'articles'))
+article_generator = article.ArticleGenerator(os.path.join(content_root_path, 'articles'))
 
 
 def get_articles() -> article.Folder:
@@ -70,10 +72,11 @@ if len(sys.argv) > 1 and sys.argv[1] == 'validate':
     logger.info('OK')
     exit(0)
 
-app = flask.Flask(__name__, template_folder=os.path.join('..', config['site_root_folder_path'], 'templates'),
-                  static_folder=os.path.join('..', config['site_root_folder_path'], 'static'), static_url_path='')
-
-with open(os.path.join(config['site_root_folder_path'], 'motd.md'), 'r') as file:
+template_path = os.path.join('..', content_root_path, 'templates')
+logger.debug(f"template path: {template_path}")
+app = flask.Flask(__name__, template_folder=template_path,
+                  static_folder=os.path.join('..', content_root_path, 'static'), static_url_path='')
+with open(os.path.join(content_root_path, 'motd.md'), 'r') as file:
     motd_list = [markupsafe.Markup(markdown.markdown(line)) for line in file.readlines()]
 
 folders_by_url: typing.Dict[str, article.Folder] = {}
@@ -107,7 +110,7 @@ def inject_common():
         'insert_sql_pretty': insert_sql_pretty,
         'comments_sql': markupsafe.Markup(markdown.markdown(sql_pretty)),
         'comments': comments_formatted,
-        'title': config['site_root_folder_path'],
+        'title': pathlib.Path(content_root_path).name,
         'motd': random.choice(motd_list)
     }
 
@@ -203,3 +206,11 @@ def signal_handler(signum, frame):
 
 
 signal.signal(signal.SIGHUP, signal_handler)
+
+
+def main():
+    global app
+    app.run()
+
+if __name__ == '__main__':
+    main()