diff --git a/mc-get.py b/mc-get.py index 423e18f..86d46ab 100755 --- a/mc-get.py +++ b/mc-get.py @@ -6,16 +6,13 @@ import os import mcgetdb from colorama import Fore, Style - -class HashError(ValueError): - """Incorrect hash""" - +db = mcgetdb.McGetDB(mcfs.mc_dir) def validate(): raise NotImplementedError -def download_cache(url: str, filename: str, size: int, hash: str): +def download_cache(url: str, filename: str, size: int): cache_file_path = os.path.join(mcfs.cache_dir, filename) if not mcfs.is_path_exist(mcfs.cache_dir): os.mkdir(mcfs.cache_dir) @@ -23,9 +20,7 @@ def download_cache(url: str, filename: str, size: int, hash: str): api.download(url, size, cache_file_path) else: print(f"{filename} is in cache.") - if not mcfs.check_file_hash(cache_file_path, hash): - os.remove(cache_file_path) - raise HashError(f"Incorrect hash for {filename}") + return filename def modpack_install(filename: str): @@ -35,30 +30,20 @@ def modpack_install(filename: str): path = file["path"].split("/") downloads = file["downloads"] print(file["path"]) - download_cache(downloads[0], path[1], file["fileSize"], file["hashes"]["sha512"]) + download_cache(downloads[0], path[1], file["fileSize"]) mcfs.install(path[1], path[0]) print(f"{Fore.YELLOW}Overriding...{Style.RESET_ALL}") mcfs.install_modpacks_override(filename) -def install(projects: list, mc_ver, loader): +def install(projects: list, version, loader): to_install = [] dependencies_to_install = [] not_found = [] unavailable = [] projects_ids = [] - already_installed = [] - - def get_project_info_from_db(slug): - _db = mcgetdb.McGetDB(mcfs.mc_dir) - return _db.select_mod(slug) + _db.select_shader(slug) + _db.select_resourcepack(slug) + _db.select_modpack(slug) def check_project(slug): - if __name__ == "__main__": - mod_info = get_project_info_from_db(slug) - if mod_info: - already_installed.append(mod_info[0]) - return id = api.check_project(project=slug) if id: projects_ids.append(id.id) @@ -89,24 +74,15 @@ def install(projects: list, mc_ver, loader): for project in projects_ids: project_data = api.project(project=project) - match project_data.project_type: - case "resourcepack": - versions = api.get_versions(project=project, game_versions=f'["{mc_ver}"]') - case "mod" | "modpack": - versions = api.get_versions(project=project, loaders=f'["{loader}"]', game_versions=f'["{mc_ver}"]') - case "shader": # TODO: Реализовать поддержку загрузчиков шейдеров - versions = api.get_versions(project=project, game_versions=f'["{mc_ver}"]') - case _: - raise NotImplementedError - + versions = api.get_versions(project=project, loaders=f'["{loader}"]', + game_versions=f'["{mc_ver}"]') if versions: to_install.append((project_data, versions[0])) dependency_solver(versions[0]) else: unavailable.append(project_data) - if to_install: - print("To install:", *[project.title + " " + version.version_number for project, version in to_install], - sep="\n\t") + + print("To install:", *[project.title + " " + version.version_number for project, version in to_install], sep="\n\t") if dependencies_to_install: print("With dependencies:", *[project.title + " " + version.version_number for project, version in dependencies_to_install], @@ -117,33 +93,15 @@ def install(projects: list, mc_ver, loader): if unavailable: print("Cannot be installed:", *[project.title for project in unavailable], sep="\n\t") - if already_installed: - print("Already installed:", *[name + " " + version for _, name, _, version, _ in already_installed], sep="\n\t") - - all_to_install = to_install + dependencies_to_install - - if not all_to_install: - return - - choose = input("Continue? [y/n] ") + choose = input("Continue? [y/n]") if choose.strip().lower() in ["n", "no"]: print("Canceled.") return - failed_to_install = [] - - for project, version in all_to_install: + for project, version in to_install + dependencies_to_install: file = type("mc_file", (object,), version.files[0]) - filename = file.filename - hash = file.hashes["sha512"] - try: - download_cache(file.url, filename, file.size, hash) - except HashError: - print(f"Failed to install {project.title} ({project.slug}) [{version.version_number}] due to an incorrect " - f"hash") - failed_to_install.append((project, version)) - continue - + filename = project.slug + ".jar" + download_cache(file.url, filename, file.size) match project.project_type: case "resourcepack": subdir = "resourcepacks" @@ -153,31 +111,11 @@ def install(projects: list, mc_ver, loader): subdir = "shaderpacks" case "modpack": modpack_install(filename) - subdir = "modpacks" + continue case _: raise NotImplementedError - if __name__ == "__main__": - db = mcgetdb.McGetDB(mcfs.mc_dir) - match project.project_type: - case "resourcepack": - db.add_resourcepack(slug=project.slug, proj_name=project.title, filename=filename, - version=version.version_number, hash=hash) - case "mod": - db.add_mod(slug=project.slug, proj_name=project.title, filename=filename, - version=version.version_number, hash=hash) - case "shader": - db.add_shader(slug=project.slug, proj_name=project.title, filename=filename, - version=version.version_number, hash=hash) - case "modpack": - db.add_modpack(slug=project.slug, proj_name=project.title, filename=filename, - version=version.version_number, hash=hash) - case _: - raise NotImplementedError mcfs.install(filename, subdir) - if failed_to_install: - print("Failed to install:", - *[project.title + " " + version.version_number for project, version in failed_to_install], sep="\n\t") def search(query: list): @@ -204,101 +142,39 @@ def clean(): print("Nothing to clear.") -def remove(projects): # TODO: 1. Проверка зависимостей? 2. Модпаки - if __name__ == "__main__": - db = mcgetdb.McGetDB(mcfs.mc_dir) - - mods_to_remove = [] - resources_to_remove = [] - shaders_to_remove = [] - modpacks_to_remove = [] - - for project in projects: - for res in db.select_mod(project): - mods_to_remove.append(res) - for res in db.select_resourcepack(project): - resources_to_remove.append(res) - for res in db.select_shader(project): - shaders_to_remove.append(res) - for res in db.select_modpack(project): - modpacks_to_remove.append(res) - - for slug, title, filename, version, _ in mods_to_remove: - local_path = os.path.join("mods", filename) - mcfs.remove(local_path) - db.remove_mod(slug) - print(f"Mod {title} v.{version} was removed.") - for _, title, filename, version, _ in resources_to_remove: - local_path = os.path.join("resourcepacks", filename) - mcfs.remove(local_path) - db.remove_resourcepack(slug) - print(f"Resource pack {title} v.{version} was removed.") - for _, title, filename, version, _ in shaders_to_remove: - local_path = os.path.join("shaderpacks", filename) - mcfs.remove(local_path) - db.remove_shader(slug) - print(f"Shader pack {title} v.{version} was removed.") - for _, title, filename, version, _ in modpacks_to_remove: - raise NotImplementedError - # local_path = os.path.join("modpacks", filename) - # mcfs.remove(local_path) - # db.remove_modpack(slug) - # print(f"Mod pack {title} v.{version} was removed.") - else: - raise NotImplementedError("Not available in module mode") - - if __name__ == "__main__": - def exit(): - import sys - sys.exit("MC installation not found. If the program is not installed in the default location, " - "then specify the path to the installation through the MC_DIR environment variable.") - - if not mcfs.is_path_exist(mcfs.mc_dir): - exit() - - db = mcgetdb.McGetDB(mcfs.mc_dir) - - def __select_version(versions): - if not versions: - return None - print("Installed MC versions: ") - for id, version in enumerate(versions): - print(id + 1, - version.version_number + (f" with {version.modloader}" if version.is_modified else ""), - sep=": ") - if len(versions) > 1: - id_to_use = -1 - while id_to_use not in range(1, len(versions)): - id_input = input(f"Select MC version to use [1-{len(versions)}]: ") - if not id_input.isnumeric(): - continue - id_to_use = int(id_input) - else: - id_to_use = 1 - selected_version = versions[id_to_use - 1] - print("Selected MC version:", selected_version.version_number + - (f" with {selected_version.modloader}" if selected_version.is_modified else "")) - return selected_version + if len(versions) > 0: + print("Installed MC versions: ") + for id, version in enumerate(versions): + print(id + 1, version.version_number + (f" with {version.modloader}" if version.is_modified else ""), + sep=": ") + if len(versions) > 1: + id_to_use = -1 + while id_to_use not in range(1, len(versions)): + id_input = input(f"Select MC version to use [1-{len(versions)}]: ") + if not id_input.isnumeric(): + continue + id_to_use = int(id_input) + else: + id_to_use = 1 + selected_version = versions[id_to_use - 1] + print("Selected MC version:", selected_version.version_number + + (f" with {selected_version.modloader}" if selected_version.is_modified else "")) + return selected_version properties = db.get_properties() if not properties: version_to_use = __select_version(mcfs.get_installed_mc_versions()) - if version_to_use: - if version_to_use.is_modified: # TODO: Добавить иерархию каталогов - db.set_properties(version_to_use.version_number, version_to_use.modloader) - else: - db.set_properties(version_to_use.version_number) - properties = db.get_properties() + if version_to_use.is_modified: # TODO: Добавить иерархию каталогов + db.set_properties(version_to_use.version_number, version_to_use.modloader) else: - properties = None - if properties: - _, mc_ver, loader, _ = properties - else: - mc_ver, loader = None, None + db.set_properties(version_to_use.version_number) + properties = db.get_properties() + print(properties) + _, mc_ver, loader, _ = properties desc = "Minecraft mods packet manager based on Modrinth API" parser = argparse.ArgumentParser(description=desc, @@ -308,7 +184,7 @@ if __name__ == "__main__": parser_install = subparsers.add_parser("install", help="Install one or more mods or resources") parser_install.add_argument("projects", nargs="+") - parser_install.add_argument("--mc_ver", default=mc_ver) + parser_install.add_argument("--version", default=mc_ver) parser_install.add_argument("--loader", default=loader) parser_search = subparsers.add_parser("search", help="Find a mod or a resource") @@ -318,12 +194,7 @@ if __name__ == "__main__": parser_clean = subparsers.add_parser("clean", help="Clean the cache of this program") - parser_remove = subparsers.add_parser("remove", help="Remove installed packages") - parser_remove.add_argument("projects", nargs="+") - kwargs = vars(parser.parse_args()) # Получаем все поля получившегося Namespace и пихаем в словарь - if not properties: - exit() globals()[kwargs.pop("method")](**kwargs) # Из глобального контекста получаем функцию с названием как в method, # заодно вытаскивая название метода из списка аргументов, # затем вызываем функцию с распакованным словарём в качестве аргумента diff --git a/mcfs.py b/mcfs.py index ca6858a..c852838 100644 --- a/mcfs.py +++ b/mcfs.py @@ -3,7 +3,7 @@ from sys import platform import shutil import zipfile import json -from hashlib import sha512 + class MCVersion: def __init__(self, version_number, is_modified=False, modloader=None): @@ -118,22 +118,3 @@ def get_installed_mc_versions(): pass versions.append(mc_ver) return sorted(versions, reverse=True) - - -def check_file_hash(path, ref_hash): - buffer_size = 65536 - hash = sha512() - with open(path, 'rb') as f: - data = True - while data: - data = f.read(buffer_size) - hash.update(data) - return hash.hexdigest() == ref_hash - - -def remove(mc_dir_rel_path): - path = os.path.join(mc_dir, mc_dir_rel_path) - if is_path_exist(path): - os.remove(path) - else: - raise FileNotFoundError diff --git a/mcgetdb.py b/mcgetdb.py index 8b6caa2..6d0bb38 100644 --- a/mcgetdb.py +++ b/mcgetdb.py @@ -3,7 +3,6 @@ import os DB_VERSION = 1 - class McGetDB: def __init_db(self): @@ -11,34 +10,8 @@ class McGetDB: db.execute(''' CREATE TABLE IF NOT EXISTS mods ( slug TEXT PRIMARY KEY NOT NULL, - proj_name TEXT NOT NULL, - filename TEXT NOT NULL, - version TEXT NOT NULL, - hash TEXT NOT NULL - );''') - db.execute(''' - CREATE TABLE IF NOT EXISTS resourcepacks ( - slug TEXT PRIMARY KEY NOT NULL, - proj_name TEXT NOT NULL, - filename TEXT NOT NULL, - version TEXT NOT NULL, - hash TEXT NOT NULL - );''') - db.execute(''' - CREATE TABLE IF NOT EXISTS shaderpacks ( - slug TEXT PRIMARY KEY NOT NULL, - proj_name TEXT NOT NULL, - filename TEXT NOT NULL, - version TEXT NOT NULL, - hash TEXT NOT NULL - );''') - db.execute(''' - CREATE TABLE IF NOT EXISTS modpacks ( - slug TEXT PRIMARY KEY NOT NULL, - proj_name TEXT NOT NULL, - filename TEXT NOT NULL, - version TEXT NOT NULL, - hash TEXT NOT NULL + install_path TEXT NOT NULL, + version TEXT NOT NULL );''') db.execute(''' CREATE TABLE IF NOT EXISTS properties ( @@ -53,21 +26,6 @@ class McGetDB: self.db = sqlite3.connect(self.db_path) self.__init_db() - self.add_mod = self.__db_insert("mods") - self.add_resourcepack = self.__db_insert("resourcepacks") - self.add_shader = self.__db_insert("shaderpacks") - self.add_modpack = self.__db_insert("modpacks") - - self.select_mod = self.__db_select_by_col("mods", "slug") - self.select_resourcepack = self.__db_select_by_col("resourcepacks", "slug") - self.select_shader = self.__db_select_by_col("shaderpacks", "slug") - self.select_modpack = self.__db_select_by_col("modpacks", "slug") - - self.remove_mod = self.__db_remove_by_col("mods", "slug") - self.remove_resourcepack = self.__db_remove_by_col("resourcepacks", "slug") - self.remove_shader = self.__db_remove_by_col("shaderpacks", "slug") - self.remove_modpack = self.__db_remove_by_col("modpacks", "slug") - def get_properties(self): properties = None with self.db as db: @@ -76,7 +34,7 @@ class McGetDB: ''').fetchone() return properties - def set_properties(self, mc_ver, modloader="NULL", dir_hierarhy="default"): + def set_properties(self, mc_ver, modloader = "NULL", dir_hierarhy = "default"): with self.db as db: db.execute(''' DELETE FROM properties; @@ -85,31 +43,11 @@ class McGetDB: INSERT INTO properties VALUES (?, ?, ?, ?) ''', (DB_VERSION, mc_ver, modloader, dir_hierarhy)) - def __db_insert(self, table): - def insertion_func(**kargs): - keys = [] - values = [] - for key, value in kargs.items(): - keys.append(key) - values.append(value) - with self.db as db: - db.execute(f''' - INSERT INTO {table} ({', '.join([key for key in keys])}) VALUES ({', '.join(['?' for _ in values])}) - ''', values) - return insertion_func + def add_mod(self): + pass - def __db_select_by_col(self, table, col): - def selection_func(col_value): - with self.db as db: - res = db.execute(f'SELECT * FROM {table} WHERE {col} = "{col_value}"') - return res.fetchall() - return selection_func - - def __db_remove_by_col(self, table, col): - def removal_func(col_value): - with self.db as db: - db.execute(f'DELETE FROM {table} WHERE {col} = "{col_value}"') - return removal_func + def remove_mod(self): + pass def update_mod(self): pass