diff options
| author | 2024-01-21 17:50:15 +0800 | |
|---|---|---|
| committer | 2024-01-21 17:50:15 +0800 | |
| commit | a184d2f54c84e13c3ec45d7fdba9d36727931bf2 (patch) | |
| tree | 2afd6aed5a830fa2e0f431bf0862e7924db8fa1b | |
| parent | 3ebc89dfeb77cf90b1760fbb17780bf896681b7e (diff) | |
| download | ipm-a184d2f54c84e13c3ec45d7fdba9d36727931bf2.tar.gz ipm-a184d2f54c84e13c3ec45d7fdba9d36727931bf2.zip | |
:sparkles: feat(api): improve install methods
| -rw-r--r-- | src/ipm/api.py | 19 | ||||
| -rw-r--r-- | src/ipm/const.py | 1 | ||||
| -rw-r--r-- | src/ipm/models/ipk.py | 4 | ||||
| -rw-r--r-- | src/ipm/models/lock.py | 64 | ||||
| -rw-r--r-- | src/ipm/utils/loader.py | 36 |
5 files changed, 114 insertions, 10 deletions
diff --git a/src/ipm/api.py b/src/ipm/api.py index ea55afb..3853faa 100644 --- a/src/ipm/api.py +++ b/src/ipm/api.py @@ -2,8 +2,9 @@ from pathlib import Path from .typing import StrPath from .utils import freeze, urlparser, loader from .models.ipk import InfiniPackage, InfiniFrozenPackage +from .models.lock import PackageLock from .exceptions import FileTypeMismatch, TomlLoadFailed, FileNotFoundError -from .const import INDEX, SRC_HOME +from .const import INDEX, STORAGE, SRC_HOME from .logging import info, success, warning, error import toml @@ -69,12 +70,14 @@ def install(uri: str, index: str = "", echo: bool = False) -> None: SRC_HOME.mkdir(parents=True, exist_ok=True) index = index or INDEX + lock = PackageLock() if uri.isalpha(): + # TODO ... elif urlparser.is_valid_url(uri): filename = uri.rstrip("/").split("/")[-1] - ipk = loader.load( + temp_ipk = loader.load_from_remote( "temp", uri.rstrip("/").rsplit("/")[0], filename, @@ -86,11 +89,19 @@ def install(uri: str, index: str = "", echo: bool = False) -> None: raise FileNotFoundError("给定的 URI 路径不存在!") if uri.endswith(".ipk"): - info("安装中...", echo) - ipk = extract(Path(uri).resolve(), SRC_HOME, echo) + temp_ipk = loader.load_from_local(path) else: raise FileTypeMismatch("文件类型与预期[.ipk]不匹配.") + if lock.has_ipk(temp_ipk.name): + raise # TODO + + info(f"开始安装[{temp_ipk.name}]中...", echo) + ipk = extract(STORAGE / temp_ipk.source_path, SRC_HOME, echo) + info("正在处理全局包锁...") + lock.add(ipk, dump=True) + info("全局锁已处理完毕.") + success(f"包[{ipk.name}]成功安装在[{ipk.source_path}].", echo) diff --git a/src/ipm/const.py b/src/ipm/const.py index 439903a..d3dbcbf 100644 --- a/src/ipm/const.py +++ b/src/ipm/const.py @@ -7,6 +7,7 @@ DEBUG = False INDEX = "https://ipm.hydroroll.team/index/" IPM_PATH = Path.home() / ".ipm" SRC_HOME = IPM_PATH / "src" +STORAGE = IPM_PATH / "storage" # 文本参数 ATTENSION = """# This file is @generated by IPM. diff --git a/src/ipm/models/ipk.py b/src/ipm/models/ipk.py index c4577e9..ef6f649 100644 --- a/src/ipm/models/ipk.py +++ b/src/ipm/models/ipk.py @@ -1,4 +1,5 @@ from pathlib import Path +from . import lock from ..typing import List, Dict, Literal from ..exceptions import SyntaxError, TomlLoadFailed @@ -38,6 +39,8 @@ class InfiniPackage: requirements: dict dependencies: dict + lock: lock.ProjectLock + def __init__(self, path: str | Path = ".") -> None: self.source_path = Path(path).resolve() toml_path = self.source_path / "infini.toml" @@ -59,6 +62,7 @@ class InfiniPackage: self.requirements = data_load["requirements"] self.dependencies = data_load["dependencies"] + # self.lock = ProjectLock @property def default_name(self) -> str: diff --git a/src/ipm/models/lock.py b/src/ipm/models/lock.py new file mode 100644 index 0000000..78f4921 --- /dev/null +++ b/src/ipm/models/lock.py @@ -0,0 +1,64 @@ +from pathlib import Path +from abc import ABCMeta +from . import ipk +from ..typing import Dict, List, StrPath, Any +from ..const import IPM_PATH, ATTENSION +from ..exceptions import SyntaxError + +import toml + + +class IpmLock(metaclass=ABCMeta): + metadata: Dict[str, str] + packages: List[Dict[str, Any]] + source_path: Path + + def __init__(self, source_path: StrPath = IPM_PATH / "inifni.lock") -> None: + IPM_PATH.mkdir(parents=True, exist_ok=True) + self.source_path = source_path + self.load() + + def load(self): + if not self.source_path.exists(): + self.source_path.write_text(ATTENSION) + self.packages = {} + else: + loaded_data = toml.load(self.source_path.open("r", encoding="utf-8")) + self.packages = loaded_data["package"] + + def dumps(self) -> dict: + return {"metadata": self.metadata, "packages": self.packages} + + def dump(self) -> str: + return toml.dump(self.source_path.open("w+", encoding="utf-8")) + + +class PackageLock(IpmLock): + """全局包锁""" + + def __init__(self) -> None: + super().__init__() + + def add(self, ipk: "ipk.InfiniPackage", dump: bool = False) -> str: + self.packages.append({"name": ipk.name, "version": ipk.version}) + return self.dump() if dump else "" + + def remove(self, name: str) -> None: + name = name.strip() + for package in self.packages: + if "name" not in package.keys(): + raise SyntaxError("异常的锁文件!") + if package["name"] == name: + self.packages.remove(package) + return + + def has_ipk(self, name: str) -> bool: + name = name.strip() + for package in self.packages: + if package["name"] == name: + return True + return False + + +class ProjectLock: + ... diff --git a/src/ipm/utils/loader.py b/src/ipm/utils/loader.py index 6c1bf25..18d98ac 100644 --- a/src/ipm/utils/loader.py +++ b/src/ipm/utils/loader.py @@ -1,27 +1,51 @@ from pathlib import Path from .freeze import extract_ipk -from ..const import SRC_HOME +from ..const import SRC_HOME, STORAGE from ..models.ipk import InfiniPackage import requests import tempfile +import shutil -def load(name: str, baseurl: str = "", filename: str = "") -> InfiniPackage: +def load_from_remote(name: str, baseurl: str = "", filename: str = "") -> InfiniPackage: ipk_bytes = requests.get(baseurl.rstrip("/") + "/" + filename).content hash_bytes = requests.get(baseurl.rstrip("/") + "/" + filename + ".hash").content temp_dir = tempfile.TemporaryDirectory() temp_path = Path(temp_dir.name).resolve() - ipk_file = (temp_path / f"{name}.ipk").open("w+b") + ipk_path = temp_path / f"{name}.ipk" + ipk_file = ipk_path.open("w+b") ipk_file.write(ipk_bytes) ipk_file.close() - hash_file = (temp_path / f"{name}.ipk.hash").open("w+b") + hash_path = temp_path / f"{name}.ipk.hash" + hash_file = hash_path.open("w+b") hash_file.write(hash_bytes) hash_file.close() - ipk = extract_ipk(ipk_file, SRC_HOME) + temp_ipk = extract_ipk(ipk_file, temp_path) + move_to = STORAGE / temp_ipk.name + move_to.mkdir(parents=True, exist_ok=True) + + shutil.copy2(ipk_file, move_to) + shutil.copy2(hash_file, move_to) + + temp_dir.cleanup() + return temp_ipk + + +def load_from_local(source_path: Path) -> InfiniPackage: + temp_dir = tempfile.TemporaryDirectory() + temp_path = Path(temp_dir.name).resolve() + + temp_ipk = extract_ipk(source_path, temp_path) + move_to = STORAGE / temp_ipk.name + move_to.mkdir(parents=True, exist_ok=True) + + shutil.copy2(source_path, move_to) + shutil.copy2(source_path.parent / (source_path.name + ".hash"), move_to) + temp_dir.cleanup() - return ipk + return temp_ipk |
