From 11dce455820f7817cc1c7bf1eadcb7187a341911 Mon Sep 17 00:00:00 2001 From: 苏向夜 Date: Mon, 22 Jan 2024 18:56:20 +0800 Subject: :sparkles: feat(api): complete version control in install --- src/ipm/api.py | 37 +++++++++++++++++++++++++++++++++--- src/ipm/utils/version.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 src/ipm/utils/version.py (limited to 'src') diff --git a/src/ipm/api.py b/src/ipm/api.py index d1e0133..1eefb52 100644 --- a/src/ipm/api.py +++ b/src/ipm/api.py @@ -1,9 +1,15 @@ from pathlib import Path from .typing import StrPath from .utils import freeze, urlparser, loader -from .exceptions import FileTypeMismatch, TomlLoadFailed, FileNotFoundError from .const import INDEX, INDEX_PATH, STORAGE, SRC_HOME from .logging import info, success, warning, error +from .exceptions import ( + FileTypeMismatch, + TomlLoadFailed, + FileNotFoundError, + PackageExsitsError, +) +from .utils.version import require_update from .models.ipk import InfiniProject, InfiniFrozenPackage from .models.lock import PackageLock from .models.index import Yggdrasil @@ -67,7 +73,13 @@ def extract( return freeze.extract_ipk(source_path, dist_path, echo) -def install(uri: str, index: str = "", echo: bool = False) -> None: +def install( + uri: str, + index: str = "", + upgrade: bool = False, + force: bool = False, + echo: bool = False, +) -> None: info("正在初始化 IPM 环境...", echo) SRC_HOME.mkdir(parents=True, exist_ok=True) @@ -113,7 +125,26 @@ def install(uri: str, index: str = "", echo: bool = False) -> None: raise FileTypeMismatch("文件类型与预期[.ipk]不匹配.") if lock.has_package(ifp.name): - raise # TODO + exists_version = lock.get_package(ifp.name)["version"] + if require_update(exists_version, ifp.version): + if not upgrade: + raise PackageExsitsError( + f"包[{ifp.name}]版本[{exists_version}]已经安装了, 使用[--upgrade]参数进行升级." + ) + else: + info(f"发现已经安装的[{ifp.name}={exists_version}], 卸载中...") + uninstall(ifp.name, confirm=True, echo=echo) + success(f"[{ifp.name}={exists_version}]卸载完成...") + else: + if not force: + raise PackageExsitsError( + f"已经安装了[{ifp.name}]版本[{exists_version}], 使用[--force]参数进行强制覆盖." + ) + else: + info(f"发现已经安装的[{ifp.name}={exists_version}], 卸载中...") + uninstall(ifp.name, confirm=True, echo=echo) + success(f"[{ifp.name}={exists_version}]卸载完成...") + lock.load(auto_completion=True) info(f"开始安装[{ifp.name}]中...", echo) ipk = extract(STORAGE / ifp.name / ifp.default_name, SRC_HOME, echo) diff --git a/src/ipm/utils/version.py b/src/ipm/utils/version.py new file mode 100644 index 0000000..6088d1c --- /dev/null +++ b/src/ipm/utils/version.py @@ -0,0 +1,49 @@ +import re + + +def require_update(old_version: str, new_version: str): + regex = r"^(\d+)\.(\d+)\.(\d+)(.*?)?(\d+?)?$" + + old_tuple = re.match(regex, old_version) + new_tuple = re.match(regex, new_version) + + old_tuple_main = tuple(map(int, filter(None, old_tuple.group(1, 2, 3)))) + new_tuple_main = tuple(map(int, filter(None, new_tuple.group(1, 2, 3)))) + + new_length = len(list(filter(None, new_tuple.groups()))) + old_length = len(list(filter(None, old_tuple.groups()))) + + if old_length == 5: + old_pre_release = old_tuple.group(4)[0] + old_pre_version = int(old_tuple.group(5)) + elif old_length == 3: + old_pre_release = "s" + old_pre_version = 1 + else: + return False + + if new_length == 5: + new_pre_release = new_tuple.group(4)[0] + new_pre_version = int(new_tuple.group(5)) + elif new_length == 3: + new_pre_release = "s" + new_pre_version = 1 + else: + return False + + if old_tuple_main < new_tuple_main: + return True + elif old_tuple_main > new_tuple_main: + return False + elif old_tuple_main == new_tuple_main: + if old_pre_release < new_pre_release: + return True + elif old_pre_release > new_pre_release: + return False + elif old_pre_release == new_pre_release: + if old_pre_version < new_pre_version: + return True + elif old_pre_version > new_pre_version: + return False + elif old_pre_version == new_pre_version: + return False -- cgit v1.2.3-70-g09d2