From a38ea890ec0966820571d7831d59981b6c153e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 29 Nov 2020 13:23:05 +0100 Subject: [PATCH 1/8] get rid of the mysite subdirectory and refactor settings --- README.md | 6 +-- drop_cache.py | 2 +- local_settings.py.example | 23 ++++++++++++ manage.py | 2 +- mysite/__init__.py | 0 mysite/local_settings.py.example | 26 ------------- mysite/settings.py | 48 ------------------------ mysite/urls.py | 6 --- mysite/wsgi.py | 16 -------- settings.py | 64 ++++++++++++++++++++++++++++++++ update.py | 2 +- urls.py | 5 +++ wsgi.py | 5 +++ 13 files changed, 103 insertions(+), 102 deletions(-) create mode 100644 local_settings.py.example delete mode 100644 mysite/__init__.py delete mode 100644 mysite/local_settings.py.example delete mode 100644 mysite/settings.py delete mode 100644 mysite/urls.py delete mode 100644 mysite/wsgi.py create mode 100644 settings.py create mode 100644 urls.py create mode 100644 wsgi.py diff --git a/README.md b/README.md index d8d4448..c90ec62 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ ## Installation -1. In the directory `mysite` copy `local_settings.py.example` to `local_settings.py` and edit `DEBUG = True` and the `SECRET_KEY` variable. +1. Copy `local_settings.py.example` to `local_settings.py` and edit `DEBUG = True` and the `SECRET_KEY` variable. 2. Configure a connection to a [PostgreSQL](https://wiki.archlinux.org/index.php/PostgreSQL) database - in the [Django database settings](https://docs.djangoproject.com/en/1.11/ref/settings/#databases) - in the `mysite/local_settings.py` file. + in the [Django database settings](https://docs.djangoproject.com/en/3.1/ref/settings/#databases) + in the `local_settings.py` file. 3. Make sure that the [pg_trgm](https://www.postgresql.org/docs/current/pgtrgm.html) extension is [created](https://www.postgresql.org/docs/current/sql-createextension.html) diff --git a/drop_cache.py b/drop_cache.py index 51bef92..1ebca34 100755 --- a/drop_cache.py +++ b/drop_cache.py @@ -5,7 +5,7 @@ import os import django from django.db import connection -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") django.setup() with connection.cursor() as c: diff --git a/local_settings.py.example b/local_settings.py.example new file mode 100644 index 0000000..1fead1e --- /dev/null +++ b/local_settings.py.example @@ -0,0 +1,23 @@ +## Reference: https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ + +## Import the common settings, which may be overridden in this file. +from settings import * + +DEBUG = False + +## Make this unique, and don't share it with anybody. +SECRET_KEY = '00000000000000000000000000000000000000000000000' + +## Must not be empty when DEBUG is False +ALLOWED_HOSTS = [] + + +## PostgreSQL database settings +#DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'archmanweb', +# 'USER': 'archmanweb', +# 'PASSWORD': 'secret', +# } +#} diff --git a/manage.py b/manage.py index 2f0a83e..19ff9c3 100755 --- a/manage.py +++ b/manage.py @@ -4,7 +4,7 @@ import os import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") try: from django.core.management import execute_from_command_line except ImportError: diff --git a/mysite/__init__.py b/mysite/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mysite/local_settings.py.example b/mysite/local_settings.py.example deleted file mode 100644 index 9f85075..0000000 --- a/mysite/local_settings.py.example +++ /dev/null @@ -1,26 +0,0 @@ -## See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ - -DEBUG = False - -## Make this unique, and don't share it with anybody. -SECRET_KEY = '00000000000000000000000000000000000000000000000' - -## Must not be empty when DEBUG is False -ALLOWED_HOSTS = [] - - -## PostgreSQL database settings -#DATABASES = { -# 'default': { -# 'ENGINE': 'django.db.backends.postgresql', -# 'NAME': 'arch_manpages', -# 'USER': 'arch_manpages', -# 'PASSWORD': 'arch_manpages', -# } -#} - - -## Path where static files are collected. -## Run `./manage.py collectstatic` when deploying updated versions. -#if DEBUG is False: -# STATIC_ROOT = "/srv/http/example.com/static/" diff --git a/mysite/settings.py b/mysite/settings.py deleted file mode 100644 index 9b042d9..0000000 --- a/mysite/settings.py +++ /dev/null @@ -1,48 +0,0 @@ -import os - -# defaults -DEBUG = False -STATIC_URL = '/arch/static/' - -from .local_settings import * - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - -INSTALLED_APPS = [ - 'django.contrib.staticfiles', - 'django.contrib.postgres', - 'archmanweb', -] - -ROOT_URLCONF = 'mysite.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - ], - }, - }, -] - -WSGI_APPLICATION = 'mysite.wsgi.application' - - -# Internationalization -# https://docs.djangoproject.com/en/1.11/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = False - -USE_L10N = False - -USE_TZ = True diff --git a/mysite/urls.py b/mysite/urls.py deleted file mode 100644 index 831b210..0000000 --- a/mysite/urls.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.urls import include, path - -urlpatterns = [ - path("arch/manpages/", include("archmanweb.urls")), -# path("", include("archmanweb.urls")), -] diff --git a/mysite/wsgi.py b/mysite/wsgi.py deleted file mode 100644 index 74e7dae..0000000 --- a/mysite/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for mysite project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") - -application = get_wsgi_application() diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..f17e7af --- /dev/null +++ b/settings.py @@ -0,0 +1,64 @@ +import os + +DEBUG = False + +# Full path to the base project directory +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + +INSTALLED_APPS = [ + "django.contrib.staticfiles", + "django.contrib.postgres", + "archmanweb", +] + +# https://docs.djangoproject.com/en/3.1/topics/http/middleware/ +MIDDLEWARE = [ + # https://docs.djangoproject.com/en/3.1/ref/middleware/#django.middleware.common.CommonMiddleware + "django.middleware.common.CommonMiddleware", + # https://docs.djangoproject.com/en/3.1/ref/csrf/ + "django.middleware.csrf.CsrfViewMiddleware", +] + +# Base of the URL hierarchy +ROOT_URLCONF = "urls" + +# requires CommonMiddleware +APPEND_SLASH = True + +# URL to serve static files +STATIC_URL = "/static/" + +# Location to collect static files +STATIC_ROOT = os.path.join(BASE_DIR, "collected_static") + +# Look for more static files in these locations +STATICFILES_DIRS = ( + os.path.join(BASE_DIR, "sitestatic"), +) + +# Static files backend that appends the MD5 hash of the file’s content to the filename +# (this allows us to use far future Expires headers) +STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" + +# Internationalization +# https://docs.djangoproject.com/en/3.1/topics/i18n/ +LANGUAGE_CODE = "en-us" +TIME_ZONE = "UTC" +USE_I18N = False +USE_L10N = False +USE_TZ = True + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "debug": DEBUG, + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + ], + }, + }, +] diff --git a/update.py b/update.py index 11dc4bc..97340f2 100755 --- a/update.py +++ b/update.py @@ -13,7 +13,7 @@ import pyalpm from finder import MANDIR, ManPagesFinder # init django -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") import django django.setup() from django.db import connection, transaction diff --git a/urls.py b/urls.py new file mode 100644 index 0000000..50a4b23 --- /dev/null +++ b/urls.py @@ -0,0 +1,5 @@ +from django.urls import include, path + +urlpatterns = [ + path("", include("archmanweb.urls")), +] diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..d119b0d --- /dev/null +++ b/wsgi.py @@ -0,0 +1,5 @@ +import os +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") + +from django.core.wsgi import get_wsgi_application +application = get_wsgi_application() -- GitLab From cfbf7c951ebffb33ee3a55cfa6574a1406ecf432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 29 Nov 2020 15:46:14 +0100 Subject: [PATCH 2/8] add sitestatic assets: proper Arch navbar and favicon --- archmanweb/static/archmanweb/base.css | 50 +------ archmanweb/templates/base.html | 33 ++++- sitestatic/archnavbar/archlogo.png | Bin 0 -> 5359 bytes sitestatic/archnavbar/archlogo.svg | 194 ++++++++++++++++++++++++++ sitestatic/archnavbar/archnavbar.css | 28 ++++ sitestatic/favicon.ico | Bin 0 -> 575 bytes 6 files changed, 253 insertions(+), 52 deletions(-) create mode 100644 sitestatic/archnavbar/archlogo.png create mode 100644 sitestatic/archnavbar/archlogo.svg create mode 100644 sitestatic/archnavbar/archnavbar.css create mode 100644 sitestatic/favicon.ico diff --git a/archmanweb/static/archmanweb/base.css b/archmanweb/static/archmanweb/base.css index fcec57a..4f1eb1d 100644 --- a/archmanweb/static/archmanweb/base.css +++ b/archmanweb/static/archmanweb/base.css @@ -1,48 +1,8 @@ -header { - padding: 10px 15px; - background: #333; - border-bottom: 5px #08c solid; - color: white !important; - display: flex; - justify-content: space-between; - align-items: center; - font-family: sans-serif; -} -header > h1 { - font-size: 1.25em; - margin: 0; -} -header > nav { - margin-bottom: 0; -} -header > nav > a { - font-weight: bold; - font-size: 1em; - text-decoration: none; - color: #999 !important; -} -header > nav > a:focus, -header > nav > a:hover { - text-decoration: underline; - color: white !important; -} -header > nav > a.selected { - color: white !important; -} -header > nav > a:not(:last-child) { - margin-right: 1em; -} - -/* responsive header */ -@media only screen and (max-width: 650px) { - header { - /* place the items in vertical direction */ - flex-direction: column; - } - - header > :not(:last-child) { - margin: 0 0 0.5rem; - } +#archnavbar form { + display: inline-block !important; + font-size: 14px !important; + line-height: 14px !important; + padding: 14px 15px 0px !important; } /* simple reset */ diff --git a/archmanweb/templates/base.html b/archmanweb/templates/base.html index de04ba8..3000ced 100644 --- a/archmanweb/templates/base.html +++ b/archmanweb/templates/base.html @@ -6,19 +6,37 @@ {% block title %}Arch manual pages{% endblock %} + + + {% block head %} {% endblock %}
-

Arch manual pages

- {% if search_form is None %} - - {% endif %} + +
{% block content %} diff --git a/sitestatic/archnavbar/archlogo.png b/sitestatic/archnavbar/archlogo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d2cd40fb499b2b37651ea67ec6f3b4400e3d157 GIT binary patch literal 5359 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 + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sitestatic/archnavbar/archnavbar.css b/sitestatic/archnavbar/archnavbar.css new file mode 100644 index 0000000..1cf4f98 --- /dev/null +++ b/sitestatic/archnavbar/archnavbar.css @@ -0,0 +1,28 @@ +/* + * ARCH GLOBAL NAVBAR + * We're forcing all generic selectors with !important + * to help prevent other stylesheets from interfering. + */ + +/* container for the entire bar */ +#archnavbar { min-height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } +#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archlogo.png') no-repeat !important; } +@media (-webkit-min-device-pixel-ratio: 1.2), (min--moz-device-pixel-ratio: 1.2), (-o-min-device-pixel-ratio: 2/1) { + #archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url(archlogo.svg) no-repeat !important;background-size:100% !important; + } +} + +/* move the heading/paragraph text offscreen */ +#archnavbarlogo p { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } +#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } + +/* make the link the same size as the logo */ +#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } + +/* display the list inline, float it to the right and style it */ +#archnavbar ul { display: block !important; list-style: none !important; margin: 0 !important; padding: 0 !important; font-size: 0px !important; text-align: right !important; } +#archnavbar ul li { display: inline-block !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 14px !important; padding: 14px 15px 0px !important; } + +/* style the links */ +#archnavbar ul#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } +#archnavbar ul li a:hover { color: white !important; text-decoration: underline !important; } diff --git a/sitestatic/favicon.ico b/sitestatic/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..55497b852fc438a7a63041822a64deac8ad92527 GIT binary patch literal 575 zcmV-F0>J%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i literal 0 HcmV?d00001 -- GitLab From 6d3287520709342c2292a66599aad864fdb86f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 29 Nov 2020 17:52:09 +0100 Subject: [PATCH 3/8] move finder, update and drop_cache scripts into the archmanweb.management submodule --- .../management/commands/man_drop_cache.py | 15 ++ .../management/commands/man_update.py | 206 ++++++++++-------- .../management/utils/finder.py | 0 drop_cache.py | 16 -- 4 files changed, 127 insertions(+), 110 deletions(-) create mode 100755 archmanweb/management/commands/man_drop_cache.py rename update.py => archmanweb/management/commands/man_update.py (68%) rename finder.py => archmanweb/management/utils/finder.py (100%) delete mode 100755 drop_cache.py diff --git a/archmanweb/management/commands/man_drop_cache.py b/archmanweb/management/commands/man_drop_cache.py new file mode 100755 index 0000000..bc4c68a --- /dev/null +++ b/archmanweb/management/commands/man_drop_cache.py @@ -0,0 +1,15 @@ +#! /usr/bin/env python3 + +from django.core.management.base import BaseCommand +from django.db import connection + +class Command(BaseCommand): + help = "Drops cached data from the database" + + def handle(self, *args, **kwargs): + with connection.cursor() as c: + c.execute("UPDATE archmanweb_content SET html = NULL WHERE html IS NOT NULL;") + c.execute("UPDATE archmanweb_content SET txt = NULL WHERE txt IS NOT NULL;") + c.execute("UPDATE archmanweb_content SET description = NULL WHERE description IS NOT NULL;") + c.execute("UPDATE archmanweb_manpage SET converted_content_id = NULL WHERE converted_content_id IS NOT NULL;") + c.execute("VACUUM FULL archmanweb_content;") diff --git a/update.py b/archmanweb/management/commands/man_update.py similarity index 68% rename from update.py rename to archmanweb/management/commands/man_update.py index 97340f2..b4947a5 100755 --- a/update.py +++ b/archmanweb/management/commands/man_update.py @@ -10,12 +10,10 @@ import subprocess import chardet import pyalpm -from finder import MANDIR, ManPagesFinder +from archmanweb.management.utils.finder import MANDIR, ManPagesFinder -# init django -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") +from django.core.management.base import BaseCommand import django -django.setup() from django.db import connection, transaction from django.db.models import Count from archmanweb.models import Package, Content, ManPage, SymbolicLink, UpdateLog, SoelimError @@ -313,93 +311,113 @@ def update_man_pages(finder, updated_pkgs): return updated_pages -if __name__ == "__main__": - # init logging - logger = logging.getLogger() - logger.setLevel(logging.INFO) - handler = logging.StreamHandler() - formatter = logging.Formatter("{levelname:8} {message}", style="{") - handler.setFormatter(formatter) - logger.addHandler(handler) - - parser = argparse.ArgumentParser(description="update man pages in the django database") - parser.add_argument("--force", action="store_true", - help="force an import of man pages from all packages, even if they were not updated recently") - parser.add_argument("--only-repos", action="store", nargs="+", metavar="NAME", - help="import packages (and man pages) only from these repositories") - parser.add_argument("--only-packages", action="store", nargs="+", metavar="NAME", - help="import man pages only from these packages") - parser.add_argument("--cache-dir", action="store", default="./.cache/", - help="path to the cache directory (default: %(default)s)") - parser.add_argument("--keep-tarballs", action="store_true", - help="keep downloaded package tarballs in the cache directory") - parser.add_argument("--workers", type=int, default=0, - help="number of workers for parallel processing (0 = use 1 worker per CPU core)") - args = parser.parse_args() - - start = datetime.datetime.now(tz=datetime.timezone.utc) - - finder = ManPagesFinder(args.cache_dir) - finder.refresh() - - # everything in a single transaction - with transaction.atomic(): - updated_pkgs = update_packages(finder, force=args.force, only_repos=args.only_repos) - if args.only_packages is None: - count_updated_pages = update_man_pages(finder, updated_pkgs) - else: - count_updated_pages = update_man_pages(finder, [p for p in updated_pkgs if p.name in args.only_packages]) - - # this is called outside of the transaction, so that the cache can be reused on errors - if args.keep_tarballs is False: - finder.clear_pkgcache() - - # convert manual pages to plain-text - # (one transaction per update, otherwise we might hit memory allocation error) - def worker(man_id): - man = ManPage.objects.get(id=man_id) - try: - man.get_converted("txt") - except SoelimError as e: - logger.error("SoelimError ({}) while converting {}.{}.{} to txt".format(str(e), man.name, man.section, man.lang)) - except subprocess.CalledProcessError as e: - logger.error("CalledProcessError while converting {}.{}.{} to txt:\nreturncode = {}\nstderr = {}" - .format(man.name, man.section, man.lang, e.returncode, e.stderr)) - - # prepare man page IDs which need to be converted - # (queryset needs to be a list for multiprocessing to work) - queryset = ManPage.objects.only("package", "lang", "content_id", "converted_content_id").filter(content__txt=None).values_list("id", flat=True) - queryset = list(queryset) - - # all existing database connections have to be closed before forking, - # each process will then recreate its own connection: - # https://stackoverflow.com/a/10684672 - django.db.connections.close_all() - - # parallel processing of the queryset - import concurrent.futures - with concurrent.futures.ProcessPoolExecutor(max_workers=args.workers or None) as executor: - executor.map(worker, queryset) - - # VACUUM cannot run inside a transaction block - if updated_pkgs or args.only_packages is not None: - logger.info("Running VACUUM FULL ANALYZE on our tables...") - for Model in [Package, Content, ManPage, SymbolicLink]: - table = Model.objects.model._meta.db_table - logger.info("--> {}".format(table)) - with connection.cursor() as cursor: - cursor.execute("VACUUM FULL ANALYZE {};".format(table)) - - end = datetime.datetime.now(tz=datetime.timezone.utc) - - # log update - log = UpdateLog() - log.timestamp = start - log.duration = end - start - log.updated_pkgs = len(updated_pkgs) - log.updated_pages = count_updated_pages - log.stats_count_man_pages = ManPage.objects.count() - log.stats_count_symlinks = SymbolicLink.objects.count() - log.stats_count_all_pkgs = Package.objects.count() - log.stats_count_pkgs_with_mans = ManPage.objects.aggregate(Count("package_id", distinct=True))["package_id__count"] - log.save() +class Command(BaseCommand): + help = "Update man pages in the Django database" + + def __init__(self, *args, **kwargs): + BaseCommand.__init__(self, *args, **kwargs) + + # TODO: use Django settings to configure the logger + # https://docs.djangoproject.com/en/3.1/topics/logging/ + logger = logging.getLogger() + logger.setLevel(logging.INFO) + handler = logging.StreamHandler() + formatter = logging.Formatter("{levelname:8} {message}", style="{") + handler.setFormatter(formatter) + logger.addHandler(handler) + + def add_arguments(self, parser): + """ + :param parser: an instance of :py:class:`argparse.ArgumentParser` + """ + parser.add_argument("--force", action="store_true", + help="force an import of man pages from all packages, even if they were not updated recently") + parser.add_argument("--only-repos", action="store", nargs="+", metavar="NAME", + help="import packages (and man pages) only from these repositories") + parser.add_argument("--only-packages", action="store", nargs="+", metavar="NAME", + help="import man pages only from these packages") + parser.add_argument("--cache-dir", action="store", default="./.cache/", + help="path to the cache directory (default: %(default)s)") + parser.add_argument("--keep-tarballs", action="store_true", + help="keep downloaded package tarballs in the cache directory") + parser.add_argument("--workers", type=int, default=0, + help="number of workers for parallel processing (0 = use 1 worker per CPU core; default: %(default)s)") + + def handle(self, **kwargs): + start = datetime.datetime.now(tz=datetime.timezone.utc) + updated_pkgs, count_updated_pages = self.do_update(**kwargs) + end = datetime.datetime.now(tz=datetime.timezone.utc) + + # log update + log = UpdateLog() + log.timestamp = start + log.duration = end - start + log.updated_pkgs = len(updated_pkgs) + log.updated_pages = count_updated_pages + log.stats_count_man_pages = ManPage.objects.count() + log.stats_count_symlinks = SymbolicLink.objects.count() + log.stats_count_all_pkgs = Package.objects.count() + log.stats_count_pkgs_with_mans = ManPage.objects.aggregate(Count("package_id", distinct=True))["package_id__count"] + log.save() + + def do_update(self, *, cache_dir, workers, + force=False, + only_repos=None, + only_packages=None, + keep_tarballs=False, + **kwargs): + finder = ManPagesFinder(cache_dir) + finder.refresh() + + # everything in a single transaction + with transaction.atomic(): + updated_pkgs = update_packages(finder, force=force, only_repos=only_repos) + if only_packages is None: + count_updated_pages = update_man_pages(finder, updated_pkgs) + else: + count_updated_pages = update_man_pages(finder, [p for p in updated_pkgs if p.name in only_packages]) + + # this is called outside of the transaction, so that the cache can be reused on errors + if keep_tarballs is False: + finder.clear_pkgcache() + + # convert manual pages to plain-text + # (one transaction per update, otherwise we might hit memory allocation error) + def worker(man_id): + man = ManPage.objects.get(id=man_id) + try: + man.get_converted("txt") + except SoelimError as e: + logger.error("SoelimError ({}) while converting {}.{}.{} to txt".format(str(e), man.name, man.section, man.lang)) + except subprocess.CalledProcessError as e: + logger.error("CalledProcessError while converting {}.{}.{} to txt:\nreturncode = {}\nstderr = {}" + .format(man.name, man.section, man.lang, e.returncode, e.stderr)) + + # prepare man page IDs which need to be converted + # (queryset needs to be a list for multiprocessing to work) + queryset = ManPage.objects.only("package", "lang", "content_id", "converted_content_id").filter(content__txt=None).values_list("id", flat=True) + queryset = list(queryset) + + # all existing database connections have to be closed before forking, + # each process will then recreate its own connection: + # https://stackoverflow.com/a/10684672 + django.db.connections.close_all() + + # parallel processing of the queryset + import concurrent.futures + # FIXME: Why the fuck does it deadlock here, after we moved the code into the Command class? + # Database connections are closed just above, which used to work before... + #with concurrent.futures.ProcessPoolExecutor(max_workers=workers or None) as executor: + with concurrent.futures.ThreadPoolExecutor(max_workers=workers or None) as executor: + executor.map(worker, queryset) + + # VACUUM cannot run inside a transaction block + if updated_pkgs or only_packages is not None: + logger.info("Running VACUUM FULL ANALYZE on our tables...") + for Model in [Package, Content, ManPage, SymbolicLink]: + table = Model.objects.model._meta.db_table + logger.info("--> {}".format(table)) + with connection.cursor() as cursor: + cursor.execute("VACUUM FULL ANALYZE {};".format(table)) + + return updated_pkgs, count_updated_pages diff --git a/finder.py b/archmanweb/management/utils/finder.py similarity index 100% rename from finder.py rename to archmanweb/management/utils/finder.py diff --git a/drop_cache.py b/drop_cache.py deleted file mode 100755 index 1ebca34..0000000 --- a/drop_cache.py +++ /dev/null @@ -1,16 +0,0 @@ -#! /usr/bin/env python3 - -import os - -import django -from django.db import connection - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "local_settings") -django.setup() - -with connection.cursor() as c: - c.execute("UPDATE archmanweb_content SET html = NULL WHERE html IS NOT NULL;") - c.execute("UPDATE archmanweb_content SET txt = NULL WHERE txt IS NOT NULL;") - c.execute("UPDATE archmanweb_content SET description = NULL WHERE description IS NOT NULL;") - c.execute("UPDATE archmanweb_manpage SET converted_content_id = NULL WHERE converted_content_id IS NOT NULL;") - c.execute("VACUUM FULL archmanweb_content;") -- GitLab From 053d46ff329e3d95e34bbaabba7fdc2b77998f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 29 Nov 2020 19:07:01 +0100 Subject: [PATCH 4/8] finder.py: avoid extracting partial tarballs left after download errors --- archmanweb/management/utils/finder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/archmanweb/management/utils/finder.py b/archmanweb/management/utils/finder.py index 9e41005..e0c4cab 100644 --- a/archmanweb/management/utils/finder.py +++ b/archmanweb/management/utils/finder.py @@ -188,9 +188,9 @@ class ManPagesFinder: # get the pkg tarball _pattern = "{}-{}-{}.pkg.tar.*".format(pkg.name, pkg.version, pkg.arch) - if not list(self.cachedir.glob(_pattern)): + if not list(f for f in self.cachedir.glob(_pattern) if not str(f).endswith(".part")): self._download_package(pkg) - tarballs = sorted(self.cachedir.glob(_pattern)) + tarballs = sorted(f for f in self.cachedir.glob(_pattern) if not str(f).endswith(".part")) assert len(tarballs) > 0, _pattern tarball = tarballs[0] -- GitLab From 1fb70f07c7f0ae3b3c2367dc6ccfcde917319f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 29 Nov 2020 20:00:15 +0100 Subject: [PATCH 5/8] merge the "About" and "Dev" pages into the README.md --- README.md | 158 ++++++++++++++++++++++++++++++++ archmanweb/templates/about.html | 69 -------------- archmanweb/templates/dev.html | 95 ------------------- archmanweb/urls.py | 1 - archmanweb/views/__init__.py | 5 - 5 files changed, 158 insertions(+), 170 deletions(-) delete mode 100644 archmanweb/templates/about.html delete mode 100644 archmanweb/templates/dev.html diff --git a/README.md b/README.md index c90ec62..d2a609c 100644 --- a/README.md +++ b/README.md @@ -38,3 +38,161 @@ for the development, you can run e.g. `update.py --only-repos core` to import only man pages from the core repository (the smallest one, download size is about 160 MiB) or even `update.py --only-packages coreutils man-pages`. + +## About + +This website was created for the [man template](https://wiki.archlinux.org/index.php/Template:Man) +on the Arch wiki. Originally, the template replaced plain text, unclickable +references to man pages with links to [man7.org](https://man7.org/linux/man-pages/), +which contains a handful of manuals taken directly from upstream. Later, we +considered switching to another site providing more manuals. Since we did not +find a suitable external site, we decided to build a new service to satisfy all +our requirements: + +1. All man pages from official Arch packages are available. Old versions and + permalinks are not necessary. +2. Functionality does not require Javascript. +3. Pages are addressable by their name and section, both occurring exactly once + in the URL to avoid problems with pages such as + [ar(1)](https://jlk.fjfi.cvut.cz/arch/manpages/man/ar.1) and + [ar(1p)](https://jlk.fjfi.cvut.cz/arch/manpages/man/ar.1p). +4. The URLs used by the _man_ template should not redirect to permalinks, + otherwise users would start copy-pasting them to the wiki and it would be + hard to check if they are the same as the canonical URLs. +5. Human-readable subsection anchors. +6. The page should clearly indicate the Arch package version containing the + page. + +See the [original discussion](https://wiki.archlinux.org/index.php/Template_talk:Man#Sources) +for details. + +We used a dynamic approach instead of building a website consisting of +completely static pages. The main building blocks are the +[Django web framework](https://www.djangoproject.com/), the +[PostgreSQL](https://www.postgresql.org/) database server, the `mandoc` tool +from the [mandoc toolset](http://mdocml.bsd.lv/) for the conversion to HTML and +the [pyalpm](https://github.com/archlinux/pyalpm) library for data extraction +from the Arch repositories. The code is available in the +[lahwaacz/archmanweb](https://github.com/lahwaacz/archmanweb) repository at +GitHub. + +Overall, this approach allows us to provide the following features without +rebuilding the whole website from scratch: + +- Listings with custom filters and orderings. +- Links to other versions of the same manual provided by different packages. +- Links to similar manuals available in other sections or languages. +- Searching in the names and descriptions of packages and manuals, similarly to + [apropos(1)](https://jlk.fjfi.cvut.cz/arch/manpages/about). + +### Similar projects + +Some similar projects, each using a different approach, are: + +- [manned.org](https://manned.org/) ([code](https://g.blicky.net/manned.git/), + [Arch BBS thread](https://bbs.archlinux.org/viewtopic.php?id=145382)) +- [man7.org](http://man7.org/linux/man-pages/) (no idea about website scripts) +- [manpages.debian.org](https://manpages.debian.org/) + ([source](https://github.com/Debian/debiman/)) +- [man.openbsd.org](http://man.openbsd.org/) (runs with the mandoc CGI script) + +## Test cases + +These links serve as test cases to ensure that all features still work, they +are not useful to regular users. + +### URLs with dots + +- intro +- intro.1 +- intro.1.en +- intro.en +- systemd.service +- systemd.service.5 +- systemd.service.5.en +- systemd.service.en +- gimp-2.8 +- gimp-2.8.1 +- gimp-2.8.1.en +- gimp-2.8.en +- CA.pl +- CA.pl.1ssl +- CA.pl.1ssl.en +- CA.pl.en + +### Best match lookup + +Ambiguous cases are ordered by section, package repository and package version, +then the first manual is selected. + +- mount redirects to + mount.8 + (not mount.2) +- gv redirects to + gv.1 + (not gv.3guile, + gv.3lua etc.) +- graphviz/gv redirects to + graphviz/gv.3guile + (not graphviz/gv.3lua etc.) +- gv.3 redirects to + gv.3guile + (not gv.1, + gv.3lua etc.) +- aliases.5 displays + extra/postfix/aliases.5 + (not community/opensmtpd/aliases.5) +- mysqld.8 displays + extra/mariadb/mysqld.8 + (not community/percona-server/mysqld.8) +- mailx and + mailx.1 redirect to + mail.1.en as a symbolic link + (not mailx.1p) + +### Language fallback + +- nvidia-smi.cs → + nvidia-smi.en → + nvidia-smi.1.en + (maybe we should try harder and avoid the double redirect) +- nvidia-smi.1.cs → + nvidia-smi.1.en +- nvidia-smi.foo → 404 +- nvidia-smi.1.foo → 404 + +### Package filter + +- nvidia-utils/nvidia-smi.en +- nvidia-340xx-utils/nvidia-smi.en +- nvidia-utils/nvidia-smi.cs → + nvidia-utils/nvidia-smi.en +- nvidia-340xx-utils/nvidia-smi.cs → + nvidia-utils/nvidia-340xx-smi.en +- foo/nvidia-smi.cs → 404 +- foo/nvidia-smi.en → 404 + +### .so macros + +There is a groff(1) extension for the +man(7) and +mdoc(7) +languages to include contents of other files using the `.so` macro. In normal +operation where manuals are stored as files on a file system, the +soelim(1) +pre-processor handles the inclusion. Our system is based on a database rather +than a file system, so we need a custom `soelim` as well. + +Some pages which contain the `.so` macro: + +- [.1.zh_CN +- pwunconv(8) +- pam(8) +- url(7) +- xorg.conf.d(5) +- glibc(7) +- systemd-logind(8) +- shorewall6.conf(5) + points to a page contained in a different package (`shorewall` instead of `shorewall6`) +- lsof(8) + (not a "hardlink", includes an invalid file `./00DIALECTS`) diff --git a/archmanweb/templates/about.html b/archmanweb/templates/about.html deleted file mode 100644 index 6c6d249..0000000 --- a/archmanweb/templates/about.html +++ /dev/null @@ -1,69 +0,0 @@ -{% extends "index.html" %} - -{% block content %} -
- -

About

- -

- This website was created for the man template - on the Arch wiki. Originally, the template replaced plain text, unclickable references to man pages with links - to man7.org, which contains a handful of manuals taken directly - from upstream. Later, we considered switching to another site providing more manuals. Since we did not find - a suitable external site, we decided to build a new service to satisfy all our requirements: -

-
    -
  1. All man pages from official Arch packages are available. Old versions and permalinks are not necessary.
  2. -
  3. Functionality does not require Javascript.
  4. -
  5. Pages are addressable by their name and section, both occurring exactly once in the URL to avoid - problems with pages such as ar(1) and - ar(1p). -
  6. -
  7. The URLs used by the man template should not redirect to permalinks, otherwise users would start - copy-pasting them to the wiki and it would be hard to check if they are the same as the canonical URLs. -
  8. -
  9. Human-readable subsection anchors.
  10. -
  11. The page should clearly indicate the Arch package version containing the page.
  12. -
-

- See the original discussion - for details. -

- -

- We used a dynamic approach instead of building a website consisting of completely static pages. The main - building blocks are the Django web framework, the - PostgreSQL database server, the mandoc tool from - the mandoc toolset for the conversion to HTML and the - pyalpm library for data extraction from the Arch repositories. - The code is available in the lahwaacz/archmanweb - repository at GitHub. -

- -

- Overall, this approach allows us to provide the following features without rebuilding the whole website - from scratch: -

-
    -
  • Listings with custom filters and orderings.
  • -
  • Links to other versions of the same manual provided by different packages.
  • -
  • Links to similar manuals available in other sections or languages.
  • -
  • Searching in the names and descriptions of packages and manuals, similarly to - apropos(1). -
- -

Similar projects

- -

- Some similar projects, each using a different approach, are: -

- - -
-{% endblock %} diff --git a/archmanweb/templates/dev.html b/archmanweb/templates/dev.html deleted file mode 100644 index 97f3318..0000000 --- a/archmanweb/templates/dev.html +++ /dev/null @@ -1,95 +0,0 @@ -{% extends "base.html" %} - -{% block head %} - -{% endblock %} - -{% block content %} -
- -

Test cases

- -

These links serve as test cases to ensure that all features still work, they are not useful to regular users.

- -

URLs with dots

- - -

Best match lookup

- -

Ambiguous cases are ordered by section, package repository and package version, then the first manual is selected.

- - - -

Language fallback

- - -

Package filter

- - -

.so macros

-

-There is a groff(1) extension for the -man(7) and mdoc(7) languages -to include contents of other files using the .so macro. In normal operation where manuals are stored -as files on a file system, the soelim(1) pre-processor handles the -inclusion. Our system is based on a database rather than a file system, so we need a custom soelim -as well. -

-

Some pages which contain the .so macro:

- - -
-{% endblock %} diff --git a/archmanweb/urls.py b/archmanweb/urls.py index 50caaae..7b40409 100644 --- a/archmanweb/urls.py +++ b/archmanweb/urls.py @@ -12,5 +12,4 @@ urlpatterns = [ r"(\.(?Phtml|txt|raw))?$", views.man_page, name="man_page"), re_path(r"^search", views.search, name="search"), - re_path(r"^(?P[a-z]+)", views.simple_view, name="simple_view"), ] diff --git a/archmanweb/views/__init__.py b/archmanweb/views/__init__.py index 980f31d..68645f8 100644 --- a/archmanweb/views/__init__.py +++ b/archmanweb/views/__init__.py @@ -23,8 +23,3 @@ def index(request): "last_updates": last_updates, } return render(request, "index.html", context) - -def simple_view(request, *, template_name): - if template_name not in {"about", "dev"}: - raise Http404() - return render(request, "{}.html".format(template_name), {}) -- GitLab From f3e93a55893332ffff768b53649be1a8cf5ddfc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Tue, 15 Dec 2020 22:33:54 +0100 Subject: [PATCH 6/8] index.html: reword the intro paragraph --- archmanweb/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archmanweb/templates/index.html b/archmanweb/templates/index.html index 1a03048..5300803 100644 --- a/archmanweb/templates/index.html +++ b/archmanweb/templates/index.html @@ -6,7 +6,7 @@

This website is a repository of all manual pages available in the Arch Linux packages. -It is an unofficial project created and maintained by the ArchWiki administrators. +The project was initially created for the man template on the Arch wiki. The code is developed in a GitHub repository.

-- GitLab From 36a6d2bba0d7f544207213508ae4c661b2e0bbbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sat, 19 Dec 2020 19:27:51 +0100 Subject: [PATCH 7/8] replace sitestatic with the archlinux-common-style repository --- .gitmodules | 3 + archlinux-common-style | 1 + archmanweb/templates/base.html | 16 +-- settings.py | 5 +- sitestatic/archnavbar/archlogo.png | Bin 5359 -> 0 bytes sitestatic/archnavbar/archlogo.svg | 194 --------------------------- sitestatic/archnavbar/archnavbar.css | 28 ---- sitestatic/favicon.ico | Bin 575 -> 0 bytes 8 files changed, 16 insertions(+), 231 deletions(-) create mode 100644 .gitmodules create mode 160000 archlinux-common-style delete mode 100644 sitestatic/archnavbar/archlogo.png delete mode 100644 sitestatic/archnavbar/archlogo.svg delete mode 100644 sitestatic/archnavbar/archnavbar.css delete mode 100644 sitestatic/favicon.ico diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fb394de --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "archlinux-common-style"] + path = archlinux-common-style + url = https://gitlab.archlinux.org/archlinux/archlinux-common-style.git diff --git a/archlinux-common-style b/archlinux-common-style new file mode 160000 index 0000000..fe41472 --- /dev/null +++ b/archlinux-common-style @@ -0,0 +1 @@ +Subproject commit fe41472481348017b99e31f205235cdcaa0d556f diff --git a/archmanweb/templates/base.html b/archmanweb/templates/base.html index 3000ced..e2f90a2 100644 --- a/archmanweb/templates/base.html +++ b/archmanweb/templates/base.html @@ -6,17 +6,17 @@ {% block title %}Arch manual pages{% endblock %} - - - - + + + + {% block head %} {% endblock %}
diff --git a/settings.py b/settings.py index f17e7af..34da583 100644 --- a/settings.py +++ b/settings.py @@ -32,8 +32,11 @@ STATIC_URL = "/static/" STATIC_ROOT = os.path.join(BASE_DIR, "collected_static") # Look for more static files in these locations +# (use a tuple to keep the directory namespaced) +# https://docs.djangoproject.com/en/3.1/ref/settings/#prefixes-optional STATICFILES_DIRS = ( - os.path.join(BASE_DIR, "sitestatic"), + ("archlinux-common", os.path.join(BASE_DIR, "archlinux-common-style/css")), + ("archlinux-common", os.path.join(BASE_DIR, "archlinux-common-style/img")), ) # Static files backend that appends the MD5 hash of the file’s content to the filename diff --git a/sitestatic/archnavbar/archlogo.png b/sitestatic/archnavbar/archlogo.png deleted file mode 100644 index 3d2cd40fb499b2b37651ea67ec6f3b4400e3d157..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5359 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 - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sitestatic/archnavbar/archnavbar.css b/sitestatic/archnavbar/archnavbar.css deleted file mode 100644 index 1cf4f98..0000000 --- a/sitestatic/archnavbar/archnavbar.css +++ /dev/null @@ -1,28 +0,0 @@ -/* - * ARCH GLOBAL NAVBAR - * We're forcing all generic selectors with !important - * to help prevent other stylesheets from interfering. - */ - -/* container for the entire bar */ -#archnavbar { min-height: 40px !important; padding: 10px 15px !important; background: #333 !important; border-bottom: 5px #08c solid !important; } -#archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url('archlogo.png') no-repeat !important; } -@media (-webkit-min-device-pixel-ratio: 1.2), (min--moz-device-pixel-ratio: 1.2), (-o-min-device-pixel-ratio: 2/1) { - #archnavbarlogo { float: left !important; margin: 0 !important; padding: 0 !important; height: 40px !important; width: 190px !important; background: url(archlogo.svg) no-repeat !important;background-size:100% !important; - } -} - -/* move the heading/paragraph text offscreen */ -#archnavbarlogo p { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } -#archnavbarlogo h1 { margin: 0 !important; padding: 0 !important; text-indent: -9999px !important; } - -/* make the link the same size as the logo */ -#archnavbarlogo a { display: block !important; height: 40px !important; width: 190px !important; } - -/* display the list inline, float it to the right and style it */ -#archnavbar ul { display: block !important; list-style: none !important; margin: 0 !important; padding: 0 !important; font-size: 0px !important; text-align: right !important; } -#archnavbar ul li { display: inline-block !important; font-size: 14px !important; font-family: sans-serif !important; line-height: 14px !important; padding: 14px 15px 0px !important; } - -/* style the links */ -#archnavbar ul#archnavbarlist li a { color: #999; font-weight: bold !important; text-decoration: none !important; } -#archnavbar ul li a:hover { color: white !important; text-decoration: underline !important; } diff --git a/sitestatic/favicon.ico b/sitestatic/favicon.ico deleted file mode 100644 index 55497b852fc438a7a63041822a64deac8ad92527..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 575 zcmV-F0>J%=P)K~y-6jgvo!6G0Tle=|GDx_9PaSMatt8xuJ=jueWZ*0zF( zjc8@z38oPY2!}RWYjKN}g`kaCi1-H-uCNkOgxf0BeA-5$w9LxMMtXHz@2@3 zyz+UJPuh|vi*mtJavK=cNwf1dpEbZ!a<``>o|1IZ?Bv;J>;8WS9J=%2sOyMVt`f_h zlJvCko4lXZH(|7*(w!f`Tnu;_ptK?Jqw7?)K+hZAu%R^ukDjFp75q4Pbjddz93wNAlTi;8fmk1LdSvP5vdgJg^M# zaG-vgp9c5>)Q7GRMsXQ9!>~RL)NlL5fD7Ck3IMJGg}hz^t^pqh0-C^eU>&Fc%V89s z01(qlD|><0z!Ts~QmejXjKU~B2rL4Jfq5~#v~m%6p46(=A2%lGz#nlao8kSq3cLUS N002ovPDHLkV1na%{Dc4i -- GitLab From 0cceda088687cbea7099c2631e0ef7ed7360f182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= Date: Sun, 10 Jan 2021 22:47:53 +0100 Subject: [PATCH 8/8] update links from GitHub to GitLab --- README.md | 2 +- archmanweb/templates/base.html | 2 +- archmanweb/templates/index.html | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d2a609c..5ad15bd 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ completely static pages. The main building blocks are the from the [mandoc toolset](http://mdocml.bsd.lv/) for the conversion to HTML and the [pyalpm](https://github.com/archlinux/pyalpm) library for data extraction from the Arch repositories. The code is available in the -[lahwaacz/archmanweb](https://github.com/lahwaacz/archmanweb) repository at +[archmanweb](https://gitlab.archlinux.org/archlinux/archmanweb) repository at GitHub. Overall, this approach allows us to provide the following features without diff --git a/archmanweb/templates/base.html b/archmanweb/templates/base.html index e2f90a2..cc4356b 100644 --- a/archmanweb/templates/base.html +++ b/archmanweb/templates/base.html @@ -60,7 +60,7 @@ {% endblock %}