From 21132d90b784fcbaed147db78f2289f9e94021a1 Mon Sep 17 00:00:00 2001 From: nixo Date: Thu, 10 Dec 2020 14:49:04 +0100 Subject: [PATCH] init --- readme.org | 10 + settings.py | 211 ++++++ setup.sh | 4 + system.scm | 86 +++ weblate-service.scm | 414 ++++++++++++ weblate.scm | 1570 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 2295 insertions(+) create mode 100644 readme.org create mode 100644 settings.py create mode 100755 setup.sh create mode 100644 system.scm create mode 100644 weblate-service.scm create mode 100644 weblate.scm diff --git a/readme.org b/readme.org new file mode 100644 index 0000000..4d49204 --- /dev/null +++ b/readme.org @@ -0,0 +1,10 @@ +* How to run + + Create dirs for postgres (=/srv/pgdata-weblate=) and weblate + (=/var/lib/weblate=) data and run + + #+begin_src shell + ./setup.sh + #+end_src + + which will start a container with all required services. diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..ed3d576 --- /dev/null +++ b/settings.py @@ -0,0 +1,211 @@ +# +# Copyright © 2012 - 2020 Michal Čihař +# +# This file is part of Weblate +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import platform +from logging.handlers import SysLogHandler + +from weblate.settings_example import * # noqa + +ADMINS = (("Weblate Admin", "noreply@your-host.xyz"),) +MANAGERS = ADMINS + +DATABASES = { + "default": { + # Use "postgresql" or "mysql". + "ENGINE": "django.db.backends.postgresql", + # Database name. + "NAME": "weblate", + # Database user. + "USER": "weblate", + # Name of role to alter to set parameters in PostgreSQL, + # use in case role name is different than user used for authentication. + # "ALTER_ROLE": "weblate", + # Database password. + # "PASSWORD": "", + # Set to empty string for localhost. + "HOST": "localhost", + # Set to empty string for default. + "PORT": "5431", + # Customizations for databases. + "OPTIONS": { + # In case of using an older MySQL server, + # which has MyISAM as a default storage + # "init_command": "SET storage_engine=INNODB", + # Uncomment for MySQL older than 5.7: + # "init_command": "SET sql_mode='STRICT_TRANS_TABLES'", + # Set emoji capable charset for MySQL: + # "charset": "utf8mb4", + # Change connection timeout in case you get MySQL gone away error: + # "connect_timeout": 28800, + }, + } +} + +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# Data Directory +DATA_DIR = "/var/lib/weblate" + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# In a Windows environment this must be set to your system time zone. +TIME_ZONE = "UTC" + + +# ENABLE THIS 3 IN PRODUCTION AND USE NGINX WITH SSL ENABLED +ENABLE_HTTPS = False +SECURE_SSL_REDIRECT = False +SESSION_COOKIE_SECURE = False + +SECRET_KEY = "RANDOM SECRET KEY" +SITE_DOMAIN = "your-host.xyz" + +MEDIA_ROOT = os.path.join(DATA_DIR, "media") +STATIC_ROOT = os.path.join(DATA_DIR, "static") + +CELERY_BEAT_SCHEDULE_FILENAME = os.path.join(DATA_DIR, "celery", "beat-schedule") +CELERY_TASK_ALWAYS_EAGER = False +CELERY_BROKER_URL = "redis://localhost:6379" +CELERY_RESULT_BACKEND = CELERY_BROKER_URL + +# Needed for makemessages, otherwise it does not discover all available locales +# and the -a parameter does not work +LOCALE_PATHS = [os.path.join(os.path.dirname(__file__), "locale")] + +DEBUG = False + +# Silent logging setup +LOGGING = { + "version": 1, + "disable_existing_loggers": True, + "filters": {"require_debug_false": {"()": "django.utils.log.RequireDebugFalse"}}, + "formatters": {"simple": {"format": "%(levelname)s %(message)s"}}, + "handlers": { + "mail_admins": { + "level": "ERROR", + "filters": ["require_debug_false"], + "class": "django.utils.log.AdminEmailHandler", + }, + "console": { + "level": "DEBUG", + "class": "logging.StreamHandler", + "formatter": "simple", + }, + }, + "loggers": { + "django.request": { + "handlers": ["mail_admins"], + "level": "ERROR", + "propagate": True, + }, + "weblate": {"handlers": [], "level": "ERROR"}, + "social": {"handlers": [], "level": "ERROR"}, + }, +} + +# Reset caches +CACHES = { + "default": + { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": "redis://127.0.0.1:6379/0", + # 'LOCATION': 'unix:///var/run/redis/redis.sock?db=0', + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + "PARSER_CLASS": "redis.connection.HiredisParser", + } + }, + "avatar": { + "BACKEND": "django.core.cache.backends.filebased.FileBasedCache", + "LOCATION": os.path.join(DATA_DIR, "avatar-cache"), + "TIMEOUT": 604800, + "OPTIONS": { + "MAX_ENTRIES": 1000, + }, + } +} + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(BASE_DIR, 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.request', + 'django.template.context_processors.csrf', + 'django.contrib.messages.context_processors.messages', + 'weblate.trans.context_processors.weblate_context', + ], + 'loaders': [ + ('django.template.loaders.cached.Loader', [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + ]), + ], + }, + }, +] + +SESSION_COOKIE_HTTPONLY = True + +# Use database backed sessions for transaction consistency in tests +SESSION_ENGINE = "django.contrib.sessions.backends.db" + +# Use weak password hasher in tests, there is no point in spending CPU time +# in hashing test passwords +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', + 'django.contrib.auth.hashers.Argon2PasswordHasher', + 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', + 'django.contrib.auth.hashers.CryptPasswordHasher' +] + +AUTHENTICATION_BACKENDS = ( + "social_core.backends.email.EmailAuth", + "social_core.backends.github.GithubOAuth2", + "social_core.backends.gitlab.GitLabOAuth2", + "weblate.accounts.auth.WeblateUserBackend", +) + +SOCIAL_AUTH_GITLAB_KEY = "" +SOCIAL_AUTH_GITLAB_SECRET = "" +SOCIAL_AUTH_GITLAB_SCOPE = ["read_user"] + +SOCIAL_AUTH_GITHUB_KEY = "" +SOCIAL_AUTH_GITHUB_SECRET = "" +SOCIAL_AUTH_GITHUB_SCOPE = ["user:email"] + +AUTH_VALIDATE_PERMS = True + +SERVER_EMAIL = "" +DEFAULT_FROM_EMAIL = "" + +EMAIL_USE_TLS = True +EMAIL_HOST = "smtp.gmail.com" +EMAIL_PORT = 587 +EMAIL_HOST_PASSWORD = "" +EMAIL_HOST_USER = "" diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..678ab1d --- /dev/null +++ b/setup.sh @@ -0,0 +1,4 @@ +set -e +CMD=$(guix system container system.scm -L . --share=/srv/pgdata-weblate --share=/var/lib/weblate --network) +echo "Running: $CMD" +sudo $CMD diff --git a/system.scm b/system.scm new file mode 100644 index 0000000..db95aac --- /dev/null +++ b/system.scm @@ -0,0 +1,86 @@ +;; Base system +(use-modules (gnu packages base)) +(use-modules (gnu bootloader)) +(use-modules (gnu bootloader grub)) +(use-modules (gnu system file-systems)) +(use-modules (guix packages)) + +;; Helpers +(use-modules (gnu packages curl)) +(use-modules (gnu packages wget)) + +(use-modules (gnu packages python)) +(use-modules (gnu packages gtk)) +(use-modules (gnu packages glib)) +(use-modules (gnu packages version-control)) + +;; Services (ssh, dhcp) +(use-modules (gnu services ssh)) +(use-modules (gnu services networking)) +(use-modules (gnu) (gnu system nss)) + +(use-modules (weblate)) +(use-modules (weblate-service)) +(use-modules (gnu services web)) +(use-modules (gnu packages web)) +(use-modules (gnu packages databases)) +(use-modules (gnu services databases)) +(use-package-modules databases geo) +(use-modules (gnu packages php)) +(use-modules (gnu packages certs)) +(use-modules (guix utils)) + +(define weblate-user + (user-account + (name "weblate") + (group "users") + (supplementary-groups '("netdev")) + (home-directory "/var/lib/weblate"))) + +(define (weblate/settings.py database-user website-url) + (local-file "settings.py")) + +(operating-system + (host-name "weblate") + (timezone "Europe/Rome") + (locale "en_US.utf8") + (locale-libcs (list glibc-2.28 (canonical-package glibc))) + (bootloader (bootloader-configuration (bootloader grub-bootloader))) + (file-systems %base-file-systems) + (users + (cons* weblate-user + %base-user-accounts)) + (packages + (cons* + pango cairo glib gobject-introspection git + nss-certs + %base-packages)) + (services + (cons* + (service dhcp-client-service-type) + ;; Weblate + (service redis-service-type) + (service weblate-service-type + (weblate-configuration + (settings-file (local-file "settings.py")) + (user "weblate") + (group "nginx") + (listen '("0.0.0.0:8765")) + (uwsgi-listen "0.0.0.0:8181") + (root "/var/lib/weblate"))) + (service postgresql-service-type ;postgre + (postgresql-configuration + (postgresql postgresql) + (port 5431) + (data-directory "/srv/pgdata-weblate") + (config-file + (postgresql-config-file + (hba-file + (plain-file "pg_hba.conf" + " +local all all trust +host all all 127.0.0.1/32 trust +host all all ::1/128 trust")))))) + %base-services)) + ;; Allow resolution of '.local' host names with mDNS. + (name-service-switch %mdns-host-lookup-nss)) diff --git a/weblate-service.scm b/weblate-service.scm new file mode 100644 index 0000000..7c5ad53 --- /dev/null +++ b/weblate-service.scm @@ -0,0 +1,414 @@ +(define-module (weblate-service) + #:use-module (weblate) + #:use-module (guix gexp) + #:use-module (guix utils) + #:use-module (guix build python-build-system) + #:use-module (guix packages) + #:use-module (gnu services) + #:use-module (gnu services web) + #:use-module (gnu packages version-control) + #:use-module (gnu packages web) + #:use-module (gnu packages python) + #:use-module (gnu packages ssh) + #:use-module (gnu packages databases) + #:use-module (gnu services shepherd) + #:use-module (guix records) + #:use-module (ice-9 match) + #:use-module (gnu system shadow) + #:export (weblate-configuration + weblate-configuration? + weblate-service-type)) + +(define-record-type* + weblate-configuration make-weblate-configuration + weblate-configuration? + (settings-file weblate-configuration-settings-file) + (user weblate-configuration-user) + (group weblate-configuration-group) + (listen weblate-configuration-listen) + (root weblate-configuration-root) + (uwsgi-listen weblate-configuration-uwsgi-listen)) + + +;; (define %weblate-accounts +;; (list (user-group (name "weblate") (system? #t)) +;; (user-account +;; (name "weblate") +;; (group "weblate") +;; (system? #t) +;; (comment "Weblate server user") +;; (home-directory "/var/empty") +;; (shell (file-append shadow "/sbin/nologin"))))) + +(define (weblate-accounts config) + (let ((user (weblate-configuration-user config)) + (group (weblate-configuration-group config))) + (list (user-group (name group) (system? #t)) + ;; FIXME: change default group in uwsgi.ini + (user-group (name "weblate") (system? #t)) + (user-account + (name user) + (group group) + (system? #t) + (comment "Weblate service user") + (home-directory "/var/empty") + ;; (shell (file-append shadow "/sbin/nologin")) + )))) + +(define weblate-service-type + (service-type (name 'weblate) + (description "Run WEBLATE") + (extensions + (list + (service-extension nginx-service-type weblate-nginx-service) + (service-extension account-service-type + weblate-accounts) + (service-extension activation-service-type + weblate-activation) + (service-extension shepherd-root-service-type + weblate-shepherd-services))))) + +(define (weblate-shepherd-services config) + (list (weblate-initial-database-setup-service config) + (uwsgi-weblate-service config) + (celery-weblate-service config))) + +;; TODO: +;; - Failed to find git-http-backend, the git exporter will not work. +;; - /var/lib/weblate/cache/fonts/ +;; - /var/lib/weblate/home/.gitconfig +;; https://develop.sentry.dev/self-hosted/ + +(define (weblate-initial-database-setup-service config) + (define start-gexp + #~(lambda () + (let ((pid (primitive-fork)) + (postgres (getpwnam "postgres"))) + (if (eq? pid 0) + (dynamic-wind + (const #t) + (lambda () + (setgid (passwd:gid postgres)) + (setuid (passwd:uid postgres)) + (primitive-exit + (if (and + (zero? + (system* #$(file-append postgresql "/bin/createuser") + "--superuser" "weblate")) + (zero? + (system* #$(file-append postgresql "/bin/createdb") + "-O" "weblate" "weblate"))) + 0 + 1))) + (lambda () + (primitive-exit 1))) + (zero? (cdr (waitpid pid))))) + (let ((pid (primitive-fork)) + (weblate (getpwnam "weblate"))) + (if (eq? pid 0) + (dynamic-wind + (const #t) + (lambda () + (setgid (passwd:gid weblate)) + (setuid (passwd:uid weblate)) + (primitive-exit + (begin + (setenv "PYTHONPATH" #$(weblate-configuration-root config)) + (setenv "DJANGO_SETTINGS_MODULE" "guix.settings") + (setenv "PATH" (string-append #$(file-append git) "/bin/")) + (if (and + (zero? + (system* #$(file-append python-weblate "/bin/weblate") + "migrate" "--no-input")) + (zero? + (system* #$(file-append python-weblate "/bin/weblate") + "createadmin" "--password" "default-password" + ;; graceful manage existing admin + ;; "--update" + ))) + 0 + 1)))) + (lambda () + (primitive-exit 1))) + (zero? (cdr (waitpid pid))))))) + (shepherd-service + (requirement '(postgres)) + (provision '(weblate-initial-database-setup)) + (start start-gexp) + (stop #~(const #f)) + (respawn? #f) + (one-shot? #t) + (documentation "Setup Weblate database."))) + +(define (weblate-activation config) + ;; Activation gexp. + #~(begin + (use-modules (guix build utils)) + (let* ((user #$(weblate-configuration-user config)) + (group #$(weblate-configuration-group config)) + (root #$(weblate-configuration-root config)) + (settings-file #$(weblate-configuration-settings-file config))) + (when (not (file-exists? root)) + (mkdir-p root) + (let* ((user (getpwnam user)) + (group (getpwnam group))) + (for-each + (lambda (dir) + (mkdir-p (string-append root "/" dir))) + '("guix" "ssh" "home" "celery" "backups" "cache" "cache/fonts")) + (for-each + (lambda (file) + ;; nginx needs to serve static files + (chmod file #o750) + (chown file (passwd:uid user) (passwd:gid group))) + (find-files root #:directories? #t)))) + ;; Delete stale pid files + (let ((pid-dir (string-append root "/celery/pids")) + (user (getpwnam user)) + (group (getpwnam group))) + (when (file-exists? pid-dir) + (delete-file-recursively pid-dir)) + (mkdir pid-dir) + (chmod pid-dir #o750) + (chown pid-dir (passwd:uid user) (passwd:gid group))) + (let ((pid-dir (string-append root "/home")) + (user (getpwnam user)) + (group (getpwnam group))) + (when (file-exists? pid-dir) + (delete-file-recursively pid-dir)) + (mkdir pid-dir) + (chmod pid-dir #o750) + (chown pid-dir (passwd:uid user) (passwd:gid group))) + (setenv "DATA_DIR" root) + (let ((guix-dir (string-append root "/guix")) + (user (getpwnam user)) + (group (getpwnam group))) + (when (file-exists? guix-dir) + (delete-file-recursively guix-dir)) + (mkdir guix-dir) + (call-with-output-file (string-append root "/guix/__init__.py") + (const #t)) + (chmod guix-dir #o750) + (chmod (string-append root "/guix/__init__.py") #o750) + (chown guix-dir (passwd:uid user) (passwd:gid group)) + ;; TODO: This is copied from the touch implementation somewhere + (copy-file settings-file (string-append root "/guix/settings.py"))) + (copy-file + #$(file-append python-weblate "/lib/python" + (version-major+minor (package-version python)) + "/site-packages/weblate/examples/weblate.uwsgi.ini") + #$(string-append (weblate-configuration-root config) "/uwsgi.ini")) + (substitute* #$(string-append (weblate-configuration-root config) "/uwsgi.ini") + ;; TODO: Change this too + ;; uid = weblate + ;; gid = weblate + (("socket\\s+=.*" all) + (string-append "socket = " + #$(weblate-configuration-uwsgi-listen config) + "\n"))) + (delete-file (string-append root "/guix/settings.py")) + (copy-file #$(weblate-configuration-settings-file config) + (string-append root "/guix/settings.py")) + (let ((user (getpwnam user)) + (group (getpwnam group))) + (for-each + (lambda (file) + (let ((file (string-append + #$(weblate-configuration-root config) + file))) + (chmod file #o750) + (chown file (passwd:uid user) (passwd:gid group)))) + '("/guix/settings.py" "/guix/__init__.py" "/uwsgi.ini"))) + (setenv "PYTHONPATH" #$(weblate-configuration-root config)) + (setenv "DJANGO_SETTINGS_MODULE" "guix.settings") + (setenv "GI_TYPELIB_PATH" + ;; FIXE: use the correct path + "/run/current-system/profile/lib/girepository-1.0") + (let ((pid (primitive-fork)) + (weblate (getpwnam "weblate"))) + (if (eq? pid 0) + (dynamic-wind + (const #t) + (lambda () + (setgid (passwd:gid weblate)) + (setuid (passwd:uid weblate)) + (primitive-exit + (if (system* + #$(file-append python-weblate "/bin/weblate") + "collectstatic" "--noinput") + 0 + 1))) + (lambda () + (primitive-exit 1))) + (zero? (cdr (waitpid pid))))) + (let ((user (getpwnam user)) + (group (getpwnam group))) + (for-each + (lambda (file) + ;; nginx needs to serve static files + (chmod file #o750) + (chown file (passwd:uid user) (passwd:gid group))) + (find-files "static" #:directories? #t)) + ;; Be sure that private key permissions are right + (let ((private-key (string-append root "/ssh/id_rsa"))) + (chmod private-key #o600) + (chown private-key (passwd:uid user) (passwd:gid group))))))) + +(define (weblate-nginx-service config) + (let ((listen (weblate-configuration-listen config)) + (root (weblate-configuration-root config))) + (list + (nginx-server-configuration + (listen listen) + (server-name '("weblate")) + (root root) + (locations + (list + (nginx-location-configuration + (uri "~ ^/favicon.ico$") + (body `(,(string-append "alias " root "/static/favicon.ico;") + "expires 30d;"))) + (nginx-location-configuration + (uri "/static/") + (body `(,(string-append "alias " root "/static/;") + "expires 30d;"))) + (nginx-location-configuration + (uri "/media/") + (body `(,(string-append "alias " root "/media/;") + "expires 30d;"))) + (nginx-location-configuration + (uri "/") + (body + `(,#~(string-append + "include " '#$nginx + "/share/nginx/conf/uwsgi_params;") + "# Needed for long running operations in" + "# admin interface" + "uwsgi_read_timeout 3600;" + "# Adjust based to uwsgi configuration:" + "# uwsgi_pass unix:///run/uwsgi/app/weblate/socket;" + ,(string-append "uwsgi_pass " + (weblate-configuration-uwsgi-listen config) + ";")))))) + (try-files (list "$uri" "$uri/index.html")))))) + +(define (uwsgi-weblate-service config) + (shepherd-service + (documentation "Run uwsgi weblate service.") + (provision '(weblate-uwsgi)) + (requirement '(networking)) + (start #~(make-forkexec-constructor + '(#$(file-append uwsgi "/bin/uwsgi") + #$(string-append (weblate-configuration-root config) "/uwsgi.ini")) + #:environment-variables + `(,(string-append "PYTHONPATH=" + #$(weblate-configuration-root config)) + "DJANGO_SETTINGS_MODULE=guix.settings" + "GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt" + "LC_ALL=en_US.utf8" "LANG=en_US.utf8" + "GI_TYPELIB_PATH=/run/current-system/profile/lib/girepository-1.0") + ;; ;; #:environment-variables + ;; (list (string-append "PYTHON_PATH=" root)) + #:user #$(weblate-configuration-user config))) + (stop #~(make-kill-destructor)))) + +;; FIXME: this is an hack to get a celery program that knows where to +;; find weblate dependencies +(define python-celery-for-weblate + (package + (inherit python-celery) + (propagated-inputs + (list + (append + (package-inputs python-celery) + `("python-weblate" ,python-weblate)))))) + +(define (celery-weblate-service config) + (shepherd-service + (documentation "Run celery weblate service. Restart with RESTART.") + (provision '(weblate-celery)) + ;; TODO: abstract the celery call and put it here according to + ;; https://docs.weblate.org/en/latest/admin/install.html#background-tasks-using-celery + ;; (actions '((shepherd-action + ;; (name 'reststart) + ;; (documentation "Restart celery runners") + ;; (procedure #~(lambda (running . args) + ;; (format #t "Hello, friend! arguments: ~s\n" + ;; args) + ;; #t))))) + (requirement '(networking)) ;redis? + (auto-start? #t) + (start #~(lambda _ ;; celery is forking + (let ((pid (primitive-fork)) + (weblate (getpwnam "weblate"))) + (if (eq? pid 0) + (dynamic-wind + (const #t) + (lambda () + (setgid (passwd:gid weblate)) + (setuid (passwd:uid weblate)) + (setenv "GIT_SSL_CAINFO" "/etc/ssl/certs/ca-certificates.crt") + (primitive-exit + (if (zero? + (system* + #$(file-append python-celery-for-weblate "/bin/celery") + "multi" "start" + ;; Processes to start + "celery" "notify" "backup" "memory" "translate" + ;; must be under a folder which is writable by weblate! + (string-append + "--pidfile=" + #$(weblate-configuration-root config) + "/celery/pids/weblate-%n.pid") + (string-append + "--logfile=" + #$(weblate-configuration-root config) + "/celery/weblate-%n%I.log") + ;; FIXME: pass as param! + (string-append "--loglevel=" "INFO") + "-A" "weblate.utils" + "--beat:celery" + "--queues:celery=celery" + "--prefetch-multiplier:celery=4" + "--queues:notify=notify" + "--prefetch-multiplier:notify=10" + "--queues:memory=memory" + "--prefetch-multiplier:memory=10" + "--queues:translate=translate" + "--prefetch-multiplier:translate=4" + "--concurrency:backup=1" + "--queues:backup=backup" + "--prefetch-multiplier:backup=2")) + 0 + 1))) + (lambda () + (primitive-exit 1))) + (zero? (cdr (waitpid pid))))) + #:environment-variables + ;; FIXME: use python-weblate store path instead of this + `(,(string-append + "PYTHONPATH=" + (string-join + (list + ;; for settings path + #$(weblate-configuration-root config) + ;; FIXME: Replace the hack above + ;; (python-celery-for-weblate) with the right list + ;; of search paths. This include weblate path and + ;; all weblate dependencies + ) + ":")) + "GIT_SSL_CAINFO=/etc/ssl/certs/ca-certificates.crt" + "DJANGO_SETTINGS_MODULE=guix.settings" + ;; Internal Weblate variable to indicate we're running inside Celery + "CELERY_WORKER_RUNNING=1") + ;; #:environment-variables + ;; '( + ;; + ;; "LC_ALL=en_US.utf8" "LANG=en_US.utf8" + ;; "GI_TYPELIB_PATH=/run/current-system/profile/lib/girepository-1.0") + ;; ;; #:environment-variables + ;; (list (string-append "PYTHON_PATH=" root)) + #:user #$(weblate-configuration-user config) + #:group #$(weblate-configuration-group config))) + (stop #~(make-kill-destructor)))) diff --git a/weblate.scm b/weblate.scm new file mode 100644 index 0000000..6baeee1 --- /dev/null +++ b/weblate.scm @@ -0,0 +1,1570 @@ +(define-module (weblate) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (gnu packages) + #:use-module (gnu packages acl) + #:use-module (gnu packages certs) + #:use-module (gnu packages autotools) + #:use-module (gnu packages django) + #:use-module (gnu packages python-xyz) + #:use-module (gnu packages algebra) + #:use-module (gnu packages adns) + #:use-module (gnu packages aidc) + #:use-module (gnu packages attr) + #:use-module (gnu packages backup) + #:use-module (gnu packages bash) + #:use-module (gnu packages check) + #:use-module (gnu packages cmake) + #:use-module (gnu packages compression) + #:use-module (gnu packages crypto) + #:use-module (gnu packages databases) + #:use-module (gnu packages dbm) + #:use-module (gnu packages djvu) + #:use-module (gnu packages docker) + #:use-module (gnu packages enchant) + #:use-module (gnu packages file) + #:use-module (gnu packages fontutils) + #:use-module (gnu packages gcc) + #:use-module (gnu packages geo) + #:use-module (gnu packages ghostscript) + #:use-module (gnu packages gl) + #:use-module (gnu packages glib) + #:use-module (gnu packages gnome) + #:use-module (gnu packages gnupg) + #:use-module (gnu packages graphviz) + #:use-module (gnu packages graphics) + #:use-module (gnu packages gsasl) + #:use-module (gnu packages gstreamer) + #:use-module (gnu packages gtk) + #:use-module (gnu packages haskell-xyz) + #:use-module (gnu packages icu4c) + #:use-module (gnu packages image) + #:use-module (gnu packages kerberos) + #:use-module (gnu packages libevent) + #:use-module (gnu packages libffi) + #:use-module (gnu packages libidn) + #:use-module (gnu packages linux) + #:use-module (gnu packages llvm) + #:use-module (gnu packages man) + #:use-module (gnu packages maths) + #:use-module (gnu packages monitoring) + #:use-module (gnu packages multiprecision) + #:use-module (gnu packages networking) + #:use-module (gnu packages ncurses) + #:use-module (gnu packages openstack) + #:use-module (gnu packages pcre) + #:use-module (gnu packages perl) + #:use-module (gnu packages photo) + #:use-module (gnu packages pkg-config) + #:use-module (gnu packages python) + #:use-module (gnu packages python-check) + #:use-module (gnu packages python-compression) + #:use-module (gnu packages python-crypto) + #:use-module (gnu packages python-science) + #:use-module (gnu packages python-web) + #:use-module (gnu packages qt) + #:use-module (gnu packages rdf) + #:use-module (gnu packages readline) + #:use-module (gnu packages sdl) + #:use-module (gnu packages search) + #:use-module (gnu packages shells) + #:use-module (gnu packages sphinx) + #:use-module (gnu packages ssh) + #:use-module (gnu packages terminals) + #:use-module (gnu packages tex) + #:use-module (gnu packages texinfo) + #:use-module (gnu packages textutils) + #:use-module (gnu packages time) + #:use-module (gnu packages tls) + #:use-module (gnu packages version-control) + #:use-module (gnu packages video) + #:use-module (gnu packages web) + #:use-module (gnu packages wxwidgets) + #:use-module (gnu packages base) + #:use-module (gnu packages xml) + #:use-module (gnu packages xorg) + #:use-module (gnu packages xdisorg) + #:use-module (gnu packages tcl) + #:use-module (gnu packages bdw-gc) + #:use-module (gnu packages serialization) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (guix hg-download) + #:use-module (guix utils) + #:use-module (guix build-system gnu) + #:use-module (guix build-system cmake) + #:use-module (guix build-system python) + #:use-module (guix build-system trivial) + #:use-module (gnu packages ruby) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26)) + +(define-public python-weblate-schemas + (package + (name "python-weblate-schemas") + (version "0.4") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/WeblateOrg/weblate_schemas.git") + (commit version))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "0vc09skp257bv5hksv4rklm1s91km9d90808wyp4yfz6m4ykp65m")))) + (build-system python-build-system) + (propagated-inputs + `(("python-jsonschema" ,python-jsonschema))) + (home-page "https://weblate.org/") + (synopsis + "A collection of schemas used by Weblate") + (description + "A collection of schemas used by Weblate") + (license #f))) + +(define-public python-translate-toolkit + (package + (name "python-translate-toolkit") + (version "3.2.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "translate-toolkit" version ".tar.gz")) + (sha256 + (base32 "01zw59j7h1mhw7vlxbsgdw9b7lsp2jda82jh3f60qhmhhvp28d8g")))) + (build-system python-build-system) + (native-inputs + `(("python-pytest" ,python-pytest) + ("python-sphinx" ,python-sphinx))) + (propagated-inputs + `(("python-babel" ,python-babel) + ("python-beautifulsoup4" ,python-beautifulsoup4) + ("python-chardet" ,python-chardet) + ("python-diff-match-patch" ,python-diff-match-patch) + ("python-levenshtein" ,python-levenshtein) + ("python-lxml" ,python-lxml) + ("python-six" ,python-six) + ("python-vobject" ,python-vobject) + ("python-pyyaml" ,python-pyyaml))) + (arguments + ;; TODO: tests are not run, because they end with + ;; TypeError: parse() missing 2 required positional arguments: 'tree' and + ;; 'parse_funcs' + ;; during test setup. + `(#:tests? #f)) + (home-page "https://toolkit.translatehouse.org") + (synopsis "Tools and API for translation and localization engineering") + (description + "Tools and API for translation and localization engineering. It contains +several utilities, as well as an API for building localization tools.") + (license license:gpl2+))) + +(define-public python-weblate-language-data + (package + (name "python-weblate-language-data") + (version "2020.13") + (source + (origin + (method url-fetch) + (uri (pypi-uri "weblate-language-data" version)) + (sha256 + (base32 + "16a3qx5schf1cc466q36yjjaqjk9ivf0s4rrkwy0y1zhs8vfmwrp")))) + (propagated-inputs + `(("python-translate-toolkit" ,python-translate-toolkit))) + (inputs + `(("python-django" ,python-django))) + (build-system python-build-system) + (home-page "https://weblate.org/") + (synopsis "Language definitions for Weblate") + (description "Language definitions for Weblate") + (license license:expat))) + +(define-public python-pkgconfig-1.5 + (package + (name "python-pkgconfig") + (version "1.5.1") + (source + (origin + (method url-fetch) + (uri (pypi-uri "pkgconfig" version)) + (sha256 + (base32 + "0krminx3qng8sicknzfvjwwcj6brbl25kwiyxbapbdmsh7cy7gwp")))) + (build-system python-build-system) + (native-inputs + `(("python-nose" ,python-nose) + ("python-pytest" ,python-pytest))) + (inputs + `(("pkg-config" ,pkg-config))) + (arguments + `(#:tests? #f + #:phases + (modify-phases %standard-phases + (add-before 'build 'patch + ;; Hard-code the path to pkg-config. + (lambda _ + (substitute* "pkgconfig/pkgconfig.py" + (("cmd = 'pkg-config") + (string-append "cmd = '" (which "pkg-config")))) + #t))))) + (home-page "https://github.com/matze/pkgconfig") + (synopsis "Python interface for pkg-config") + (description "This module provides a Python interface to pkg-config. It +can be used to find all pkg-config packages, check if a package exists, +check if a package meets certain version requirements, query CFLAGS and +LDFLAGS and parse the output to build extensions with setup.py.") + (license license:expat))) + +(define-public xmlsec-openssl + (package + (inherit xmlsec) + (name "xmlsec-openssl") + ;; (native-inputs + ;; ;; For tests. + ;; `(("openssl:bin" ,nss "bin") ; for certutil + ;; ,@(package-native-inputs xmlsec))) + (inputs + `(("openssl" ,openssl) + ("libltdl" ,libltdl))) + (synopsis "XML Security Library (using OpenSSL instead of GnuTLS)"))) + +(define-public python-xmlsec + (package + (name "python-xmlsec") + (version "1.3.9") + (source + (origin + (method url-fetch) + (uri (pypi-uri "xmlsec" version)) + (sha256 + (base32 + "1c4k42zv3plm6v65p7z6l5rxyf50h40d02nhc16vq7cjrfvdf4rx")))) + (build-system python-build-system) + (arguments + '(#:tests? #f)) + (propagated-inputs + `(("python-lxml" ,python-lxml) + ("python-setuptools_scm" ,python-setuptools-scm) + ("python-toml" ,python-toml) + ("python-pkgconfig" ,python-pkgconfig-1.5))) + (native-inputs + `(("pkg-config" ,pkg-config))) + (inputs + `(("xmlsec" ,xmlsec-openssl) + ("openssl" ,openssl) + ("libltdl" ,libltdl))) + (home-page + "https://github.com/mehcode/python-xmlsec") + (synopsis + "Python bindings for the XML Security Library") + (description + "Python bindings for the XML Security Library") + (license license:expat))) + +(define-public python-python3-saml + (package + (name "python-python3-saml") + (version "1.9.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "python3-saml" version)) + (sha256 + (base32 + "1ni38csisy0gymqh62zvi7f2v1f0yagpghdar63im6knj5ajxjk8")))) + (build-system python-build-system) + (arguments + ;no module named tests + `(#:tests? #f)) + (propagated-inputs + `(("python-defusedxml" ,python-defusedxml) + ("python-isodate" ,python-isodate) + ("python-xmlsec" ,python-xmlsec))) + (native-inputs + `(("python-coverage" ,python-coverage) + ("python-coveralls" ,python-coveralls) + ("python-flake8" ,python-flake8) + ("python-freezegun" ,python-freezegun) + ("python-pylint" ,python-pylint))) + (home-page + "https://github.com/onelogin/python3-saml") + (synopsis + "Onelogin Python Toolkit. Add SAML support to your Python software using this library") + (description + "Onelogin Python Toolkit. Add SAML support to your Python software using this library") + (license license:expat))) + +(define-public python-social-auth-core + (package + (name "python-social-auth-core") + (version "3.3.3") + (source + (origin + (method url-fetch) + (uri (pypi-uri "social-auth-core" version)) + (sha256 + (base32 + "1h3zwzgf5q5i6kdl2samxs8z14j29rypyr3dp0vwrcn2ispy2v1g")))) + (build-system python-build-system) + (arguments + '(#:tests? #f)) + (propagated-inputs + `(("python-cryptography" ,python-cryptography) + ("python-defusedxml" ,python-defusedxml) + ("python-oauthlib" ,python-oauthlib) + ("python-openid" ,python-openid) + ("python-pyjwt" ,python-pyjwt) + ;; ("python-python3-openid" ,python-python3-openid) + ("python-requests" ,python-requests) + ("python-python3-saml" ,python-python3-saml) + ("python-jose" ,python-jose) + ("python-requests-oauthlib" + ,python-requests-oauthlib) + ("python-ecdsa" ,python-ecdsa) + ("python-six" ,python-six))) + (inputs + `(("python-pytest" ,python-pytest) + ("python-pytest-cov" ,python-pytest-cov) + ("python-httpretty" ,python-httpretty) + ("python-unittest2" ,python-unittest2))) + (home-page + "https://github.com/python-social-auth/social-core") + (synopsis + "Python social authentication made simple.") + (description + "Python social authentication made simple.") + (license license:bsd-3))) + +(define-public python-social-auth-app-django + (package + (name "python-social-auth-app-django") + (version "4.0.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "social-auth-app-django" version)) + (sha256 + (base32 + "0h48f19ag4g08349azfwizwz7r6bj8cmz72i4cc9q35ky1yyas9c")))) + (build-system python-build-system) + ;; (inputs + ;; `(("python-mock" ,python-mock))) + (arguments + ;; requested setting SOCIAL_AUTH_POSTGRES_JSONFIELD, but settings + ;; are not configured. You must either define the environment + ;; variable DJANGO_SETTINGS_MODULE or call settings.configure() + ;; before accessing settings. + '(#:tests? #f)) + (propagated-inputs + `(("python-six" ,python-six) + ("python-translate-toolkit" ,python-translate-toolkit) + ("python-social-auth-core" ,python-social-auth-core) + ("python-django" ,python-django))) + (home-page + "https://github.com/python-social-auth/social-app-django") + (synopsis + "Python Social Authentication, Django integration.") + (description + "Python Social Authentication, Django integration.") + (license license:bsd-3))) + +(define-public python-siphashc + (package + (name "python-siphashc") + (version "2.1") + (source + (origin + (method url-fetch) + (uri (pypi-uri "siphashc" version)) + (sha256 + (base32 + "14mrhzqlxkljr826079zqzcknzspsdhqn7syvg1i3570y5a28r21")))) + (build-system python-build-system) + (home-page + "https://github.com/WeblateOrg/siphashc") + (synopsis "Python module (in c) for siphash-2-4") + (description + "Python module (in c) for siphash-2-4") + (license #f))) + +(define-public python-setuptools-44 + (package + (name "python-setuptools") + (version "44.0.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "setuptools" version ".zip")) + (sha256 + (base32 + "025h5cnxcmda1893l6i12hrwdvs1n8r31qs6q4pkif2v7rrggfp5")) + (modules '((guix build utils))) + (snippet + '(begin + ;; Remove included binaries which are used to build self-extracting + ;; installers for Windows. + ;; TODO: Find some way to build them ourself so we can include them. + (for-each delete-file (find-files "setuptools" "^(cli|gui).*\\.exe$")) + #t)))) + (build-system python-build-system) + ;; FIXME: Tests require pytest, which itself relies on setuptools. + ;; One could bootstrap with an internal untested setuptools. + (arguments + `(#:tests? #f)) + (home-page "https://pypi.org/project/setuptools/") + (synopsis + "Library designed to facilitate packaging Python projects") + (description + "Setuptools is a fully-featured, stable library designed to facilitate +packaging Python projects, where packaging includes: +Python package and module definitions, +distribution package metadata, +test hooks, +project installation, +platform-specific details, +Python 3 support.") + ;; TODO: setuptools now bundles the following libraries: + ;; packaging, pyparsing, six and appdirs. How to unbundle? + (license (list license:psfl ; setuptools itself + license:expat ; six, appdirs, pyparsing + license:asl2.0 ; packaging is dual ASL2/BSD-2 + license:bsd-2)))) + +(define-public python-asttokens + (package + (name "python-asttokens") + (version "2.0.4") + (source + (origin + (method url-fetch) + (uri (pypi-uri "asttokens" version)) + (sha256 + (base32 + "0a2ixiz04aw4p0aivxh47k3fa9ql804l3y5iv5gcih9aizi5fbm4")))) + (build-system python-build-system) + (propagated-inputs `(("python-six" ,python-six))) + (native-inputs + `(("python-astroid" ,python-astroid) + ("python-setuptools-scm" ,python-setuptools-scm) + ("python-wheel" ,python-wheel) + ("python-toml" ,python-toml) + ("python-setuptools" ,python-setuptools-44) + ("python-pytest" ,python-pytest))) + (home-page + "https://github.com/gristlabs/asttokens") + (synopsis + "Annotate AST trees with source code positions") + (description + "Annotate AST trees with source code positions") + (license license:asl2.0))) + +(define-public python-executing + (package + (name "python-executing") + (version "0.5.3") + (source + (origin + (method url-fetch) + (uri (pypi-uri "executing" version)) + (sha256 + (base32 + "0yb3fy0zhk02hbjy7l5lg350wbvvd4127d3lfz56yq0b3s29q0qc")))) + (inputs `(("python-setuptools-scm" ,python-setuptools-scm) + ("python-wheel" ,python-wheel) + ("python-toml" ,python-toml) + ("python-asttokens" ,python-asttokens))) + (build-system python-build-system) + (home-page + "https://github.com/alexmojaki/executing") + (synopsis + "Get the currently executing AST node of a frame, and other information") + (description + "Get the currently executing AST node of a frame, and other information") + (license license:expat))) + +(define-public python-pure-eval + (package + (name "python-pure-eval") + (version "0.1.1") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/alexmojaki/pure_eval.git") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "19q32wxw9zwy2dsm8ryajmx4fxr3bgymilcrvpq8c70ywb54cj1q")))) + (arguments + `(#:tests? #f + #:phases + (modify-phases %standard-phases + (add-before 'build 'set-version + (lambda _ + (substitute* "pyproject.toml" + ((".*tool\\.setuptools_scm.*" all) "") + ((".*write_to.*" all) "")) + (call-with-output-file "pure_eval/version.py" + (lambda (port) + (format port + "__version__ = '~a'" version)))))))) + (build-system python-build-system) + (propagated-inputs + `(("python-setuptools_scm" ,python-setuptools-scm) + ("python-setuptools" ,python-setuptools-44) + ("python-toml" ,python-toml) + ("python-wheel" ,python-wheel))) + (home-page + "") + (synopsis + "") + (description + "") + (license #f))) + +(define-public python-sentry-sdk + (package + (name "python-sentry-sdk") + (version "0.19.4") + (source + (origin + (method url-fetch) + (uri (pypi-uri "sentry-sdk" version)) + (sha256 + (base32 + "074cfrhkimavq333zfg8mr9030hdjqbscjryrdk2ylsf13nz0lhh")))) + (build-system python-build-system) + (arguments '(#:tests? #f)) + (propagated-inputs + `(("python-aiohttp" ,python-aiohttp) + ("python-botocore" ,python-botocore) + ("python-bottle" ,python-bottle) + ("python-celery" ,python-celery) + ("python-certifi" ,python-certifi) + ("python-falcon" ,python-falcon) + ("python-django" ,python-django) + ("python-flask" ,python-flask) + ("python-blinker" ,python-blinker) + ("python-pure-eval" ,python-pure-eval) + ("python-executing" ,python-executing) + ("python-asttokens" ,python-asttokens) + ("python-rq" ,python-rq) + ("python-urllib3" ,python-urllib3))) + (home-page + "https://github.com/getsentry/sentry-python") + (synopsis + "Python client for Sentry (https://sentry.io)") + (description + "Python client for Sentry (https://sentry.io)") + (license license:bsd-3))) + +(define-public python-redis-lock + (package + (name "python-redis-lock") + (version "3.7.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "python-redis-lock" version)) + (sha256 + (base32 + "0x437capjc2z36xp7kyn3cx5zis4bi46c9swry56liwxwdva8ra2")))) + (build-system python-build-system) + (propagated-inputs + `(("python-redis" ,python-redis))) + (home-page + "https://github.com/ionelmc/python-redis-lock") + (synopsis + "Lock context manager implemented via redis SETNX/BLPOP.") + (description + "Lock context manager implemented via redis SETNX/BLPOP.") + (license license:bsd-2))) + +(define-public python-wirerope + (package + (name "python-wirerope") + (version "0.4.2") + (source + (origin + (method url-fetch) + (uri (pypi-uri "wirerope" version)) + (sha256 + (base32 + "17dp3i85ik2d8f5x240a7h7rxqyymv35aakr11rk39m6ygfnjcwh")))) + (build-system python-build-system) + (propagated-inputs `(("python-six" ,python-six))) + (native-inputs + `(("python-pytest" ,python-pytest) + ("python-pytest-cov" ,python-pytest-cov))) + (home-page + "https://github.com/youknowone/wirerope") + (synopsis + "'Turn functions and methods into fully controllable objects'") + (description + "'Turn functions and methods into fully controllable objects'") + (license #f))) + +(define-public python-pycodestyle + (package + (name "python-pycodestyle") + (version "2.6.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "pycodestyle" version)) + (sha256 + (base32 + "0bhr6ia0hmgx3nhgibc9pmkzhlh1zcqk707i5fbxgs702ll7v2n5")))) + (arguments + ;; 'testsuite.test_all' has no attribute 'suite' + '(#:tests? #f)) + (build-system python-build-system) + (home-page "https://pycodestyle.readthedocs.io/") + (synopsis "Python style guide checker") + (description "Python style guide checker") + (license license:expat))) + +(define-public python-tox-pyenv + (package + (name "python-tox-pyenv") + (version "1.1.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "tox-pyenv" version)) + (sha256 + (base32 + "1r4r4pyg6zkxsldahl3g36iz6xyh5yrvziajahxhpv3saw9j4v4i")))) + (build-system python-build-system) + (propagated-inputs + `(("python-tox" ,python-tox) + ("python-pycodestyle" ,python-pycodestyle) + ("python-mock" ,python-mock) + ("python-pylint" ,python-pylint))) + (home-page + "https://github.com/samstav/tox-pyenv") + (synopsis + "tox plugin that makes tox use `pyenv which` to find python executables") + (description + "tox plugin that makes tox use `pyenv which` to find python executables") + (license license:asl2.0))) + +(define-public python-methodtools + (package + (name "python-methodtools") + (version "0.4.2") + (source + (origin + (method url-fetch) + (uri (pypi-uri "methodtools" version)) + (sha256 + (base32 + "1ini66jcfmz7bx1w6383fmfbr0lynqq6vlxx5vnk0nxfjgfm0c30")))) + (build-system python-build-system) + (propagated-inputs + `(("python-wirerope" ,python-wirerope))) + (native-inputs + `(("python-pytest" ,python-pytest) + ("python-pytest-cov" ,python-pytest-cov) + ("python-tox" ,python-tox) + ("python-tox-pyenv" ,python-tox-pyenv) + ("python-sphinx" ,python-sphinx))) + (home-page + "https://github.com/youknowone/methodtools") + (synopsis "Expand standard functools to methods") + (description + "Expand standard functools to methods") + (license #f))) + +(define-public python-borgbackup + (package + (name "python-borgbackup") + (version "1.1.14") + (source + (origin + (method url-fetch) + (uri (pypi-uri "borgbackup" version)) + (sha256 + (base32 + "1fpdj73cgp96xwasdcifxl7q2pr1my2f4vfdjpv771llri3hgfvx")))) + (build-system python-build-system) + (inputs `(("openssl" ,openssl) + ("lz4" ,lz4) + ("libb2" ,libb2) + ("zstd" ,zstd) + ("acl" ,acl))) + (propagated-inputs + `(("python-setuptools_scm" ,python-setuptools-scm))) + (arguments + `(#:phases + (modify-phases %standard-phases + (replace 'build + (lambda* (#:key inputs #:allow-other-keys) + (setenv "BORG_OPENSSL_PREFIX" + (string-append (assoc-ref inputs "openssl"))) + (setenv "BORG_LIBLZ4_PREFIX" + (string-append (assoc-ref inputs "lz4"))) + (setenv "BORG_LIBB2_PREFIX" + (string-append (assoc-ref inputs "libb2"))) + (setenv "BORG_LIBZSTD_PREFIX" + (string-append (assoc-ref inputs "zstd"))) + (invoke "python" "setup.py" "build")))))) + (home-page "https://borgbackup.readthedocs.io/") + (synopsis + "Deduplicated, encrypted, authenticated and compressed backups") + (description + "Deduplicated, encrypted, authenticated and compressed backups") + (license license:bsd-3))) + +(define-public python-user-agents + (package + (name "python-user-agents") + (version "2.2.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "user-agents" version)) + (sha256 + (base32 + "09mddriffm9rkwr30081fy9n3cn976ms8pwc8p8hhlxnilbjavfk")))) + (build-system python-build-system) + (arguments + `(#:tests? #f)) ;missing devices.json test file in release + (propagated-inputs + `(("python-ua-parser" ,python-ua-parser))) + (home-page "https://github.com/selwin/python-user-agents") + (synopsis "User Agent strings parsing library") + (description + "A library to identify devices (phones, tablets) and their capabilities by +parsing (browser/HTTP) user agent strings.") + (license license:expat))) + +(define-public python-ua-parser + (package + (name "python-ua-parser") + (version "0.10.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "ua-parser" version)) + (sha256 + (base32 + "0csh307zfz666kkk5idrw3crj1x8q8vsqgwqil0r1n1hs4p7ica7")))) + (build-system python-build-system) + (arguments `(#:tests? #f)) + (native-inputs + `(("python-pyyaml" ,python-pyyaml))) + (home-page "https://github.com/ua-parser/uap-python") + (synopsis "User agent parser") + (description + "@code{ua-parser} is a Python port of Browserscope's user agent parser.") + (license license:asl2.0))) + +(define-public python-translation-finder + (package + (name "python-translation-finder") + (version "2.5") + (source + (origin + (method url-fetch) + (uri (pypi-uri "translation-finder" version)) + (sha256 + (base32 + "1cmx0f38cl8g5wy16j5z1i1yqab1m4kvfj2lp9l91dcz8dasawmy")))) + (build-system python-build-system) + (arguments + `(#:phases + (modify-phases %standard-phases + (add-before 'build 'remove-failing-test + (lambda _ + (delete-file "translation_finder/test_api.py") + #t))))) + (propagated-inputs + `(("python-chardet" ,python-chardet) + ("python-pathlib2" ,python-pathlib2) + ("python-ruamel.yaml" ,python-ruamel.yaml) + ("python-weblate-language-data" + ,python-weblate-language-data) + ("python-six" ,python-six))) + (native-inputs + `(("python-codecov" ,python-codecov) + ("python-codacy-coverage" ,python-codacy-coverage) + ("python-pytest-cov" ,python-pytest-cov) + ("python-pytest-runner" ,python-pytest-runner) + ("python-twine" ,python-twine))) + (home-page "https://weblate.org/") + (synopsis "Translation file finder for Weblate") + (description "This package provides a function to find translation file in +the source code of a project. It supports many translation file formats and +is part of the Weblate translation platform.") + (license license:gpl3+))) + +(define-public python-redis-lock + (package + (name "python-redis-lock") + (version "3.6.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "python-redis-lock" version)) + (sha256 + (base32 + "1xx8n35hh3jrg4xi564v3jbxgs94sdb619dyrsxlgkzg5xzvhybc")))) + (build-system python-build-system) + (propagated-inputs + `(("python-redis" ,python-redis))) + (home-page + "https://github.com/ionelmc/python-redis-lock") + (synopsis + "Lock context manager implemented via redis SETNX/BLPOP.") + (description + "Lock context manager implemented via redis SETNX/BLPOP.") + (license license:bsd-2))) + +(define-public python-jellyfish + (package + (name "python-jellyfish") + (version "0.8.0") + (source (origin + (method url-fetch) + (uri (pypi-uri "jellyfish" version)) + (sha256 + (base32 + "1larbd0m1i60243y9w4gy6hx98zysx57xgwmi6rrxsjfpc6hjk6v")))) + (build-system python-build-system) + (native-inputs + `(("python-pytest" ,python-pytest))) + (home-page "https://github.com/jamesturk/jellyfish") + (synopsis "Approximate and phonetic matching of strings") + (description "Jellyfish uses a variety of string comparison and phonetic +encoding algorithms to do fuzzy string matching.") + (license license:bsd-2) + (properties `((python2-variant . ,(delay python2-jellyfish)))))) + +(define-public python-hiredis + (package + (name "python-hiredis") + (version "1.1.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "hiredis" version)) + (sha256 + (base32 + "0cii3kfmv6kpiasp720sw9ymgr8g5915ysrdzybhpxg06gpj2q4r")))) + (arguments + '(#:tests? #f)) + (build-system python-build-system) + (home-page "https://github.com/redis/hiredis-py") + (synopsis "Python wrapper for hiredis") + (description "Python wrapper for hiredis") + (license license:bsd-3))) + +(define-public python-diff-match-patch + (package + (name "python-diff-match-patch") + (version "20200713") + (source + (origin + (method url-fetch) + (uri (pypi-uri "diff-match-patch" version)) + (sha256 + (base32 + "063s8zcxz787xfg7d1wxpqh59fxg3iz85ww9zhyz4vaqm80mlvys")))) + (arguments + '(#:tests? #f)) + (build-system python-build-system) + (home-page "https://code.google.com/p/google-diff-match-patch") + (synopsis "Synchronize plain text") + (description "Diff Match and Patch libraries offer robust algorithms to +perform the operations required for synchronizing plain text.") + (license license:asl2.0))) + +(define-public python-pre-commit + (package + (name "python-pre-commit") + (version "2.9.3") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/pre-commit/pre-commit") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "1dsvk7gnm53pcrqqra4gljw00pgbkjw82rarxfrvhvyy1l3s02nz")))) + (build-system python-build-system) + (arguments + `(#:tests? #f ;FIXME! + #:phases + (modify-phases %standard-phases + ;; open-fdes permission denied? + (delete 'reset-gzip-timestamps)) + ;; #:phases + ;; (modify-phases %standard-phases + ;; (replace 'check + ;; (lambda _ + ;; (invoke "pytest" "tests")))) + )) + (native-inputs + `(("python-pytest" ,python-pytest) + ("python-tox" ,python-tox) + ("python-re-assert" ,python-re-assert) + ;; required for tests + ("which" ,which) + ("gem" ,ruby) + ("git" ,git))) + (propagated-inputs + `(("python-cfgv" ,python-cfgv) + ("python-identify" ,python-identify) + ("python-importlib-metadata" + ,python-importlib-metadata) + ("python-importlib-resources" + ,python-importlib-resources) + ("python-nodeenv" ,python-nodeenv) + ("python-pyyaml" ,python-pyyaml) + ("python-toml" ,python-toml) + ("python-virtualenv" ,python-virtualenv))) + (home-page + "https://github.com/pre-commit/pre-commit") + (synopsis + "A framework for managing and maintaining multi-language pre-commit hooks.") + (description + "A framework for managing and maintaining multi-language pre-commit hooks.") + (license license:expat))) + +(define-public python-aws-xray-sdk-0 + (package + (name "python-aws-xray-sdk") + (version "0.95") + (home-page "https://github.com/aws/aws-xray-sdk-python") + (source (origin + (method git-fetch) + (uri (git-reference (url home-page) (commit version))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "1mzr5n1k32ivsgi9bd5sfz70gy3gybpvh5qyvs9zi28xiin6i2yy")))) + (build-system python-build-system) + ;; (arguments + ;; `(#:phases (modify-phases %standard-phases + ;; (add-after 'unpack 'disable-tests + ;; (lambda _ + ;; (for-each delete-file + ;; '(;; These tests require packages not yet in Guix. + ;; "tests/ext/aiobotocore/test_aiobotocore.py" + ;; "tests/ext/aiohttp/test_middleware.py" + ;; "tests/ext/pg8000/test_pg8000.py" + ;; "tests/ext/psycopg2/test_psycopg2.py" + ;; "tests/ext/pymysql/test_pymysql.py" + ;; "tests/ext/pynamodb/test_pynamodb.py" + ;; "tests/test_async_recorder.py" + + ;; ;; FIXME: Why is this failing? + ;; "tests/test_patcher.py" + + ;; ;; TODO: How to configure Django for these tests. + ;; "tests/ext/django/test_db.py" + ;; "tests/ext/django/test_middleware.py" + + ;; ;; These tests want to access httpbin.org. + ;; "tests/ext/requests/test_requests.py" + ;; "tests/ext/httplib/test_httplib.py" + ;; "tests/ext/aiohttp/test_client.py")))) + ;; (replace 'check + ;; (lambda _ + ;; (setenv "PYTHONPATH" + ;; (string-append "./build/lib:.:" + ;; (getenv "PYTHONPATH"))) + ;; (invoke "pytest" "-vv" "tests")))))) + (arguments `(#:tests? #f)) + (native-inputs + `( ;; These are required for the test suite. + ("python-bottle" ,python-bottle) + ("python-flask" ,python-flask) + ("python-flask-sqlalchemy" ,python-flask-sqlalchemy) + ("python-pymysql" ,python-pymysql) + ("python-pytest" ,python-pytest) + ("python-pytest-aiohttp" ,python-pytest-aiohttp) + ("python-requests" ,python-requests) + ("python-sqlalchemy" ,python-sqlalchemy) + ("python-webtest" ,python-webtest))) + (propagated-inputs + `(("python-aiohttp" ,python-aiohttp) + ("python-botocore" ,python-botocore) + ("python-future" ,python-future) + ("python-jsonpickle" ,python-jsonpickle) + ("python-urllib3" ,python-urllib3) + ("python-wrapt" ,python-wrapt))) + (synopsis "Profile applications on AWS X-Ray") + (description + "The AWS X-Ray SDK for Python enables Python developers to record and +emit information from within their applications to the AWS X-Ray service.") + (license license:asl2.0))) + +(define-public python-nose-random + (package + (name "python-nose-random") + ;; only tag existing, from 4 years ago + (version "1.0.0") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/ZoomerAnalytics/nose-random") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + "1dsvk7gnm53pcrqqra4gljw00pgbkjw82rarxfrvhvyy1l3s02na")))) + (build-system python-build-system) + (home-page + "https://github.com/ZoomerAnalytics/nose-random") + (synopsis "") + (description "") + (license #f))) + +(define-public python-jsondiff + (package + (name "python-jsondiff") + ;; python-moto wants this exact version! + (version "1.1.1") + (source + (origin + (method url-fetch) + (uri (pypi-uri "jsondiff" version)) + (sha256 + (base32 + "14vqiyxdsrrq0qzpk6mxk4cdnyixyicsm5766kx8whg95mw3f11d")))) + ;; should add nose random, see above + (arguments `(#:tests? #f)) + (build-system python-build-system) + (home-page + "https://github.com/ZoomerAnalytics/jsondiff") + (synopsis + "Diff JSON and JSON-like structures in Python") + (description + "Diff JSON and JSON-like structures in Python") + (license #f))) + +(define-public python-moto-1.3.7 + (package + (name "python-moto") + ;; XXX: Use a pre-release for compatibility with latest botocore & friends. + (version "1.3.7") + (source (origin + (method url-fetch) + (uri (pypi-uri "moto" version)) + (sha256 + (base32 + "1igwndp6xhwy7sqfpd3ry5p45dfi5qayq8n7nbwdjl5j9khf578j")))) + (build-system python-build-system) + ;; (arguments + ;; `(#:phases (modify-phases %standard-phases + ;; (add-after 'unpack 'patch-hardcoded-executable-names + ;; (lambda _ + ;; (substitute* "moto/batch/models.py" + ;; (("/bin/sh") + ;; (which "sh"))) + ;; (substitute* (find-files "tests" "\\.py$") + ;; (("#!/bin/bash") + ;; (string-append "#!" (which "bash")))) + ;; #t)) + ;; (replace 'check + ;; (lambda _ + ;; (setenv "PYTHONPATH" (string-append "./build/lib:" + ;; (getenv "PYTHONPATH"))) + ;; (invoke "pytest" "-vv" "-m" "not network" + ;; ;; These tests require Docker. + ;; "-k" "not test_terminate_job \ + ;; and not test_invoke_function_from_sqs_exception")))))) + (native-inputs + `(("python-flask" ,python-flask) + ("python-flask-cors" ,python-flask-cors) + ("python-freezegun" ,python-freezegun) + ("python-parameterized" ,python-parameterized) + ("python-pytest" ,python-pytest) + ("python-sure" ,python-sure))) + (propagated-inputs + `(("python-aws-xray-sdk" ,python-aws-xray-sdk-0) + ("python-boto" ,python-boto) + ("python-jsondiff" ,python-jsondiff) + ("python-boto3" ,python-boto3) + ("python-botocore" ,python-botocore) + ("python-cfn-lint" ,python-cfn-lint) + ("python-cryptography" ,python-cryptography) + ("python-dateutil" ,python-dateutil) + ("python-docker" ,python-docker) + ("python-idna" ,python-idna) + ("python-jinja2" ,python-jinja2) + ("python-jose" ,python-jose) + ("python-jsondiff" ,python-jsondiff) + ("python-mock" ,python-mock) + ("python-pytz" ,python-pytz) + ("python-pyyaml" ,python-pyyaml) + ("python-requests" ,python-requests) + ("python-responses" ,python-responses) + ("python-six" ,python-six) + ("python-sshpubkeys" ,python-sshpubkeys) + ("python-werkzeug" ,python-werkzeug) + ("python-xmltodict" ,python-xmltodict))) + (home-page "https://github.com/spulec/moto") + (synopsis "Mock out the boto library") + (description + "@code{moto} is a library designed to easily mock out the +@code{boto} library.") + (license license:asl2.0))) + +(define-public python-celery + (package + (name "python-celery") + (version "5.0.3") + (source + (origin + (method url-fetch) + (uri (pypi-uri "celery" version)) + (sha256 + (base32 + "12x6xnljyp5j8dxpas1cag3jr83nqb27k2bfjhfc957wlvyb1g6p")))) + (build-system python-build-system) + ;; enabling tests I'm pulling in alot of old dependencies + (arguments + '(#:tests? #f)) + (native-inputs + `(("python-case" ,python-case) + ("python-pytest" ,python-pytest))) + (propagated-inputs + `(("python-pytz" ,python-pytz) + ("python-msgpack" ,python-msgpack) + ("python-pre-commit" ,python-pre-commit) + ("python-pyyaml" ,python-pyyaml) + ("python-click-plugins" ,python-click-plugins) + ("python-billiard" ,python-billiard) + ("python-pygobject" ,python-pygobject) + ("python-kombu" ,python-kombu))) + (home-page "https://celeryproject.org") + (synopsis "Distributed Task Queue") + (description "Celery is an asynchronous task queue/job queue based on +distributed message passing. It is focused on real-time operation, but +supports scheduling as well. The execution units, called tasks, are executed +concurrently on a single or more worker servers using multiprocessing, +Eventlet, or gevent. Tasks can execute asynchronously (in the background) or +synchronously (wait until ready).") + (license license:bsd-3) + (properties `((python2-variant . ,(delay python2-celery)))))) + +(define-public python-click-repl + (package + (name "python-click-repl") + (version "0.1.6") + (source + (origin + (method url-fetch) + (uri (pypi-uri "click-repl" version)) + (sha256 + (base32 + "1mcmz95595nrp4r58spy1ac993db26hk4q97isghbmn4md99vwmr")))) + (build-system python-build-system) + (propagated-inputs + `(("python-click" ,python-click) + ("python-prompt-toolkit" ,python-prompt-toolkit) + ("python-six" ,python-six))) + (home-page + "https://github.com/untitaker/click-repl") + (synopsis "REPL plugin for Click") + (description "REPL plugin for Click") + (license license:expat))) + +(define-public python-click-didyoumean + (package + (name "python-click-didyoumean") + (version "0.0.3") + (source + (origin + (method url-fetch) + (uri (pypi-uri "click-didyoumean" version)) + (sha256 + (base32 + "1svaza5lpvdbmyrx5xi0riqzq4hb9wnlpqrg6r8zy14pbi42j8hi")))) + (build-system python-build-system) + (propagated-inputs + `(("python-click" ,python-click))) + (home-page + "https://github.com/timofurrer/click-didyoumean") + (synopsis + "Enable git-like did-you-mean feature in click.") + (description + "Enable git-like did-you-mean feature in click.") + (license #f))) + +(define-public python-vine + (package + (name "python-vine") + (version "5.0.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "vine" version)) + (sha256 + (base32 + "0zk3pm0g7s4qfn0gk28lfmsyplvisaxi6826cgpq5njkm4j1cfvx")))) + (build-system python-build-system) + (native-inputs + `(("python-pytest" ,python-pytest) + ("python-case" ,python-case))) + (home-page "https://github.com/celery/vine") + (synopsis "Promises for Python") + (description + "@code{vine} provides a special implementation of promises in that it can +be used both for \"promise of a value\" and lazy evaluation. The biggest +upside for this is that everything in a promise can also be a promise, +e.g. filters, callbacks and errbacks can all be promises.") + (license license:bsd-3))) + +(define-public python-amqp + (package + (name "python-amqp") + (version "5.0.2") + (source + (origin + (method url-fetch) + (uri (pypi-uri "amqp" version)) + (sha256 + (base32 + "117pnbhwvlcmwvm9d4aw3yp417898c2x3xkg92rikz5pxsxb7mgw")))) + (build-system python-build-system) + (arguments '(#:tests? #f)) ;some tests requiring network + (native-inputs + `(("python-case" ,python-case) + ("python-pytest-sugar" ,python-pytest-sugar) + ("python-pytest-rerunfailures" ,python-pytest-rerunfailures) + ("python-mock" ,python-mock))) + (propagated-inputs + `(("python-vine" ,python-vine))) + (home-page "https://github.com/celery/py-amqp") + (synopsis + "Low-level AMQP client for Python (fork of amqplib)") + (description + "This is a fork of amqplib which was originally written by Barry Pederson. +It is maintained by the Celery project, and used by kombu as a pure python +alternative when librabbitmq is not available.") + (license license:lgpl2.1+) + (properties `((python2-variant . ,(delay python2-amqp)))))) + +(define-public python-kombu + (package + (name "python-kombu") + (version "5.0.2") + (source + (origin + (method url-fetch) + (uri (pypi-uri "kombu" version)) + (sha256 + (base32 + "0g5c0lg2abva1d8nrc824jk5fcvf8kbbbvhb8xyx86271ax5z5pl")))) + (build-system python-build-system) + (native-inputs + `(("python-mock" ,python-mock) + ("python-case" ,python-case) + ("python-pyro4" ,python-pyro4) + ("python-pytest-sugar" ,python-pytest-sugar) + ("python-pytz" ,python-pytz))) + (propagated-inputs + `(("python-anyjson" ,python-anyjson) + ("python-amqp" ,python-amqp) + ("python-redis" ,python-redis))) + (home-page "https://kombu.readthedocs.io") + (synopsis "Message passing library for Python") + (description "The aim of Kombu is to make messaging in Python as easy as +possible by providing an idiomatic high-level interface for the AMQ protocol, +and also provide proven and tested solutions to common messaging problems. +AMQP is the Advanced Message Queuing Protocol, an open standard protocol for +message orientation, queuing, routing, reliability and security, for which the +RabbitMQ messaging server is the most popular implementation.") + (license license:bsd-3) + (properties `((python2-variant . ,(delay python2-kombu)))))) + +(define-public python-billiard + (package + (name "python-billiard") + (version "3.6.3.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "billiard" version)) + (sha256 + (base32 + "0spssl3byzqsplra166d59jx8iqfxyzvcbx7vybkmwr5ck72a5yr")))) + (arguments + '(#:tests? #f)) + (build-system python-build-system) + (native-inputs + `(("python-case" ,python-case) + ("python-pytest" ,python-pytest))) + (home-page "https://github.com/celery/billiard") + (synopsis + "Python multiprocessing fork with improvements and bugfixes") + (description + "Billiard is a fork of the Python 2.7 multiprocessing package. The +multiprocessing package itself is a renamed and updated version of R Oudkerk's +pyprocessing package. This standalone variant is intended to be compatible with +Python 2.4 and 2.5, and will draw its fixes/improvements from python-trunk.") + (license license:bsd-3) + (properties `((python2-variant . ,(delay python2-billiard)))))) + +(define-public python-pytest-rerunfailures + (package + (name "python-pytest-rerunfailures") + (version "9.1.1") + (source + (origin + (method url-fetch) + (uri (pypi-uri "pytest-rerunfailures" version)) + (sha256 + (base32 + "1wi711wn0xdzd8zwpirsd4p5ycpf2krymdaf84c3j6qjzhbimc8w")))) + (build-system python-build-system) + (propagated-inputs + `(("python-pytest" ,python-pytest) + ("python-setuptools" ,python-setuptools-44))) + (home-page + "https://github.com/pytest-dev/pytest-rerunfailures") + (synopsis + "pytest plugin to re-run tests to eliminate flaky failures") + (description + "pytest plugin to re-run tests to eliminate flaky failures") + (license #f))) + +(define-public python-phply + (package + (name "python-phply") + (version "1.2.5") + (source + (origin + (method url-fetch) + (uri (pypi-uri "phply" version)) + (sha256 + (base32 + "0gwz4j0pp479bwg6iwk7kcdbr1s4x9fikqri0b4ddn7vi198fibx")))) + (build-system python-build-system) + (propagated-inputs + `(("python-ply" ,python-ply) + ("python-nose" ,python-nose))) + (home-page "https://github.com/viraptor/phply") + (synopsis + "Lexer and parser for PHP source implemented using PLY") + (description + "Lexer and parser for PHP source implemented using PLY") + (license license:bsd-3))) + +(define-public python-iniparse + (package + (name "python-iniparse") + (version "0.5") + (source + (origin + (method url-fetch) + (uri (pypi-uri "iniparse" version)) + (sha256 + (base32 + "0hm8784r25l5wrl274x65329l0b7pq3vfyq10jssrrr6slwm4blk")))) + (build-system python-build-system) + (propagated-inputs `(("python-six" ,python-six))) + ;; FIXME: failing tests + (arguments '(#:tests? #f)) + (home-page + "https://github.com/candlepin/python-iniparse") + (synopsis "Accessing and Modifying INI files") + (description "Accessing and Modifying INI files") + (license license:expat))) + +(define-public python-aeidon + (package + (name "python-aeidon") + (version "1.7.0") + (source + (origin + (method url-fetch) + (uri (pypi-uri "aeidon" version)) + (sha256 + (base32 + "0mhkm3gihkvdznmxhlizzihziknjfb3jvlc0dy80zvjxwvf4hpcp")))) + (build-system python-build-system) + (propagated-inputs + `(("python-chardet" ,python-chardet))) + (home-page "https://otsaloma.io/gaupol/") + (synopsis + "aeidon is a Python package for reading, writing and manipulating text-based subtitle files. It is used by the gaupol package, which provides a subtitle editor with a GTK+ user interface.") + (description + "aeidon is a Python package for reading, writing and manipulating text-based subtitle files. It is used by the gaupol package, which provides a subtitle editor with a GTK+ user interface.") + (license #f))) + +(define-public python-weblate + (package + (name "python-weblate") + (version "4.3.2") + (source + (origin + (method url-fetch) + (uri (pypi-uri "Weblate" version)) + (sha256 + (base32 + "0hmb5qvrjsspskf9fm71myyp9y03pql8rm6vksxw8jxhxnc27v82")))) + (build-system python-build-system) + (arguments + `(#:tests? #f + #:phases + (modify-phases %standard-phases + (add-after 'build 'fix-uwsgi-python-path + (let* ((python-version ,(version-major+minor (package-version python))) + (weblate-dir + (string-append "/lib/python" + python-version "/site-packages/"))) + (lambda* (#:key inputs outputs #:allow-other-keys) + (substitute* "weblate/examples/weblate.uwsgi.ini" + (("\\[uwsgi\\]" all) + (string-append all "\n" + "plugins-dir = " + (string-append (assoc-ref inputs "uwsgi-python")) + "/lib/uwsgi/")) + (("python3") "python") + (("wsgi-file.*") + (string-append + "wsgi-file = " (assoc-ref outputs "out") + weblate-dir "weblate/wsgi.py")) + ((".*python-path.*") + (string-join + (map + (lambda (path) + (string-append "python-path = " path)) + (append + (list (string-append (assoc-ref outputs "out") weblate-dir)) + ;; TODO: Use search-path-as-string->list + (string-split (getenv "PYTHONPATH") #\:))) + "\n")) + (("virtualenv.*" all) (string-append "# " all)))))) + (add-after 'build 'set-vcs-paths + (lambda* (#:key inputs #:allow-other-keys) + (substitute* "weblate/vcs/git.py" + (("_cmd = \"git\"") + (format #f "_cmd = ~s" + (string-append (assoc-ref inputs "git") "/bin/git")))) + (substitute* "weblate/gitexport/utils.py" + (("\"git\"") (string-append + "\"" + (assoc-ref inputs "git") "/bin/git" + "\"")) + (("\"/usr/lib/git\"") + (string-append + "\"" + (assoc-ref inputs "git") + ;; path where git-http-backend lives + "/libexec/git-core" + "\""))) + (substitute* "weblate/vcs/mercurial.py" + (("_cmd = \"hg\"") + (format #f "_cmd = ~s" + (string-append (assoc-ref inputs "hg") "/bin/hg")))) + (substitute* "weblate/vcs/ssh.py" + (("exec ssh") + (string-append "exec " (assoc-ref inputs "openssh") "/bin/ssh")) + (("ssh-keyscan") + (string-append (assoc-ref inputs "openssh") "/bin/ssh-keyscan")) + (("ssh-keygen") + (string-append (assoc-ref inputs "openssh") "/bin/ssh-keygen"))))) + (add-after 'unpack 'fix-git-cacert-paths + ;; Weblate runs git in a cleaned environment, in which only + ;; env variables are kept. add GIT_SSL_CAINFO and GIT_EXEC_PATH + ;; to the allowed ones + (lambda _ + (substitute* "weblate/trans/util.py" + (("HTTPS_PROXY\"," all) + (string-append all "\"GIT_SSL_CAINFO\", \"GIT_EXEC_PATH\",")))))))) + (inputs + `(("uwsgi-python" ,uwsgi "python") + ("git" ,git) + ("openssh" ,openssh) + ("hg" ,mercurial))) + (propagated-inputs + `(("cairo" ,cairo) + ("pango" ,pango) + ("glib" ,glib) + ("nss-certs" ,nss-certs) + ("gobject-introspection" ,gobject-introspection) + ("python-bleach" ,python-bleach) + ("python-borgbackup" ,python-borgbackup) + ("python-celery" ,python-celery) + ("python-cssselect" ,python-cssselect) + ("python-cython" ,python-cython) + ("python-dateutil" ,python-dateutil) + ("python-diff-match-patch" + ,python-diff-match-patch) + ("python-django" ,python-django) + ("python-django-appconf" ,python-django-appconf) + ("python-django-compressor" + ,python-django-compressor) + ("python-django-crispy-forms" + ,python-django-crispy-forms) + ("python-django-filter" ,python-django-filter) + ("python-django-redis" ,python-django-redis) + ("python-djangorestframework" + ,python-djangorestframework) + ("python-filelock" ,python-filelock) + ("python-gitpython" ,python-gitpython) + ("python-hiredis" ,python-hiredis) + ("python-html2text" ,python-html2text) + ("python-jellyfish" ,python-jellyfish) + ("python-jsonschema" ,python-jsonschema) + ("python-lxml" ,python-lxml) + ("python-methodtools" ,python-methodtools) + ("python-misaka" ,python-misaka) + ("python-openpyxl" ,python-openpyxl) + ("python-pillow" ,python-pillow) + ("python-pycairo" ,python-pycairo) + ("python-pygobject" ,python-pygobject) + ("python-pyparsing" ,python-pyparsing) + ("python-redis-lock" ,python-redis-lock) + ("python-requests" ,python-requests) + ("python-setuptools" ,python-setuptools-44) + ("python-siphashc" ,python-siphashc) + ("python-social-auth-app-django" + ,python-social-auth-app-django) + ("python-social-auth-core" + ,python-social-auth-core) + ("python-translate-toolkit" + ,python-translate-toolkit) + ("python-translation-finder" + ,python-translation-finder) + ("python-user-agents" ,python-user-agents) + ("python-weblate-language-data" + ,python-weblate-language-data) + ("python-weblate-schemas" + ,python-weblate-schemas) + ("python-psycopg2" ,python-psycopg2) + ("python-mysqlclient" ,python-mysqlclient) + ("python-packaging" ,python-packaging) + ("python-sentry-sdk" ,python-sentry-sdk) + ("python-redis-lock" ,python-redis-lock) + ("python-diff-match-patch" ,python-diff-match-patch) + ("python-hiredis" ,python-hiredis) + ("python-click-repl" ,python-click-repl) + ("python-click-didyoumean" ,python-click-didyoumean) + ("python-jellyfish" ,python-jellyfish) + ("python-ua-parser" ,python-ua-parser) + ("python-vine" ,python-vine) + ("python-iniparse" ,python-iniparse) + ("python-aeidon" ,python-aeidon) + ("python-phply" ,python-phply) + ("python-whoosh" ,python-whoosh))) + (home-page "https://weblate.org/") + (synopsis + "A web-based continuous localization system with tight version control integration") + (description + "A web-based continuous localization system with tight version control integration") + (license #f))) + +python-aeidon