initial commit
This commit is contained in:
79
pythonapp/Instance/ABS.py
Normal file
79
pythonapp/Instance/ABS.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from pythonapp.Libs.ConfigDataClass import Config
|
||||
|
||||
|
||||
class InstanceFileNaming:
|
||||
config_dir = '.vaiola'
|
||||
main_config = 'instance.json'
|
||||
requirements_dir = 'requirements.d'
|
||||
manual_requirements = 'requirements.txt'
|
||||
pinned_packages = 'pinned.txt'
|
||||
excluded_packages = 'excluded.txt'
|
||||
env_dir = 'env'
|
||||
app_dir = 'app'
|
||||
|
||||
|
||||
@dataclass
|
||||
class InstanceConfig(Config):
|
||||
instance_type: str = 'basic'
|
||||
config_dir_rel_path: Path = Path(InstanceFileNaming.config_dir)
|
||||
env_path: Path = Path(InstanceFileNaming.env_dir)
|
||||
env_type: str = None
|
||||
requirements_dir: Path = Path(InstanceFileNaming.config_dir) / InstanceFileNaming.requirements_dir
|
||||
manual_requirements_path: Path = Path(InstanceFileNaming.config_dir) / InstanceFileNaming.manual_requirements
|
||||
pinned_packages_path: Path = Path(InstanceFileNaming.config_dir) / InstanceFileNaming.pinned_packages
|
||||
excluded_packages_path: Path = Path(InstanceFileNaming.config_dir) / InstanceFileNaming.excluded_packages
|
||||
created: bool = False
|
||||
app: Path = Path(InstanceFileNaming.app_dir)
|
||||
app_installed: bool = None
|
||||
app_extensions_dir: Path = None
|
||||
app_models_dir: Path = None
|
||||
app_output_dir: Path = None
|
||||
app_input_dir: Path = None
|
||||
app_user_dir: Path = None
|
||||
|
||||
class Instance:
|
||||
def __init__(self):
|
||||
self.path: Path | None = None
|
||||
self.config: InstanceConfig | None = None
|
||||
|
||||
def insert_component_reqs(self, name: str, req_file: str | Path):
|
||||
try:
|
||||
with open('req_file', 'r') as file:
|
||||
lines = [line.strip() for line in file]
|
||||
req = []
|
||||
opt = []
|
||||
req_bool = True
|
||||
for line in lines:
|
||||
if line.startswith("#"):
|
||||
req_bool = False
|
||||
if req_bool: req.append(line)
|
||||
else: opt.append(line)
|
||||
|
||||
with open(self.path / self.config.requirements_dir / (name + '.req'), 'w') as file:
|
||||
for line in req: file.write(line + '\n')
|
||||
with open(self.path / self.config.requirements_dir / (name + '.opt'), 'w') as file:
|
||||
for line in opt: file.write(line + '\n')
|
||||
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError(f"Cannot update requirements for {name}, file {req_file} not exists")
|
||||
raise NotImplemented
|
||||
|
||||
def install_git_app(self, url: str, requirements_file_in_app_dir = 'requirements.txt',
|
||||
extensions_dir: str = None,
|
||||
models_dir: str = None,
|
||||
output_dir: str = None,
|
||||
input_dir: str = None,
|
||||
user_dir: str = None,
|
||||
):
|
||||
raise NotImplemented
|
||||
|
||||
def install_reqs(self, name, req_file: Path):
|
||||
raise NotImplemented
|
||||
|
||||
def create(self):
|
||||
raise NotImplemented
|
||||
|
||||
def install_packages(self, pkgs: list, repo, extra, pin=False):
|
||||
raise NotImplemented
|
||||
144
pythonapp/Instance/Instance.py
Normal file
144
pythonapp/Instance/Instance.py
Normal file
@@ -0,0 +1,144 @@
|
||||
import os.path
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
from pythonapp.Decider.ABS import SimpleDecider
|
||||
from pythonapp.Env.Venv import Venv, Env
|
||||
from pythonapp.Env.StandaloneEnv import StandalonePythonEnv
|
||||
from pythonapp.Libs.git import git
|
||||
from pythonapp.Decider.misc import *
|
||||
from pythonapp.Libs.pip_api import pip_api
|
||||
from .ABS import InstanceConfig, InstanceFileNaming, Instance as ABSInstance
|
||||
from ..Decider.Loader import Loader
|
||||
|
||||
|
||||
class Instance(ABSInstance):
|
||||
def __init__(self, path: str, env: str = 'venv', python = 'python3'):
|
||||
self.path = Path(path)
|
||||
self.config = InstanceConfig(os.path.join(self.path, InstanceFileNaming.main_config))
|
||||
self.config.env_type = self.config.env_type or env
|
||||
self.config.created = (Path(self.path) / self.config.config_dir_rel_path).exists()
|
||||
|
||||
|
||||
if self.config.env_type == 'venv':
|
||||
self.env: Env = Venv(str(self.path / self.config.env_path), python)
|
||||
elif self.config.env_type == 'standalone':
|
||||
self.env: Env = StandalonePythonEnv(str(self.path / self.config.env_path), python)
|
||||
|
||||
|
||||
def insert_component_reqs(self, name: str, req_file: str | Path):
|
||||
try:
|
||||
req, opt = requirements_separator(req_file)
|
||||
os.makedirs(self.path / self.config.requirements_dir, exist_ok=True)
|
||||
with open(self.path / self.config.requirements_dir / (name + '.req'), 'w') as file:
|
||||
for line in req: file.write(line + '\n')
|
||||
with open(self.path / self.config.requirements_dir / (name + '.opt'), 'w') as file:
|
||||
for line in opt: file.write(line + '\n')
|
||||
|
||||
except FileNotFoundError:
|
||||
raise RuntimeError(f"Cannot update requirements for {name}, file {req_file} not exists")
|
||||
|
||||
def _symlink_move_dir(self, orig_dir: Path, dest: Path, obj_name: Path):
|
||||
cwd = os.getcwd()
|
||||
os.chdir(self.path)
|
||||
shutil.move(orig_dir / obj_name, dest)
|
||||
os.symlink(os.path.relpath(orig_dir, dest), orig_dir / obj_name)
|
||||
os.chdir(orig_dir)
|
||||
with open(".gitignore", "a") as file:
|
||||
file.write(str(obj_name) + '\n')
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
def install_git_app(self, url: str, requirements_file_in_app_dir = 'requirements.txt',
|
||||
extensions_dir: str = None,
|
||||
models_dir: str = None,
|
||||
output_dir: str = None,
|
||||
input_dir: str = None,
|
||||
user_dir: str = None,
|
||||
):
|
||||
if os.path.exists(self.config.app):
|
||||
raise RuntimeError("App installed previously. Multiapp instances is not supported")
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
git.clone(url, tmp_dir)
|
||||
try:
|
||||
self.install_reqs('app', Path(tmp_dir) / requirements_file_in_app_dir)
|
||||
except RuntimeError as e: raise TypeError(e)
|
||||
|
||||
self.config.app_extensions_dir = Path(extensions_dir) if extensions_dir else None
|
||||
self.config.app_models_dir = Path(models_dir) if models_dir else None
|
||||
self.config.app_output_dir = Path(output_dir) if output_dir else None
|
||||
self.config.app_input_dir = Path(input_dir) if input_dir else None
|
||||
self.config.app_user_dir = Path(user_dir) if user_dir else None
|
||||
self.config.save()
|
||||
|
||||
git.clone(url, self.path / self.config.app)
|
||||
|
||||
if self.config.app_extensions_dir:
|
||||
self._symlink_move_dir(Path(os.path.dirname(self.config.app / self.config.app_extensions_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_extensions_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_extensions_dir)))
|
||||
if self.config.app_models_dir:
|
||||
self._symlink_move_dir(Path(os.path.dirname(self.config.app / self.config.app_models_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_models_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_models_dir)))
|
||||
if self.config.app_output_dir:
|
||||
self._symlink_move_dir(Path(os.path.dirname(self.config.app / self.config.app_output_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_output_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_output_dir)))
|
||||
if self.config.app_input_dir:
|
||||
self._symlink_move_dir(Path(os.path.dirname(self.config.app / self.config.app_input_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_input_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_input_dir)))
|
||||
if self.config.app_user_dir:
|
||||
self._symlink_move_dir(Path(os.path.dirname(self.config.app / self.config.app_user_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_user_dir)),
|
||||
Path(os.path.basename(self.config.app / self.config.app_user_dir)))
|
||||
|
||||
|
||||
def install_reqs(self, name, req_file: Path):
|
||||
packages, errors, state = SimpleDecider.decide(self, req_file, self.env.pip_path)
|
||||
if not packages: raise RuntimeError("Cannot install packages due conflicts")
|
||||
self.env.install_pkgs([p.requirement_str for p in packages])
|
||||
self.insert_component_reqs(name, req_file)
|
||||
|
||||
|
||||
def create(self):
|
||||
os.makedirs(self.path / self.config.config_dir_rel_path, exist_ok=True)
|
||||
self.config.save()
|
||||
self.env.create()
|
||||
|
||||
|
||||
def install_packages(self, pkgs: list, repo: str = None, extra: str = None, pin=False):
|
||||
packages = [RequirementInfo.from_requirement_string(p, 'manual', 'manual') for p in pkgs]
|
||||
packages, errors, state = SimpleDecider.decide(self, packages, self.env.pip_path, manual=True)
|
||||
pkgs = [p.requirement_str for p in packages]
|
||||
print("manually install packages", pkgs)
|
||||
self.env.install_pkgs(pkgs, repo, extra)
|
||||
|
||||
for pkg in pkgs: self._write_unique_string(pkg, file_path=self.path / self.config.manual_requirements_path)
|
||||
if pin:
|
||||
for pkg in pkgs: self._write_unique_string(pkg, file_path=self.path / self.config.pinned_packages_path)
|
||||
|
||||
def exclude_packages(self, pkgs: list[str]):
|
||||
for pkg in pkgs: self._write_unique_string(pkg, file_path=self.path / self.config.excluded_packages_path)
|
||||
|
||||
|
||||
def _write_unique_string(self, string, file_path):
|
||||
existing_lines = set()
|
||||
if file_path.exists():
|
||||
with open(file_path, 'r') as file:
|
||||
existing_lines = set(line.strip() for line in file)
|
||||
|
||||
with open(file_path, 'a') as file:
|
||||
if string not in existing_lines:
|
||||
file.write(string + '\n')
|
||||
|
||||
def _delete_string(self, string, file_path):
|
||||
with open(file_path, 'r') as file:
|
||||
lines = file.readlines()
|
||||
filtered_lines = [line for line in lines if line.rstrip('\n') != string]
|
||||
with open(file_path, 'w') as file:
|
||||
file.writelines(filtered_lines)
|
||||
|
||||
|
||||
|
||||
0
pythonapp/Instance/__init__.py
Normal file
0
pythonapp/Instance/__init__.py
Normal file
BIN
pythonapp/Instance/__pycache__/ABS.cpython-313.pyc
Normal file
BIN
pythonapp/Instance/__pycache__/ABS.cpython-313.pyc
Normal file
Binary file not shown.
BIN
pythonapp/Instance/__pycache__/Instance.cpython-313.pyc
Normal file
BIN
pythonapp/Instance/__pycache__/Instance.cpython-313.pyc
Normal file
Binary file not shown.
BIN
pythonapp/Instance/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
pythonapp/Instance/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
Reference in New Issue
Block a user