diff --git a/.gitignore b/.gitignore index 1def7b9..5717ee2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .* !.gitignore __pycache__ -secret.txt \ No newline at end of file +secret.txt +/local_test/ diff --git a/README.md b/README.md index bd687e9..a8e3fc7 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,9 @@ TODO: https://github.com/django-auth-ldap/django-auth-ldap --- -Developer info ----------------- +# Developer info + +## package installation / debugging Please send your pull request to https://github.com/YunoHost-Apps/pyinventory_ynh @@ -102,4 +103,32 @@ root@yunohost:~# cat /etc/systemd/system/pyinventory.service root@yunohost:~# systemctl reload-or-restart pyinventory root@yunohost:~# journalctl --unit=pyinventory --follow -``` \ No newline at end of file +``` + +## 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. + +For this, just run `local_test.py` in a PyInventory virtualenv. + +e.g.: +```bash +~$ git clone https://github.com/jedie/PyInventory.git +~$ git clone https://github.com/YunoHost-Apps/pyinventory_ynh.git +~$ cd PyInventory/ +~/PyInventory$ make install +~/PyInventory$ poetry shell +(pyinventory-yd_5sxYx-py3.8) ~/PyInventory$ cd ../pyinventory_ynh/ +(pyinventory-yd_5sxYx-py3.8) ~/pyinventory_ynh$ ./local_test.py +... +Django version 2.2.17, using settings 'ynh_pyinventory_settings' +Starting development server at http://127.0.0.1:8000/ +``` + +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/` \ No newline at end of file diff --git a/conf/create_superuser.py b/conf/create_superuser.py new file mode 100644 index 0000000..021836c --- /dev/null +++ b/conf/create_superuser.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +import argparse +import os +import sys + + +def main(): + os.environ['DJANGO_SETTINGS_MODULE'] = 'ynh_pyinventory_settings' + + parser = argparse.ArgumentParser( + description='Create or update Django super user.' + ) + parser.add_argument('--username') + parser.add_argument('--password') + + args = parser.parse_args() + username = args.username + password = args.password + + import django + django.setup() + + from django.contrib.auth import get_user_model + User = get_user_model() + super_user = User.objects.filter(username=username).first() + if super_user: + print('Update existing super user and set his password.', file=sys.stderr) + super_user.set_password(password) + super_user.save() + else: + print('Create new super user', file=sys.stderr) + User.objects.create_superuser( + username=username, + email='', + password=password + ) + + +if __name__ == '__main__': + main() diff --git a/conf/ynh_pyinventory_settings.py b/conf/ynh_pyinventory_settings.py index 8b1bee1..b7d2e4e 100644 --- a/conf/ynh_pyinventory_settings.py +++ b/conf/ynh_pyinventory_settings.py @@ -23,7 +23,7 @@ assert FINAL_HOME_PATH.is_dir(), f'Directory not exists: {FINAL_HOME_PATH}' FINAL_WWW_PATH = __Path('__FINAL_WWW_PATH__') # /var/www/$app assert FINAL_WWW_PATH.is_dir(), f'Directory not exists: {FINAL_WWW_PATH}' -LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app//pyinventory.log +LOG_FILE = __Path('__LOG_FILE__') # /var/log/$app/pyinventory.log assert LOG_FILE.is_file(), f'File not exists: {LOG_FILE}' PATH_URL = '__PATH_URL__' # $YNH_APP_ARG_PATH diff --git a/local_test.py b/local_test.py new file mode 100755 index 0000000..fe38671 --- /dev/null +++ b/local_test.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +""" + Start PyInventory in YunoHost setup locally. + Note: + You can only run this script, if you are in a activated PyInventory venv! + see README for details ;) +""" + +import os +import shlex +import subprocess +import sys +from pathlib import Path + +os.environ['DJANGO_SETTINGS_MODULE'] = 'ynh_pyinventory_settings' + +try: + import inventory_project # noqa +except ImportError as err: + raise ImportError( + 'Couldn\'t import PyInventory. Did you ' + 'forget to activate a virtual environment?' + ) from err + + +BASE_PATH = Path(__file__).parent.absolute() +TEST_PATH = BASE_PATH / 'local_test' +CONF_PATH = BASE_PATH / 'conf' + +FINAL_HOME_PATH = TEST_PATH / 'opt_yunohost' +FINAL_WWW_PATH = TEST_PATH / 'var_www' +LOG_FILE = TEST_PATH / 'var_log_pyinventory.log' + +MANAGE_PY_FILE = CONF_PATH / 'manage.py' +CREATE_SUPERUSER_FILE = CONF_PATH / 'create_superuser.py' +SETTINGS_FILE = CONF_PATH / 'ynh_pyinventory_settings.py' +URLS_FILE = CONF_PATH / 'ynh_urls.py' + +REPLACES = { + '__FINAL_HOME_PATH__': str(FINAL_HOME_PATH), + '__FINAL_WWW_PATH__': str(FINAL_WWW_PATH), + '__LOG_FILE__': str(TEST_PATH / 'var_log_pyinventory.log'), + + '__PATH_URL__': 'app_path', + '__DOMAIN__': '127.0.0.1', + + 'django.db.backends.postgresql': 'django.db.backends.sqlite3', + "'NAME': '__APP__',": f"'NAME': '{TEST_PATH / 'test_db.sqlite'}',", + + 'django_redis.cache.RedisCache': 'django.core.cache.backends.dummy.DummyCache', + + 'DEBUG = False': 'DEBUG = True', + + # Just use the default logging setup from PyInventory project: + 'LOGGING = {': 'HACKED_DEACTIVATED_LOGGING = {', +} + + +def verbose_check_call(command, verbose=True, **kwargs): + """ 'verbose' version of subprocess.check_call() """ + if verbose: + print('_' * 100) + msg = f'Call: {command!r}' + verbose_kwargs = ', '.join(f'{k}={v!r}' for k, v in sorted(kwargs.items())) + if verbose_kwargs: + msg += f' (kwargs: {verbose_kwargs})' + print(f'{msg}\n', flush=True) + + env = os.environ.copy() + env['PYTHONUNBUFFERED'] = '1' + + popenargs = shlex.split(command) + subprocess.check_call( + popenargs, + universal_newlines=True, + env=env, + **kwargs + ) + + +def call_manage_py(args): + verbose_check_call( + command=f'{sys.executable} manage.py {args}', + cwd=FINAL_HOME_PATH, + ) + + +def copy_patch(src_file, replaces=None): + dst_file = FINAL_HOME_PATH / src_file.name + print(f'{src_file.relative_to(BASE_PATH)} -> {dst_file.relative_to(BASE_PATH)}') + + with src_file.open('r') as f: + content = f.read() + + if replaces: + for old, new in replaces.items(): + content = content.replace(old, new) + + with dst_file.open('w') as f: + f.write(content) + + +def main(): + print('-' * 100) + + assert BASE_PATH.is_dir() + assert CONF_PATH.is_dir() + assert SETTINGS_FILE.is_file() + assert URLS_FILE.is_file() + + for p in (TEST_PATH, FINAL_HOME_PATH, FINAL_WWW_PATH): + if p.is_dir(): + print(f'Already exists: "{p.relative_to(BASE_PATH)}", ok.') + else: + print(f'Create: "{p.relative_to(BASE_PATH)}"') + p.mkdir(parents=True, exist_ok=True) + + LOG_FILE.touch(exist_ok=True) + + # conf/manage.py -> local_test/manage.py + copy_patch(src_file=MANAGE_PY_FILE) + + # conf/create_superuser.py -> local_test/opt_yunohost/create_superuser.py + copy_patch(src_file=CREATE_SUPERUSER_FILE) + + # conf/ynh_pyinventory_settings.py -> local_test/ynh_pyinventory_settings.py + copy_patch(src_file=SETTINGS_FILE, replaces=REPLACES) + + # conf/ynh_urls.py -> local_test/ynh_urls.py + copy_patch(src_file=URLS_FILE, replaces=REPLACES) + + # call "local_test/manage.py" via subprocess: + call_manage_py('check --deploy') + call_manage_py('migrate --no-input') + call_manage_py('collectstatic --no-input') + + verbose_check_call( + command=f'{sys.executable} create_superuser.py --username="test" --password="test"', + cwd=FINAL_HOME_PATH, + ) + + try: + call_manage_py('runserver --nostatic') + except KeyboardInterrupt: + print('\nBye ;)') + + +if __name__ == '__main__': + main()