Skip to content

Commit

Permalink
Implement plugin dependency installation mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
Wrench56 committed Jul 12, 2024
1 parent f948564 commit a7e093d
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 24 deletions.
4 changes: 4 additions & 0 deletions src/backend/config/config.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[frontend]
build = "npm run build"
install = "npm install"
show_output = true
motd = "Memory: {{teal}}{{memory_used}} MB{{end}} / {{memory_total}} MB\nCPU: {{teal}}{{cpu_percent}}%{{end}}\nUsers: {{teal}}{{active_users}}{{end}}\nHave a great day!"

[backend]
install_plugin_deps = "pip install -r"

[login]
disable_statuses = []
widgets = ["header", "version", "motd", "status", "sysinfo"]
Expand Down
66 changes: 66 additions & 0 deletions src/backend/plugins/dependencies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import json
import logging
import os
import subprocess
import sys

from plugins import unpack
from utils import config
from utils.const import FRONTEND_PATH, PLUGINS_DIR


def python(plugin_name: str) -> bool:
req_path = f'{PLUGINS_DIR}/{plugin_name}/requirements.txt'
if not os.path.exists(req_path):
logging.warning(f'"requirements.txt" for plugin "{
plugin_name}" does not exist')
return True

# TODO: Check the returned value
try:
subprocess.check_call(
[sys.executable, '-m', *config.fetch().get('backend').get('install_plugin_deps').split(' '), req_path])
except Exception as e:
unpack.revert(plugin_name)
raise e

return True


def node(plugin_name: str) -> bool:
plugin_dir = f'{PLUGINS_DIR}/{plugin_name}'
if not os.path.exists(f'{plugin_dir}/package.json'):
logging.warning(f'"package.json" for plugin "{
plugin_name}" does not exist')
return True

if not _merge_dependencies(plugin_dir):
return False

# TODO: Check the returned value
subprocess.check_call(args=config.fetch().get('frontend').get(
'install').split(' '), cwd=FRONTEND_PATH, shell=True)
return True


def _merge_dependencies(plugin_dir: str) -> bool:
with open(f'{plugin_dir}/package.json', 'r', encoding='utf-8') as f:
source_data = json.load(f)
plugin_dependencies = source_data.get('dependencies')
f.close()

with open(f'{FRONTEND_PATH}/package.json', 'r', encoding='utf-8') as f:
package_json = json.load(f)
f.close()
if package_json.get('dependencies') is None:
logging.error('Frontend\'s package.json is corrupted')
return False

package_json['dependencies'].update(plugin_dependencies)

with open(f'{FRONTEND_PATH}/package.json', 'w', encoding='utf-8') as f:
json.dump(package_json, f, indent=2)
f.write('\n')
f.close()

return True
31 changes: 22 additions & 9 deletions src/backend/plugins/downloader.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from plugins import handler, priority, unpack, validate
from plugins import dependencies, handler, priority, unpack, validate
from utils.const import PLUGINS_DOWNLOAD

import logging
Expand All @@ -21,14 +21,27 @@ def from_url(url: str) -> bool:
name = config['plugin'].get('name').replace('-', '_')
zip_url = config['plugin'].get('zip_url')

if not _download_plugin_zip(zip_url, name):
return False
if not unpack.unzip(name):
return False
if not unpack.unpack(name, 'Plugin.toml'):
return False
if not unpack.distribute(name):
return False
try:
if not _download_plugin_zip(zip_url, name):
return False
if not unpack.unzip(name):
unpack.revert(name)
return False
if not unpack.unpack(name, 'Plugin.toml'):
unpack.revert(name)
return False
if not unpack.distribute(name):
unpack.revert(name)
return False
if not dependencies.python(name):
unpack.revert(name)
return False
if not dependencies.node(name):
unpack.revert(name)
return False
except Exception as e:
unpack.revert(name)
raise e

priority.add_new_plugin(name, 2)
handler.load(name)
Expand Down
39 changes: 24 additions & 15 deletions src/backend/plugins/unpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@
import zipfile


def unzip(name: str) -> bool:
_clear_prev_installation(name)
with zipfile.ZipFile(f'{PLUGINS_DOWNLOAD}/{name}.zip', 'r') as zip_ref:
zip_ref.extractall(f'{PLUGINS_DIR}/{name}')
def unzip(plugin_name: str) -> bool:
_clear_prev_installation(plugin_name)
with zipfile.ZipFile(f'{PLUGINS_DOWNLOAD}/{plugin_name}.zip', 'r') as zip_ref:
zip_ref.extractall(f'{PLUGINS_DIR}/{plugin_name}')

return True


def _clear_prev_installation(name: str) -> None:
if os.path.exists(f'{PLUGINS_DIR}/{name}'):
shutil.rmtree(f'{PLUGINS_DIR}/{name}')
def _clear_prev_installation(plugin_name: str) -> None:
if os.path.exists(f'{PLUGINS_DIR}/{plugin_name}'):
shutil.rmtree(f'{PLUGINS_DIR}/{plugin_name}')


def _find_target_file(root_dir: str, target: str) -> Optional[str]:
Expand Down Expand Up @@ -67,19 +67,28 @@ def distribute(plugin_name: str) -> bool:
_clear_frontend_installation(plugin_name)
root_dir = f'{PLUGINS_DIR}/{plugin_name}'
if os.path.exists(f'{root_dir}/frontend'):
shutil.move(f'{root_dir}/frontend', f'{FRONTEND_PLUGINS_DIR}/{plugin_name}')
shutil.move(f'{root_dir}/frontend',
f'{FRONTEND_PLUGINS_DIR}/{plugin_name}')
else:
logging.warning(f'Frontend directorty of plugin "{plugin_name}" does not exist')
logging.warning(f'Frontend directorty of plugin "{
plugin_name}" does not exist')

if os.path.exists(f'{root_dir}/pages'):
shutil.move(f'{root_dir}/pages', f'{FRONTEND_PAGES_DIR}/{plugin_name}')
else:
logging.warning(f'Pages directory of plugin "{plugin_name}" does not exist')
logging.warning(f'Pages directory of plugin "{
plugin_name}" does not exist')
return True


def _clear_frontend_installation(name: str) -> None:
if os.path.exists(f'{FRONTEND_PLUGINS_DIR}/{name}'):
shutil.rmtree(f'{FRONTEND_PLUGINS_DIR}/{name}')
if os.path.exists(f'{FRONTEND_PAGES_DIR}/{name}'):
shutil.rmtree(f'{FRONTEND_PAGES_DIR}/{name}')
def _clear_frontend_installation(plugin_name: str) -> None:
if os.path.exists(f'{FRONTEND_PLUGINS_DIR}/{plugin_name}'):
shutil.rmtree(f'{FRONTEND_PLUGINS_DIR}/{plugin_name}')
if os.path.exists(f'{FRONTEND_PAGES_DIR}/{plugin_name}'):
shutil.rmtree(f'{FRONTEND_PAGES_DIR}/{plugin_name}')


def revert(plugin_name: str) -> None:
logging.info(f'Reverting installation of plugin "{plugin_name}"')
_clear_prev_installation(plugin_name)
_clear_frontend_installation(plugin_name)

0 comments on commit a7e093d

Please sign in to comment.