# installer download pkg by cid, than install it to target dir import logging import asyncio import aiohttp import aiofiles import os from typing import Tuple from ndn_client import ContentId,NDN_Client from .pkg import PackageInfo,PackageMediaInfo from .env import PackageEnv logger = logging.getLogger(__name__) INSTALL_TASK_STATE_DONE = 0 INSTALL_TASK_STATE_CHECK_DEPENDENCY = 1 INSTALL_TASK_STATE_INSTALL_DEPENDENCY = 2 INSTALL_TASK_STATE_DOWNLOADING = 3 INSTALL_TASK_STATE_INSTALLING = 4 INSTALL_TAKS_STATE_ERROR = 5 class PackageInstallTask: def __init__(self,owner:PackageEnv) -> None: self.owner = owner self.state = INSTALL_TASK_STATE_CHECK_DEPENDENCY self.pkg_media_info = None self.working_task = None self.dependency_tasks = None self.error_str = None class PackageInstaller: def __init__(self,owner_env:PackageEnv) -> None: self.all_tasks = {} self.owner_env = owner_env def install(self,pkg_name:str, install_from_dependency = False, can_upgrade = True,skip_depends = False,options = None)->Tuple[PackageInstallTask,str]: the_pkg_info : PackageInfo = None is_upgrade : bool = False need_backup : bool = False pkg_id,version_str,cid = PackageInfo.parse_pkg_name(pkg_name) media_info : PackageMediaInfo = self.owner_env.get_media_info(pkg_name) # must use index-db? if media_info is not None: if cid is not None: if can_upgrade: is_upgrade = True else: error_str = f"{pkg_name},{cid} already installed!" logger.error(error_str) return None,error_str else: the_pkg_info = self.owner_env.lookup(pkg_id,version_str,None) if the_pkg_info is None: error_str = f"{pkg_name} old version exist in local but not found in index db!" logger.error(error_str) return None,error_str else: is_upgrade = True need_backup = True if the_pkg_info is None: the_pkg_info = self.owner_env.lookup(pkg_id,version_str,cid) if the_pkg_info is None: error_str = f"{pkg_name} ,cid:{cid} not found in index db" logger.error(error_str) return None,error_str result_task = self.all_tasks.get(the_pkg_info.cid) if result_task is not None: return result_task,"already installing" logger.info(f"start download&install {pkg_name},install_from_dependency={install_from_dependency},upgrade={is_upgrade},backup={need_backup},target_pkg_info={the_pkg_info}") result_task = PackageInstallTask(self.owner_env) self.all_tasks[the_pkg_info.cid] = result_task async def download_and_install_pkg()->int: # check dependency if skip_depends is False: result_task.dependency_tasks = {} self.get_dependency_tasks(the_pkg_info,result_task.dependency_tasks) result_task.state = INSTALL_TASK_STATE_INSTALL_DEPENDENCY for depend_pkg_name in result_task.dependency_tasks: # check pkg in local? # install miss pkg pass result_task.state = INSTALL_TASK_STATE_DOWNLOADING install_full_path = "" target_full_path = "" old_package_full_path = "" is_download_directy = False if the_pkg_info.target_media_type == the_pkg_info.source_media_type: is_download_directy = True if is_upgrade: target_full_path = "" else: target_full_path = "" else: pass urls = self.owner_env.get_pkg_urls(the_pkg_info) #download client = NDN_Client() # set watch download_result = await client.get_file(the_pkg_info.cid,urls,target_full_path,options) if download_result !=0: result_task.state = INSTALL_TAKS_STATE_ERROR return result_task.state result_task.state = INSTALL_TASK_STATE_INSTALLING if is_download_directy is False: install_media_result = False install_media_result = await self.owner_env.do_pkg_media_trans(the_pkg_info,target_full_path,install_full_path) if install_media_result is False: result_task.state = INSTALL_TAKS_STATE_ERROR result_task.error_str = "install media error,from {target_full_path} to {install_full_path}" return result_task.state # last step,save install flag : install by manual or install by dependency ## save cid dir if is_upgrade: os.rename(old_package_full_path, old_package_full_path + ".old" ) os.rename(target_full_path,install_full_path) ## update/create version link ## update pkg state ## remove old version result_task.state = INSTALL_TASK_STATE_DONE return result_task.state result_task.working_task = asyncio.create_task(download_and_install_pkg()) return result_task,None def uninstall(self): pass def get_dependency_tasks(self,pkg:PackageInfo,dependency_tasks): pass async def check_dependency(self,pkg:PackageInfo,task_list:{}) -> bool: for depend_pkg_name in pkg.depends: depend_task = task_list.get(depend_pkg_name) if depend_task is not None: logger.debug(f"{pkg.name}'s depend pkg {depend_pkg_name} already in task list") continue depend_task = PackageInstallTask(self.owner_env) task_list[depend_pkg_name] = depend_task depend_pkg_info = self.owner_env.lookup(depend_pkg_name) if depend_pkg_info is None: logger.warn(f"{pkg.name}'s depend pkg {depend_pkg_name} not found in index db") return False if await self.check_dependency(depend_pkg_info,task_list) is False: return False return True