diff --git a/pluGET.py b/pluGET.py index 43d6df4..cd74836 100644 --- a/pluGET.py +++ b/pluGET.py @@ -8,21 +8,16 @@ import argparse # check if folder 'src' is accessible with all modules needed and if not exit try: from src.handlers.handle_config import check_config, validate_config - from src.utils.console_output import rename_console_title, clear_console, print_logo - from src.utils.utilities import check_requirements, api_test_spiget + from src.utils.console_output import rename_console_title, clear_console, print_logo, print_console_logo + from src.utils.utilities import check_requirements, api_test_spiget, check_for_pluGET_update from src.handlers.handle_input import handle_input -except: +except TypeError: print("Folder 'src' not found in the directory or missing files or broken functions detected! \ \nPlease redownload the files from here: https://www.github.com/Neocky/pluGET") sys.exit() if __name__ == "__main__": - rename_console_title() - check_config() - validate_config() - api_test_spiget() - check_requirements() parser = argparse.ArgumentParser(description="Arguments for pluGET", formatter_class=argparse.ArgumentDefaultsHelpFormatter) #parser.add_argument("-a", "--archive", action="store_true", help="archive mode") @@ -31,11 +26,21 @@ if __name__ == "__main__": parser.add_argument("object", help="Object/Plugin Name", nargs='?', default=None) parser.add_argument("version", help="Version", nargs='?', default=None) args = vars(parser.parse_args()) + + rename_console_title() + check_config() + validate_config() + api_test_spiget() + check_requirements() + if args["mode"] is not None and args["object"] is not None: # arguments were used so call the handle_input function to get the right function call + print_console_logo() + check_for_pluGET_update() handle_input(args["mode"], args["object"], args["version"], arguments_from_console=True) else: # no arguments were used so start pluGET console - clear_console() + #clear_console() print_logo() + check_for_pluGET_update() handle_input() diff --git a/src/handlers/handle_input.py b/src/handlers/handle_input.py index b80c23f..b60339b 100644 --- a/src/handlers/handle_input.py +++ b/src/handlers/handle_input.py @@ -4,6 +4,7 @@ Handles the input through the pluGET command line from src.utils.console_output import rich_print_error from src.plugin.plugin_downloader import get_specific_plugin, search_specific_plugin +from src.plugin.plugin_updatechecker import check_installed_plugins # check @@ -36,8 +37,7 @@ def handle_input(input_command=None, input_selected_object=None, input_parameter case True: get_specific_plugin(input_selected_object, input_parameter) case _: - print("get search specific package") - #searchPackage(inputSelectedObject) + search_specific_plugin(input_selected_object) case "update": print("update package") @@ -57,7 +57,7 @@ def handle_input(input_command=None, input_selected_object=None, input_parameter #checkInstalledServerjar() case _: print("check plugins") - #checkInstalledPackage(inputSelectedObject, inputParams) + check_installed_plugins(input_selected_object, input_parameter) case "search": search_specific_plugin(input_selected_object) diff --git a/src/plugin/plugin_downloader.py b/src/plugin/plugin_downloader.py index b38243a..80d4c31 100644 --- a/src/plugin/plugin_downloader.py +++ b/src/plugin/plugin_downloader.py @@ -111,7 +111,7 @@ def download_specific_plugin_version_spiget(plugin_id, download_path, version_id try: file_size = int(r.headers.get('content-length')) # create progress bar - download_task = progress.add_task(" [bright_red]Downloading...", total=file_size) + download_task = progress.add_task(" [cyan]Downloading...", total=file_size) except TypeError: # Content-lenght returned nothing file_size = 0 diff --git a/src/plugin/plugin_updatechecker.py b/src/plugin/plugin_updatechecker.py new file mode 100644 index 0000000..962ff25 --- /dev/null +++ b/src/plugin/plugin_updatechecker.py @@ -0,0 +1,251 @@ +""" +Handles the plugin checking and updating +""" + +import os +import re +from pathlib import Path +from rich.progress import track + + +from src.handlers.handle_config import config_value +from src.utils.utilities import api_do_request + +class plugin(): + """ + Create plugin class to store installed plugins inside it + """ + def __init__(self, plugin_name, plugin_file_version) -> None: + self.plugin_name = plugin_name + self.plugin_file_version = plugin_file_version + + + @staticmethod + def create_plugin_list() -> list: + """ + Creates a global array list to store plugins + """ + global INSTALLEDPLUGINLIST + INSTALLEDPLUGINLIST = [] + return INSTALLEDPLUGINLIST + + + @staticmethod + def add_to_plugin_list(plugin_name, plugin_file_version) -> None: + """ + Adds a plugin to global installed plugin lists + """ + INSTALLEDPLUGINLIST.append(plugin(plugin_name, plugin_file_version)) + return None + + @staticmethod + def get_plugin_list_length() -> int: + """ + Returns the lenght of the plugin list + """ + return len(INSTALLEDPLUGINLIST) + + + + +#plugin.create_plugin_list() +#plugin.add_to_plugin_list("test2", 12345) +#for i in INSTALLEDPLUGINLIST: print(i.plugin_name) +#print(plugin.get_plugin_list_length()) + +def get_plugin_file_name(plugin_full_name) -> str: + """ + Finds the full plugin name of the given string + Example LuckPerms-5.4.30.jar -> Luckperms + + :param plugin_full_name: Full filename of plugin + + :returns: Full plugin name + """ + plugin_full_name2 = plugin_full_name + # find number.jar + plugin_file_version = re.search(r'([\d.]+[.jar]+)', plugin_full_name2) + try: + plugin_file_version_full = plugin_file_version.group() + except AttributeError: + plugin_file_version_full = plugin_file_version + # remove number from plugin name + plugin_name_only = plugin_full_name2.replace(plugin_file_version_full, '') + # remove - from plugin name + plugin_name_only = re.sub(r'(\-$)', '', plugin_name_only) + # remove -v from plugin name + plugin_name_only = re.sub(r'(\-v$)', '', plugin_name_only) + return plugin_name_only + + +def get_plugin_file_version(plugin_full_name) -> str: + """ + Gets the version of the plugin + + :param plugin_full_name: Full filename of plugin + + :returns: Version of plugin as string + """ + plugin_file_version = re.search(r'([\d.]+[.jar]+)', plugin_full_name) + plugin_file_version = plugin_file_version.group() + plugin_file_version = plugin_file_version.replace('.jar', '') + if plugin_file_version.endswith('.'): + print("get_plugin_file_version endswith .") + #plugin_file_version = eggCrackingJar(plugin_full_name, 'version') + return plugin_file_version + + +def get_latest_spigot_plugin_version(plugin_id) -> str: + """ + Gets the latest spigot plugin version + + :param plugin_id: Plugin Spigot ID + + :returns: Name of the latest update + """ + url = f"https://api.spiget.org/v2/resources/{plugin_id}/versions/latest" + latest_update_search = api_do_request(url) + return str(latest_update_search["name"]) + + +def create_plugin_version_tuple(plugin_version_string) -> tuple: + """ + Create a tuple of all version numbers + + :param plugin_version_string: Plugin Version + + :returns: Tuple of all version numbers + """ + return tuple(map(int, (plugin_version_string.split(".")))) + + +def get_plugin_version_without_letters(plugin_version_string) -> str: + """ + Returns the version without letters from the plugin version + + :param plugin_version_string: Plugin Version + + :returns: Plugin versioon without letters + """ + return re.sub(r'([A-Za-z]*)', '', plugin_version_string) + + +def compare_plugin_version(plugin_latest_version, plugin_file_version) -> bool: + """ + Check if plugin version is outdated + + :param plugin_latest_version: Latest available plugin version + :param plugin_file_version: Installed plugin version + + :returns: Bool if plugin version is outdated + """ + try: + plugin_version_tuple = create_plugin_version_tuple( + get_plugin_version_without_letters(plugin_file_version)) + plugin_latest_version_tuple = create_plugin_version_tuple( + get_plugin_version_without_letters(plugin_latest_version)) + except ValueError: + return False + if plugin_version_tuple < plugin_latest_version_tuple: + return True + else: + return False + + +def check_installed_plugins(input_selected_object="all", input_parameter=None) -> None: + """ + Gets installed plugins and checks it against the apis if there are updates for the plugins available + """ + config_values = config_value() + plugin.create_plugin_list() + match config_values.connection: + case "sftp": + # TODO add sftp adn ftp support + #connection = createSFTPConnection() + #pluginList = sftp_listAll(connection) + print("sftp list all") + case "ftp": + print("ftp list all") + case _: + plugin_folder_path = config_values.path_to_plugin_folder + plugin_list = os.listdir(plugin_folder_path) + + # create simple progress bar from rich + for plugin_file in track(plugin_list, description="Checking...", transient=True, style="bright_yellow"): + plugin_no_attributes = False + match config_values.connection: + case "sftp": + #plugin_attributes = sftp_validateFileAttributes(connection, f"config_values.remote_plugin_folder_on_server}/{plugin}") + print("sftp check_installed_plugins") + + case "ftp": + #plugin_attributes = ftp_validateFileAttributes(connection, f"config_values.remote_plugin_folder_on_server}/{plugin}") + print("ftp check_installed_plugins") + case _: + if not os.path.isfile(Path(f"{plugin_folder_path}/{plugin_file}")): + plugin_no_attributes = True + if not re.search(r'.jar$', plugin_file): + plugin_no_attributes = True + # skip plugin if no attributes were found + if plugin_no_attributes == True: + continue + + plugin_file_name = get_plugin_file_name(plugin_file) + plugin_file_version = get_plugin_file_version(plugin_file) + # check repository of plugin + plugin_spigot_id = search_plugin_spigot(plugin_file, plugin_file_name, plugin_file_version) + # TODO add more plugin repositories here + print(plugin_file_name) + print(plugin_file_version) + print(plugin_spigot_id) + + + + +def search_plugin_spigot(plugin_file, plugin_file_name, plugin_file_version) -> int: + """ + Search the spigot api for the installed plugin and add it to the installed plugin list + + :param plugin_file: Full file name of plugin + :param plugin_file_name: Name of plugin file + :param plugin_file_version: Version of plugin file + + :returns: Plugin ID of Spigot Plugin + """ + url = f"https://api.spiget.org/v2/search/resources/{plugin_file_name}?field=name&sort=-downloads" + plugin_list = api_do_request(url) + plugin_file_version2 = plugin_file_version + for i in range(3): + if i == 1: + plugin_file_version2 = re.sub(r'(\-\w*)', '', plugin_file_version) + if i == 2: + """ + pluginNameinYML = eggCrackingJar(plugin_file, 'name') + url = "https://api.spiget.org/v2/search/resources/" + pluginNameinYML + "?field=name&sort=-downloads" + try: + plugin_list = api_do_request(url) + except ValueError: + continue + """ + + #plugin_file_version = plugin_file_version2 # ? + + for plugin in plugin_list: + plugin_id = plugin["id"] + url2 = f"https://api.spiget.org/v2/resources/{plugin_id}/versions?size=100&sort=-name" + try: + plugin_versions = api_do_request(url2) + except ValueError: + continue + for updates in plugin_versions: + update_version_name = updates["name"] + if plugin_file_version2 in update_version_name: + spigot_update_id = updates["id"] + plugin_latest_version = get_latest_spigot_plugin_version(plugin_id) + plugin_is_outdated = compare_plugin_version(plugin_latest_version, update_version_name) + #addToPluginList(plugin_file, plugin_id, spigot_update_id, plugin_latest_version , plugin_is_outdated) + return plugin_id, plugin_is_outdated + + #plugin_id = spigot_update_id = plugin_latest_version = plugin_is_outdated = None + #addToPluginList(plugin_file, plugin_id, spigot_update_id, plugin_latest_version , plugin_is_outdated) + return None diff --git a/src/settings.py b/src/settings.py new file mode 100644 index 0000000..e9ab140 --- /dev/null +++ b/src/settings.py @@ -0,0 +1,8 @@ +""" +Constant values + +PLUGETVERSION = current version of pluGET +""" + +# constant values +PLUGETVERSION = "1.6.8" diff --git a/src/utils/console_output.py b/src/utils/console_output.py index f713714..7f38f89 100644 --- a/src/utils/console_output.py +++ b/src/utils/console_output.py @@ -5,6 +5,8 @@ import os from rich.console import Console +from src.settings import PLUGETVERSION + def rich_print_error(error_message) -> None: """ @@ -17,7 +19,7 @@ def rich_print_error(error_message) -> None: def rename_console_title() -> None: """ - Renames the console title on first startup + Renames the console title on first startup """ os.system("title " + "pluGET │ By Neocky") return None @@ -25,7 +27,7 @@ def rename_console_title() -> None: def clear_console() -> None: """ - Clears the console on first startup + Clears the console on first startup """ os.system('cls' if os.name=='nt' else 'clear') return None @@ -33,7 +35,7 @@ def clear_console() -> None: def print_logo() -> None: """ - Prints the logo of pluGET and the link to the github repo + Prints the logo of pluGET and the link to the github repo """ # use rich console console = Console() @@ -136,3 +138,14 @@ def print_logo() -> None: console.print(" └────────────────────────────────────┘", style="bright_black") console.print(" ───────────────────────────────────────────────────") return None + + +def print_console_logo() -> None: + """ + Prints the logo of pluGET if it is called from console + """ + console = Console() + console.print(f"[not bold][bright_magenta]pluGET [bright_green]{PLUGETVERSION} ", end='') + console.print("created by Neocky → ", end='') + console.print("https://github.com/Neocky/pluGET", style="link https://github.com/Neocky/pluGET") + return None diff --git a/src/utils/utilities.py b/src/utils/utilities.py index 85d8b12..81b47a6 100644 --- a/src/utils/utilities.py +++ b/src/utils/utilities.py @@ -6,10 +6,37 @@ import os import sys import requests import shutil +import re from pathlib import Path +from rich.console import Console from src.utils.console_output import rich_print_error from src.handlers.handle_config import config_value +from src.settings import PLUGETVERSION + + +def check_for_pluGET_update() -> None: + """ + Check with the github api if there is a new version for pluGET available and print download message if this is + the case + """ + response = api_do_request("https://api.github.com/repos/Neocky/pluGET/releases/latest") + # get '.1.6.10' as output + full_version_string = re.search(r"[\.?\d]*$", response["name"]) + # remove '.' to get '1.6.10' as output + version = re.sub(r"^\.*", "", full_version_string.group()) + console = Console() + try: + pluget_installed_version_tuple = tuple(map(int, (PLUGETVERSION.split(".")))) + plugin_latest_version_tuple = tuple(map(int, (version.split(".")))) + except ValueError: + console.print("Couldn't check if new version of pluGET is available") + return None + if pluget_installed_version_tuple < plugin_latest_version_tuple: + print(f"A new version for pluGET is available: {version}") + console.print("Download it here: ", end='') + console.print("https://github.com/Neocky/pluGET", style="link https://github.com/Neocky/pluGET") + return None def api_do_request(url) -> list: