diff options
| author | user@node5.net <user@node5.net> | 2026-05-12 18:50:37 +0200 |
|---|---|---|
| committer | user@node5.net <user@node5.net> | 2026-05-12 18:50:37 +0200 |
| commit | 5a4bcbe84adb3aac980451259819f3029d7499c8 (patch) | |
| tree | 16f7befb7f752abb41b923c44eaaa4247fe16b15 | |
| parent | 1d81f5dbf63d361c76744fcd759904c4bf616fcc (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.lock | 46 | ||||
| -rw-r--r-- | flake.nix | 39 | ||||
| -rw-r--r-- | pyproject.toml | 19 | ||||
| -rw-r--r-- | src/article.py | 9 | ||||
| -rw-r--r-- | src/blog_node5_net.py | 27 |
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() |
