ai-suite-rocm-local/services/services.py

169 lines
5.8 KiB
Python

import logging
import os
import subprocess
import utils
from main import PATH, PYTHON_EXEC, logger, LEVEL
class Stack:
def __init__(self, name: str, path: str, port: int, url: str):
self.name = name
self.path = os.path.join(PATH, path)
self.url = url
self.port = port
self.process = None
if self.is_installed():
self.update()
else:
self.check_for_broken_install()
self.create_venv()
self.install()
def install(self):
self.create_file('.installed', 'true')
logger.info(f"Installed {self.name}")
def is_installed(self):
return self.file_exists('.installed')
def check_for_broken_install(self):
if not self.is_installed() and len(os.listdir(self.path)) > 0:
logger.warning("Found files from a previous/borked/crashed installation, cleaning up...")
self.bash(f"rm -rf {self.path}")
self.create_dir('')
def update(self, folder: str = 'webui'):
if self.dir_exists(folder):
logger.info(f"Updating {self.name}")
self.git_pull(folder)
else:
logger.warning(f"Could not update {self.name} as {folder} does not exist")
def uninstall(self):
self.bash(f"rm -rf {self.path}")
def start(self):
pass
def stop(self):
pass
def restart(self):
self.stop()
self.start()
def status(self):
pass
# Python/Bash utils
def create_venv(self):
venv_path = os.path.join(self.path, 'venv')
if not self.has_venv():
logger.debug(f"Creating venv for {self.name}")
self.bash(f"{PYTHON_EXEC} -m venv {venv_path} --system-site-packages")
self.pip("install --upgrade pip")
else:
logger.debug(f"Venv already exists for {self.name}")
def has_venv(self) -> bool:
return self.dir_exists('venv')
def pip_install(self, package: str | list, no_deps: bool = False):
if isinstance(package, list):
for p in package:
self.pip(f"install -U {p} {'--no-deps' if no_deps else ''}")
else:
self.pip(f"install -U {package} {'--no-deps' if no_deps else ''}")
def install_requirements(self, filename: str = 'requirements.txt'):
self.pip(f"install -r {filename}")
def pip(self, cmd: str, env=[], current_dir: str = None):
self.bash(f"{' '.join(env)} {self.path}/venv/bin/pip {cmd}", current_dir)
def python(self, cmd: str, env=[], current_dir: str = None):
self.bash(f"{' '.join(env)} {self.path}/venv/bin/python {cmd}", current_dir)
def bash(self, cmd: str, current_dir: str = None):
cmd = f"cd {self.path if current_dir is None else os.path.join(self.path, current_dir)} && {cmd}"
logger.debug(f"Running command: {cmd}")
if LEVEL == logging.DEBUG:
process = subprocess.Popen(cmd, shell=True)
process.wait()
if process.returncode != 0:
raise Exception(f"Failed to run command: {cmd}")
else:
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if process.returncode != 0:
logger.fatal(f"Failed to run command: {cmd}")
logger.fatal(f"Error: {err.decode('utf-8')}")
logger.fatal(f"Output: {out.decode('utf-8')}")
raise Exception(f"Failed to run command: {cmd}")
# Git utils
def git_clone(self, url: str, branch: str = None, dest: str = None):
self.bash(f"git clone {f"-b {branch}" if branch is not None else ''} {url} {'' if dest is None else dest}")
def git_pull(self, repo_folder: str, force: bool = False):
self.bash(f"git reset --hard HEAD {'&& git clean -f -d' if force else ''} && git pull", repo_folder)
# Prebuilt utils
def install_from_prebuilt(self, name):
for prebuilt in utils.get_prebuilts():
if prebuilt['name'].split("-")[0] == name:
self.pip(f"install {prebuilt['browser_download_url']}")
return
# File utils
def create_file(self, name, content):
with open(os.path.join(self.path, name), 'w') as f:
f.write(content)
def create_dir(self, name):
logger.debug(f"Creating directory {name}")
os.makedirs(os.path.join(self.path, name), exist_ok=True)
def remove_file(self, name):
logger.debug(f"Removing file {name}")
os.remove(os.path.join(self.path, name))
def remove_dir(self, name):
logger.debug(f"Removing directory {name}")
os.rmdir(os.path.join(self.path, name))
def move_file_or_dir(self, src, dest):
logger.debug(f"Moving file/dir {src} to {dest}")
os.rename(os.path.join(self.path, src), os.path.join(self.path, dest))
def move_all_files_in_dir(self, src, dest):
logger.debug(f"Moving all files in directory {src} to {dest}")
for file in os.listdir(os.path.join(self.path, src)):
os.rename(os.path.join(self.path, src, file), os.path.join(self.path, dest, file))
def file_exists(self, name):
return os.path.exists(os.path.join(self.path, name))
def dir_exists(self, name):
return os.path.exists(os.path.join(self.path, name))
def remove_line_in_file(self, contains: str | list, file: str):
logger.debug(f"Removing lines containing {contains} in {file}")
if isinstance(contains, list):
for c in contains:
self.bash(f"sed -i '/{c}/d' {file}")
else:
self.bash(f"sed -i '/{contains}/d' {file}")
def replace_line_in_file(self, match: str, replace: str, file: str):
logger.debug(f"Replacing lines containing {match} with {replace} in {file}")
self.bash(f"sed -i 's/{match}/{replace}/g' {file}")