1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/pyinventory_ynh.git synced 2024-09-03 20:16:09 +02:00

Merge pull request #121 from YunoHost-Apps/manifest-v2

Manifest v2
This commit is contained in:
Jens Diemer 2023-11-09 20:10:20 +01:00 committed by GitHub
commit 4e4377f790
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 2752 additions and 3826 deletions

View file

@ -15,18 +15,15 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
# https://github.com/marketplace/actions/checkout
with:
fetch-depth: 0
- uses: actions/cache@v3 - name: Set up Python
# https://github.com/marketplace/actions/cache uses: actions/setup-python@v4
with: with:
path: ~/.cache/ python-version: '3.9'
key: dot-cache-files
- name: 'Install dependencies' - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip
pip install toml pip install toml
- name: 'Clone YunoHost apps package linter' - name: 'Clone YunoHost apps package linter'
@ -34,8 +31,7 @@ jobs:
git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter git clone --depth=1 https://github.com/YunoHost/package_linter ~/package_linter
- name: 'Install requirements' - name: 'Install requirements'
run: | run: pip3 install toml
pip3 install toml
- name: 'Run linter' - name: 'Run linter'
run: | run: |

View file

@ -1,69 +0,0 @@
name: pytest
on:
# Allow to manually trigger the workflow
workflow_dispatch:
push:
branches:
- master
pull_request:
schedule:
- cron: '0 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.10", "3.9"]
env:
PYTHONUNBUFFERED: 1
PYTHONWARNINGS: always
steps:
- uses: actions/checkout@v3
# https://github.com/marketplace/actions/checkout
with:
fetch-depth: 0
- name: 'fetch master and testing (for Darker/Black)'
run: |
git fetch origin master
git fetch origin testing
- name: 'Set up Python ${{ matrix.python-version }}'
uses: actions/setup-python@v2
with:
python-version: '${{ matrix.python-version }}'
- uses: actions/cache@v3
# https://github.com/marketplace/actions/cache
with:
path: ~/.cache/
key: dot-cache-files
- name: 'Install package'
run: |
pip3 install poetry
make install
- name: 'List installed packages'
run: |
poetry run pip freeze
- name: 'Run tests with Python v${{ matrix.python-version }}'
run: |
make pytest
- name: 'Run Safety check'
run: |
make safety
- name: 'Upload coverage report'
uses: codecov/codecov-action@v3
# https://github.com/marketplace/actions/codecov
with:
fail_ci_if_error: false
verbose: true

66
.github/workflows/tests.yml vendored Normal file
View file

@ -0,0 +1,66 @@
name: tests
on:
push:
branches:
- main
pull_request:
schedule:
- cron: '0 8 * * *'
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.11", "3.10", "3.9"]
env:
PYTHONUNBUFFERED: 1
PYTHONWARNINGS: always
steps:
- name: Checkout
run: |
echo $GITHUB_REF $GITHUB_SHA
git clone https://github.com/$GITHUB_REPOSITORY.git .
git fetch origin $GITHUB_SHA:temporary-ci-branch
git checkout $GITHUB_SHA || (git fetch && git checkout $GITHUB_SHA)
- name: 'fetch master'
run: |
git fetch origin master
- name: 'Set up Python ${{ matrix.python-version }}'
uses: actions/setup-python@v4
# https://github.com/marketplace/actions/setup-python
with:
python-version: '${{ matrix.python-version }}'
cache: 'pip' # caching pip dependencies
cache-dependency-path: '**/requirements.dev.txt'
- name: 'Bootstrap dev venv'
# The first CLI call will create the .venv
run: |
./dev-cli.py version
- name: 'dev CLI help'
run: |
./dev-cli.py --help
- name: 'Safety'
run: |
./dev-cli.py safety
- name: 'Run tests with Python v${{ matrix.python-version }}'
run: |
.venv/bin/coverage erase
./dev-cli.py coverage
- name: 'Upload coverage report'
uses: codecov/codecov-action@v3
# https://github.com/marketplace/actions/codecov
with:
fail_ci_if_error: false
verbose: true

12
.gitignore vendored
View file

@ -1,13 +1,17 @@
.* .*
*.egg-info
__pycache__
/dist/
/coverage.*
/htmlcov/
*.orig
!.github !.github
!.editorconfig !.editorconfig
!.flake8 !.flake8
!.gitignore !.gitignore
!.gitkeep !.gitkeep
!/doc/screenshots/.gitkeep !/doc/screenshots/.gitkeep
__pycache__
secret.txt secret.txt
/local_test/ /local_test/
/coverage.json
/coverage.xml
/htmlcov/

View file

@ -1,65 +0,0 @@
SHELL := /bin/bash
MAX_LINE_LENGTH := 100
all: help
help:
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9 -]+:.*?## / {printf "\033[36m%-22s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
check-poetry:
@if [[ "$(shell poetry --version 2>/dev/null)" == *"Poetry"* ]] ; \
then \
echo "Poetry found, ok." ; \
else \
echo 'Please install poetry first, with e.g.:' ; \
echo 'make install-poetry' ; \
exit 1 ; \
fi
install-base-req: ## Install needed base packages via apt
sudo apt install python3-pip python3-venv
install-poetry: ## install or update poetry
curl -sSL https://install.python-poetry.org | python3 -
install: check-poetry ## install project via poetry
python3 -m venv .venv
poetry install
update: check-poetry ## update the sources and installation and generate "conf/requirements.txt"
python3 -m venv .venv
poetry self update
poetry update -v
poetry install
poetry export -f requirements.txt --output conf/requirements.txt
lint: ## Run code formatters and linter
poetry run darker --check
poetry run isort --check-only .
poetry run flake8 .
fix-code-style: ## Fix code formatting
poetry run darker
poetry run isort .
tox-listenvs: check-poetry ## List all tox test environments
poetry run tox --listenvs
tox: check-poetry ## Run pytest via tox with all environments
poetry run tox
pytest: install ## Run pytest
poetry run pytest
local-test: install ## Run local_test.py to run the project locally
poetry run python3 ./local_test.py
local-diff-settings: ## Run "manage.py diffsettings" with local test
poetry run python3 local_test/opt_yunohost/manage.py diffsettings
safety: ## Run https://github.com/pyupio/safety
poetry run safety check --full-report
##############################################################################
.PHONY: help check-poetry install-poetry install update local-test

168
README.md
View file

@ -16,15 +16,17 @@ If you don't have YunoHost, please consult [the guide](https://yunohost.org/#/in
## Overview ## Overview
[![tests](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml)
[![codecov](https://codecov.io/github/jedie/pyinventory_ynh/branch/main/graph/badge.svg)](https://app.codecov.io/github/jedie/pyinventory_ynh)
[![pyinventory_ynh @ PyPi](https://img.shields.io/pypi/v/pyinventory_ynh?label=pyinventory_ynh%20%40%20PyPi)](https://pypi.org/project/pyinventory_ynh/)
[![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/pyproject.toml)
[![License GPL-3.0-or-later](https://img.shields.io/pypi/l/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/LICENSE)
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/). [PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![Integration level](https://dash.yunohost.org/integration/pyinventory_ynh.svg)](https://dash.yunohost.org/appci/app/pyinventory_ynh) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.maintain.svg)
[![Install pyinventory_ynh with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory_ynh)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;) Pull requests welcome ;)
@ -33,7 +35,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Shipped version:** 0.19.2~ynh1 **Shipped version:** 0.19.3~ynh1
## Screenshots ## Screenshots
@ -47,162 +49,26 @@ More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
## Settings and upgrades ## Settings and upgrades
Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file. Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file.
You can edit the file `/opt/yunohost/pyinventory/local_settings.py` to enable or disable features. You can edit the file `/home/yunohost.app/django_example/local_settings.py` to enable or disable features.
Test sending emails: Test sending emails, e.g.:
```bash ```bash
ssh admin@yourdomain.tld ssh admin@yourdomain.tld
root@yunohost:~# cd /opt/yunohost/pyinventory/ root@yunohost:~# /home/yunohost.app/pyinventory/manage.py sendtestemail --admins
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
``` ```
Background info: Error mails are send to all [settings.ADMINS](https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ADMINS). By default the YunoHost admin is inserted here. How to debug a django YunoHost app, take a look into:
To check current ADMINS run:
```bash * https://github.com/YunoHost-Apps/django_example_ynh#developer-info
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
If you prefere to send error emails to a extrnal email address, just do something like this:
```bash
echo "ADMINS = (('Your Name', 'example@domain.tld'),)" >> /opt/yunohost/pyinventory/local_settings.py
```
To check the effective settings, run this:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py diffsettings
```
# Miscellaneous
## SSO authentication
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported via [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration):
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
* All new users will be created as normal users
* Login via SSO is fully supported
* User Email, First / Last name will be updated from SSO data
## Links
* Report a bug about this package: https://github.com/YunoHost-Apps/pyinventory_ynh
* Report a bug about PyInventory itself: https://github.com/jedie/PyInventory
* YunoHost website: https://yunohost.org/
---
# Developer info
## package installation / debugging
Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh
Try 'main' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
```
Try 'testing' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
To remove call e.g.:
```bash
sudo yunohost app remove pyinventory
```
Backup / remove / restore cycle, e.g.:
```bash
yunohost backup create --apps pyinventory
yunohost backup list
archives:
- pyinventory-pre-upgrade1
- 20201223-163434
yunohost app remove pyinventory
yunohost backup restore 20201223-163434 --apps pyinventory
```
Debug installation, e.g.:
```bash
root@yunohost:~# ls -la /var/www/pyinventory/
total 18
drwxr-xr-x 4 root root 4 Dec 8 08:36 .
drwxr-xr-x 6 root root 6 Dec 8 08:36 ..
drwxr-xr-x 2 root root 2 Dec 8 08:36 media
drwxr-xr-x 7 root root 8 Dec 8 08:40 static
root@yunohost:~# ls -la /opt/yunohost/pyinventory/
total 58
drwxr-xr-x 5 pyinventory pyinventory 11 Dec 8 08:39 .
drwxr-xr-x 3 root root 3 Dec 8 08:36 ..
-rw-r--r-- 1 pyinventory pyinventory 460 Dec 8 08:39 gunicorn.conf.py
-rw-r--r-- 1 pyinventory pyinventory 0 Dec 8 08:39 local_settings.py
-rwxr-xr-x 1 pyinventory pyinventory 274 Dec 8 08:39 manage.py
-rw-r--r-- 1 pyinventory pyinventory 171 Dec 8 08:39 secret.txt
drwxr-xr-x 6 pyinventory pyinventory 6 Dec 8 08:37 venv
-rw-r--r-- 1 pyinventory pyinventory 115 Dec 8 08:39 wsgi.py
-rw-r--r-- 1 pyinventory pyinventory 4737 Dec 8 08:39 settings.py
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py check
PyInventory v0.8.2 (Django v2.2.17)
DJANGO_SETTINGS_MODULE='settings'
PROJECT_PATH:/opt/yunohost/pyinventory/venv/lib/python3.7/site-packages
BASE_PATH:/opt/yunohost/pyinventory
System check identified no issues (0 silenced).
root@yunohost:~# tail -f /var/log/pyinventory/pyinventory.log
root@yunohost:~# cat /etc/systemd/system/pyinventory.service
root@yunohost:~# systemctl reload-or-restart pyinventory
root@yunohost:~# journalctl --unit=pyinventory --follow
```
## local test
For quicker developing of PyInventory in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git
~$ cd pyinventory_ynh/
~/pyinventory_ynh$ make
install-poetry install or update poetry
install install PyInventory via poetry
update update the sources and installation
local-test Run local_test.py to run pyinventory_ynh locally
~/pyinventory_ynh$ make install-poetry
~/pyinventory_ynh$ make install
~/pyinventory_ynh$ make local-test
```
Notes:
* SQlite database will be used
* A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/`
## Documentation and resources ## Documentation and resources
* Official app website: <https://github.com/YunoHost-Apps/pyinventory_ynh>
* Official user documentation: <https://github.com/jedie/PyInventory> * Official user documentation: <https://github.com/jedie/PyInventory>
* Official admin documentation: <https://github.com/YunoHost-Apps/pyinventory_ynh> * Official admin documentation: <https://github.com/YunoHost-Apps/pyinventory_ynh>
* Upstream app code repository: <https://github.com/jedie/PyInventory> * Upstream app code repository: <https://github.com/YunoHost-Apps/pyinventory_ynh>
* YunoHost documentation for this app: <https://yunohost.org/app_pyinventory> * YunoHost Store: <https://apps.yunohost.org/app/pyinventory>
* Report a bug: <https://github.com/YunoHost-Apps/pyinventory_ynh/issues> * Report a bug: <https://github.com/YunoHost-Apps/pyinventory_ynh/issues>
## Developer info ## Developer info

View file

@ -16,15 +16,17 @@ Si vous navez pas YunoHost, regardez [ici](https://yunohost.org/#/install) po
## Vue densemble ## Vue densemble
[![tests](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml)
[![codecov](https://codecov.io/github/jedie/pyinventory_ynh/branch/main/graph/badge.svg)](https://app.codecov.io/github/jedie/pyinventory_ynh)
[![pyinventory_ynh @ PyPi](https://img.shields.io/pypi/v/pyinventory_ynh?label=pyinventory_ynh%20%40%20PyPi)](https://pypi.org/project/pyinventory_ynh/)
[![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/pyproject.toml)
[![License GPL-3.0-or-later](https://img.shields.io/pypi/l/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/LICENSE)
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/). [PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![Integration level](https://dash.yunohost.org/integration/pyinventory_ynh.svg)](https://dash.yunohost.org/appci/app/pyinventory_ynh) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.maintain.svg)
[![Install pyinventory_ynh with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory_ynh)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;) Pull requests welcome ;)
@ -33,7 +35,7 @@ This package for YunoHost used [django-yunohost-integration](https://github.com/
More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
**Version incluse :** 0.19.2~ynh1 **Version incluse :** 0.19.3~ynh1
## Captures décran ## Captures décran
@ -47,162 +49,26 @@ More screenshots are here: jedie.github.io/tree/master/screenshots/PyInventory
## Settings and upgrades ## Settings and upgrades
Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file. Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file.
You can edit the file `/opt/yunohost/pyinventory/local_settings.py` to enable or disable features. You can edit the file `/home/yunohost.app/django_example/local_settings.py` to enable or disable features.
Test sending emails: Test sending emails, e.g.:
```bash ```bash
ssh admin@yourdomain.tld ssh admin@yourdomain.tld
root@yunohost:~# cd /opt/yunohost/pyinventory/ root@yunohost:~# /home/yunohost.app/pyinventory/manage.py sendtestemail --admins
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
``` ```
Background info: Error mails are send to all [settings.ADMINS](https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ADMINS). By default the YunoHost admin is inserted here. How to debug a django YunoHost app, take a look into:
To check current ADMINS run:
```bash * https://github.com/YunoHost-Apps/django_example_ynh#developer-info
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
If you prefere to send error emails to a extrnal email address, just do something like this:
```bash
echo "ADMINS = (('Your Name', 'example@domain.tld'),)" >> /opt/yunohost/pyinventory/local_settings.py
```
To check the effective settings, run this:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py diffsettings
```
# Miscellaneous
## SSO authentication
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported via [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration):
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
* All new users will be created as normal users
* Login via SSO is fully supported
* User Email, First / Last name will be updated from SSO data
## Links
* Report a bug about this package: https://github.com/YunoHost-Apps/pyinventory_ynh
* Report a bug about PyInventory itself: https://github.com/jedie/PyInventory
* YunoHost website: https://yunohost.org/
---
# Developer info
## package installation / debugging
Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh
Try 'main' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
```
Try 'testing' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
To remove call e.g.:
```bash
sudo yunohost app remove pyinventory
```
Backup / remove / restore cycle, e.g.:
```bash
yunohost backup create --apps pyinventory
yunohost backup list
archives:
- pyinventory-pre-upgrade1
- 20201223-163434
yunohost app remove pyinventory
yunohost backup restore 20201223-163434 --apps pyinventory
```
Debug installation, e.g.:
```bash
root@yunohost:~# ls -la /var/www/pyinventory/
total 18
drwxr-xr-x 4 root root 4 Dec 8 08:36 .
drwxr-xr-x 6 root root 6 Dec 8 08:36 ..
drwxr-xr-x 2 root root 2 Dec 8 08:36 media
drwxr-xr-x 7 root root 8 Dec 8 08:40 static
root@yunohost:~# ls -la /opt/yunohost/pyinventory/
total 58
drwxr-xr-x 5 pyinventory pyinventory 11 Dec 8 08:39 .
drwxr-xr-x 3 root root 3 Dec 8 08:36 ..
-rw-r--r-- 1 pyinventory pyinventory 460 Dec 8 08:39 gunicorn.conf.py
-rw-r--r-- 1 pyinventory pyinventory 0 Dec 8 08:39 local_settings.py
-rwxr-xr-x 1 pyinventory pyinventory 274 Dec 8 08:39 manage.py
-rw-r--r-- 1 pyinventory pyinventory 171 Dec 8 08:39 secret.txt
drwxr-xr-x 6 pyinventory pyinventory 6 Dec 8 08:37 venv
-rw-r--r-- 1 pyinventory pyinventory 115 Dec 8 08:39 wsgi.py
-rw-r--r-- 1 pyinventory pyinventory 4737 Dec 8 08:39 settings.py
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py check
PyInventory v0.8.2 (Django v2.2.17)
DJANGO_SETTINGS_MODULE='settings'
PROJECT_PATH:/opt/yunohost/pyinventory/venv/lib/python3.7/site-packages
BASE_PATH:/opt/yunohost/pyinventory
System check identified no issues (0 silenced).
root@yunohost:~# tail -f /var/log/pyinventory/pyinventory.log
root@yunohost:~# cat /etc/systemd/system/pyinventory.service
root@yunohost:~# systemctl reload-or-restart pyinventory
root@yunohost:~# journalctl --unit=pyinventory --follow
```
## local test
For quicker developing of PyInventory in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git
~$ cd pyinventory_ynh/
~/pyinventory_ynh$ make
install-poetry install or update poetry
install install PyInventory via poetry
update update the sources and installation
local-test Run local_test.py to run pyinventory_ynh locally
~/pyinventory_ynh$ make install-poetry
~/pyinventory_ynh$ make install
~/pyinventory_ynh$ make local-test
```
Notes:
* SQlite database will be used
* A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/`
## Documentations et ressources ## Documentations et ressources
* Site officiel de lapp : <https://github.com/YunoHost-Apps/pyinventory_ynh>
* Documentation officielle utilisateur : <https://github.com/jedie/PyInventory> * Documentation officielle utilisateur : <https://github.com/jedie/PyInventory>
* Documentation officielle de ladmin : <https://github.com/YunoHost-Apps/pyinventory_ynh> * Documentation officielle de ladmin : <https://github.com/YunoHost-Apps/pyinventory_ynh>
* Dépôt de code officiel de lapp : <https://github.com/jedie/PyInventory> * Dépôt de code officiel de lapp : <https://github.com/YunoHost-Apps/pyinventory_ynh>
* Documentation YunoHost pour cette app : <https://yunohost.org/app_pyinventory> * YunoHost Store: <https://apps.yunohost.org/app/pyinventory>
* Signaler un bug : <https://github.com/YunoHost-Apps/pyinventory_ynh/issues> * Signaler un bug : <https://github.com/YunoHost-Apps/pyinventory_ynh/issues>
## Informations pour les développeurs ## Informations pour les développeurs

View file

@ -1,33 +0,0 @@
# See here for more information
# https://github.com/YunoHost/package_check#syntax-check_process-file
# Move this file from check_process.default to check_process when you have filled it.
;; Test complet
; Manifest
domain="domain.tld" (DOMAIN)
path="/path" (PATH)
admin="john" (USER)
is_public=1 (PUBLIC|public=1|private=0)
password="pass"
port="666" (PORT)
; Checks
pkg_linter=1
setup_sub_dir=1
setup_root=1
setup_nourl=0
setup_private=0
setup_public=1
upgrade=1
backup_restore=1
multi_instance=1
port_already_use=0
change_url=1
;;; Options
Email=
Notification=none
;;; Upgrade options
; commit=CommitHash
name=Name and date of the commit.
manifest_arg=domain=DOMAIN&path=PATH&admin=USER&language=fr&is_public=1&password=pass&port=666&

View file

@ -17,4 +17,4 @@ accesslog = '__LOG_FILE__'
errorlog = '__LOG_FILE__' errorlog = '__LOG_FILE__'
# https://docs.gunicorn.org/en/latest/settings.html#pidfile # https://docs.gunicorn.org/en/latest/settings.html#pidfile
pidfile = '__FINALPATH__/gunicorn.pid' pidfile = '__DATA_DIR__/gunicorn.pid' # /home/yunohost.app/$app/gunicorn.pid

View file

@ -1,4 +1,4 @@
#!__FINALPATH__/venv/bin/python #!__DATA_DIR__/venv/bin/python
import os import os
import sys import sys

View file

@ -1,8 +1,8 @@
location __PATH__/static/ { location __PATH__/static/ {
# Service static files by nginx # Service static files by nginx
# e.g.: /var/www/$app/static # e.g.: /var/www/$app/static/
alias __PUBLIC_PATH__/static/; alias __INSTALL_DIR__/static/;
expires 30d; expires 30d;
} }

View file

@ -1,255 +1,367 @@
asgiref==3.7.2 ; python_version >= "3.9" and python_version < "4" \ #
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# ./dev-cli.py update
#
asgiref==3.7.2 \
--hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \ --hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
--hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed --hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
async-timeout==4.0.3 ; python_version >= "3.9" and python_full_version <= "3.11.2" \ # via django
async-timeout==4.0.3 \
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \ --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028 --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
bleach==6.0.0 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory-ynh (pyproject.toml)
--hash=sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414 \ bleach==6.1.0 \
--hash=sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4 --hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \
bx-django-utils==63 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6
--hash=sha256:0023c0c18c8ce21fbee0e3bb563cd0283749495ca22cab1857ac971e4ee2bb05 \ # via django-tools
--hash=sha256:3b050d9d9d4e496e082c29d98d7633eb89ad028c658743b0032ee88e7e49be63 bx-django-utils==67 \
bx-py-utils==85 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:8740fdaf98ed68a8ddb3af025d9b4f87c99101405898ddca86810b0c384b215a \
--hash=sha256:8d6ee4bb0c431304b812f5bebb1bc8e2ab05f1b6c2f8d16d352cbcee5e916cd2 \ --hash=sha256:aca0ae5c91a62e4f594172b8c43468c701516f99ae50d99412d5299ba375df03
--hash=sha256:df023fa05cda8e969d2cbdb4cc348d8b7670567a2fe775faf7a0c869ec56eaa2 # via pyinventory
certifi==2023.7.22 ; python_version >= "3.9" and python_version < "4" \ bx-py-utils==88 \
--hash=sha256:32fbc7e9ff3dfb0a817c80fb1d165ec559643dab59c0be549e646acbf8223b75 \
--hash=sha256:3a6f4eeef6abcac834b2c1ea4c5211130fd930a064aa0baabddd7c2bd00e38ac
# via
# bx-django-utils
# cli-base-utilities
# django-tools
# pyinventory
certifi==2023.7.22 \
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
charset-normalizer==3.2.0 ; python_version >= "3.9" and python_version < "4" \ # via requests
--hash=sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96 \ charset-normalizer==3.3.2 \
--hash=sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c \ --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
--hash=sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710 \ --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
--hash=sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706 \ --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
--hash=sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020 \ --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
--hash=sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252 \ --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
--hash=sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad \ --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
--hash=sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329 \ --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
--hash=sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a \ --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
--hash=sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f \ --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
--hash=sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6 \ --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
--hash=sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4 \ --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
--hash=sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a \ --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
--hash=sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46 \ --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
--hash=sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2 \ --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
--hash=sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23 \ --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
--hash=sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace \ --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
--hash=sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd \ --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
--hash=sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982 \ --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
--hash=sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10 \ --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
--hash=sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2 \ --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
--hash=sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea \ --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
--hash=sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09 \ --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
--hash=sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5 \ --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
--hash=sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149 \ --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
--hash=sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489 \ --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
--hash=sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9 \ --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
--hash=sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80 \ --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
--hash=sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592 \ --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
--hash=sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3 \ --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
--hash=sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6 \ --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
--hash=sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed \ --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
--hash=sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c \ --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
--hash=sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200 \ --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
--hash=sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a \ --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
--hash=sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e \ --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
--hash=sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d \ --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
--hash=sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6 \ --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
--hash=sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623 \ --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
--hash=sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669 \ --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
--hash=sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3 \ --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
--hash=sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa \ --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
--hash=sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9 \ --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
--hash=sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2 \ --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
--hash=sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f \ --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
--hash=sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1 \ --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
--hash=sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4 \ --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
--hash=sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a \ --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
--hash=sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8 \ --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
--hash=sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3 \ --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
--hash=sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029 \ --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
--hash=sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f \ --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
--hash=sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959 \ --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
--hash=sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22 \ --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
--hash=sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7 \ --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
--hash=sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952 \ --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
--hash=sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346 \ --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
--hash=sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e \ --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
--hash=sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d \ --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
--hash=sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299 \ --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
--hash=sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd \ --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
--hash=sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a \ --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
--hash=sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3 \ --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
--hash=sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037 \ --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
--hash=sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94 \ --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
--hash=sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c \ --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
--hash=sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858 \ --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
--hash=sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a \ --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
--hash=sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449 \ --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
--hash=sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c \ --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
--hash=sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918 \ --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
--hash=sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1 \ --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
--hash=sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c \ --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
--hash=sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac \ --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
--hash=sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
colorama==0.4.6 ; python_version >= "3.9" and python_version < "4" and sys_platform == "win32" \ --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
colorlog==6.7.0 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
--hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
--hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
--hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
--hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
--hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
# via requests
cli-base-utilities==0.4.4 \
--hash=sha256:110bef895fb7dfc29662f463ccedc4c985a880afbde2e6dea387d0d2f96f4985 \
--hash=sha256:72d4248776519a21c3448d6e348511ce6fe8c3742c154e158473236c8278fb1c
# via pyinventory-ynh (pyproject.toml)
click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
# via
# cli-base-utilities
# rich-click
colorlog==6.7.0 \
--hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \ --hash=sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662 \
--hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5 --hash=sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5
defusedxml==0.7.1 ; python_version >= "3.9" and python_version < "4" \ # via
# django-yunohost-integration
# pyinventory
defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \ --hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 --hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
diff-match-patch==20230430 ; python_version >= "3.9" and python_version < "4" \ # via odfpy
diff-match-patch==20230430 \
--hash=sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c \ --hash=sha256:953019cdb9c9d2c9e47b5b12bcff3cf4746fc4598eb406076fa1fc27e6a1f15c \
--hash=sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93 --hash=sha256:dce43505fb7b1b317de7195579388df0746d90db07015ed47a85e5e44930ef93
django-admin-sortable2==2.1.9 ; python_version >= "3.9" and python_version < "4" \ # via
--hash=sha256:6de19689cb2f131d256ce19d2fd148728d551943d8463b1d81f6334adfa0b6fc \ # django-import-export
--hash=sha256:bf036785c598685a0019eb08340b88fe6ca74bd178033e2290e6c41b62fa4bf1 # django-reversion-compare
django-axes==6.1.0 ; python_version >= "3.9" and python_full_version < "4.0.0" \ django==4.2.7 \
--hash=sha256:a7d509dc76e67440839522a182dc63ecafc3bac3af9de6f263d2bcec1154e50e \ --hash=sha256:8e0f1c2c2786b5c0e39fe1afce24c926040fad47c8ea8ad30aaf1188df29fc41 \
--hash=sha256:e3d44d4ec64ba6d470ef01b6c4b53b6b3747de96821f7c0ef96c64bffa9f6f74 --hash=sha256:e1d37c51ad26186de355cbcec16613ebdabfa9689bbade9c538835205a8abbe9
django-ckeditor==6.7.0 ; python_version >= "3.9" and python_version < "4" \ # via
# bx-django-utils
# django-admin-sortable2
# django-axes
# django-ckeditor
# django-dbbackup
# django-debug-toolbar
# django-import-export
# django-js-asset
# django-redis
# django-reversion
# django-reversion-compare
# django-tagulous
# django-tools
# django-yunohost-integration
# pyinventory
django-admin-sortable2==2.1.10 \
--hash=sha256:3756b02c7d09c5b37efe657718d5aae2b75f46fd01bbfe1c39d4e60651019d79 \
--hash=sha256:98d1c8d268398c3c3aff4752f766b2c307a5bd97174938c29f818d8a4697854d
# via pyinventory
django-axes==6.1.1 \
--hash=sha256:29c48ff5f09046afd5e9a16e96d3bbb79f6c11c59f0a7bbd732559e60d0aa9fa \
--hash=sha256:cd1bc4f7becc8e9243eb4090dffa258d7d7125ca0ce3153b6ffc920bccbf2c3f
# via django-yunohost-integration
django-ckeditor==6.7.0 \
--hash=sha256:0489f7a6ae93360d328f77cea17c04891103cbdfa6c962af386bbe47e811671b \ --hash=sha256:0489f7a6ae93360d328f77cea17c04891103cbdfa6c962af386bbe47e811671b \
--hash=sha256:73399fb8f56f565e7519b57adbd7c585623db2cdc8c75666f56918d3eecf7906 --hash=sha256:73399fb8f56f565e7519b57adbd7c585623db2cdc8c75666f56918d3eecf7906
django-dbbackup==4.0.2 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory
django-dbbackup==4.0.2 \
--hash=sha256:1874d684abc22260972a67668a6db3331b24d7e1e8af89eaffdcd61eb27dbc2a \ --hash=sha256:1874d684abc22260972a67668a6db3331b24d7e1e8af89eaffdcd61eb27dbc2a \
--hash=sha256:3ccde831f1a8268fb031b37a8e7e2de3abb556623023af1e859cd7104c09ea2a --hash=sha256:3ccde831f1a8268fb031b37a8e7e2de3abb556623023af1e859cd7104c09ea2a
django-debug-toolbar==4.2.0 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory
django-debug-toolbar==4.2.0 \
--hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \ --hash=sha256:af99128c06e8e794479e65ab62cc6c7d1e74e1c19beb44dcbf9bad7a9c017327 \
--hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc --hash=sha256:bc7fdaafafcdedefcc67a4a5ad9dac96efd6e41db15bc74d402a54a2ba4854dc
django-import-export==3.2.0 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory
--hash=sha256:1d3f2cb2ee3cca0386ed60651fa1623be989f130d9fbdf98a67f7dc3a94b8a37 \ django-import-export==3.3.2 \
--hash=sha256:38fd7b9439b9e3aa1a4747421c1087a5bc194e915a28d795fb8429a5f8028f2d --hash=sha256:9a5c7c191014e4defb01573ee94864b60724a203f1b8a7e5e67a03f06b27b62d \
django-js-asset==2.1.0 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:d13e7508190f46442280bd7d04efcf49af6521350a70a6f9e06447ef28d6a41d
# via pyinventory
django-js-asset==2.1.0 \
--hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \ --hash=sha256:36a3a4dd6e9efc895fb127d13126020f6ec1ec9469ad42878d42143f22495d90 \
--hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6 --hash=sha256:be6f69ae5c4865617aa7726c48eddb64089a1e7d4ea7d22a35a3beb8282020f6
django-redis==5.3.0 ; python_version >= "3.9" and python_full_version < "4.0.0" \ # via django-ckeditor
--hash=sha256:2d8660d39f586c41c9907d5395693c477434141690fd7eca9d32376af00b0aac \ django-redis==5.4.0 \
--hash=sha256:8bc5793ec06b28ea802aad85ec437e7646511d4e571e07ccad19cfed8b9ddd44 --hash=sha256:6a02abaa34b0fea8bf9b707d2c363ab6adc7409950b2db93602e6cb292818c42 \
django-reversion-compare==0.16.2 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:ebc88df7da810732e2af9987f7f426c96204bf89319df4c6da6ca9a2942edd5b
# via django-yunohost-integration
django-reversion==5.0.8 \
--hash=sha256:229ad0d2819416157502ff13d81bad2366227b763ce85b63b8a223edb756a513 \
--hash=sha256:45d378bc6e606df6b2ad0077aec8b0a00e35f18c74ca2a1ae9cc262ceb32fb9a
# via django-reversion-compare
django-reversion-compare==0.16.2 \
--hash=sha256:5629f226fc73bd7b95de47b2e21e2eba2fa39f004ba0fee6d460e96676c0dc9b \ --hash=sha256:5629f226fc73bd7b95de47b2e21e2eba2fa39f004ba0fee6d460e96676c0dc9b \
--hash=sha256:9d7d096534f5d0e49d7419a8a29b4517580e6a7855529e594d10bfb373f980ab --hash=sha256:9d7d096534f5d0e49d7419a8a29b4517580e6a7855529e594d10bfb373f980ab
django-reversion==5.0.4 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory
--hash=sha256:a591cbce8621b5d036a37617554668b5ef2eb9777682e3af20b6401ee87cfbc5 \ django-tagulous==1.3.3 \
--hash=sha256:c12bab452d31dd3c244456cf1df383acf14ba147cf99404c5e44412596de42fc
django-tagulous==1.3.3 ; python_version >= "3.9" and python_version < "4" \
--hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478 \ --hash=sha256:ad3bb85f4cce83a47e4c0257143229cb92a294defa02fe661823b0442b35d478 \
--hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe --hash=sha256:d445590ae1b5cb9b8c5a425f97bf5f01148a33419c19edeb721ebd9fdd6792fe
django-tools==0.54.0 ; python_version >= "3.9" and python_version < "4" \ # via pyinventory
django-tools==0.54.0 \
--hash=sha256:5040a91282be9d1c9d379b0c65da50bcb3691bff03cee54fd4123ace238c3a43 \ --hash=sha256:5040a91282be9d1c9d379b0c65da50bcb3691bff03cee54fd4123ace238c3a43 \
--hash=sha256:a7b7bfa5b9c5a81966454d17dffb2403cee25a806c858ee0486a08798227598f --hash=sha256:a7b7bfa5b9c5a81966454d17dffb2403cee25a806c858ee0486a08798227598f
django-yunohost-integration[ynh]==0.5.2 ; python_version >= "3.9" and python_full_version < "4.0.0" \ # via
--hash=sha256:05d96ae0689eb1b8c7bc30e0d247fddb1c18d2845c17a6e4ca533ed47731a4cb \ # django-yunohost-integration
--hash=sha256:6689115f88dc84acaf94dc01ce940023f566bf933f57115563120912a14cbeff # pyinventory
django==4.1.10 ; python_version >= "3.9" and python_version < "4" \ django-yunohost-integration[ynh]==0.6.0 \
--hash=sha256:26d0260c2fb8121009e62ffc548b2398dea2522b6454208a852fb0ef264c206c \ --hash=sha256:9596ab56b66edf1b56eccaceb4b5807df237e752128e79568cd13b075267f26f \
--hash=sha256:56343019a9fd839e2e5bf203daf45f25af79d5bffa4c71d56eae4f4404d82ade --hash=sha256:dfb72b94ae30e02948dd60ca76d56da4ca6a74ea04f357b8d61b94807fca0493
et-xmlfile==1.1.0 ; python_version >= "3.9" and python_version < "4" \ # via
# django-yunohost-integration
# pyinventory-ynh (pyproject.toml)
et-xmlfile==1.1.0 \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \ --hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada --hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada
gunicorn==21.2.0 ; python_version >= "3.9" and python_version < "4" \ # via openpyxl
gunicorn==21.2.0 \
--hash=sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0 \ --hash=sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0 \
--hash=sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033 --hash=sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033
icdiff==2.0.6 ; python_version >= "3.9" and python_version < "4" \ # via
--hash=sha256:a2673b335d671e64fc73c44e1eaa0aa01fd0e68354e58ee17e863ab29912a79a # django-yunohost-integration
idna==3.4 ; python_version >= "3.9" and python_version < "4" \ # pyinventory
icdiff==2.0.7 \
--hash=sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762 \
--hash=sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f
# via django-tools
idna==3.4 \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \ --hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2 --hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
markuppy==1.14 ; python_version >= "3.9" and python_version < "4" \ # via requests
markdown-it-py==3.0.0 \
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
# via rich
markuppy==1.14 \
--hash=sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f --hash=sha256:1adee2c0a542af378fe84548ff6f6b0168f3cb7f426b46961038a2bcfaad0d5f
odfpy==1.4.1 ; python_version >= "3.9" and python_version < "4" \ # via tablib
mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
# via markdown-it-py
odfpy==1.4.1 \
--hash=sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec --hash=sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec
openpyxl==3.1.2 ; python_version >= "3.9" and python_version < "4" \ # via tablib
openpyxl==3.1.2 \
--hash=sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184 \ --hash=sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184 \
--hash=sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5 --hash=sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5
packaging==23.1 ; python_version >= "3.9" and python_version < "4" \ # via tablib
--hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \ packaging==23.2 \
--hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
pillow==10.0.0 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
--hash=sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5 \ # via
--hash=sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530 \ # django-yunohost-integration
--hash=sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d \ # gunicorn
--hash=sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca \ pillow==10.1.0 \
--hash=sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891 \ --hash=sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d \
--hash=sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992 \ --hash=sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de \
--hash=sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7 \ --hash=sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616 \
--hash=sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3 \ --hash=sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839 \
--hash=sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba \ --hash=sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099 \
--hash=sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3 \ --hash=sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a \
--hash=sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3 \ --hash=sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219 \
--hash=sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f \ --hash=sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106 \
--hash=sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538 \ --hash=sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b \
--hash=sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3 \ --hash=sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412 \
--hash=sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d \ --hash=sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b \
--hash=sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c \ --hash=sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7 \
--hash=sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017 \ --hash=sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2 \
--hash=sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3 \ --hash=sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7 \
--hash=sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223 \ --hash=sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14 \
--hash=sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e \ --hash=sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f \
--hash=sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3 \ --hash=sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27 \
--hash=sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6 \ --hash=sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57 \
--hash=sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640 \ --hash=sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262 \
--hash=sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334 \ --hash=sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28 \
--hash=sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1 \ --hash=sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610 \
--hash=sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba \ --hash=sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172 \
--hash=sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa \ --hash=sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273 \
--hash=sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0 \ --hash=sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e \
--hash=sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396 \ --hash=sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d \
--hash=sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d \ --hash=sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818 \
--hash=sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485 \ --hash=sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f \
--hash=sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf \ --hash=sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9 \
--hash=sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43 \ --hash=sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01 \
--hash=sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37 \ --hash=sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7 \
--hash=sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2 \ --hash=sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651 \
--hash=sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd \ --hash=sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312 \
--hash=sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86 \ --hash=sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80 \
--hash=sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967 \ --hash=sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666 \
--hash=sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629 \ --hash=sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061 \
--hash=sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568 \ --hash=sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b \
--hash=sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed \ --hash=sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992 \
--hash=sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f \ --hash=sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593 \
--hash=sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551 \ --hash=sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4 \
--hash=sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3 \ --hash=sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db \
--hash=sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614 \ --hash=sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba \
--hash=sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff \ --hash=sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd \
--hash=sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d \ --hash=sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e \
--hash=sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883 \ --hash=sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212 \
--hash=sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684 \ --hash=sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb \
--hash=sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0 \ --hash=sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2 \
--hash=sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de \ --hash=sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34 \
--hash=sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b \ --hash=sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256 \
--hash=sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3 \ --hash=sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f \
--hash=sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199 \ --hash=sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2 \
--hash=sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51 \ --hash=sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38 \
--hash=sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90 --hash=sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996 \
pprintpp==0.4.0 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a \
--hash=sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793
# via pyinventory
pprintpp==0.4.0 \
--hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \ --hash=sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d \
--hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403 --hash=sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403
psycopg2==2.9.7 ; python_version >= "3.9" and python_full_version < "4.0.0" \ # via django-tools
--hash=sha256:1a6a2d609bce44f78af4556bea0c62a5e7f05c23e5ea9c599e07678995609084 \ psycopg2==2.9.9 \
--hash=sha256:44d93a0109dfdf22fe399b419bcd7fa589d86895d3931b01fb321d74dadc68f1 \ --hash=sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981 \
--hash=sha256:8275abf628c6dc7ec834ea63f6f3846bf33518907a2b9b693d41fd063767a866 \ --hash=sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516 \
--hash=sha256:91e81a8333a0037babfc9fe6d11e997a9d4dac0f38c43074886b0d9dead94fe9 \ --hash=sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3 \
--hash=sha256:b22ed9c66da2589a664e0f1ca2465c29b75aaab36fa209d4fb916025fb9119e5 \ --hash=sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa \
--hash=sha256:b6bd7d9d3a7a63faae6edf365f0ed0e9b0a1aaf1da3ca146e6b043fb3eb5d723 \ --hash=sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a \
--hash=sha256:c7949770cafbd2f12cecc97dea410c514368908a103acf519f2a346134caa4d5 \ --hash=sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693 \
--hash=sha256:d1210fcf99aae6f728812d1d2240afc1dc44b9e6cba526a06fb8134f969957c2 \ --hash=sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372 \
--hash=sha256:d5c5297e2fbc8068d4255f1e606bfc9291f06f91ec31b2a0d4c536210ac5c0a2 \ --hash=sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e \
--hash=sha256:e9b04cbef584310a1ac0f0d55bb623ca3244c87c51187645432e342de9ae81a8 \ --hash=sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59 \
--hash=sha256:f00cc35bd7119f1fed17b85bd1007855194dde2cbd8de01ab8ebb17487440ad8 --hash=sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156 \
pyinventory==0.19.2 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024 \
--hash=sha256:06424c8ddf8521cf5806d834e3aede8254a4960f538a210bfd88508d88fb1d36 \ --hash=sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913 \
--hash=sha256:2d92a7f4b4a7b3191819f671e95070b3dd8844fdf2ceb8d971da1e61b094db24 --hash=sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c
python-stdnum==1.18 ; python_version >= "3.9" and python_version < "4" \ # via django-yunohost-integration
--hash=sha256:bcc763d9c49ae23da5d2b7a686d5fd1deec9d9051341160a10d1ac723a26bec0 \ pygments==2.16.1 \
--hash=sha256:d7f2a3c7ef4635c957b9cbdd9b1993d1f6ee3a2959f03e172c45440d99f296eb --hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
pytz==2023.3 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
--hash=sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588 \ # via rich
--hash=sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb pyinventory==0.19.3 \
pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:42e5710956e466df389ddf01c1ab8f9c432890b745a2a32765085c67fda78cfa \
--hash=sha256:b9efc88ca43aa57c4e04f2024087e50015bd9fc969730e3049258b06d048cce4
# via pyinventory-ynh (pyproject.toml)
python-stdnum==1.19 \
--hash=sha256:133ec82f56390ea74c190569e98f2fb14b869808b1d54785708f22d0fead8b3f \
--hash=sha256:1b5b401ad3f45b798b0317313b781a433f5d7a5ff2c9feb8054664f76f78644e
# via bx-django-utils
pytz==2023.3.post1 \
--hash=sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b \
--hash=sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7
# via django-dbbackup
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \ --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
--hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \ --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
--hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \ --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
@ -257,7 +369,10 @@ pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4" \
--hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \ --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
--hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \ --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
--hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \ --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \ --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
--hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
--hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \ --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
--hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \ --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
--hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \ --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
@ -265,9 +380,12 @@ pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4" \
--hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \ --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \ --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \ --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
--hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \ --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
--hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \ --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \ --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \ --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \ --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \ --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
@ -282,46 +400,79 @@ pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4" \
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \ --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
--hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \ --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \ --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \ --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \ --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
--hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \ --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
--hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \ --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
--hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \ --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \ --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
redis==5.0.0 ; python_version >= "3.9" and python_full_version < "4.0.0" \ # via
--hash=sha256:06570d0b2d84d46c21defc550afbaada381af82f5b83e5b3777600e05d8e2ed0 \ # django-yunohost-integration
--hash=sha256:5cea6c0d335c9a7332a460ed8729ceabb4d0c489c7285b0a86dbbf8a017bd120 # tablib
requests==2.31.0 ; python_version >= "3.9" and python_version < "4" \ redis==5.0.1 \
--hash=sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f \
--hash=sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f
# via django-redis
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
setuptools==68.1.0 ; python_version >= "3.9" and python_full_version < "4.0.0" \ # via pyinventory
--hash=sha256:d59c97e7b774979a5ccb96388efc9eb65518004537e85d52e81eaee89ab6dd91 \ rich==13.6.0 \
--hash=sha256:e13e1b0bc760e9b0127eda042845999b2f913e12437046e663b833aa96d89715 --hash=sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245 \
six==1.16.0 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef
# via
# cli-base-utilities
# rich-click
rich-click==1.7.1 \
--hash=sha256:660c8ea345343f47c5de88f62afa34a19d9f4c7accdd9c6e39dc17eece6affcd \
--hash=sha256:c37d19af85c86b9a256c18e9d23637ae89478300ec8dc5e220c6ca213675f2f9
# via cli-base-utilities
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
sqlparse==0.4.4 ; python_version >= "3.9" and python_version < "4" \ # via bleach
sqlparse==0.4.4 \
--hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \ --hash=sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3 \
--hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c --hash=sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c
tablib[html,ods,xls,xlsx,yaml]==3.5.0 ; python_version >= "3.9" and python_version < "4" \ # via
# django
# django-debug-toolbar
tablib[html,ods,xls,xlsx,yaml]==3.5.0 \
--hash=sha256:9821caa9eca6062ff7299fa645e737aecff982e6b2b42046928a6413c8dabfd9 \ --hash=sha256:9821caa9eca6062ff7299fa645e737aecff982e6b2b42046928a6413c8dabfd9 \
--hash=sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33 --hash=sha256:f6661dfc45e1d4f51fa8a6239f9c8349380859a5bfaa73280645f046d6c96e33
typing-extensions==4.7.1 ; python_version >= "3.9" and python_version < "3.11" \ # via
--hash=sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36 \ # django-import-export
--hash=sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2 # tablib
tzdata==2023.3 ; python_version >= "3.9" and python_version < "4" and sys_platform == "win32" \ tomlkit==0.12.2 \
--hash=sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a \ --hash=sha256:df32fab589a81f0d7dc525a4267b6d7a64ee99619cbd1eeb0fae32c1dd426977 \
--hash=sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda --hash=sha256:eeea7ac7563faeab0a1ed8fe12c2e5a51c61f933f2502f7e9db0241a65163ad0
urllib3==2.0.4 ; python_version >= "3.9" and python_version < "4" \ # via cli-base-utilities
--hash=sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11 \ typing-extensions==4.8.0 \
--hash=sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4 --hash=sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0 \
webencodings==0.5.1 ; python_version >= "3.9" and python_version < "4" \ --hash=sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef
# via rich-click
urllib3==2.0.7 \
--hash=sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84 \
--hash=sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e
# via requests
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \ --hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923 --hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
xlrd==2.0.1 ; python_version >= "3.9" and python_version < "4" \ # via bleach
xlrd==2.0.1 \
--hash=sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd \ --hash=sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd \
--hash=sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88 --hash=sha256:f72f148f54442c6b056bf931dbc34f986fd0c3b0b6b5a58d013c9aef274d0c88
xlwt==1.3.0 ; python_version >= "3.9" and python_version < "4" \ # via tablib
xlwt==1.3.0 \
--hash=sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e \ --hash=sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e \
--hash=sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88 --hash=sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88
# via tablib
# The following packages are considered to be unsafe in a requirements file:
setuptools==68.2.2 \
--hash=sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87 \
--hash=sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a
# via django-axes

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# Please do not modify this file, it will be reset at the next update. # Please do not modify this file, it will be reset at the next update.
# You can edit the file __FINALPATH__/local_settings.py and add/modify the settings you need. # You can edit the file __DATA_DIR__/local_settings.py and add/modify the settings you need.
# The parameters you add in local_settings.py will overwrite these, # The parameters you add in local_settings.py will overwrite these,
# but you can use the options and documentation in this file to find out what can be done. # but you can use the options and documentation in this file to find out what can be done.
@ -22,16 +22,16 @@ from inventory_project.settings.prod import * # noqa:F401,F403 isort:skip
from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip from django_yunohost_integration.base_settings import LOGGING # noqa:F401 isort:skip
FINALPATH = __Path('__FINALPATH__') # /opt/yunohost/$app DATA_DIR_PATH = __Path('__DATA_DIR__') # /home/yunohost.app/$app/
assert FINALPATH.is_dir(), f'Directory not exists: {FINALPATH}' assert DATA_DIR_PATH.is_dir(), f'Directory not exists: {DATA_DIR_PATH}'
PUBLIC_PATH = __Path('__PUBLIC_PATH__') # /var/www/$app INSTALL_DIR_PATH = __Path('__INSTALL_DIR__') # /var/www/$app/
assert PUBLIC_PATH.is_dir(), f'Directory not exists: {PUBLIC_PATH}' assert INSTALL_DIR_PATH.is_dir(), f'Directory not exists: {INSTALL_DIR_PATH}'
LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app/pyinventory_ynh.log LOG_FILE_PATH = __Path('__LOG_FILE__') # /var/log/$app/pyinventory_ynh.log
assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}' assert LOG_FILE_PATH.is_file(), f'File not exists: {LOG_FILE_PATH}'
PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH PATH_URL = '__PATH__'
PATH_URL = PATH_URL.strip('/') PATH_URL = PATH_URL.strip('/')
YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yunohost/current_host YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yunohost/current_host
@ -40,7 +40,7 @@ YNH_CURRENT_HOST = '__YNH_CURRENT_HOST__' # YunoHost main domain from: /etc/yun
# config_panel.toml settings: # config_panel.toml settings:
DEBUG_ENABLED = '__DEBUG_ENABLED__' DEBUG_ENABLED = '__DEBUG_ENABLED__'
DEBUG = bool(int(DEBUG_ENABLED)) DEBUG = DEBUG_ENABLED == 'YES'
LOG_LEVEL = '__LOG_LEVEL__' LOG_LEVEL = '__LOG_LEVEL__'
ADMIN_EMAIL = '__ADMIN_EMAIL__' ADMIN_EMAIL = '__ADMIN_EMAIL__'
@ -52,8 +52,6 @@ DEFAULT_FROM_EMAIL = '__DEFAULT_FROM_EMAIL__'
# Function that will be called to finalize a user profile: # Function that will be called to finalize a user profile:
YNH_SETUP_USER = 'setup_user.setup_project_user' YNH_SETUP_USER = 'setup_user.setup_project_user'
SECRET_KEY = __get_or_create_secret(FINALPATH / 'secret.txt') # /opt/yunohost/$app/secret.txt
if 'axes' not in INSTALLED_APPS: if 'axes' not in INSTALLED_APPS:
INSTALLED_APPS.append('axes') # https://github.com/jazzband/django-axes INSTALLED_APPS.append('axes') # https://github.com/jazzband/django-axes
@ -61,6 +59,9 @@ if 'axes' not in INSTALLED_APPS:
INSTALLED_APPS.append('django_yunohost_integration.apps.YunohostIntegrationConfig') INSTALLED_APPS.append('django_yunohost_integration.apps.YunohostIntegrationConfig')
SECRET_KEY = __get_or_create_secret(DATA_DIR_PATH / 'secret.txt') # /home/yunohost.app/$app/secret.txt
MIDDLEWARE.insert( MIDDLEWARE.insert(
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1, MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
# login a user via HTTP_REMOTE_USER header from SSOwat: # login a user via HTTP_REMOTE_USER header from SSOwat:
@ -154,8 +155,8 @@ else:
STATIC_URL = '/static/' STATIC_URL = '/static/'
MEDIA_URL = '/media/' MEDIA_URL = '/media/'
STATIC_ROOT = str(PUBLIC_PATH / 'static') STATIC_ROOT = str(INSTALL_DIR_PATH / 'static')
MEDIA_ROOT = str(PUBLIC_PATH / 'media') MEDIA_ROOT = str(INSTALL_DIR_PATH / 'media')
# _____________________________________________________________________________ # _____________________________________________________________________________
# django-ckeditor # django-ckeditor
@ -165,16 +166,15 @@ CKEDITOR_BASEPATH = STATIC_URL + 'ckeditor/ckeditor/'
# _____________________________________________________________________________ # _____________________________________________________________________________
# Django-dbbackup # Django-dbbackup
DBBACKUP_STORAGE_OPTIONS['location'] = str(FINALPATH / 'backups') DBBACKUP_STORAGE_OPTIONS['location'] = str(DATA_DIR_PATH / 'backups')
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Set log file to e.g.: /var/log/$app/$app.log # Set log file to e.g.: /var/log/$app/$app.log
LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE) LOGGING['handlers']['log_file']['filename'] = str(LOG_FILE_PATH)
LOGGING['loggers']['inventory'] = { LOGGING['loggers']['inventory'] = {
'handlers': ['syslog', 'log_file', 'mail_admins'], 'handlers': ['syslog', 'log_file', 'mail_admins'],
'level': 'INFO',
'propagate': False, 'propagate': False,
} }
for __logger_name in LOGGING['loggers'].keys(): for __logger_name in LOGGING['loggers'].keys():

View file

@ -5,9 +5,9 @@ After=redis.service postgresql.service
[Service] [Service]
User=__APP__ User=__APP__
Group=__APP__ Group=__APP__
WorkingDirectory=__FINALPATH__/ WorkingDirectory=__DATA_DIR__/
ExecStart=__FINALPATH__/venv/bin/gunicorn --config __FINALPATH__/gunicorn.conf.py wsgi ExecStart=__DATA_DIR__/venv/bin/gunicorn --config __DATA_DIR__/gunicorn.conf.py wsgi
StandardOutput=syslog StandardOutput=syslog
StandardError=syslog StandardError=syslog

View file

@ -5,7 +5,7 @@ from django.urls import path
if settings.PATH_URL: if settings.PATH_URL:
# settings.PATH_URL is the $YNH_APP_ARG_PATH # settings.PATH_URL is __PATH__
# Prefix all urls with "PATH_URL": # Prefix all urls with "PATH_URL":
urlpatterns = [ urlpatterns = [
# MEDIA_URL contains the "PATH_URL" already: # MEDIA_URL contains the "PATH_URL" already:

View file

@ -1,3 +1,4 @@
# https://yunohost.org/en/packaging_config_panels
# https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example # https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example
version = "1.0" version = "1.0"
@ -14,13 +15,16 @@ services = ["__APP__"]
ask = "from email" ask = "from email"
type = "email" type = "email"
help = "Default email address to use for various automated emails." help = "Default email address to use for various automated emails."
bind = "default_from_email:__FINALPATH__/settings.py" #
# We can't use "__DATA_DIR__" in bind value, because of this bug:
# https://github.com/YunoHost/issues/issues/2283
bind = "default_from_email:/home/yunohost.app/__APP__/settings.py"
[main.config.admin_email] [main.config.admin_email]
ask = "ADMIN email" ask = "ADMIN email"
type = "email" type = "email"
help = "EMail address for error emails." help = "EMail address for error emails."
bind = "admin_email:__FINALPATH__/settings.py" bind = "admin_email:/home/yunohost.app/__APP__/settings.py"
[main.config.debug_enabled] [main.config.debug_enabled]
ask = "DEBUG mode" ask = "DEBUG mode"
@ -28,11 +32,11 @@ services = ["__APP__"]
yes = "1" yes = "1"
no = "0" no = "0"
help = "Should be never enabled in production!" help = "Should be never enabled in production!"
bind = "debug_enabled:__FINALPATH__/settings.py" bind = "debug_enabled:/home/yunohost.app/__APP__/settings.py"
[main.config.log_level] [main.config.log_level]
type = "string" type = "string"
ask = "Log Level" ask = "Log Level"
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
default = "WARNING" default = "WARNING"
bind = "log_level:__FINALPATH__/settings.py" bind = "log_level:/home/yunohost.app/__APP__/settings.py"

115
dev-cli.py Executable file
View file

@ -0,0 +1,115 @@
#!/usr/bin/env python3
"""
bootstrap CLI
~~~~~~~~~~~~~
Just call this file, and the magic happens ;)
"""
import hashlib
import subprocess
import sys
import venv
from pathlib import Path
def print_no_pip_error():
print('Error: Pip not available!')
print('Hint: "apt-get install python3-venv"\n')
try:
from ensurepip import version
except ModuleNotFoundError as err:
print(err)
print('-' * 100)
print_no_pip_error()
raise
else:
if not version():
print_no_pip_error()
sys.exit(-1)
assert sys.version_info >= (3, 9), 'Python version is too old!'
if sys.platform == 'win32': # wtf
# Files under Windows, e.g.: .../.venv/Scripts/python.exe
BIN_NAME = 'Scripts'
FILE_EXT = '.exe'
else:
# Files under Linux/Mac and all other than Windows, e.g.: .../.venv/bin/python
BIN_NAME = 'bin'
FILE_EXT = ''
BASE_PATH = Path(__file__).parent
VENV_PATH = BASE_PATH / '.venv'
BIN_PATH = VENV_PATH / BIN_NAME
PYTHON_PATH = BIN_PATH / f'python{FILE_EXT}'
PIP_PATH = BIN_PATH / f'pip{FILE_EXT}'
PIP_SYNC_PATH = BIN_PATH / f'pip-sync{FILE_EXT}'
DEP_LOCK_PATH = BASE_PATH / 'requirements.dev.txt'
DEP_HASH_PATH = VENV_PATH / '.dep_hash'
# script file defined in pyproject.toml as [console_scripts]
# (Under Windows: ".exe" not added!)
PROJECT_SHELL_SCRIPT = BIN_PATH / 'pyinventory_ynh_dev'
def get_dep_hash():
"""Get SHA512 hash from lock file content."""
return hashlib.sha512(DEP_LOCK_PATH.read_bytes()).hexdigest()
def store_dep_hash():
"""Generate .venv/.dep_hash"""
DEP_HASH_PATH.write_text(get_dep_hash())
def venv_up2date():
"""Is existing .venv is up-to-date?"""
if DEP_HASH_PATH.is_file():
return DEP_HASH_PATH.read_text() == get_dep_hash()
return False
def verbose_check_call(*popen_args):
print(f'\n+ {" ".join(str(arg) for arg in popen_args)}\n')
return subprocess.check_call(popen_args)
def main(argv):
assert DEP_LOCK_PATH.is_file(), f'File not found: "{DEP_LOCK_PATH}" !'
# Create virtual env in ".venv/":
if not PYTHON_PATH.is_file():
print('Create virtual env here:', VENV_PATH.absolute())
builder = venv.EnvBuilder(symlinks=True, upgrade=True, with_pip=True)
builder.create(env_dir=VENV_PATH)
# Update pip
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip')
if not PIP_SYNC_PATH.is_file():
# Install pip-tools
verbose_check_call(PYTHON_PATH, '-m', 'pip', 'install', '-U', 'pip-tools')
if not PROJECT_SHELL_SCRIPT.is_file() or not venv_up2date():
# install requirements via "pip-sync"
verbose_check_call(PIP_SYNC_PATH, str(DEP_LOCK_PATH))
# install project
verbose_check_call(PIP_PATH, 'install', '--no-deps', '-e', '.')
store_dep_hash()
# Call our entry point CLI:
try:
verbose_check_call(PROJECT_SHELL_SCRIPT, *argv[1:])
except subprocess.CalledProcessError as err:
sys.exit(err.returncode)
if __name__ == '__main__':
main(sys.argv)

View file

@ -1,12 +1,14 @@
[![tests](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/tests.yml)
[![codecov](https://codecov.io/github/jedie/pyinventory_ynh/branch/main/graph/badge.svg)](https://app.codecov.io/github/jedie/pyinventory_ynh)
[![pyinventory_ynh @ PyPi](https://img.shields.io/pypi/v/pyinventory_ynh?label=pyinventory_ynh%20%40%20PyPi)](https://pypi.org/project/pyinventory_ynh/)
[![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/pyproject.toml)
[![License GPL-3.0-or-later](https://img.shields.io/pypi/l/pyinventory_ynh)](https://github.com/YunoHost-Apps/pyinventory_ynh/blob/main/LICENSE)
[PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/). [PyInventory](https://github.com/jedie/PyInventory) is a libre web-based management to catalog things including state and location etc. using [Python](https://www.python.org/)/[Django](https://www.djangoproject.com/).
[![Integration level](https://dash.yunohost.org/integration/pyinventory.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![CI Pipeline](https://ci-apps.yunohost.org/ci/badges/pyinventory.status.svg)](https://ci-apps.yunohost.org/ci/apps/pyinventory/) [![Maintain status](https://ci-apps.yunohost.org/ci/badges/pyinventory.maintain.svg)](https://dash.yunohost.org/appci/app/pyinventory) [![Integration level](https://dash.yunohost.org/integration/pyinventory_ynh.svg)](https://dash.yunohost.org/appci/app/pyinventory_ynh) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.status.svg) ![](https://ci-apps.yunohost.org/ci/badges/pyinventory_ynh.maintain.svg)
[![Install pyinventory_ynh with YunoHost](https://install-app.yunohost.org/install-with-yunohost.svg)](https://install-app.yunohost.org/?app=pyinventory_ynh)
[![pytest](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml/badge.svg?branch=master)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/pytest.yml) [![YunoHost apps package linter](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml/badge.svg)](https://github.com/YunoHost-Apps/pyinventory_ynh/actions/workflows/package_linter.yml) [![Coverage Status on codecov.io](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh/branch/master/graph/badge.svg)](https://codecov.io/gh/YunoHost-Apps/pyinventory_ynh)
![pyinventory @ PyPi](https://img.shields.io/pypi/v/pyinventory?label=pyinventory%20%40%20PyPi)
![Python Versions](https://img.shields.io/pypi/pyversions/pyinventory)
![License GPL V3+](https://img.shields.io/pypi/l/pyinventory)
Pull requests welcome ;) Pull requests welcome ;)

View file

@ -1,152 +1,15 @@
## Settings and upgrades ## Settings and upgrades
Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file. Almost everything related to PyInventory's configuration is handled in a `"../conf/settings.py"` file.
You can edit the file `/opt/yunohost/pyinventory/local_settings.py` to enable or disable features. You can edit the file `/home/yunohost.app/django_example/local_settings.py` to enable or disable features.
Test sending emails: Test sending emails, e.g.:
```bash ```bash
ssh admin@yourdomain.tld ssh admin@yourdomain.tld
root@yunohost:~# cd /opt/yunohost/pyinventory/ root@yunohost:~# /home/yunohost.app/pyinventory/manage.py sendtestemail --admins
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
``` ```
Background info: Error mails are send to all [settings.ADMINS](https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-ADMINS). By default the YunoHost admin is inserted here. How to debug a django YunoHost app, take a look into:
To check current ADMINS run:
```bash * https://github.com/YunoHost-Apps/django_example_ynh#developer-info
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py sendtestemail --admins
```
If you prefere to send error emails to a extrnal email address, just do something like this:
```bash
echo "ADMINS = (('Your Name', 'example@domain.tld'),)" >> /opt/yunohost/pyinventory/local_settings.py
```
To check the effective settings, run this:
```bash
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py diffsettings
```
# Miscellaneous
## SSO authentication
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported via [django-yunohost-integration](https://github.com/YunoHost-Apps/django_yunohost_integration):
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
* All new users will be created as normal users
* Login via SSO is fully supported
* User Email, First / Last name will be updated from SSO data
## Links
* Report a bug about this package: https://github.com/YunoHost-Apps/pyinventory_ynh
* Report a bug about PyInventory itself: https://github.com/jedie/PyInventory
* YunoHost website: https://yunohost.org/
---
# Developer info
## package installation / debugging
Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh
Try 'main' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/master --debug
```
Try 'testing' branch, e.g.:
```bash
sudo yunohost app install https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
or
sudo yunohost app upgrade pyinventory -u https://github.com/YunoHost-Apps/pyinventory_ynh/tree/testing --debug
```
To remove call e.g.:
```bash
sudo yunohost app remove pyinventory
```
Backup / remove / restore cycle, e.g.:
```bash
yunohost backup create --apps pyinventory
yunohost backup list
archives:
- pyinventory-pre-upgrade1
- 20201223-163434
yunohost app remove pyinventory
yunohost backup restore 20201223-163434 --apps pyinventory
```
Debug installation, e.g.:
```bash
root@yunohost:~# ls -la /var/www/pyinventory/
total 18
drwxr-xr-x 4 root root 4 Dec 8 08:36 .
drwxr-xr-x 6 root root 6 Dec 8 08:36 ..
drwxr-xr-x 2 root root 2 Dec 8 08:36 media
drwxr-xr-x 7 root root 8 Dec 8 08:40 static
root@yunohost:~# ls -la /opt/yunohost/pyinventory/
total 58
drwxr-xr-x 5 pyinventory pyinventory 11 Dec 8 08:39 .
drwxr-xr-x 3 root root 3 Dec 8 08:36 ..
-rw-r--r-- 1 pyinventory pyinventory 460 Dec 8 08:39 gunicorn.conf.py
-rw-r--r-- 1 pyinventory pyinventory 0 Dec 8 08:39 local_settings.py
-rwxr-xr-x 1 pyinventory pyinventory 274 Dec 8 08:39 manage.py
-rw-r--r-- 1 pyinventory pyinventory 171 Dec 8 08:39 secret.txt
drwxr-xr-x 6 pyinventory pyinventory 6 Dec 8 08:37 venv
-rw-r--r-- 1 pyinventory pyinventory 115 Dec 8 08:39 wsgi.py
-rw-r--r-- 1 pyinventory pyinventory 4737 Dec 8 08:39 settings.py
root@yunohost:~# cd /opt/yunohost/pyinventory/
root@yunohost:/opt/yunohost/pyinventory# source venv/bin/activate
(venv) root@yunohost:/opt/yunohost/pyinventory# ./manage.py check
PyInventory v0.8.2 (Django v2.2.17)
DJANGO_SETTINGS_MODULE='settings'
PROJECT_PATH:/opt/yunohost/pyinventory/venv/lib/python3.7/site-packages
BASE_PATH:/opt/yunohost/pyinventory
System check identified no issues (0 silenced).
root@yunohost:~# tail -f /var/log/pyinventory/pyinventory.log
root@yunohost:~# cat /etc/systemd/system/pyinventory.service
root@yunohost:~# systemctl reload-or-restart pyinventory
root@yunohost:~# journalctl --unit=pyinventory --follow
```
## local test
For quicker developing of PyInventory in the context of YunoHost app,
it's possible to run the Django developer server with the settings
and urls made for YunoHost installation.
e.g.:
```bash
~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git
~$ cd pyinventory_ynh/
~/pyinventory_ynh$ make
install-poetry install or update poetry
install install PyInventory via poetry
update update the sources and installation
local-test Run local_test.py to run pyinventory_ynh locally
~/pyinventory_ynh$ make install-poetry
~/pyinventory_ynh$ make install
~/pyinventory_ynh$ make local-test
```
Notes:
* SQlite database will be used
* A super user with username `test` and password `test` is created
* The page is available under `http://127.0.0.1:8000/app_path/`

View file

@ -1,32 +0,0 @@
"""
Build a "local_test" YunoHost installation and start the Django dev. server against it.
Run via:
make local-test
see README for details ;)
"""
from pathlib import Path
try:
from django_yunohost_integration.local_test import create_local_test
except ImportError as err:
raise ImportError('Did you forget to activate a virtual environment?') from err
BASE_PATH = Path(__file__).parent
def main():
create_local_test(
django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test',
runserver=True,
extra_replacements={
'__DEBUG_ENABLED__': '1',
},
)
if __name__ == '__main__':
main()

View file

@ -1,47 +0,0 @@
{
"name": "PyInventory",
"id": "pyinventory",
"packaging_format": 1,
"description": {
"en": "Web based management to catalog things including state and location etc."
},
"version": "0.19.2~ynh1",
"url": "https://github.com/jedie/PyInventory",
"upstream": {
"license": "GPL-3.0-or-later",
"admindoc": "https://github.com/YunoHost-Apps/pyinventory_ynh",
"userdoc": "https://github.com/jedie/PyInventory",
"code": "https://github.com/jedie/PyInventory"
},
"license": "GPL-3.0-or-later",
"maintainer": {
"name": "Jens Diemer",
"email": "pyinventory_ynh@jensdiemer.de"
},
"previous_maintainers": [],
"requirements": {
"yunohost": ">=11"
},
"multi_instance": true,
"services": [
"nginx", "postgresql", "redis"
],
"arguments": {
"install" : [
{
"name": "domain",
"type": "domain"
},
{
"name": "path",
"type": "path",
"example": "/pyinventory",
"default": "/pyinventory"
},
{
"name": "admin",
"type": "user"
}
]
}
}

110
manifest.toml Normal file
View file

@ -0,0 +1,110 @@
# https://yunohost.org/en/packaging_manifest
packaging_format = 2
id = "pyinventory"
name = "PyInventory"
description.en = "Web based management to catalog things including state and location etc."
version = "0.19.3~ynh1"
maintainers = ["Jens Diemer"]
[upstream]
# https://yunohost.org/en/packaging_manifest#upstream-section
license = "GPL-3.0-or-later"
website = "https://github.com/YunoHost-Apps/pyinventory_ynh"
admindoc = "https://github.com/YunoHost-Apps/pyinventory_ynh"
userdoc = "https://github.com/jedie/PyInventory"
code = "https://github.com/YunoHost-Apps/pyinventory_ynh"
[integration]
# https://yunohost.org/en/packaging_manifest#integration-section
yunohost = ">=11"
architectures = "all"
multi_instance = true
ldap = true
sso = true
disk = "50M" # **estimate** minimum disk requirement. e.g. 20M, 400M, 1G, ...
ram.build = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
ram.runtime = "50M" # **estimate** minimum ram requirement. e.g. 50M, 400M, 1G, ...
[install]
[install.domain]
# this is a generic question - ask strings are automatically handled by Yunohost's core
type = "domain"
[install.path]
# this is a generic question - ask strings are automatically handled by Yunohost's core
# setting $path and template variable __PATH__
type = "path"
default = "/pyinventory_ynh"
[install.admin]
# this is a generic question - ask strings are automatically handled by Yunohost's core
type = "user"
default = "admin"
[install.init_main_permission]
type = "group"
default = "admins"
[install.default_from_email] # __DEFAULT_FROM_EMAIL__
ask.en = "Default email address to use for various automated emails."
type = "email"
example = "admin@example.com"
[install.admin_email] # __ADMIN_EMAIL__
ask.en = "EMail address for error emails."
type = "email"
example = "admin@example.com"
[install.debug_enabled] # __DEBUG_ENABLED__
ask.en = "Should be never enabled in production!"
type = "select"
choices = ["YES", "NO"]
default = "NO"
[install.log_level] # __LOG_LEVEL__
ask.en = "Logging level"
type = "select"
choices = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
default = "WARNING"
[resources]
[resources.system_user]
# This will provision/deprovision a unix system user
[resources.install_dir]
# https://yunohost.org/en/packaging_apps_resources#install-dir
# This will create/remove the install dir as /var/www/$app/
# and store the corresponding setting $install_dir and template variable __INSTALL_DIR__
[resources.data_dir]
# https://yunohost.org/en/packaging_apps_resources#data-dir
# This will create/remove the data dir as /home/yunohost.app/$app/
# and store the corresponding setting $data_dir and template variable __DATA_DIR__
[resources.permissions]
# https://yunohost.org/en/packaging_apps_resources#permissions
# This will configure SSOwat permission for $domain/$path/
# The initial allowed group of user is configured via the init_main_permission question (public=visitors, private=all_users)
main.url = "/"
[resources.ports]
# https://yunohost.org/en/packaging_apps_resources#ports
# This will pick a random port for reverse-proxying and store it as the $port setting
[resources.apt]
# https://yunohost.org/en/packaging_apps_resources#apt
# This will automatically install/uninstall the following apt packages
packages = "build-essential, python3-dev, python3-pip, python3-venv, git, libpq-dev, postgresql, postgresql-contrib"
[resources.database]
# https://yunohost.org/en/packaging_apps_resources#database
# This will automatically provision/deprovison a Postgres DB
# and store the corresponding credentials in settings $db_user, $db_name, $db_pwd
type = "postgresql"

2122
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
"""
pyinventory_ynh
Web based management to catalog things including state and location etc.
"""
__version__ = '0.19.3+ynh1'
__author__ = 'Jens Diemer <pyinventory_ynh@jensdiemer.de>'

View file

370
pyinventory_ynh/cli/dev.py Normal file
View file

@ -0,0 +1,370 @@
"""
CLI for development
"""
import logging
import sys
from pathlib import Path
import rich_click as click
from bx_py_utils.path import assert_is_file
from cli_base.cli_tools.subprocess_utils import verbose_check_call
from cli_base.cli_tools.version_info import print_version
from django_yunohost_integration.local_test import create_local_test
from manageprojects.utilities import code_style
from manageprojects.utilities.publish import publish_package
from rich import print # noqa; noqa
from rich_click import RichGroup
import pyinventory_ynh
logger = logging.getLogger(__name__)
PACKAGE_ROOT = Path(pyinventory_ynh.__file__).parent.parent
assert_is_file(PACKAGE_ROOT / 'pyproject.toml')
OPTION_ARGS_DEFAULT_TRUE = dict(is_flag=True, show_default=True, default=True)
OPTION_ARGS_DEFAULT_FALSE = dict(is_flag=True, show_default=True, default=False)
ARGUMENT_EXISTING_DIR = dict(
type=click.Path(exists=True, file_okay=False, dir_okay=True, readable=True, path_type=Path)
)
ARGUMENT_NOT_EXISTING_DIR = dict(
type=click.Path(
exists=False,
file_okay=False,
dir_okay=True,
readable=False,
writable=True,
path_type=Path,
)
)
ARGUMENT_EXISTING_FILE = dict(
type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, path_type=Path)
)
class ClickGroup(RichGroup): # FIXME: How to set the "info_name" easier?
def make_context(self, info_name, *args, **kwargs):
info_name = './dev-cli.py'
return super().make_context(info_name, *args, **kwargs)
@click.group(
cls=ClickGroup,
epilog='Project Homepage: https://github.com/YunoHost-Apps/pyinventory_ynh',
)
def cli():
pass
@click.command()
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def mypy(verbose: bool = True):
"""Run Mypy (configured in pyproject.toml)"""
verbose_check_call('mypy', '.', cwd=PACKAGE_ROOT, verbose=verbose, exit_on_error=True)
cli.add_command(mypy)
@click.command()
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def coverage(verbose: bool = True):
"""
Run and show coverage.
"""
verbose_check_call('coverage', 'run', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'combine', '--append', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'report', '--fail-under=30', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'xml', verbose=verbose, exit_on_error=True)
verbose_check_call('coverage', 'json', verbose=verbose, exit_on_error=True)
cli.add_command(coverage)
@click.command()
def install():
"""
Run pip-sync and install 'pyinventory_ynh' via pip as editable.
"""
verbose_check_call('pip-sync', PACKAGE_ROOT / 'requirements.dev.txt')
verbose_check_call('pip', 'install', '--no-deps', '-e', '.')
cli.add_command(install)
@click.command()
def safety():
"""
Run safety check against current requirements files
"""
verbose_check_call('safety', 'check', '-r', 'requirements.dev.txt')
cli.add_command(safety)
@click.command()
def update():
"""
Update "requirements*.txt" dependencies files
"""
bin_path = Path(sys.executable).parent
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip')
verbose_check_call(bin_path / 'pip', 'install', '-U', 'pip-tools')
extra_env = dict(
CUSTOM_COMPILE_COMMAND='./dev-cli.py update',
)
pip_compile_base = [
bin_path / 'pip-compile',
'--verbose',
'--allow-unsafe', # https://pip-tools.readthedocs.io/en/latest/#deprecations
'--resolver=backtracking', # https://pip-tools.readthedocs.io/en/latest/#deprecations
'--upgrade',
'--generate-hashes',
]
# Only "prod" dependencies:
verbose_check_call(
*pip_compile_base,
'pyproject.toml',
'--output-file',
'conf/requirements.txt',
extra_env=extra_env,
)
# dependencies + "dev"-optional-dependencies:
verbose_check_call(
*pip_compile_base,
'pyproject.toml',
'--extra=dev',
'--output-file',
'requirements.dev.txt',
extra_env=extra_env,
)
verbose_check_call(bin_path / 'safety', 'check', '-r', 'requirements.dev.txt')
# Install new dependencies in current .venv:
verbose_check_call(bin_path / 'pip-sync', 'requirements.dev.txt')
cli.add_command(update)
@click.command()
def publish():
"""
Build and upload this project to PyPi
"""
_run_unittest_cli(verbose=False, exit_after_run=False) # Don't publish a broken state
publish_package(
module=pyinventory_ynh,
package_path=PACKAGE_ROOT,
distribution_name='pyinventory_ynh',
)
cli.add_command(publish)
@click.command()
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def fix_code_style(color: bool = True, verbose: bool = False):
"""
Fix code style of all pyinventory_ynh source code files via darker
"""
code_style.fix(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
cli.add_command(fix_code_style)
@click.command()
@click.option('--color/--no-color', **OPTION_ARGS_DEFAULT_TRUE)
@click.option('--verbose/--no-verbose', **OPTION_ARGS_DEFAULT_FALSE)
def check_code_style(color: bool = True, verbose: bool = False):
"""
Check code style by calling darker + flake8
"""
code_style.check(package_root=PACKAGE_ROOT, color=color, verbose=verbose)
cli.add_command(check_code_style)
@click.command()
def update_test_snapshot_files():
"""
Update all test snapshot files (by remove and recreate all snapshot files)
"""
def iter_snapshot_files():
yield from PACKAGE_ROOT.rglob('*.snapshot.*')
removed_file_count = 0
for item in iter_snapshot_files():
item.unlink()
removed_file_count += 1
print(f'{removed_file_count} test snapshot files removed... run tests...')
# Just recreate them by running tests:
_run_unittest_cli(
extra_env=dict(
RAISE_SNAPSHOT_ERRORS='0', # Recreate snapshot files without error
),
verbose=False,
exit_after_run=False,
)
new_files = len(list(iter_snapshot_files()))
print(f'{new_files} test snapshot files created, ok.\n')
cli.add_command(update_test_snapshot_files)
def _run_unittest_cli(extra_env=None, verbose=True, exit_after_run=True):
"""
Call the origin unittest CLI and pass all args to it.
"""
if extra_env is None:
extra_env = dict()
extra_env.update(
dict(
PYTHONUNBUFFERED='1',
PYTHONWARNINGS='always',
)
)
args = sys.argv[2:]
if not args:
if verbose:
args = ('--verbose', '--locals', '--buffer')
else:
args = ('--locals', '--buffer')
verbose_check_call(
sys.executable,
'-m',
'unittest',
*args,
timeout=15 * 60,
extra_env=extra_env,
)
if exit_after_run:
sys.exit(0)
@click.command() # Dummy command
def test():
"""
Run unittests
"""
_run_unittest_cli()
# TODO: Replace pytest with normal Django unittests:
# cli.add_command(test)
def _run_tox():
verbose_check_call(sys.executable, '-m', 'tox', *sys.argv[2:])
sys.exit(0)
@click.command() # Dummy "tox" command
def tox():
"""
Run tox
"""
_run_tox()
# TODO: cli.add_command(tox)
@click.command()
def version():
"""Print version and exit"""
# Pseudo command, because the version always printed on every CLI call ;)
sys.exit(0)
cli.add_command(version)
@click.command()
def local_test():
"""
Build a "local_test" YunoHost installation and start the Django dev. server against it.
"""
create_local_test(
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
destination=PACKAGE_ROOT / 'local_test',
runserver=True,
extra_replacements={
'__DEBUG_ENABLED__': '1',
},
)
cli.add_command(local_test)
@click.command()
def diffsettings():
"""
Run "diffsettings" manage command against a "local_test" YunoHost installation.
"""
destination = PACKAGE_ROOT / 'local_test'
create_local_test(
django_settings_path=PACKAGE_ROOT / 'conf' / 'settings.py',
destination=destination,
runserver=False,
extra_replacements={
'__DEBUG_ENABLED__': '1',
},
)
app_path = destination / 'opt_yunohost'
verbose_check_call(sys.executable, app_path / 'manage.py', 'diffsettings', cwd=app_path)
cli.add_command(diffsettings)
@click.command()
def pytest():
"""
Run tests via "pytest"
"""
verbose_check_call(sys.executable, '-m', 'pytest', *sys.argv[2:], cwd=PACKAGE_ROOT)
cli.add_command(pytest)
def main():
print_version(pyinventory_ynh)
if len(sys.argv) >= 2:
# Check if we just pass a command call
command = sys.argv[1]
if command == 'test':
# TODO: Call: _run_unittest_cli()
verbose_check_call(sys.executable, '-m', 'pytest', cwd=PACKAGE_ROOT)
sys.exit(0)
elif command == 'tox':
_run_tox()
# Execute Click CLI:
cli()

View file

@ -0,0 +1,6 @@
import os
import unittest.util
# Hacky way to expand the failed test output:
unittest.util._MAX_LENGTH = os.environ.get('UNITTEST_MAX_LENGTH', 300)

View file

@ -0,0 +1,10 @@
from bx_py_utils.test_utils.unittest_utils import BaseDocTests
import pyinventory_ynh
class DocTests(BaseDocTests):
def test_doctests(self):
self.run_doctests(
modules=(pyinventory_ynh,),
)

View file

@ -0,0 +1,68 @@
import subprocess
from unittest import TestCase
from bx_py_utils.path import assert_is_file
from manageprojects.test_utils.click_cli_utils import subprocess_cli
from manageprojects.test_utils.project_setup import check_editor_config, get_py_max_line_length
from manageprojects.utilities import code_style
from packaging.version import Version
from pyinventory_ynh import __version__
from pyinventory_ynh.cli.dev import PACKAGE_ROOT
class ProjectSetupTestCase(TestCase):
def test_version(self):
self.assertIsNotNone(__version__)
version = Version(__version__) # Will raise InvalidVersion() if wrong formatted
self.assertEqual(str(version), __version__)
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py'
assert_is_file(dev_cli_bin)
output = subprocess.check_output([dev_cli_bin, 'version'], text=True)
self.assertIn(f'pyinventory_ynh v{__version__}', output)
def test_code_style(self):
dev_cli_bin = PACKAGE_ROOT / 'dev-cli.py'
assert_is_file(dev_cli_bin)
try:
output = subprocess_cli(
cli_bin=dev_cli_bin,
args=('check-code-style',),
exit_on_error=False,
)
except subprocess.CalledProcessError as err:
self.assertIn('.venv/bin/darker', err.stdout) # darker was called?
else:
if 'Code style: OK' in output:
self.assertIn('.venv/bin/darker', output) # darker was called?
return # Nothing to fix -> OK
# Try to "auto" fix code style:
try:
output = subprocess_cli(
cli_bin=dev_cli_bin,
args=('fix-code-style',),
exit_on_error=False,
)
except subprocess.CalledProcessError as err:
output = err.stdout
self.assertIn('.venv/bin/darker', output) # darker was called?
# Check again and display the output:
try:
code_style.check(package_root=PACKAGE_ROOT)
except SystemExit as err:
self.assertEqual(err.code, 0, 'Code style error, see output above!')
def test_check_editor_config(self):
check_editor_config(package_root=PACKAGE_ROOT)
max_line_length = get_py_max_line_length(package_root=PACKAGE_ROOT)
self.assertEqual(max_line_length, 119)

View file

@ -1,61 +1,87 @@
[tool.poetry] [project]
name = "pyinventory_ynh" name = "pyinventory_ynh"
description = "YunoHost app package for: https://github.com/jedie/PyInventory" dynamic = ["version"]
version = "0.19.2+ynh1" description = "Web based management to catalog things including state and location etc."
authors = ["Jens Diemer <pyinventory_ynh@jensdiemer.de>"] license = {text = "GPL-3.0-or-later"}
homepage = "https://github.com/YunoHost-Apps/pyinventory_ynh" readme = "README.md"
license = "GPL-3.0-or-later" authors = [
readme = 'README.md' {name = 'Jens Diemer', email = 'pyinventory_ynh@jensdiemer.de'}
]
requires-python = ">=3.9" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye)
dependencies = [
"pyinventory", # https://github.com/jedie/PyInventory
#
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml
"django_yunohost_integration[ynh]>=0.6.0", # https://github.com/YunoHost-Apps/django_yunohost_integration
#
"cli-base-utilities>=0.4.4", # https://github.com/jedie/cli-base-utilities
#
# indirect depencies, added because we didn't create the requirements.txt with Python <3.11
# See: https://github.com/jazzband/pip-tools/issues/1326
"async-timeout", # needed by redis for python<=3.11.2
]
[project.optional-dependencies]
dev = [
"bx_django_utils", # https://github.com/boxine/bx_django_utils
"beautifulsoup4", # https://pypi.org/project/beautifulsoup4/
#
# TODO: Remove "pytest" and use normal unittests ;)
"pytest",
"pytest-cov",
"pytest-django",
#
"manageprojects>=0.15.0", # https://github.com/jedie/manageprojects
"pip-tools", # https://github.com/jazzband/pip-tools/
"tox", # https://github.com/tox-dev/tox
"coverage", # https://github.com/nedbat/coveragepy
"autopep8", # https://github.com/hhatto/autopep8
"pyupgrade", # https://github.com/asottile/pyupgrade
"flake8", # https://github.com/pycqa/flake8
"pyflakes", # https://github.com/PyCQA/pyflakes
"codespell", # https://github.com/codespell-project/codespell
"EditorConfig", # https://github.com/editorconfig/editorconfig-core-py
"safety", # https://github.com/pyupio/safety
"mypy", # https://github.com/python/mypy
"twine", # https://github.com/pypa/twine
[tool.poetry.urls] # https://github.com/akaihola/darker
"Bug Tracker" = "https://github.com/jedie/PyInventory/issues" # https://github.com/ikamensh/flynt
# https://github.com/pycqa/isort
# https://github.com/pygments/pygments
"darker[flynt, isort, color]",
[tool.poetry.dependencies] # indirect depencies added because of bug:
python = ">=3.9,<4.0.0" # Stay with 3.9 until YunoHost used >=Debian 11 (Bullseye) # https://github.com/pypa/pip/issues/9644 / https://github.com/jazzband/pip-tools/issues/1866
# # to avoid errors like:
pyinventory = ">=0.19.2" # https://github.com/jedie/PyInventory # In --require-hashes mode, all requirements must have their versions pinned with ==. These do not: ...
# "tomli", # Only needed for Python <3.11
# extras "ynh" will install: gunicorn, psycopg2, django-redis and django-axes "exceptiongroup", # needed by pytest
# see: https://github.com/YunoHost-Apps/django_yunohost_integration/blob/main/pyproject.toml ]
django_yunohost_integration = {version = ">=0.5.1", extras = ["ynh"]} # https://github.com/YunoHost-Apps/django_yunohost_integration
[project.urls]
Documentation = "https://github.com/YunoHost-Apps/pyinventory_ynh"
Source = "https://github.com/YunoHost-Apps/pyinventory_ynh"
[tool.poetry.dev-dependencies] [project.scripts]
bx_py_utils = "*" # https://github.com/boxine/bx_py_utils pyinventory_ynh_app = "pyinventory_ynh.__main__:main"
bx_django_utils = "*" # https://github.com/boxine/bx_django_utils pyinventory_ynh_dev = "pyinventory_ynh.cli.dev:main"
tox = ">=4.4.4" # https://github.com/tox-dev/tox
coverage= "*" # https://github.com/nedbat/coveragepy
flake8 = "*" # https://github.com/pycqa/flake8
EditorConfig = "*" # https://github.com/editorconfig/editorconfig-core-py
safety = "*" # https://github.com/pyupio/safety
mypy = "*" # https://github.com/python/mypy
twine = "*" # https://github.com/pypa/twine
poetry-publish = "*" # https://github.com/jedie/poetry-publish
pytest = "*"
pytest-cov = "*"
pytest-django = "*"
requests = "*" # https://github.com/psf/requests
packaging = "*" # https://github.com/pypa/packagi
beautifulsoup4 = "*" # https://pypi.org/project/beautifulsoup4/
# https://github.com/akaihola/darker
# https://github.com/ikamensh/flynt
# https://github.com/pycqa/isort
# https://github.com/pygments/pygments
darker = { version = "*", extras = ["flynt", "isort", "color"] }
tomli = "*" # https://github.com/hukkin/tomli
# tomli only needed for Python <3.11, but see bug:
# https://github.com/pypa/pip/issues/9644#issuecomment-1456583402
#tomli = {version = "*", markers = "python_version < \"3.11\""} # https://github.com/hukkin/tomli
[build-system] [build-system]
requires = ["poetry-core"] requires = ["setuptools>=61.0", "setuptools_scm>=7.1"]
build-backend = "poetry.core.masonry.api" build-backend = "setuptools.build_meta"
[tool.setuptools.packages.find]
where = ["."]
include = ["pyinventory_ynh*"]
[tool.setuptools.dynamic]
version = {attr = "pyinventory_ynh.__version__"}
[tool.darker] [tool.darker]
src = ['.'] src = ['.']
# YunoHost apps still use "master" istead of "main", isn't it?
revision = "origin/master..." revision = "origin/master..."
line_length = 119 line_length = 119
verbose = true verbose = true
@ -77,7 +103,7 @@ log_level = "INFO"
atomic=true atomic=true
profile='black' profile='black'
skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"] skip_glob=[".*", "*/htmlcov/*","*/migrations/*","*/local_test/*"]
known_first_party=['inventory', 'inventory_project'] known_first_party=['inventory', 'inventory_project', 'pyinventory_ynh']
line_length=119 line_length=119
lines_after_imports=2 lines_after_imports=2
@ -114,6 +140,10 @@ branch = true
parallel = true parallel = true
concurrency = ["multiprocessing"] concurrency = ["multiprocessing"]
source = ['.'] source = ['.']
# TODO: pytest -> Django unitests:
#command_line = '-m unittest --verbose --locals --buffer'
command_line = '-m pytest'
disable_warnings = ["couldnt-parse"]
[tool.coverage.report] [tool.coverage.report]
omit = ['.*', '*/tests/*'] omit = ['.*', '*/tests/*']
@ -132,18 +162,32 @@ exclude_lines = [
legacy_tox_ini = """ legacy_tox_ini = """
[tox] [tox]
isolated_build = True isolated_build = True
envlist = py{311,310,39} envlist = py{312,311,310,39}
skip_missing_interpreters = True skip_missing_interpreters = True
[testenv] [testenv]
passenv = * passenv = *
skip_install = true skip_install = true
allowlist_externals = make commands_pre =
pip install -U pip-tools
pip-sync requirements.dev.txt
commands = commands =
make pytest {envpython} -m coverage run --context='{envname}'
{envpython} -m coverage combine --append
{envpython} -m coverage xml
{envpython} -m coverage report
""" """
[tool.mypy]
warn_unused_configs = true
ignore_missing_imports = true
allow_redefinition = true # https://github.com/python/mypy/issues/7165
show_error_codes = true
plugins = []
exclude = ['.venv', 'tests']
[manageprojects] # https://github.com/jedie/manageprojects [manageprojects] # https://github.com/jedie/manageprojects
initial_revision = "b204761" initial_revision = "b204761"
initial_date = 2022-12-21T20:25:20+01:00 initial_date = 2022-12-21T20:25:20+01:00
@ -160,11 +204,13 @@ upstream_url = "https://github.com/jedie/PyInventory"
ynh_app_pkg_name = "pyinventory_ynh" ynh_app_pkg_name = "pyinventory_ynh"
ynh_app_url = "https://github.com/YunoHost-Apps/pyinventory_ynh" ynh_app_url = "https://github.com/YunoHost-Apps/pyinventory_ynh"
bug_tracker_url = "https://github.com/jedie/PyInventory/issues" bug_tracker_url = "https://github.com/jedie/PyInventory/issues"
upstream_version = "0.17.0" upstream_version = "0.19.2"
ynh_version = "1" ynh_version = "1"
package_description = "Web based management to catalog things including state and location etc." package_description = "Web based management to catalog things including state and location etc."
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
_template = "https://github.com/jedie/cookiecutter_templates/" _template = "https://github.com/jedie/cookiecutter_templates/"
applied_migrations = [ applied_migrations = [
"877e2ec", # 2023-08-17T20:54:24+02:00 "877e2ec", # 2023-08-17T20:54:24+02:00
"be3f649", # 2023-08-22T19:36:57+02:00
"c1a9d97", # 2023-11-01T19:59:17+01:00
] ]

1139
requirements.dev.txt Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,15 +4,6 @@
# RETRIEVE ARGUMENTS FROM THE MANIFEST # RETRIEVE ARGUMENTS FROM THE MANIFEST
#================================================= #=================================================
domain=$YNH_APP_ARG_DOMAIN
path_url=$YNH_APP_ARG_PATH
admin=$YNH_APP_ARG_ADMIN
# Currently not used: PyInventory has no public pages, yet!
is_public=$YNH_APP_ARG_IS_PUBLIC
app=$YNH_APP_INSTANCE_NAME
# Transfer the main SSO domain to the App: # Transfer the main SSO domain to the App:
ynh_current_host=$(cat /etc/yunohost/current_host) ynh_current_host=$(cat /etc/yunohost/current_host)
__YNH_CURRENT_HOST__=${ynh_current_host} __YNH_CURRENT_HOST__=${ynh_current_host}
@ -22,7 +13,7 @@ __YNH_CURRENT_HOST__=${ynh_current_host}
#================================================= #=================================================
# 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG # 'debug_enabled' -> '__DEBUG_ENABLED__' -> settings.DEBUG
debug_enabled="0" debug_enabled="NO" # "YES" or "NO" string
# 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL # 'log_level' -> '__LOG_LEVEL__' -> settings.LOG_LEVEL
log_level="WARNING" log_level="WARNING"
@ -37,23 +28,62 @@ default_from_email="${app}@${domain}"
# SET CONSTANTS # SET CONSTANTS
#================================================= #=================================================
public_path=/var/www/$app # e.g.: point pip cache to: /home/yunohost.app/$app/.cache/
final_path=/opt/yunohost/$app XDG_CACHE_HOME="$data_dir/.cache/"
log_path=/var/log/$app log_path=/var/log/$app
log_file="${log_path}/${app}.log" log_file="${log_path}/${app}.log"
#================================================= #=================================================
# COMMON VARIABLES # HELPERS
#================================================= #=================================================
# Needed base dependencies: myynh_setup_python_venv() {
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git" # Always recreate everything fresh with current python version
ynh_secure_remove "$data_dir/venv"
# Postgres and Python's "psycopg2": # Skip pip because of: https://github.com/YunoHost/issues/issues/1960
pkg_dependencies="${pkg_dependencies} libpq-dev postgresql postgresql-contrib" python3 -m venv --without-pip "$data_dir/venv"
# dependencies used by the app chown -c -R "$app:" "$data_dir"
pkg_dependencies="${pkg_dependencies} libjpeg-dev"
# run source in a 'sub shell'
(
set +o nounset
source "$data_dir/venv/bin/activate"
set -o nounset
set -x
ynh_exec_as $app $data_dir/venv/bin/python3 -m ensurepip
ynh_exec_as $app $data_dir/venv/bin/pip3 install --upgrade wheel pip setuptools
ynh_exec_as $app $data_dir/venv/bin/pip3 install --no-deps -r "$data_dir/requirements.txt"
)
}
myynh_setup_log_file() {
(
set -x
mkdir -p "$(dirname "$log_file")"
touch "$log_file"
chown -c -R $app:$app "$log_path"
chmod -c o-rwx "$log_path"
)
}
myynh_fix_file_permissions() {
(
set -x
# /var/www/$app/
chown -c -R "$app:www-data" "$install_dir"
chmod -c o-rwx "$install_dir"
# /home/yunohost.app/$app/
chown -c -R "$app:" "$data_dir"
chmod -c o-rwx "$data_dir"
)
}
#================================================= #=================================================
# Redis HELPERS # Redis HELPERS

View file

@ -9,21 +9,6 @@
source ../settings/scripts/_common.sh source ../settings/scripts/_common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
ynh_abort_if_errors
#=================================================
# LOAD SETTINGS
#=================================================
ynh_print_info --message="Loading installation settings..."
app=$YNH_APP_INSTANCE_NAME
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
domain=$(ynh_app_setting_get --app="$app" --key=domain)
#================================================= #=================================================
# DECLARE DATA AND CONF FILES TO BACKUP # DECLARE DATA AND CONF FILES TO BACKUP
#================================================= #=================================================
@ -33,8 +18,11 @@ ynh_print_info --message="Declaring files to be backed up..."
# BACKUP THE APP MAIN DIR # BACKUP THE APP MAIN DIR
#================================================= #=================================================
ynh_backup --src_path="$final_path" # /var/www/$app/
ynh_backup --src_path="$public_path" ynh_backup --src_path="$install_dir"
# /home/yunohost.app/$app/
ynh_backup --src_path="$data_dir"
#================================================= #=================================================
# BACKUP THE NGINX CONFIGURATION # BACKUP THE NGINX CONFIGURATION

View file

@ -6,81 +6,9 @@
# IMPORT GENERIC HELPERS # IMPORT GENERIC HELPERS
#================================================= #=================================================
YNH_APP_ARG_DOMAIN=$YNH_APP_NEW_DOMAIN
YNH_APP_ARG_PATH=$YNH_APP_NEW_PATH
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#=================================================
# RETRIEVE ARGUMENTS
#=================================================
old_domain=$YNH_APP_OLD_DOMAIN
old_path=$YNH_APP_OLD_PATH
new_domain=$YNH_APP_NEW_DOMAIN
new_path=$YNH_APP_NEW_PATH
#=================================================
# LOAD SETTINGS
#=================================================
ynh_script_progression --message="Loading installation settings..."
admin=$(ynh_app_setting_get --app="$app" --key=admin)
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
log_path=$(ynh_app_setting_get --app="$app" --key=log_path)
port=$(ynh_app_setting_get --app="$app" --key=port)
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
db_name=$(ynh_sanitize_dbid --db_name="$app")
db_user=$db_name
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
#-------------------------------------------------
# config_panel.toml settings:
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
#=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#=================================================
ynh_script_progression --message="Backing up the app before changing its URL (may take a while)..." --weight=40
# Backup the current version of the app
ynh_backup_before_upgrade
ynh_clean_setup () {
# Remove the new domain config file, the remove script won't do it as it doesn't know yet its location.
ynh_secure_remove --file="/etc/nginx/conf.d/$new_domain.d/$app.conf"
# restore it if the upgrade fails
ynh_restore_upgradebackup
}
# Exit if an error occurs during the execution of the script
ynh_abort_if_errors
#=================================================
# CHECK WHICH PARTS SHOULD BE CHANGED
#=================================================
change_domain=0
if [ "$old_domain" != "$new_domain" ]
then
change_domain=1
fi
change_path=0
if [ "$old_path" != "$new_path" ]
then
change_path=1
fi
#================================================= #=================================================
# STANDARD MODIFICATIONS # STANDARD MODIFICATIONS
#================================================= #=================================================
@ -88,66 +16,31 @@ fi
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd service '$app'..." ynh_script_progression --message="Stopping systemd service '$app'..."
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
#=================================================
# STANDARD MODIFICATIONS
#================================================= #=================================================
# MODIFY URL IN NGINX CONF # MODIFY URL IN NGINX CONF
#================================================= #=================================================
ynh_script_progression --message="Updating nginx web server configuration..." ynh_script_progression --message="Updating nginx web server configuration..."
nginx_conf_path=/etc/nginx/conf.d/$old_domain.d/$app.conf ynh_change_url_nginx_config
# Change the path in the nginx config file
if [ $change_path -eq 1 ]
then
# Make a backup of the original nginx config file if modified
ynh_backup_if_checksum_is_different --file="$nginx_conf_path"
# Set global variables for nginx helper
domain="$old_domain"
path_url="$new_path"
# Create a dedicated nginx config
ynh_add_nginx_config "public_path" "port"
fi
# Change the domain for nginx
if [ $change_domain -eq 1 ]
then
# Delete file checksum for the old conf file location
ynh_delete_file_checksum --file="$nginx_conf_path"
mv $nginx_conf_path /etc/nginx/conf.d/$new_domain.d/$app.conf
# Store file checksum for the new config file location
ynh_store_file_checksum --file="/etc/nginx/conf.d/$new_domain.d/$app.conf"
fi
#================================================= #=================================================
# SPECIFIC MODIFICATIONS # UPDATE DJANGO SETTINGS
#================================================= #=================================================
# MODIFY SETTINGS ynh_script_progression --message="Update $app settings file..." --weight=1
#=================================================
ynh_script_progression --message="Modify $app config file..."
domain=$YNH_APP_NEW_DOMAIN path=$new_path
path_url=$YNH_APP_NEW_PATH domain=$new_domain
ynh_add_config --template="settings.py" --destination="$final_path/settings.py" ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
#=================================================
# GENERIC FINALISATION
#================================================= #=================================================
# START SYSTEMD SERVICE # START SYSTEMD SERVICE
#================================================= #=================================================
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
#=================================================
# RELOAD NGINX
#=================================================
ynh_script_progression --message="Reloading nginx web server..."
ynh_systemd_action --service_name=nginx --action=reload
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT

View file

@ -7,159 +7,93 @@
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#================================================= # Install parameters are automatically saved as settings
# MANAGE SCRIPT FAILURE #
#================================================= # Settings are automatically loaded as bash variables
# in every app script context, therefore typically these will exist:
# - $domain
# - $path
# - $language
# ... etc
#
# Resources defined in the manifest are provisioned prior to this script
# and corresponding settings are also available, such as:
# - $install_dir
# - $port
# - $db_name
# ...
# Exit if an error occurs during the execution of the script #
ynh_abort_if_errors # $app is the app id (i.e. 'example' for first install,
# or 'example__2', '__3', ... for multi-instance installs)
#
#=================================================
# SETTINGS
#=================================================
ynh_script_progression --message="Storing installation settings..."
# Logging:
log_file="/var/log/$app/$app.log"
ynh_app_setting_set --app=$app --key=log_file --value="$log_file"
# Redis:
redis_db=$(ynh_redis_get_free_db)
ynh_app_setting_set --app=$app --key=redis_db --value="$redis_db"
# App settings:
ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
#================================================= #=================================================
# CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS # CHECK IF THE APP CAN BE INSTALLED WITH THESE ARGS
#================================================= #=================================================
ynh_script_progression --message="Validating installation parameters..." ynh_script_progression --message="Validating installation parameters..."
# Path for e.g. "static" files, served by nginx: mkdir -p "$install_dir/media" "$install_dir/static"
test ! -e "$public_path" || ynh_die --message="This path already contains a folder"
# Path for own config files, e.g.: Django's settings.py:
test ! -e "$final_path" || ynh_die --message="This path already contains a folder"
# Register (book) web path
ynh_webpath_register --app="$app" --domain="$domain" --path_url="$path_url"
mkdir -p "$public_path/media" "$public_path/static"
mkdir -p "$final_path"
mkdir -p "$log_path"
touch "${log_file}"
#================================================= #=================================================
# STORE SETTINGS FROM MANIFEST # SETUP LOG FILE
#================================================= #=================================================
ynh_script_progression --message="Storing installation settings..." ynh_script_progression --message="Setup logging..."
ynh_app_setting_set --app="$app" --key=admin --value="$admin" myynh_setup_log_file
ynh_app_setting_set --app="$app" --key=public_path --value="$public_path"
ynh_app_setting_set --app="$app" --key=final_path --value="$final_path"
ynh_app_setting_set --app="$app" --key=log_path --value="$log_file"
ynh_app_setting_set --app="$app" --key=domain --value="$domain" # Use logrotate to manage application logfile(s)
ynh_app_setting_set --app="$app" --key=path --value="$path_url" ynh_use_logrotate --logfile="$log_file" --specific_user=$app
# Find a free port
port=$(ynh_find_port --port=8000)
# Set port as application setting
# https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/setting
ynh_app_setting_set --app="$app" --key=port --value="$port"
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
redis_db=$(ynh_redis_get_free_db)
ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
#-------------------------------------------------
# config_panel.toml settings:
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled"
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level"
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email"
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email"
#=================================================
# STANDARD MODIFICATIONS
#=================================================
# INSTALL DEPENDENCIES
#=================================================
ynh_script_progression --message="Installing $app dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
#=================================================
# CREATE A PostgreSQL DATABASE
#=================================================
ynh_script_progression --message="Creating a PostgreSQL database..."
db_name=$(ynh_sanitize_dbid --db_name="$app")
db_user=$db_name
ynh_app_setting_set --app="$app" --key=db_name --value="$db_name"
ynh_psql_test_if_first_run
# Initialize database and store postgres password for upgrade
ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name"
#=================================================
# NGINX CONFIGURATION
#=================================================
ynh_script_progression --message="Configuring nginx web server..."
# Create a dedicated nginx config
# https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
ynh_add_nginx_config "public_path" "port"
#=================================================
# CREATE DEDICATED USER
#=================================================
ynh_script_progression --message="Configuring system user '$app'..."
# A home directory for venv and settings etc.
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
#================================================= #=================================================
# PYTHON VIRTUALENV # PYTHON VIRTUALENV
#================================================= #=================================================
ynh_script_progression --message="Create Python virtualenv..." --weight=5 ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
cp ../conf/requirements.txt "$data_dir/requirements.txt"
# Always recreate everything fresh with current python version myynh_setup_python_venv
ynh_secure_remove "${final_path}/venv"
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
python3 -m venv --without-pip "${final_path}/venv"
cp ../conf/requirements.txt "$final_path/requirements.txt"
chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell'
(
set +o nounset
source "${final_path}/venv/bin/activate"
set -o nounset
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
)
#================================================= #=================================================
# copy config files # copy config files
# ================================================ # ================================================
ynh_script_progression --message="Create $app configuration files..." ynh_script_progression --message="Create $app configuration files..."
ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py" ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
ynh_add_config --template="manage.py" --destination="$final_path/manage.py" ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
chmod +x "$final_path/manage.py" chmod -c +x "$data_dir/manage.py"
ynh_add_config --template="settings.py" --destination="$final_path/settings.py" ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py" ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
ynh_add_config --template="urls.py" --destination="$final_path/urls.py" ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py" ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
touch "$final_path/local_settings.py" touch "$data_dir/local_settings.py"
#================================================= #=================================================
# MIGRATE / COLLECTSTATIC / CREATEADMIN # MIGRATE / COLLECTSTATIC / CREATEADMIN
#================================================= #=================================================
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10 ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
cd "$final_path" || exit cd "$data_dir" || exit
# Just for debugging: # Just for debugging:
./manage.py diffsettings ./manage.py diffsettings
@ -174,72 +108,46 @@ cd "$final_path" || exit
# This may fail in some cases with errors, etc., but the app works and the user can fix issues later. # This may fail in some cases with errors, etc., but the app works and the user can fix issues later.
./manage.py check --deploy || true ./manage.py check --deploy || true
#=================================================
# SETUP LOGROTATE
#=================================================
ynh_script_progression --message="Configuring log rotation..."
# Use logrotate to manage app-specific logfile(s)
ynh_use_logrotate "$log_file"
#================================================= #=================================================
# INTEGRATE SERVICE IN YUNOHOST # INTEGRATE SERVICE IN YUNOHOST
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --log="${log_file}" yunohost service add $app
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
#================================================= #=================================================
# SECURE FILES AND DIRECTORIES # SECURE FILES AND DIRECTORIES
#================================================= #=================================================
ynh_script_progression --message="Set file permissions..."
# Set permissions to app files myynh_fix_file_permissions
chown -R "$app:" "$log_path"
chown -R "$app:www-data" "$public_path"
chown -R "$app:" "$final_path"
chmod o-rwx "$log_path"
chmod o-rwx "$public_path"
chmod o-rwx "$final_path"
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5 ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
# https://yunohost.org/en/contribute/packaging_apps/helpers # https://yunohost.org/en/packaging_apps_helpers#ynh-add-systemd-config
# https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd # https://github.com/YunoHost/yunohost/blob/dev/helpers/systemd
ynh_add_systemd_config --service="$app" --template="systemd.service" ynh_add_systemd_config --service=$app --template="systemd.service"
#=================================================
# SETUP SSOWAT
#=================================================
ynh_script_progression --message="Configuring SSOwat..."
# Make app public if necessary or protect it
if [ $is_public -eq 1 ]
then
# Everyone can access the app.
# The "main" permission is automatically created before the install script.
ynh_permission_update --permission "main" --add "visitors"
fi
#================================================= #=================================================
# Start the app server via systemd # Start the app server via systemd
#================================================= #=================================================
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
#================================================= #=================================================
# RELOAD NGINX # NGINX CONFIGURATION
#================================================= #=================================================
ynh_script_progression --message="Reloading nginx web server..." ynh_script_progression --message="Configuring nginx web server..."
ynh_systemd_action --service_name="nginx" --action="reload" # Create a dedicated nginx config
# https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
ynh_add_nginx_config "public_path" "port"
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT

View file

@ -9,17 +9,6 @@
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#=================================================
# LOAD SETTINGS
#=================================================
ynh_script_progression --message="Loading installation settings..."
domain=$(ynh_app_setting_get --app="$app" --key=domain)
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
db_user=$db_name
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
#================================================= #=================================================
# STANDARD REMOVE # STANDARD REMOVE
#================================================= #=================================================
@ -27,10 +16,10 @@ final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
#================================================= #=================================================
# Remove a service from the admin panel, added by `yunohost service add` # Remove a service from the admin panel, added by `yunohost service add`
if yunohost service status "$app" >/dev/null 2>&1 if yunohost service status $app >/dev/null 2>&1
then then
ynh_script_progression --message="Removing $app service integration..." ynh_script_progression --message="Removing $app service integration..."
yunohost service remove "$app" yunohost service remove $app
fi fi
#================================================= #=================================================
@ -38,15 +27,7 @@ fi
#================================================= #=================================================
ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5 ynh_script_progression --message="Stopping and removing systemd service '$app'..." --weight=5
ynh_remove_systemd_config --service="$app" ynh_remove_systemd_config --service=$app
#=================================================
# REMOVE THE PostgreSQL DATABASE
#=================================================
ynh_script_progression --message="Removing the PostgreSQL database..."
# Remove a database if it exists, along with the associated user
ynh_psql_remove_db --db_user=$db_user --db_name=$db_name
##================================================= ##=================================================
## REMOVE REDIS DB ## REMOVE REDIS DB
@ -54,22 +35,16 @@ ynh_psql_remove_db --db_user=$db_user --db_name=$db_name
ynh_redis_remove_db ynh_redis_remove_db
#=================================================
# REMOVE DEPENDENCIES
#=================================================
ynh_script_progression --message="Removing dependencies..." --weight=10
# Remove metapackage and its dependencies
ynh_exec_warn_less ynh_remove_app_dependencies
#================================================= #=================================================
# REMOVE APP MAIN DIR # REMOVE APP MAIN DIR
#================================================= #=================================================
ynh_script_progression --message="Removing app main directory..." ynh_script_progression --message="Removing app main directory..."
# Remove the app directory securely # /var/www/$app/
ynh_secure_remove --file="$public_path" ynh_secure_remove --file="$install_dir"
ynh_secure_remove --file="$final_path"
# /home/yunohost.app/$app/
ynh_secure_remove --file="$data_dir"
#================================================= #=================================================
# REMOVE NGINX CONFIGURATION # REMOVE NGINX CONFIGURATION
@ -87,16 +62,6 @@ ynh_script_progression --message="Removing logrotate configuration..."
# Remove the app-specific logrotate config # Remove the app-specific logrotate config
ynh_remove_logrotate ynh_remove_logrotate
#=================================================
# GENERIC FINALIZATION
#=================================================
# REMOVE DEDICATED USER
#=================================================
ynh_script_progression --message="Removing the dedicated system user..."
# Delete a system user
ynh_system_user_delete --username="$app"
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT
#================================================= #=================================================

View file

@ -9,39 +9,12 @@
source ../settings/scripts/_common.sh source ../settings/scripts/_common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#=================================================
# MANAGE SCRIPT FAILURE
#=================================================
ynh_abort_if_errors
#=================================================
# LOAD SETTINGS
#=================================================
ynh_script_progression --message="Loading settings..."
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
db_name=$(ynh_app_setting_get --app="$app" --key=db_name)
db_user=$db_name
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
domain=$(ynh_app_setting_get --app="$app" --key=domain)
path_url=$(ynh_app_setting_get --app="$app" --key=path)
#=================================================
# CHECK IF THE APP CAN BE RESTORED
#=================================================
ynh_script_progression --message="Validating restoration parameters..."
test ! -d $final_path \
|| ynh_die --message="There is already a directory: $final_path "
#================================================= #=================================================
# STANDARD RESTORATION STEPS # STANDARD RESTORATION STEPS
#================================================= #=================================================
# RESTORE THE NGINX CONFIGURATION # RESTORE THE NGINX CONFIGURATION
#================================================= #=================================================
ynh_script_progression --message="Restoring the NGINX web server configuration..." --weight=1
ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf" ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
@ -50,74 +23,31 @@ ynh_restore_file --origin_path="/etc/nginx/conf.d/$domain.d/$app.conf"
#================================================= #=================================================
ynh_script_progression --message="Restoring $app main directory..." ynh_script_progression --message="Restoring $app main directory..."
ynh_restore_file --origin_path="$final_path" ynh_restore_file --origin_path="$install_dir"
ynh_restore_file --origin_path="$public_path" ynh_restore_file --origin_path="$data_dir"
#================================================= ynh_script_progression --message="Set file permissions..."
# RECREATE THE DEDICATED USER myynh_fix_file_permissions
#=================================================
ynh_script_progression --message="Recreating the dedicated system user..."
# Create the dedicated user (if not existing)
ynh_system_user_create --username=$app --home_dir="$final_path" --use_shell
#=================================================
# RESTORE USER RIGHTS
#=================================================
# Restore permissions on app files
chown -R "$app:www-data" "$public_path"
chown -R "$app:" "$final_path"
#=================================================
# SPECIFIC RESTORATION
#=================================================
# REINSTALL DEPENDENCIES
#=================================================
ynh_script_progression --message="Reinstalling dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
#================================================= #=================================================
# PYTHON VIRTUALENV # PYTHON VIRTUALENV
# Maybe the backup contains a other Python version # Maybe the backup contains a other Python version
#================================================= #=================================================
ynh_script_progression --message="Recreate Python virtualenv..." --weight=5 ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
# Always recreate everything fresh with current python version myynh_setup_python_venv
ynh_secure_remove "${final_path}/venv"
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
python3 -m venv --without-pip "${final_path}/venv"
chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell'
(
set +o nounset
source "${final_path}/venv/bin/activate"
set -o nounset
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
)
#================================================= #=================================================
# RESTORE THE PostgreSQL DATABASE # RESTORE THE PostgreSQL DATABASE
#================================================= #=================================================
ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=5 ynh_script_progression --message="Restoring the PostgreSQL database..." --weight=5
ynh_psql_test_if_first_run
ynh_psql_setup_db --db_user="$db_user" --db_name="$db_name" --db_pwd="$db_pwd"
ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql ynh_psql_connect_as --user=$db_user --password=$db_pwd --database=$db_name < ./db.sql
#================================================= #=================================================
# RESTORE SYSTEMD # RESTORE SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Restoring the systemd configuration..." ynh_script_progression --message="Restoring the systemd $app configuration..."
ynh_restore_file --origin_path="/etc/systemd/system/$app.service" ynh_restore_file --origin_path="/etc/systemd/system/$app.service"
systemctl enable $app.service --quiet systemctl enable $app.service --quiet
@ -127,15 +57,14 @@ systemctl enable $app.service --quiet
#================================================= #=================================================
ynh_script_progression --message="Integrating service in YunoHost..." ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --log="${log_file}" yunohost service add $app
#================================================= #=================================================
# RESTORE THE LOGROTATE CONFIGURATION # RESTORE THE LOGROTATE CONFIGURATION
#================================================= #=================================================
ynh_script_progression --message="Setup logging..."
mkdir -p "$log_path" myynh_setup_log_file
touch "${log_file}"
chown -R "$app:" "$log_path"
ynh_restore_file --origin_path="/etc/logrotate.d/$app" ynh_restore_file --origin_path="/etc/logrotate.d/$app"
#================================================= #=================================================
@ -143,15 +72,8 @@ ynh_restore_file --origin_path="/etc/logrotate.d/$app"
#================================================= #=================================================
# SECURE FILES AND DIRECTORIES # SECURE FILES AND DIRECTORIES
#================================================= #=================================================
ynh_script_progression --message="Set file permissions..."
# Set permissions to app files myynh_fix_file_permissions
chown -R "$app:" "$log_path"
chown -R "$app:www-data" "$public_path"
chown -R "$app:" "$final_path"
chmod o-rwx "$log_path"
chmod o-rwx "$public_path"
chmod o-rwx "$final_path"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
@ -160,7 +82,7 @@ chmod o-rwx "$final_path"
#================================================= #=================================================
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
#================================================= #=================================================
# RELOAD NGINX # RELOAD NGINX

View file

@ -7,68 +7,29 @@
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#=================================================
# LOAD SETTINGS
#=================================================
ynh_script_progression --message="Loading installation settings..."
admin=$(ynh_app_setting_get --app="$app" --key=admin)
public_path=$(ynh_app_setting_get --app="$app" --key=public_path)
final_path=$(ynh_app_setting_get --app="$app" --key=final_path)
log_path=$(ynh_app_setting_get --app="$app" --key=log_path)
domain=$(ynh_app_setting_get --app="$app" --key=domain)
path_url=$(ynh_app_setting_get --app="$app" --key=path)
port=$(ynh_app_setting_get --app="$app" --key=port)
db_pwd=$(ynh_app_setting_get --app="$app" --key=psqlpwd)
db_name=$(ynh_sanitize_dbid --db_name="$app")
db_user=$db_name
redis_db=$(ynh_app_setting_get --app="$app" --key=redis_db)
#------------------------------------------------- #-------------------------------------------------
# config_panel.toml settings: # config_panel.toml settings:
debug_enabled=$(ynh_app_setting_get --app="$app" --key=debug_enabled)
if [ -z "$debug_enabled" ]; then if [ -z "$debug_enabled" ]; then
debug_enabled="0" debug_enabled="0"
ynh_app_setting_set --app="$app" --key=debug_enabled --value="$debug_enabled" ynh_app_setting_set --app=$app --key=debug_enabled --value="$debug_enabled"
fi fi
log_level=$(ynh_app_setting_get --app="$app" --key=log_level)
if [ -z "$log_level" ]; then if [ -z "$log_level" ]; then
log_level="WARNING" log_level="WARNING"
ynh_app_setting_set --app="$app" --key=log_level --value="$log_level" ynh_app_setting_set --app=$app --key=log_level --value="$log_level"
fi fi
admin_email=$(ynh_app_setting_get --app="$app" --key=admin_email)
if [ -z "$admin_email" ]; then if [ -z "$admin_email" ]; then
admin_email="${admin}@${domain}" admin_email="${admin}@${domain}"
ynh_app_setting_set --app="$app" --key=admin_email --value="$admin_email" ynh_app_setting_set --app=$app --key=admin_email --value="$admin_email"
fi fi
default_from_email=$(ynh_app_setting_get --app="$app" --key=default_from_email)
if [ -z "$default_from_email" ]; then if [ -z "$default_from_email" ]; then
default_from_email="${app}@${domain}" default_from_email="${app}@${domain}"
ynh_app_setting_set --app="$app" --key=default_from_email --value="$default_from_email" ynh_app_setting_set --app=$app --key=default_from_email --value="$default_from_email"
fi fi
#=================================================
# BACKUP BEFORE UPGRADE THEN ACTIVE TRAP
#=================================================
ynh_script_progression --message="Backing up $app before upgrading (may take a while)..." --weight=40
# Backup the current version of the app
ynh_backup_before_upgrade
ynh_clean_setup () {
# restore it if the upgrade fails
ynh_restore_upgradebackup
}
# Exit if an error occurs during the execution of the script
ynh_abort_if_errors
#================================================= #=================================================
# STANDARD UPGRADE STEPS # STANDARD UPGRADE STEPS
#================================================= #=================================================
@ -76,91 +37,44 @@ ynh_abort_if_errors
#================================================= #=================================================
ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5 ynh_script_progression --message="Stopping systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="stop" ynh_systemd_action --service_name=$app --action="stop" --log_path="$log_file"
#=================================================
# NGINX CONFIGURATION
#=================================================
ynh_script_progression --message="Upgrading nginx web server configuration..."
# Create a dedicated nginx config
# https://yunohost.org/en/contribute/packaging_apps/helpers
# https://github.com/YunoHost/yunohost/blob/dev/helpers/nginx
ynh_add_nginx_config "public_path" "port"
#=================================================
# SPECIFIC UPGRADE
#=================================================
# Update dependencies
#=================================================
ynh_script_progression --message="Upgrading dependencies..." --weight=20
ynh_exec_warn_less ynh_install_app_dependencies "$pkg_dependencies"
#=================================================
# CREATE DEDICATED USER
#=================================================
ynh_script_progression --message="Making sure dedicated system user exists..."
# Create a system user
ynh_system_user_create --username="$app" --home_dir="$final_path" --use_shell
#================================================= #=================================================
# SETUP SYSTEMD # SETUP SYSTEMD
#================================================= #=================================================
ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5 ynh_script_progression --message="Configuring systemd service '$app'..." --weight=5
ynh_add_systemd_config --service="$app" --template="systemd.service" ynh_add_systemd_config --service=$app --template="systemd.service"
#================================================= #=================================================
# PYTHON VIRTUALENV # PYTHON VIRTUALENV
#================================================= #=================================================
ynh_script_progression --message="Recreate Python virtualenv..." --weight=5 ynh_script_progression --message="Create and setup Python virtualenv..." --weight=45
cp ../conf/requirements.txt "$data_dir/requirements.txt"
# Always recreate everything fresh with current python version myynh_setup_python_venv
ynh_secure_remove "${final_path}/venv"
# Skip pip because of: https://github.com/YunoHost/issues/issues/1960
python3 -m venv --without-pip "${final_path}/venv"
cp ../conf/requirements.txt "$final_path/requirements.txt"
chown -R "$app:" "$final_path"
#=================================================
# PIP INSTALLATION
#=================================================
ynh_script_progression --message="Install project via pip..." --weight=45
#run source in a 'sub shell'
(
set +o nounset
source "${final_path}/venv/bin/activate"
set -o nounset
ynh_exec_as $app $final_path/venv/bin/python3 -m ensurepip
ynh_exec_as $app $final_path/venv/bin/pip3 install --upgrade wheel pip setuptools
ynh_exec_as $app $final_path/venv/bin/pip3 install --no-deps -r "$final_path/requirements.txt"
)
#================================================= #=================================================
# copy config files # copy config files
# ================================================ # ================================================
ynh_script_progression --message="Create project configuration files..." ynh_script_progression --message="Create project configuration files..."
ynh_add_config --template="gunicorn.conf.py" --destination="$final_path/gunicorn.conf.py" ynh_add_config --template="gunicorn.conf.py" --destination="$data_dir/gunicorn.conf.py"
ynh_add_config --template="manage.py" --destination="$final_path/manage.py" ynh_add_config --template="manage.py" --destination="$data_dir/manage.py"
chmod +x "$final_path/manage.py" chmod -c +x "$data_dir/manage.py"
ynh_add_config --template="settings.py" --destination="$final_path/settings.py" ynh_add_config --template="settings.py" --destination="$data_dir/settings.py"
ynh_add_config --template="setup_user.py" --destination="$final_path/setup_user.py" ynh_add_config --template="setup_user.py" --destination="$data_dir/setup_user.py"
ynh_add_config --template="urls.py" --destination="$final_path/urls.py" ynh_add_config --template="urls.py" --destination="$data_dir/urls.py"
ynh_add_config --template="wsgi.py" --destination="$final_path/wsgi.py" ynh_add_config --template="wsgi.py" --destination="$data_dir/wsgi.py"
#================================================= #=================================================
# MIGRATE PYINVENTORY # MIGRATE PYINVENTORY
#================================================= #=================================================
ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10 ynh_script_progression --message="migrate/collectstatic/createadmin..." --weight=10
cd "$final_path" || exit cd "$data_dir" || exit
# Just for debugging: # Just for debugging:
./manage.py diffsettings ./manage.py diffsettings
@ -182,43 +96,23 @@ cd "$final_path" || exit
ynh_script_progression --message="Upgrading logrotate configuration..." ynh_script_progression --message="Upgrading logrotate configuration..."
# Use logrotate to manage app-specific logfile(s) # Use logrotate to manage app-specific logfile(s)
ynh_use_logrotate --non-append ynh_use_logrotate --logfile="$log_file" --specific_user=$app --non-append
#=================================================
# INTEGRATE SERVICE IN YUNOHOST
#=================================================
ynh_script_progression --message="Integrating service in YunoHost..."
yunohost service add $app --log="${log_file}"
#================================================= #=================================================
# GENERIC FINALIZATION # GENERIC FINALIZATION
#================================================= #=================================================
# SECURE FILES AND DIRECTORIES # SECURE FILES AND DIRECTORIES
#================================================= #=================================================
ynh_script_progression --message="Set file permissions..."
# Set permissions to app files myynh_fix_file_permissions
chown -R "$app:" "$log_path"
chown -R "$app:www-data" "$public_path"
chown -R "$app:" "$final_path"
chmod o-rwx "$log_path"
chmod o-rwx "$public_path"
chmod o-rwx "$final_path"
#================================================= #=================================================
# Start the app server via systemd # Start the app server via systemd
#================================================= #=================================================
ynh_script_progression --message="Starting systemd service '$app'..." --weight=5 ynh_script_progression --message="Starting systemd service '$app'..." --weight=5
ynh_systemd_action --service_name="$app" --action="start" yunohost service add $app
ynh_systemd_action --service_name=$app --action="start" --log_path="$log_file"
#=================================================
# RELOAD NGINX
#=================================================
ynh_script_progression --message="Reloading nginx web server..."
ynh_systemd_action --service_name=nginx --action=reload
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT

31
tests.toml Normal file
View file

@ -0,0 +1,31 @@
test_format = 1.0
[default]
# ------------
# Tests to run
# ------------
# NB: the tests to run are automatically deduced by the CI script according to the
# content of the app's manifest. The declarations below allow to customize which
# tests are ran, possibly add special test suite to test special args, or
# declare which commits to test upgrade from.
#
# You can also decide (though this is discouraged!) to ban/ignore some tests,
# The test IDs to be used in only/exclude statements are:
# install.root, install.subdir, install.nourl, install.multi, backup_restore, upgrade, upgrade.someCommitId change_url
#exclude = ["install.private", "install.multi"]
# -------------------------------
# Default args to use for install
# -------------------------------
# By default, the CI will automagically fill the 'standard' args
# such as domain, path, admin, is_public and password with relevant values
# and also install args with a "default" provided in the manifest..
# It should only make sense to declare custom args here for args with no default values
args.default_from_email = "default_from_email@example.tld"
args.admin_email = "admin_email@example.tld"

View file

@ -11,7 +11,7 @@ import sys
from pathlib import Path from pathlib import Path
import django import django
from django_yunohost_integration.local_test import create_local_test from django_yunohost_integration.local_test import CreateResults, create_local_test
BASE_PATH = Path(__file__).parent.parent BASE_PATH = Path(__file__).parent.parent
@ -21,23 +21,23 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
def pytest_configure(): def pytest_configure():
print('Compile YunoHost files...') print('Compile YunoHost files...')
final_path = create_local_test( result: CreateResults = create_local_test(
django_settings_path=BASE_PATH / 'conf' / 'settings.py', django_settings_path=BASE_PATH / 'conf' / 'settings.py',
destination=BASE_PATH / 'local_test', destination=BASE_PATH / 'local_test',
runserver=False, runserver=False,
extra_replacements={ extra_replacements={
'__DEBUG_ENABLED__': '0', '__DEBUG_ENABLED__': 'NO', # "YES" or "NO" string
'__LOG_LEVEL__': 'INFO', '__LOG_LEVEL__': 'INFO',
'__ADMIN_EMAIL__': 'foo-bar@test.tld', '__ADMIN_EMAIL__': 'foo-bar@test.tld',
'__DEFAULT_FROM_EMAIL__': 'django_app@test.tld', '__DEFAULT_FROM_EMAIL__': 'django_app@test.tld',
}, },
) )
print('Local test files created here:') print('Local test files created:')
print(f'"{final_path}"') print(result)
os.chdir(final_path) os.chdir(result.data_dir_path)
final_home_str = str(final_path) data_dir = str(result.data_dir_path)
if final_home_str not in sys.path: if data_dir not in sys.path:
sys.path.insert(0, final_home_str) sys.path.insert(0, data_dir)
django.setup() django.setup()

View file

@ -27,16 +27,16 @@ class DjangoYnhTestCase(HtmlAssertionMixin, TestCase):
assert settings.PATH_URL == 'app_path' assert settings.PATH_URL == 'app_path'
assert str(settings.FINALPATH).endswith('/local_test/opt_yunohost') assert str(settings.DATA_DIR_PATH).endswith('/local_test/opt_yunohost')
assert str(settings.PUBLIC_PATH).endswith('/local_test/var_www') assert str(settings.INSTALL_DIR_PATH).endswith('/local_test/var_www')
assert str(settings.LOG_FILE).endswith('/local_test/var_log_pyinventory.log') assert str(settings.LOG_FILE_PATH).endswith('/local_test/var_log_pyinventory.log')
assert settings.ROOT_URLCONF == 'urls' assert settings.ROOT_URLCONF == 'urls'
assert reverse('admin:index') == '/app_path/' assert reverse('admin:index') == '/app_path/'
def test_config_panel_settings(self): def test_config_panel_settings(self):
# config_panel.toml settings, set via tests.conftest.pytest_configure(): # config_panel.toml settings, set via tests.conftest.pytest_configure():
assert settings.DEBUG_ENABLED == '0' and settings.DEBUG is False assert settings.DEBUG_ENABLED == 'NO' and settings.DEBUG is False
assert settings.LOG_LEVEL == 'INFO' assert settings.LOG_LEVEL == 'INFO'
assert settings.ADMIN_EMAIL == 'foo-bar@test.tld' assert settings.ADMIN_EMAIL == 'foo-bar@test.tld'
assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld' assert settings.DEFAULT_FROM_EMAIL == 'django_app@test.tld'

View file

@ -4,7 +4,7 @@
<div id="branding"> <div id="branding">
<h1 id="site-name"> <h1 id="site-name">
<a href="/app_path/"> <a href="/app_path/">
PyInventory v0.19.2 PyInventory v0.19.3
</a> </a>
</h1> </h1>
</div> </div>
@ -28,11 +28,34 @@
Log out Log out
</button> </button>
</form> </form>
<button class="theme-toggle">
<div class="visually-hidden theme-label-when-auto">
Toggle theme (current theme: auto)
</div>
<div class="visually-hidden theme-label-when-light">
Toggle theme (current theme: light)
</div>
<div class="visually-hidden theme-label-when-dark">
Toggle theme (current theme: dark)
</div>
<svg aria-hidden="true" class="theme-icon-when-auto">
<use xlink:href="#icon-auto">
</use>
</svg>
<svg aria-hidden="true" class="theme-icon-when-dark">
<use xlink:href="#icon-moon">
</use>
</svg>
<svg aria-hidden="true" class="theme-icon-when-light">
<use xlink:href="#icon-sun">
</use>
</svg>
</button>
</div> </div>
</div> </div>
<!-- END Header --> <!-- END Header -->
<div class="main" id="main"> <div class="main" id="main">
<div class="content"> <div class="content" id="content-start" tabindex="-1">
<!-- Content --> <!-- Content -->
<div class="colMS" id="content"> <div class="colMS" id="content">
<h1> <h1>
@ -66,4 +89,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,7 +1,4 @@
import difflib
import os import os
import shutil
import subprocess
from pathlib import Path from pathlib import Path
from unittest import TestCase from unittest import TestCase
@ -16,7 +13,8 @@ from bx_py_utils.path import assert_is_dir, assert_is_file
from django_tools.unittest_utils.project_setup import check_editor_config from django_tools.unittest_utils.project_setup import check_editor_config
from django_yunohost_integration.test_utils import assert_project_version from django_yunohost_integration.test_utils import assert_project_version
from inventory import __version__ from inventory import __version__ as inventory_version
from pyinventory_ynh import __version__ as pyinventory_ynh_version
PACKAGE_ROOT = Path(__file__).parent.parent PACKAGE_ROOT = Path(__file__).parent.parent
@ -31,68 +29,25 @@ def assert_file_contains_string(file_path, string):
def test_version(): def test_version():
if 'GITHUB_ACTION' not in os.environ: assert inventory_version in pyinventory_ynh_version, f'{inventory_version!r} not in {pyinventory_ynh_version!r}'
# Github has a rate-limiting... So don't fetch the API if we run as GitHub action
assert_project_version(
current_version=__version__,
github_project_url='https://github.com/jedie/PyInventory',
)
pyproject_toml_path = Path(PACKAGE_ROOT, 'pyproject.toml') assert '+ynh' in pyinventory_ynh_version, f'{pyinventory_ynh_version!r} does not contain "+ynh"'
pyproject_toml = tomllib.loads(pyproject_toml_path.read_text(encoding='UTF-8'))
pyproject_version = pyproject_toml['tool']['poetry']['version']
assert pyproject_version.startswith(
f'{__version__}+ynh'
), f'{pyproject_version!r} does not start with "{__version__}+ynh"'
# pyproject.toml needs a PEP 440 conform version and used "+ynh" # pyproject.toml needs a PEP 440 conform version and used "+ynh"
# the YunoHost syntax is: "~ynh", just "convert this: # the YunoHost syntax is: "~ynh", just "convert this:
manifest_version = pyproject_version.replace('+', '~') manifest_version = pyinventory_ynh_version.replace('+', '~')
assert_file_contains_string( assert_file_contains_string(
file_path=Path(PACKAGE_ROOT, 'manifest.json'), file_path=Path(PACKAGE_ROOT, 'manifest.toml'),
string=f'"version": "{manifest_version}"', string=f'version = "{manifest_version}"',
) )
if 'GITHUB_ACTION' not in os.environ:
def poetry_check_output(*args): # Github has a rate-limiting... So don't fetch the API if we run as GitHub action
poerty_bin = shutil.which('poetry') assert_project_version(
current_version=inventory_version,
output = subprocess.check_output( github_project_url='https://github.com/jedie/PyInventory',
(poerty_bin,) + args,
text=True,
env=os.environ,
stderr=subprocess.STDOUT,
cwd=str(PACKAGE_ROOT),
)
print(output)
return output
def test_poetry_check():
output = poetry_check_output('check')
assert output == 'All set!\n'
def test_requirements_txt():
requirements_txt = PACKAGE_ROOT / 'conf' / 'requirements.txt'
assert_is_file(requirements_txt)
output = poetry_check_output('export', '-f', 'requirements.txt')
assert 'Warning' not in output
current_content = requirements_txt.read_text()
diff = '\n'.join(
difflib.unified_diff(
current_content.splitlines(),
output.splitlines(),
fromfile=str(requirements_txt),
tofile='FRESH EXPORT',
) )
)
print(diff)
assert diff == '', f'{requirements_txt} is not up-to-date! (Hint: call: "make update")'
def test_screenshot_filenames(): def test_screenshot_filenames():
@ -118,40 +73,36 @@ def test_check_editor_config():
check_editor_config(package_root=PACKAGE_ROOT) check_editor_config(package_root=PACKAGE_ROOT)
def _call_make(*args): class ManifestTestCase(TestCase):
make_bin = shutil.which('make') def test_manifest_toml(self):
assert make_bin manifest_path = PACKAGE_ROOT / 'manifest.toml'
return subprocess.check_output( assert_is_file(manifest_path)
(make_bin,) + args,
text=True,
env=dict(PATH=os.environ['PATH']),
stderr=subprocess.STDOUT,
cwd=str(PACKAGE_ROOT),
)
cfg = tomllib.loads(manifest_path.read_text(encoding='UTF-8'))
def test_check_code_style(): self.assertEqual(cfg['packaging_format'], 2)
# First try:
try:
_call_make('lint')
except subprocess.CalledProcessError:
# Fix and test again:
try:
_call_make('fix-code-style')
_call_make('lint')
except subprocess.CalledProcessError as err:
raise AssertionError(f'Linting error:\n{"-"*100}\n{err.stdout}\n{"-"*100}')
class ConfigPanelTestCase(TestCase):
def test_config_panel_toml(self):
config_panel_path = PACKAGE_ROOT / 'config_panel.toml'
assert_is_file(config_panel_path)
cfg = tomllib.loads(config_panel_path.read_text(encoding='UTF-8'))
self.assertEqual(cfg['version'], '1.0')
self.assertEqual( self.assertEqual(
set(cfg['main']['config'].keys()), set(cfg['install'].keys()),
{'name', 'default_from_email', 'admin_email', 'debug_enabled', 'log_level'}, {
'admin',
'admin_email',
'debug_enabled',
'default_from_email',
'domain',
'init_main_permission',
'log_level',
'path',
},
)
self.assertEqual(
set(cfg['resources'].keys()),
{
'apt',
'data_dir',
'database',
'install_dir',
'permissions',
'ports',
'system_user',
},
) )