Дата и время публикации:
Проблема и решение
1. Суть проблемы
Реализация локального сервера, замещающего репозитарий testPyPI, которые является публичным индексным репозитарием пакетов Python (Python Package Index, PyPI) и устраняющий угрозу разрушения реального индекса, исходя от pypi.org
Что также делает приватной разработку проектов Python, который может содержать один или несколько пакетов.
pypiserver предоставляет минимальную функциональность совместимую с pip или easy_install (легкая установка и развертывание).[3.1] Он реализован на базе проекта bottle [3.2] и работает с пакетами из регулярной директории. Поддерживает форматы пакетов wheel, eggs [3.3], и так называемой, конечной и зачастую бинарной сборки bdists [3.4], упакованной в бинарном формате одним из выбранных архиватором или упаковщика менеджера пакета Linux формата. Может использоваться вместе с PGP-сигнатурами и загружен либо с помощью утилитами pip, setuptools, twine, pypi-uploader или просто скопирован с scp [3.1].
2. Решение
2.1 Конфигурация, установка и запуск минимального сервера PyPI
Предоставляется пакетом pypiserver, который нужно установить и создать директорию локального репозитария, как показано в дампе 2.1.1
Дамп 2.1.1
$ pip install pypiserver $ mkdir /home/$USER/yocto-poky/pypi-packages ... WARNING: The script pypi-server is installed in '/home/user/.local/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use —no-warn-script-location. ...
В данном случае, директорией локального репозитария /home/$USER/yocto-poky/pypi-packages находится на внешнем носителе информации, смонтированным в точке монтирования /home/$USER/yocto-poky
Далее, в ручную разбиваем директорию на поддиректории, где каждая из них соответствует названию проекта, дерево которого показано в дампе 2.1.2
Дамп 2.1.2
├── bar │ └── bar-0.1.tar.gz └── foo ├── Foo-1.0.tar.gz └── Foo-2.0.tar.gz
В котором показано дерево репозитария, состоящего из поддиректорий с нормализованными именами проекта, внутри которой находятся загружаемые файлы архивов. При этом, в случае наличия нескольких версий, имена файлов архивов должны иметь версии, подобно тому, какие имеют проект bar (одну версию — 0.1), а Foo (c версиями 1.0 и 2.0)
Каждая поддиректория должна иметь нормализованное имя проекта, в соответствии с требованиями PEP 503[3.7], что выражеается в том, что имя поддиректория проекта Foo должна быть приведена к foo, a Bar — bar [3.6]. PEP 503[3.7] так же требует наличие текстовой (индексной) страницы в HTML5, как показано в листинге 2.1.3 . При этом, это требование является обязательно, например, если вместо pypiserver будет использоваться apache2.
Листинг 2.1.4
<!DOCTYPE html> <html> <body> <a href="/foo/">foo <a href="/bar/">bar </body> </html>
В показанной структуре индексной страницы должны быть указаны линки от корня репозитария "/" с привязкой тэга к тексту и имеющий атрибут href, который ссылается на соответствующий проект согласно PEP 503 [3.7].
Поэтому теперь можем попробовать запустить pypiserver, например на сетевом порту 8080, т.к. на моей машине на порту 80 крутится Apache2 c собственном локальном хранилище Git-репозитариев [3.8] . Пробный запуск pypiserver показан в дампе 2.1.5
Дамп 2.1.5
/home/user/.local/bin/pypi-server -p 8080 /home/$USER/yocto-poky/pypi-packages 127.0.0.1 - - [24/Feb/2022 17:35:13] "GET / HTTP/1.1" 200 1007 127.0.0.1 - - [24/Feb/2022 17:35:13] "GET /favicon.ico HTTP/1.1" 404 711 127.0.0.1 - - [24/Feb/2022 17:35:37] "GET /packages/ HTTP/1.1" 200 333 127.0.0.1 - - [24/Feb/2022 17:35:43] "GET /simple/ HTTP/1.1" 200 241 127.0.0.1 - - [24/Feb/2022 17:35:47] "GET /packages/ HTTP/1.1" 200 333 127.0.0.1 - - [24/Feb/2022 17:36:43] "GET /packages/ HTTP/1.1" 200 333 127.0.0.1 - - [24/Feb/2022 17:36:43] "GET /favicon.ico HTTP/1.1" 404 711 ...
Где показан удачный результат загрузки индексной страницы (/packages/) с кодом 200 и факт отказа при загрузки favicon.ico с кодом 404, отсутствие которого не влияет на функционирования pypi-packages, что и подтверждает нам динамически созданная страница для http://localhost:8080
Рисунок 2.1.6
2.2 Запуск в фоновом режиме под менеджера сеанса Systemd
Так как, в моем случае все было установлено в домашней директории, поэтому воспользовался функцию в systemd, реализующую долговременную службу (user_lingering) и позволяющей запускать службу до входа пользователя в систему [3.10]. Для чего, нужно сначало активировать эту функцию, как показано в дампе 2.2.1
Дамп 2.2.1
user@home2:~$ loginctl enable-linger user
При этом, если выполнить loginctl через sudo, то все остальные попытки запуска закончаться ошибкой, которая показан в дампе 2.2.2
Дамп 2.2.2
user@home2:~$ systemctl --user enable pypi-server.service Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=@.host --user to connect to bus of other user)
Потому что у самого пользователя не была активирована функция user_lingering в systemd [3.12]
После активации этой функции у пользователя, для запуска pypi-server нужно создать директорию ~/.config/systemd/user/ , если она не создана и поместить свой unit-файл с расширением .service
Пользовательский процесс systemd запускается сразу после первого входа пользователя в систему, и будет убит после завершения последнего сеанса пользователя. Иногда, может быть полезно запустить службу сразу после загрузки, и поддерживать процесс systemd запущенным даже после завершения последнего сеанса пользователя, например, чтобы некоторый пользовательский процесс работал без какой-либо открытой сессии. Для этой цели используются долговременные службы, которые запускаются из директории ~/.config/systemd/user/ и в unit-файле, как показано в дампе 2.2.3
Дамп 2.2.3
# саt ~/.config/systemd/user/pypi-server.service [Unit] Description=pypiserver daemon [Service] ExecStart=/home/user/.local/bin/pypi-server -p 8080 --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages ExecStop=/bin/kill -TERM $MAINPID ExecReload=/bin/kill -HUP $MAINPID Restart=always WorkingDirectory=/home/user/yocto-poky/pypi-packages [Install] WantedBy=default.target
Теперь нужно, активировать функцию и попробовать запустить сервис, как показано в дампе 2.2.4
Дамп 2.2.4
$ systemctl --user enable pypi-server.service Created symlink /home/user/.config/systemd/user/default.target.wants/pypi-server.service → /home/user/.config/systemd/user/pypi-server.service. ... user@home2:~$ systemctl --user daemon-reload ... user@home2:~$ systemctl --user start pypi-server user@home2:~$ systemctl --user status pypi-server ● pypi-server.service - pypiserver daemon Loaded: loaded (/home/user/.config/systemd/user/pypi-server.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2022-02-25 10:19:21 MSK; 5s ago Main PID: 6741 (pypi-server) Tasks: 1 (limit: 16615) Memory: 17.6M CPU: 201ms CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/pypi-server.service └─6741 /usr/bin/python3 /home/user/.local/bin/pypi-server -p 8080 --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages фев 25 10:19:21 home2 systemd[946]: Started pypiserver daemon.
В случае внесения изменения в файл pypi-server может потребоваться выполнить systemctl с --user daemon-reload, как показано выше в дампе 2.2.4
Для отключения функции поддержки долговременной службы выполните команду из дампа 2.2.5
Дамп 2.2.5
$ systemctl --user stop pypi-server.service $ systemctl --user disable pypi-server.service $ loginctl disable-linger
Соответственно, перед этим мне нужно было остановить службу pypi-server и деактивировать. А уже потом отключить поддежку запуска долговременных служб у пользователя.
2.3 Поддержка процедуры аутентификации
Для ее включения, мне понадобилось установить модуль passlib, который поддерживает разбор, требуемый также при запуске приложения wsgi в Apaches, файла аутентификации формата htpasswd, как показано в дампе 2.3.1
Дамп 2.3.1
$ pip install passlib
Соответственно, после чего добавил пользователя pypisrv, который не зарегистрирован в системе, как показано в дампе 2.3.2
Дамп 2.3.2
$ htpasswd -sc /home/$USER/yocto-poky/pypi-packages/.htpasswd pypisrv
После чего, мне оставалось лишь сделать правки в файл ~/.config/systemd/user/pypi-server.service, как показано в дампе 2.3.3
Дамп 2.3.3
# саt ~/.config/systemd/user/pypi-server.service [Unit] Description=pypiserver daemon [Service] ExecStart=/home/user/.local/bin/pypi-server -p 8080 -a update,download -P /home/$USER/yocto-poky/pypi-packages/.htpasswd --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages ExecStop=/bin/kill -TERM $MAINPID ExecReload=/bin/kill -HUP $MAINPID Restart=always WorkingDirectory=/home/user/yocto-poky/pypi-packages [Install] WantedBy=default.target
В результате, мной были добавлена опция -a (--authenticate) c установленными действиями для аутентификации, такие как updatе или download, и вместе с ней опция -P , где искать файл с паролями.
Далее, мне осталось лишь перезапустить сервиc pypi-sever, как показано в дампе 2.3.4
Дамп 2.3.4
~$ systemctl --user daemon-reload ~$ systemctl --user restart pypi-server.service ~$ systemctl --user status pypi-server.service ● pypi-server.service - pypiserver daemon Loaded: loaded (/home/user/.config/systemd/user/pypi-server.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2022-02-27 21:58:08 MSK; 4s ago Main PID: 20479 (pypi-server) Tasks: 1 (limit: 16615) Memory: 19.1M CPU: 261ms CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/pypi-server.service └─20479 /usr/bin/python3 /home/user/.local/bin/pypi-server -p 8080 -a update,download -P /home/user/yocto-poky/pypi-packages/.htpasswd --log-file /home/user/.local/log/pypi-server.log /home/user/yo>
После чего, установил разработанный мной пакет shellenv-package-rjaan, как показано в дампе 2.3.5
Дамп 2.3.5
~$ pip install --index-url http://localhost:8080/simple/ shellenv-package-rjaan Defaulting to user installation because normal site-packages is not writeable Looking in indexes: http://localhost:8080/simple/ warning: missing-index-doctype × The package index page being used does not have a proper HTML doctype declaration. ╰─> Problematic URL: http://localhost:8080/simple/shellenv-package-rjaan/ note: This is an issue with the page at the URL mentioned above. hint: You might need to reach out to the owner of that package index, to get this fixed. See https://github.com/pypa/pip/issues/10825 for context. Collecting shellenv-package-rjaan User for localhost:8080: pypisrv Password: Downloading http://localhost:8080/packages/myprog/shellenv-package-rjaan-0.1.tar.gz (2.8 kB) Installing build dependencies ... done Getting requirements to build wheel ... done Preparing metadata (pyproject.toml) ... done Building wheels for collected packages: shellenv-package-rjaan Building wheel for shellenv-package-rjaan (pyproject.toml) ... done Created wheel for shellenv-package-rjaan: filename=shellenv_package_rjaan-0.1-py3-none-any.whl size=3539 sha256=7441388ce993b19cd95b0246c7c0b0d53a83517f38ac4b63fdc6e83dc191a28e Stored in directory: /home/user/.cache/pip/wheels/a7/40/d7/e11b7c490a75e5e7decde841885bd8e03e85b615e4d551eeb4 Successfully built shellenv-package-rjaan Installing collected packages: shellenv-package-rjaan Successfully installed shellenv-package-rjaan-0.1
При этом, для загрузки пакета мне понадобилось ввести пару значений аутентификационных данных (выделено жирным), состоящие из имени пользователя – pypisrv и его пароля, установленные ранее в дампе 2.3.2
2.4 Запуск в apache2
В моем случае, речь шла об начальной интеграции хранилища Git-репозитариев, настроенного ранее [3.10], и индексируемого репозитария пакетов Python (Python package index) на уровне разграничения полномочий, потому что все процессы с сайтами в моей конфигурации порождаются от имени пользователя git, а это значит все ранее устанавливаемые которого пораждаются apache2
Поэтому мне понадобилось установить те же самые пакеты Python у пользователя git, что устанавливались ранее во время разворачивания pypi-server, как это показано в дампе 2.4.1
Дамп 2.4.1
$ sudo -u git pip install pypiserver [sudo] пароль для user: Collecting pypiserver Downloading pypiserver-1.4.2-py2.py3-none-any.whl (77 kB) |████████████████████████████████| 77 kB 711 kB/s Installing collected packages: pypiserver WARNING: The script pypi-server is installed in '/home/git/.local/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed pypiserver-1.4.2 $ sudo -u git pip install passlib Collecting passlib Downloading passlib-1.7.4-py2.py3-none-any.whl (525 kB) |████████████████████████████████| 525 kB 2.4 MB/s Installing collected packages: passlib Successfully installed passlib-1.7.4 $ sudo -u git mkdir -p /home/git/pypisrv/wsgi
Для использования Apache2 в связке с pypiserver предпочтительно использовать mod_wsgi [3.1], как предлагается в проекте Buttle [3.13]. Для чего, нужно удостверится, что установлен соответсвующий пакет. Так для Debian-11 таким пакетом является libapache2-mod-wsgi-py3, проверка наличия и установка которого показана в дампе 2.4.2
Дамп 2.4.2
$ apt search libapache2-mod-wsgi-py3 Сортировка… Готово Полнотекстовый поиск… Готово libapache2-mod-wsgi-py3/stable 4.7.1-3+b1 i386 Python 3 WSGI adapter module for Apache $ sudo apt install libapache2-mod-wsgi-py3 [sudo] пароль для user: Чтение списков пакетов… Готово Построение дерева зависимостей… Готово Чтение информации о состоянии… Готово Следующие НОВЫЕ пакеты будут установлены: libapache2-mod-wsgi-py3 ... apache2_invoke: Enable module wsgi
Далее, в директории /etc/apache2, как показано в дампе 2.4.3, настраиваем альтернативные порты 8443 и 8080
Дамп 2.4.3
... Listen 80 Listen 8080 <IfModule ssl_module> Listen 443 Listen 8443 </IfModule> <IfModule mod_gnutls.c> Listen 443 Listen 8443 </IfModule> ...
На основании уже имеющегося файла 000-default.conf в директории /etc/apache2/sites-available создал 001-default.conf под порт 8080 и привел, как показано в дампе 2.4.4
Дамп 2.4.4
sudoedit /etc/apache2/sites-available/001-default.conf ... <VirtualHost *:8080> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin root@localhost DocumentRoot /home/git/pypisrv <Directory /home/git/pypisrv> Require all granted </Directory> # WSGI Settings WSGIScriptAlias / /home/git/pypisrv/wsgi/pypiserver.wsgi WSGIDaemonProcess pypisrv user=git group=git umask=0007 \ processes=1 threads=5 maximum-requests=500 \ display-name=wsgi-pypisrv inactivity-timeout=300 WSGIProcessGroup pypisrv # Required for authentication (https://github.com/pypiserver/pypiserver/issues/288) WSGIPassAuthorization On <Directory /home/git/pypisrv/wsgi> <Files pypiserver.wsgi> Require all granted </Files> </Directory> # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with "a2disconf". #Include conf-available/serve-cgi-bin.conf </VirtualHost>
Как показано в листинге 2.4.5, конструктором pypiserver:app() запускается pypiserver в bottle-приложении со следующей ключевые значения конфигурации:
- root= путь к корневой директории индексного репозитария пакетов Python;
- redirect_to_fallback= установлен в False, запрет переадресации, в случае установки в True должен быть установлен fallback_url=, например fallback_url="http://pypi.python.org/simple";
- password_file= путь к файлу .htpasswd;
- overwrite= в значении True устанавливает перезапись существующих пакетов.
Перезапускаем сервер, как показано в дампе 2.4.6
Дамп 2.4.6
$ sudo service apache2 reload $ sudo service apache2 restart $ sudo service apache2 status ● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2022-02-28 17:25:59 MSK; 3min 0s ago Docs: https://httpd.apache.org/docs/2.4/ Process: 21212 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS) Main PID: 21216 (apache2) Tasks: 64 (limit: 16615) Memory: 53.3M CPU: 699ms CGroup: /system.slice/apache2.service ├─21216 /usr/sbin/apache2 -k start ├─21217 /usr/sbin/apache2 -k start ├─21218 wsgi-pypisrv -k start ├─21219 /usr/sbin/apache2 -k start └─21220 /usr/sbin/apache2 -k start фев 28 17:25:59 home2 systemd[1]: Starting The Apache HTTP Server... фев 28 17:25:59 home2 systemd[1]: Started The Apache HTTP Server.
После чего,, мне осталось лишь настроить доступ Apach-пользователя pypisrv к только что запущенному виртуальном узлу, как это делалось ранее и показано в дампе 2.4.7
Дамп 2.4.7
$ htpasswd -sc /home/git/pypi-packages/.htpasswd pypisrv
Теперь, мне лишь осталось обеспечить доступ по HTTPS и альтернативному порту 8443, т.к. родной порт 443 планирую использовать в дальнейшем с виртуальным узлом, выделенный для обслуживания хранилища Git-репозитариев.
Поэтому переименовал файл 001-default.conf в 002-default.conf в директории /etc/apache2/sites-available и привел к виду, как показано в листинге 2.4.8
Дамп 2.4.8
<VirtualHost *:8443> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin root@localhost DocumentRoot /home/git/pypisrv <Directory /home/git/pypisrv> Require all granted </Directory> # WSGI Settings WSGIScriptAlias / /home/git/pypisrv/wsgi/pypiserver.wsgi #WSGIDaemonProcess pypisrv user=git group=git umask=0007 \ # processes=1 threads=5 maximum-requests=500 \ # display-name=wsgi-pypisrv inactivity-timeout=300 WSGIProcessGroup pypisrv # Required for authentication (https://github.com/pypiserver/pypiserver/issues/288) WSGIPassAuthorization On <Directory /home/git/pypisrv/wsgi> <Files pypiserver.wsgi> Require all granted </Files> </Directory> # SSL Engine Switch: # Enable/Disable SSL for this virtual host. SSLEngine on # A self-signed (snakeoil) certificate can be created by installing # the ssl-cert package. See # /usr/share/doc/apache2/README.Debian.gz for more info. # If both key and certificate are stored in the same file, only the # SSLCertificateFile directive is needed. SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key # SSL Protocol Adjustments: # The safe and default but still SSL/TLS standard compliant shutdown # approach is that mod_ssl sends the close notify alert but doesn't wait for # the close notify alert from client. When you need a different shutdown # approach you can use one of the following variables: # o ssl-unclean-shutdown: # This forces an unclean shutdown when the connection is closed, i.e. no # SSL close notify alert is send or allowed to received. This violates # the SSL/TLS standard but is needed for some brain-dead browsers. Use # this when you receive I/O errors because of the standard approach where # mod_ssl sends the close notify alert. # o ssl-accurate-shutdown: # This forces an accurate shutdown when the connection is closed, i.e. a # SSL close notify alert is send and mod_ssl waits for the close notify # alert of the client. This is 100% SSL/TLS standard compliant, but in # practice often causes hanging connections with brain-dead browsers. Use # this only for browsers where you know that their SSL implementation # works correctly. # Notice: Most problems of broken clients are also related to the HTTP # keep-alive facility, so you usually additionally want to disable # keep-alive for those clients, too. Use variable "nokeepalive" for this. # Similarly, one has to force some clients to use HTTP/1.0 to workaround # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and # "force-response-1.0" for this. BrowserMatch "MSIE [2-6]" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 # MSIE 7 and newer should be able to use keepalive BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown # allow user who has a certificate to access a particular URL if user presented it. # <Location /> # SSLRequireSSL On # SSLVerifyClient optional # SSLVerifyDepth 1 # SSLOptions +StdEnvVars +StrictRequire # </Location> # SSL Engine Options: # Set various options for the SSL engine. # o FakeBasicAuth: # Translate the client X.509 into a Basic Authorisation. This means that # the standard Auth/DBMAuth methods can be used for access control. The # user name is the `one line' version of the client's X.509 certificate. # Note that no password is obtained from the user. Every entry in the user # file needs this password: `xxj31ZMTZzkVA'. # o ExportCertData: # This exports two additional environment variables: SSL_CLIENT_CERT and # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the # server (always existing) and the client (only existing when client # authentication is used). This can be used to import the certificates # into CGI scripts. # o StdEnvVars: # This exports the standard SSL/TLS related `SSL_*' environment variables. # Per default this exportation is switched off for performance reasons, # because the extraction step is an expensive operation and is usually # useless for serving static content. So one usually enables the # exportation for CGI and SSI requests only. # o OptRenegotiate: # This enables optimized SSL connection renegotiation handling when SSL # directives are used in per-directory context. SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire </VirtualHost>
При этом, строчки для WSGIDaemonProcess были закоментированы, т.к. является достяжимой к WSGIDaemonProcess из конфигурации виртуального узла для порта 8080
После чего, нужно задействовать готовый профиль default-ssl, как показано в дампе 2.4.9
Дамп 2.4.9
sudo a2ensite 002-default.conf sudo systemctl restart apache2 sudo systemctl reload apache2
В результате получил картинку, которая показана на рисунке 2.4.10
Рисунок 2.4.10
2.5 Установка пакетов
После чего, смог сделать разработку более безопасной своего первого и маленького проекта shellenv, реализующий функциональность SHELL-команды env(1), которая относится к архаичной системе (legacy system) и выполняемой интерпретатором команд dash, sh, bash, ksh или более свежим их аналогом zsh
Далее, полученные файлы закладываем в локальный индексный репозитарий пакетов Python, который находится в директории /home/git/pypisrv/, как показано в дампе 2.5.1
Дамп 2.5.1
~ /home/git/pypisrv$ exa --tree . ├── shellenv/ └── shellenv-package-rjaan-0.1.tar.gz
После чего, можно выполнить установку пакета shellenv, как показано в дампе 2.5.2
Дамп 2.5.2
pip install --upgrade -U shellenv-package-rjaan --extra-index-url http://localhost:8080/simple
При этом, если использовать --index-url, то возникает ошибка разрешения зависимостей.
Для включения загрузки и установки пакетов с использованием механизма аутентификации в файле /home/git/pypisrv/wsgi/pypiserver.wsgi нужно добавить соответствующую строчку (выделенную жирным) в листинге 2.5.3
Дамп 2.5.3
#!/usr/bin/env python3
# An example pypiserver-wsgi.py for use with apache2 and mod_wsgi, edit as necessary.
#
# apache virtualhost configuration for mod_wsgi daemon mode:
# Alias /robots.txt /srv/yoursite/htdocs/robots.txt
# WSGIPassAuthorization On
# WSGIScriptAlias / /srv/yoursite/cfg/pypiserver.wsgi
# WSGIDaemonProcess pypisrv user=pypisrv group=pypisrv processes=1 threads=5 maximum-requests=500 umask=0007 display-name=wsgi-pypisrv inactivity-timeout=300
# WSGIProcessGroup pypisrv
USER="git"
PACKAGES = "/home/"+USER+"/pypisrv/"
HTPASSWD = PACKAGES+".htpasswd"
import pypiserver
conf = pypiserver.default_config (
root= PACKAGES,
redirect_to_fallback=False,
password_file=HTPASSWD,
auther=pam.authenticate,
overwrite=True )
application = pypiserver.app(**conf)
Добавленная мной строчка auther=pam.authenticate, нужна для реализации поддержки аутентификации провойдеров узлов децентрализованной беспроводной сети (ad hoc authentification providers)[3.19], которая основывается на файловой базы данных учетных записей в среде Linux и подобных Unix-систем.
При этом, нужно доставить пакет pam для пользователя git, от имени которого запускается apache2 и соответственно, как показано в дампе 2.5.4
Дамп 2.5.4
$ sudo -u git pip install --upgrade pam Requirement already satisfied: pam in /home/git/.local/lib/python3.9/site-packages (0.2.0) Collecting pam Using cached pam-0.2.0-py3-none-any.whl (976 bytes) Downloading pam-0.1.4.tar.gz (2.6 kB) Requirement already satisfied: python-pam in /home/git/.local/lib/python3.9/site-packages (from pam) (1.8.4)
После чего, можно попробовать установить пакет shellenv, как показано ниже.
2.6 Совместное использование Git и индексного репозитраия пакетов Python
Выполнить клонирование пакета shellenv из локального git-репозитария, как показано в дампе 2.6.1
Дамп 2.6.1
$ LANG=C git clone git://localhost/python-shellenv.git Cloning into 'python-shellenv'... remote: Enumerating objects: 28, done. remote: Counting objects: 100% (28/28), done. remote: Compressing objects: 100% (22/22), done. Receiving objects: 100% (28/28), 4.73 KiB | 4.73 MiB/s, done. remote: Total 28 (delta 5), reused 0 (delta 0), pack-reused 0 Resolving deltas: 100% (5/5), done.
Перейти в python-shellenv и выполнить сборку пакета, после чего пакет поместить, как показано в дампе 2.5.1
3. Библиография
3.1 pypiserver - minimal PyPI server for use with pip/easy_install
3.2 Bottle: Python Web Framework
3.4 Python. Creating Built Distributions
3.5 Монтирования партиций (носителей информации) по ее метке.
3.6 PyPA. Hosting your own simple repository
3.7 Python. PEP 503 -- Simple Repository API
3.8 Как разворачивать свой собственное (локальное) хранилище Git репозитариев
3.9 provide systemd service template for pypiserver #137
3.10 ArchLinux. Systemd (Русский)/User (Русский)
3.12 0.0.35: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined
3.13 bottle’s documentation on the Apache’s module MOD_WSGI
3.14 Список файлов пакета libapache2-mod-wsgi-py3 в bullseye для архитектуры amd64
3.15 wolfg, wolfg1969 оn gist.github.com
3.16 pypiserver on GitHub
3.17 How to setup apache fo multi user