diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 383e65c..633ac00 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13.0-rc.2"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} @@ -18,6 +18,7 @@ jobs: run: | python -m pip install --upgrade pip pip install pylint + pip install -r requirements.txt - name: Analysing the code with pylint run: | pylint $(git ls-files '*.py') diff --git a/.gitignore b/.gitignore index 1e12e92..6b5820e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ __pycache__/ *~ # C extensions *.so +.venv diff --git a/__init__.py b/__init__.py index 6b257d4..99fd715 100644 --- a/__init__.py +++ b/__init__.py @@ -8,23 +8,28 @@ """ import os -from flask import Flask -import flask +import urllib.parse from io import StringIO -import re + +import flask +from flask import Flask + from . import templatehelper -import urllib.parse -import yaml -def create_app(): + +def create_application(): """ Factory for creating a Flask application. """ - app = Flask(__name__, instance_relative_config=True, static_folder='templates/{}/static'.format(templatehelper.config['template'])) - # paths sent by flask are relative to the "public" directory. This prefix should be added to get paths relative to the pages root directory. + application = Flask( + __name__, + instance_relative_config=True, + static_folder=f"templates/{templatehelper.CONFIG['template']}/static") + # paths sent by flask are relative to the "public" directory. This prefix should be added to + # get paths relative to the pages root directory. pathprefix = '' - - @app.route('/') + + @application.route('/') def serve_directory_or_file(path): """ Main handler for all paths @@ -35,11 +40,13 @@ def serve_directory_or_file(path): return serve_error(404, "File not found...") if os.path.isdir(fullpath): return serve_directory(path) - else: - # If a specified path exists, dreamhost seems to serve the file directly without invoking this Flask application. - # As nonexistent paths are taken care of above, this else-branch is not expected to ever be called. It is left in as a - # stub though, in case this ever changes. - return serve_file(path) + + # If a specified path exists, dreamhost seems to serve the file directly without + # invoking this Flask application. + # As nonexistent paths are taken care of above, this else-branch is not expected to + # ever be called. It is left in as a + # stub though, in case this ever changes. + return serve_file(path) def serve_directory(path): """ @@ -48,27 +55,48 @@ def serve_directory(path): if not path.endswith('/') and len(path) > 1: # Ensure paths always end with a "/" return flask.redirect('/' + path + '/') - else: - return flask.render_template(os.path.join(templatehelper.config['template'], 'directory.html'), pathprefix = pathprefix, path = path, templatehelper = templatehelper) - - @app.route('/') + return flask.render_template( + os.path.join(templatehelper.CONFIG['template'], 'directory.html'), + pathprefix = pathprefix, + path = path, + templatehelper = templatehelper) + + @application.route('/') def serve_root(): """ - `@app.route('/')` doesn't match '/' and thus this convenience function is needed. + `@application.route('/')` doesn't match '/' and thus this convenience function + is needed. """ return serve_directory_or_file(os.path.curdir) def serve_error(code, message=None): - if os.path.exists(os.path.join(__name__, 'templates', templatehelper.config['template'], '%d.html' % (code))): - template = '%d.html' % (code) + if os.path.exists( + os.path.join( + __name__, + 'templates', + templatehelper.CONFIG['template'], + f'{code}.html')): + template = f'{code}.html' else: template = 'error.html' - return flask.make_response((flask.render_template(os.path.join(templatehelper.config['template'], template), code=code, message=message, templatehelper=templatehelper, pathprefix=pathprefix, path=''), code, None)) + return flask.make_response(( + flask.render_template( + os.path.join(templatehelper.CONFIG['template'], template), + code=code, + message=message, + templatehelper=templatehelper, + pathprefix=pathprefix, + path=''), + code, + None)) def serve_file(path): + """ + Left as just a stub as it is unlikely to be called anytime soon. + """ return flask.send_file(os.path.join('..', 'public', path)) - return app + return application # Create an instance of the scms application. -app = create_app() \ No newline at end of file +app = create_application() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a73b78c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +flask +pyyaml +regex diff --git a/scms.fcgi.example b/scms.fcgi.example index af4021a..84f1669 100644 --- a/scms.fcgi.example +++ b/scms.fcgi.example @@ -1,11 +1,14 @@ -#!/home/user/venv/bin/python +#!/home//venv/bin/python + +# scms Copyright (C) 2020 - nomike +# This program comes with ABSOLUTELY NO WARRANTY; for details see LICENSE. +# This is free software, and you are welcome to redistribute it +# under certain conditions; type `show c' for details. + import sys -sys.path.append('..') +sys.path.append('.') sys.path.append('../scms') from flup.server.fcgi import WSGIServer -from scms import app - -if __name__ == '__main__': - WSGIServer(app).run() +from scms import app as application diff --git a/templatehelper.py b/templatehelper.py index 17a3ba5..32031d3 100644 --- a/templatehelper.py +++ b/templatehelper.py @@ -5,33 +5,33 @@ Example: {% for parentpath, parentname in templatehelper.getparents(path) %} - {{ parentname }} + + {{ parentname }} + {% endfor %} """ +import fnmatch +import json +import mimetypes import os -import re + import regex -import mimetypes -import fnmatch -from datetime import datetime, tzinfo, timezone import yaml -import markdown -import urllib -import json -config = None -with open("../config.yaml") as file: - config = yaml.load(file, Loader=yaml.SafeLoader) +CONFIG = None +with open("../config.yaml", encoding='utf-8') as file: + CONFIG = yaml.load(file, Loader=yaml.SafeLoader) -# paths sent by flask are relative to the "public" directory. This prefix should be added to get paths relative to the pages root directory. -#TODO: This is a redundant specification and should be avoided. -pathprefix = '' +# paths sent by flask are relative to the "public" directory. This prefix should be added to get +# paths relative to the pages root directory. +PATHPREFIX = '' # List of official MIME Types: http://www.iana.org/assignments/media-types/media-types.xhtml # If you want additional mimetypes to be covered, add them to this list. -# The types map to FontAwesome identifiers. Check out https://fontawesome.com/icons?d=gallery for a list of available images. +# The types map to FontAwesome identifiers. Check out https://fontawesome.com/icons?d=gallery +# for a list of available images. mimetype_fas_mapping = { # Media 'image': 'fa-file-image', @@ -62,22 +62,27 @@ def listdir(path): List all child-elements of the specified path. Hidden files and, files ending in ".scmsfasicon" and files ending with a "~" are ignored. - You can also ignore additional files by creating a file called ".scmsignore" in the current folder. + You can also ignore additional files by creating a file called ".scmsignore" in the current + folder. All files listed in there will not be listed. - If a file named "index" is present, it is supposed to be rendered as the main content of the page - and thus it will be ommited from the list as well. + If a file named "index" is present, it is supposed to be rendered as the main content of the + page and thus it will be ommited from the list as well. """ ignorelist = ['index', 'index.md', '*.scmsfasicon', '*.scmstarget'] - if os.path.exists(os.path.join(pathprefix, path, '.scmsignore')): - with open(os.path.join(pathprefix, path, '.scmsignore')) as file: - ignorelist.extend([line.strip('\n') for line in file.readlines()]) - dirlist = [os.path.basename(f) for f in os.listdir(os.path.join(pathprefix, path)) if regex.match('^(?!\\.).*(? newest['timestamp']: - newest['file'] = os.path.join(root, path) + newest['file'] = os.path.join(root, directory) newest['timestamp'] = timestamp - for path in files: - timestamp = os.path.getmtime(os.path.join(root, path)) + for directory in files: + timestamp = os.path.getmtime(os.path.join(root, directory)) if timestamp > newest['timestamp']: - newest['file'] = os.path.join(root, path) + newest['file'] = os.path.join(root, directory) newest['timestamp'] = timestamp return newest diff --git a/templates/nomike.com/base.html b/templates/nomike.com/base.html index eaafc20..c7b4c14 100644 --- a/templates/nomike.com/base.html +++ b/templates/nomike.com/base.html @@ -1,4 +1,4 @@ -{% if not templatehelper.os.path.exists(templatehelper.os.path.join('public', path, '.scmsnotemplate')): -%} +{% if not templatehelper.os.path.exists(templatehelper.os.path.join(path, '.scmsnotemplate')): -%} @@ -35,11 +35,11 @@ {% endblock %} {% block menu %}{% endblock %}
- {% endif -%} {% block content -%}{% endblock -%} {% if not templatehelper.os.path.exists(templatehelper.os.path.join('public', path, '.scmsnotemplate')): -%} + {% endif -%} {% block content -%}{% endblock -%} {% if not templatehelper.os.path.exists(templatehelper.os.path.join(path, '.scmsnotemplate')): -%}

 

diff --git a/templates/nomike.com/directory.html b/templates/nomike.com/directory.html index 71a8dd4..755514d 100644 --- a/templates/nomike.com/directory.html +++ b/templates/nomike.com/directory.html @@ -1,15 +1,15 @@ {# scms Copyright (C) 2020 - nomike This program comes with ABSOLUTELY NO WARRANTY; for details see LICENSE. This is free software, and you are welcome to redistribute it under certain conditions -#} {% extends templatehelper.os.path.join(templatehelper.config['template'], 'base.html') - -%} {% block title %}/{{ path }}{% endblock %}\ {% block menu %} {% if not templatehelper.os.path.exists(templatehelper.os.path.join('public', path, '.scmsnonavigation')): -%} + -%} {% block title %}/{{ path }}{% endblock %}\ {% block menu %} {% if not templatehelper.os.path.exists(templatehelper.os.path.join(path, '.scmsnonavigation')): -%} {% endif -%} {% endblock -%} {% block content -%} {% if templatehelper.os.path.isfile(templatehelper.os.path.join(pathprefix, path,'index.md')) -%} {{ templatehelper.markdown.markdown(templatehelper.readfile(templatehelper.os.path.join(pathprefix,path,'index.md')),extensions=['fenced_code','toc','tables'])