diff --git a/.gitignore b/.gitignore index cf44e1e..8f38a63 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +config.yaml + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/README.md b/README.md index c6f6416..31b0c5b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,61 @@ +# About this Fork +This fork adds support for multiple servers with a server switching system +``` +server [servername] +``` +As well as a new config file `config.yaml` +```yaml +Servers: + Srv1: + Connection: local + ServerRootPath: C:/Users/USER/Desktop/server + PluginFolderPath: C:/Users/USER/Desktop/server/plugins + SeperateDownloadPath: false + + Srv2: + Connection: sftp + ServerRootPath: / + PluginFolderPath: /plugins + SeperateDownloadPath: /plugins/updated + + Server: mc.example.com + Username: joe + Password: pass + Port: 22 + + Srv3: + Connection: ftp + ServerRootPath: / + PluginFolderPath: /plugins + SeperateDownloadPath: false + + Server: mc.example.com + Username: joe + Password: pass + Port: 21 + + AnotherServerName: + Connection: local + ServerRootPath: /srv/mc + PluginFolderPath: /srv/mc/plugins + SeperateDownloadPath: /srv/mc/plugins/downloaded + + # more can be added +``` +### Features I plan to add in the future +- Improved CLI with support for one word commands +- Modular plugin and serverjar system / more repos +- Batch actions across multiple servers + +
+ +--- + +
+
+

diff --git a/pluget.py b/pluget.py index 0a26d93..b455427 100644 --- a/pluget.py +++ b/pluget.py @@ -7,10 +7,11 @@ 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.handlers.handle_config import check_config, read_config, validate_config 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.utils.utilities import api_test_spiget, check_for_pluGET_update from src.handlers.handle_input import handle_input + from src.handlers.handle_server import server_list 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") @@ -29,8 +30,9 @@ if __name__ == "__main__": rename_console_title() check_config() validate_config() + read_config() api_test_spiget() - check_requirements() + # 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 @@ -41,5 +43,5 @@ if __name__ == "__main__": # no arguments were used so start pluGET console clear_console() print_logo() - check_for_pluGET_update() + # check_for_pluGET_update() handle_input() diff --git a/src/config-sample.yaml b/src/config-sample.yaml new file mode 100644 index 0000000..14d432b --- /dev/null +++ b/src/config-sample.yaml @@ -0,0 +1,37 @@ +Servers: + Srv1: + Connection: local + ServerRootPath: C:/Users/USER/Desktop/server + PluginFolderPath: C:/Users/USER/Desktop/server/plugins + SeperateDownloadPath: false + + Srv2: + Connection: sftp + ServerRootPath: / + PluginFolderPath: /plugins + SeperateDownloadPath: /plugins/updated + + Server: mc.example.com + Username: joe + Password: pass + Port: 22 + + Srv3: + Connection: ftp + ServerRootPath: / + PluginFolderPath: /plugins + SeperateDownloadPath: false + + Server: mc.example.com + Username: joe + Password: pass + Port: 21 + + Srv4: + Connection: local + ServerRootPath: /srv/mc + PluginFolderPath: /srv/mc/plugins + SeperateDownloadPath: /srv/mc/plugins/downloaded + + # more can be added + diff --git a/src/handlers/handle_config.py b/src/handlers/handle_config.py index 849594e..020b6f2 100644 --- a/src/handlers/handle_config.py +++ b/src/handlers/handle_config.py @@ -5,105 +5,109 @@ import os import sys import ruamel.yaml +import shutil from pathlib import Path from rich.console import Console +from src.servers.local import local_server +from src.servers.ftp import ftp_server +from src.servers.sftp import sftp_server +from src.handlers.handle_server import server_list +from src.handlers import handle_server - -class config_value(): +def read_config(): """ - Class which holds all the available configuration values from the config file and which will be used later in - the process of updating plugins - If bool in config can't be read it will default to 'False' + Reads the config file and populates the server handler """ - def __init__(self): - yaml = ruamel.yaml.YAML() - with open("pluGET_config.yaml", "r") as config_file: - data = yaml.load(config_file) - self.connection = str(data["Connection"]).lower() - self.path_to_plugin_folder = Path(data["Local"]["PathToPluginFolder"]) - self.local_seperate_download_path = True if data["Local"]["SeperateDownloadPath"] == True else False - self.local_path_to_seperate_download_path = Path(data["Local"]["PathToSeperateDownloadPath"]) - self.server = data["Remote"]["Server"] - self.username = data["Remote"]["Username"] - self.password = data["Remote"]["Password"] - self.sftp_port = int(data["Remote"]["SFTP_Port"]) - self.ftp_port = int(data["Remote"]["FTP_Port"]) - self.remote_seperate_download_path = True if data["Remote"]["SeperateDownloadPath"] == True else False - self.remote_path_to_seperate_download_path = data["Remote"]["PathToSeperateDownloadPath"] - self.remote_plugin_folder_on_server = data["Remote"]["PluginFolderOnServer"] + yaml = ruamel.yaml.YAML() + with open("config.yaml", "r") as config_file: + data = yaml.load(config_file) + for server in data["Servers"]: + data2 = data["Servers"][server] + + match data2["Connection"]: + case "local": + temp = local_server() + case "ftp": + temp = ftp_server() + case "sftp": + temp = sftp_server() + temp.name = str(server) + temp.connection = data2["Connection"] + temp.root_path = Path(data2["ServerRootPath"]) + temp.plugin_path = Path(data2["PluginFolderPath"]) + temp.seperate_download_path = data2["SeperateDownloadPath"] + if temp.connection == "sftp" or temp.connection == "ftp": + temp.server = data2["Server"] + temp.username = data2["Username"] + temp.password = data2["Password"] + temp.port = int(data2["Port"]) + + server_list[str(server)] = temp + handle_server.active_server = server_list[next(iter(server_list))] + def check_config() -> None: """ Check if there is a pluGET_config.yml file in the same folder as pluget.py and if not create a new config and exit the programm """ - if not os.path.isfile("pluGET_config.yaml"): + if not os.path.isfile("config.yaml"): create_config() return None def create_config() -> None: """ - Creates the yaml config in the current directory with the filename pluGET_config.yml + copies the sample config file into the root folder """ - # this is the whole yaml code because of weird formating indention is not possible - configuration = """\ -# -# Configuration File for pluGET -# https://www.github.com/Neocky/pluGET -# - -# What should be used for the connection (local, sftp, ftp) - Connection: local - - Local: - PathToPluginFolder: C:/Users/USER/Desktop/plugins - # If a different folder should be used to store the updated plugins change to (True/False) and the path below - SeperateDownloadPath : False - PathToSeperateDownloadPath: C:/Users/USER/Desktop/plugins - - Remote: - Server: 0.0.0.0 - Username: user - Password: password - # If a different Port for SFTP/FTP will be used - SFTP_Port: 22 - FTP_Port: 21 - # If a different folder should be used to store the updated plugins change to (True/False) and the path below - SeperateDownloadPath : False - PathToSeperateDownloadPath: /plugins/updated - # Change the path below if the plugin folder path is different on the SFTP/FTP server (Change only if you know what you are doing) - PluginFolderOnServer: /plugins - """ - # load ruamel.yaml to get the # commands right in the yaml code - yaml = ruamel.yaml.YAML() - code = yaml.load(configuration) - with open("pluGET_config.yaml", "w") as config_file: - yaml.dump(code, config_file) - - config_file_path = os.path.abspath("pluGET_config.yaml") + shutil.copyfile('src/config-sample.yaml', 'config.yaml') + config_file_path = os.path.abspath("config.yaml") print(f"Path of config file: {config_file_path}") print("Config created. Edit config before executing again!") input("Press any key + enter to exit...") sys.exit() - def validate_config() -> None: """ - Validates the config variables after config class is loaded and exit if error is detected and print error + Check for missing entries in the config """ - accepted_values = [ - ("local", "sftp", "ftp") - ] - # exit afterwards if there is an error in config - exit_afterwards = False - config = config_value() - # rich console for nice colors + yaml = ruamel.yaml.YAML() + with open("config.yaml", "r") as config_file: + data = yaml.load(config_file) console = Console() - if config.connection not in accepted_values[0]: - console.print(f"Error in Config! Accepted values for key 'Connection' are {accepted_values[0]}", - style="bright_red") + exit_afterwards = False + + if "Servers" not in data: + console.print(f"Config file is malformed",style="bright_red",highlight=False) exit_afterwards = True - if exit_afterwards: + else: + for server in data["Servers"]: + temp = data["Servers"][server] + keys = ["Connection","ServerRootPath","PluginFolderPath","SeperateDownloadPath"] + remote_keys = ["Server","Username","Password","port"] + + if temp == None: + console.print(f"'{str(server)}' is malformed",style="bright_red",highlight=False) + exit_afterwards = True + else: + for cur in keys: + if cur not in temp: + console.print(f"'{str(server)}' is missing key '{cur}'",style="bright_red",highlight=False) + exit_afterwards = True + + if "Connection" in temp: + accepted_values = ("local", "sftp", "ftp") + if temp["Connection"] not in accepted_values: + console.print(f"'{server}' has invalid key 'Connection' Valid options: {accepted_values}",style="bright_red",highlight=False) + exit_afterwards = True + + if temp["Connection"] == "sftp" or temp["Connection"] == "ftp": + for cur in remote_keys: + if cur not in temp: + console.print(f"'{str(server)}' is missing key '{cur}'",style="bright_red",highlight=False) + exit_afterwards = True + if exit_afterwards: sys.exit() + + diff --git a/src/handlers/handle_ftp.py b/src/handlers/handle_ftp.py deleted file mode 100644 index df84be9..0000000 --- a/src/handlers/handle_ftp.py +++ /dev/null @@ -1,187 +0,0 @@ -import os -import sys -import ftplib -import re - -from src.utils.console_output import rich_print_error -from src.handlers.handle_config import config_value - - -def ftp_create_connection(): - """ - Creates a connection to the ftp server with the given values in the config - - :returns: ftp connection type - """ - config_values = config_value() - try: - ftp = ftplib.FTP() - ftp.connect(config_values.server, config_values.ftp_port) - ftp.login(config_values.username, config_values.password) - return ftp - except UnboundLocalError: - rich_print_error("Error: [SFTP]: Check your config file!") - rich_print_error("Exiting program...") - sys.exit() - - -def ftp_show_plugins(ftp) -> None: - """ - Prints all plugins in the plugin folder - - :param ftp: ftp connection - - :returns: None - """ - config_values = config_value() - ftp.cwd(config_values.remote_plugin_folder_on_server) - for attr in ftp.dir(): - print(attr.filename, attr) - return None - - -def ftp_upload_file(ftp, path_item) -> None: - """ - Uploads a file to the ftp server - - :param ftp: ftp connection - :param path_item: Name of the item which should be uploaded - - :returns: None - """ - config_values = config_value() - if config_values.remote_seperate_download_path is True: - path_upload_folder = config_values.remote_path_to_seperate_download_path - else: - path_upload_folder = config_values.remote_plugin_folder_on_server - try: - ftp.cwd(path_upload_folder) - path_item = os.path.relpath(path_item, 'TempSFTPFolder/') - path_item = str(path_item) - current_directory = os.getcwd() - os.chdir('TempSFTPFolder') - with open (path_item, 'rb') as plugin_file: - ftp.storbinary('STOR '+ str(path_item), plugin_file) - except FileNotFoundError: - rich_print_error("Error: [FTP]: The 'plugins' folder couldn't be found on the remote host!") - rich_print_error("Error: [FTP]: Aborting uploading.") - os.chdir(current_directory) - ftp.close() - return None - - -def ftp_upload_server_jar(ftp, path_item) -> None: - """ - Uploads a serverjar to the root folder of the ftp host - - :param ftp: ftp connection - :param path_item: Name of the file which should be uploaded - - :returns: None - """ - try: - ftp.cwd('.') - path_item = os.path.relpath(path_item, 'TempSFTPFolder/') - path_item = str(path_item) - current_directory = os.getcwd() - os.chdir('TempSFTPFolder') - with open (path_item, 'rb') as server_jar: - ftp.storbinary('STOR '+ str(path_item), server_jar) - except FileNotFoundError: - rich_print_error("Error: [FTP]: The 'root' folder couldn't be found on the remote host!") - rich_print_error("Error: [FTP]: Aborting uploading.") - os.chdir(current_directory) - ftp.close() - return None - - -def ftp_list_all(ftp): - """ - Returns a list with all installed plugins in the plugin folder of the ftp host - - :param ftp: ftp connection - - :returns: List of all plugins in plugin folder - """ - config_values = config_value() - try: - ftp.cwd(config_values.remote_plugin_folder_on_server) - installed_plugins = ftp.nlst() - except FileNotFoundError: - rich_print_error("Error: [FTP]: The 'plugins' folder couldn't be found on the remote host!") - - try: - return installed_plugins - except UnboundLocalError: - rich_print_error("Error: [FTP]: No plugins were found.") - - -def ftp_list_files_in_server_root(ftp): - """ - Returns a list with all files in the root folder of the ftp host - - :param ftp: ftp connection - - :returns: List of all files in root folder - """ - try: - ftp.cwd('.') - filesInServerRoot = ftp.nlst() - except FileNotFoundError: - rich_print_error("Error: [FTP]: The 'root' folder couldn't be found on the remote host!") - - try: - return filesInServerRoot - except UnboundLocalError: - rich_print_error("Error: [FTP]: No Serverjar was found.") - - -def ftp_download_file(ftp, path_download, file) -> None: - """ - Download a file of the ftp server - - :param ftp: ftp connection - :param path_download: Path to save downloaded file to - :param file: File to download - - :returns None - """ - config_values = config_value() - ftp.cwd(config_values.remote_plugin_folder_on_server) - filedata = open(path_download,'wb') - ftp.retrbinary('RETR '+file, filedata.write) - filedata.close() - ftp.quit() - return None - - -def ftp_is_file(ftp, plugin_path) -> bool: - """ - Check if file on ftp host is a file and not a directory - - :param ftp: ftp connection - :param plugin_path - - :returns: True if file is a file and not a directory - """ - if ftp.nlst(plugin_path) == [plugin_path]: - return True - else: - return False - - -def ftp_validate_file_attributes(ftp, plugin_path) -> bool: - """ - Check if a file is a legitimate plugin file - - :param ftp: ftp connection - :param plugin_path: Path of file to check - - :returns: If file is a plugin file or not - """ - if ftp_is_file(ftp, plugin_path) is False: - return False - if re.search(r'.jar$', plugin_path): - return True - else: - return False diff --git a/src/handlers/handle_input.py b/src/handlers/handle_input.py index f0e8d07..de9e8b4 100644 --- a/src/handlers/handle_input.py +++ b/src/handlers/handle_input.py @@ -8,11 +8,14 @@ from src.plugin.plugin_remover import delete_plugin from src.plugin.plugin_downloader import get_specific_plugin_spiget, search_specific_plugin_spiget from src.plugin.plugin_updatechecker import check_installed_plugins, update_installed_plugins from src.serverjar.serverjar_updatechecker import \ - check_update_available_installed_server_jar, update_installed_server_jar + check_update_available_installed_server_jar, update_installed_server_jar from src.serverjar.serverjar_paper_velocity_waterfall import serverjar_papermc_update from src.serverjar.serverjar_purpur import serverjar_purpur_update +from src.handlers.handle_server import server_list +from src.handlers import handle_server +# server # check # update # get @@ -53,7 +56,18 @@ def handle_input( # KeyboardInterrupt was triggered and None was returned so exit return - match input_command: + match input_command: + case "server": + match input_selected_object: + case "is": + print(handle_server.active_server.name) + case _: + try: + handle_server.active_server = server_list[input_selected_object] + print("Set to "+handle_server.active_server.name) + except KeyError: + print("Invalid server name") + case "get": match input_selected_object.isdigit(): case True: @@ -110,7 +124,7 @@ def get_input() -> str: :returns: Optional parameter """ input_command = None - print("\n'STRG + C' to exit") + # print("\n'STRG + C' to exit") while True: try: input_command, input_selected_object, *input_parameter = input("pluGET >> ").split() diff --git a/src/handlers/handle_server.py b/src/handlers/handle_server.py new file mode 100644 index 0000000..01a2a71 --- /dev/null +++ b/src/handlers/handle_server.py @@ -0,0 +1,6 @@ +""" +Stores variables related to server switching +""" + +server_list = {} +active_server = None \ No newline at end of file diff --git a/src/handlers/handle_sftp.py b/src/handlers/handle_sftp.py deleted file mode 100644 index 8d794de..0000000 --- a/src/handlers/handle_sftp.py +++ /dev/null @@ -1,168 +0,0 @@ -import sys -import os -import pysftp -import paramiko -import stat -import re - -from src.utils.console_output import rich_print_error -from src.handlers.handle_config import config_value - - -def sftp_create_connection(): - """ - Creates a sftp connection with the given values in the config file - - :returns: SFTP connection type - """ - config_values = config_value() - cnopts = pysftp.CnOpts() - cnopts.hostkeys = None # TODO fix this - try: - sftp = pysftp.Connection(config_values.server, username=config_values.username, \ - password=config_values.password, port=config_values.sftp_port, cnopts=cnopts) - except paramiko.ssh_exception.AuthenticationException: - rich_print_error("Error: [SFTP]: Wrong Username/Password") - except paramiko.ssh_exception.SSHException: - rich_print_error("Error: [SFTP]: The SFTP server isn't available.") - try: - return sftp - except UnboundLocalError: - rich_print_error("Error: [SFTP]: Check your config file!") - rich_print_error("Exiting program...") - sys.exit() - - -def sftp_show_plugins(sftp) -> None: - """ - Prints all plugins in the sftp folder - - :param sftp: sftp connection - - :returns: None - """ - config_values = config_value() - sftp.cd(config_values.remote_plugin_folder_on_server) - for attr in sftp.listdir_attr(): - print(attr.filename, attr) - sftp.close() - return None - - -def sftp_upload_file(sftp, path_item) -> None: - """ - Uploads a file to the set folder from the config file - - :param sftp: sftp connection - :param path_item: The upload path with the item name - - :returns: None - """ - config_values = config_value() - if config_values.remote_seperate_download_path is True: - path_upload_folder = config_values.remote_path_to_seperate_download_path - else: - path_upload_folder = config_values.remote_plugin_folder_on_server - try: - sftp.chdir(path_upload_folder) - sftp.put(path_item) - except FileNotFoundError: - rich_print_error("Error: [SFTP]: The 'plugins' folder couldn't be found on the remote host!") - rich_print_error("Error: [SFTP]: Aborting uploading.") - sftp.close() - return None - - -def sftp_upload_server_jar(sftp, path_item) -> None: - """ - Uploads the server jar to the root folder - - :param sftp: sftp connection - :param path_item: The upload path with the item name - - :returns: None - """ - try: - sftp.chdir('.') - sftp.put(path_item) - except FileNotFoundError: - rich_print_error("Error: [SFTP]: The 'root' folder couldn't be found on the remote host!") - rich_print_error("Error: [SFTP]: Aborting uploading.") - sftp.close() - return None - - -def sftp_list_all(sftp): - """ - List all plugins in the 'plugins' folder on the sftp host - - :param sftp: sftp connection - - :return: List of plugins in plugin folder - """ - config_values = config_value() - try: - sftp.chdir(config_values.remote_plugin_folder_on_server) - installed_plugins = sftp.listdir() - except FileNotFoundError: - rich_print_error("Error: [SFTP]: The 'plugins' folder couldn't be found on the remote host!") - - try: - return installed_plugins - except UnboundLocalError: - rich_print_error("Error: [SFTP]: No plugins were found.") - - -def sftp_list_files_in_server_root(sftp): - """ - List all files in the root folder on the sftp host - - :param sftp: sftp connection - - :returns: List of files in root folder - """ - try: - files_in_server_root = sftp.listdir() - except FileNotFoundError: - rich_print_error("Error: [SFTP]: The 'root' folder couldn't be found on the remote host!") - try: - return files_in_server_root - except UnboundLocalError: - rich_print_error("Error: [SFTP]: No Serverjar was found.") - - -def sftp_download_file(sftp, file) -> None: - """ - Downloads a plugin file from the sftp host to a temporary folder - - :param sftp: sftp connection - :param file: Filename of plugin - - :returns: None - """ - config_values = config_value() - sftp.cwd(config_values.remote_plugin_folder_on_server) - current_directory = os.getcwd() - os.chdir('TempSFTPFolder') - sftp.get(file) - sftp.close() - os.chdir(current_directory) - return None - - -def sftp_validate_file_attributes(sftp, plugin_path) -> bool: - """ - Check if the file is a legitimate plugin file - - :param sftp: sftp connection - param plugin_path: Path of the single plugin file - - :returns: If file is a plugin file or not - """ - plugin_sftp_attribute = sftp.lstat(plugin_path) - if stat.S_ISDIR(plugin_sftp_attribute.st_mode): - return False - elif re.search(r'.jar$', plugin_path): - return True - else: - return False diff --git a/src/plugin/plugin_downloader.py b/src/plugin/plugin_downloader.py index fb8438c..483b5eb 100644 --- a/src/plugin/plugin_downloader.py +++ b/src/plugin/plugin_downloader.py @@ -13,9 +13,7 @@ from rich.progress import Progress from src.utils.utilities import convert_file_size_down, remove_temp_plugin_folder, create_temp_plugin_folder from src.utils.utilities import api_do_request from src.utils.console_output import rich_print_error -from src.handlers.handle_config import config_value -from src.handlers.handle_sftp import sftp_create_connection, sftp_upload_file -from src.handlers.handle_ftp import ftp_create_connection, ftp_upload_file +from src.handlers import handle_server def handle_regex_plugin_name(full_plugin_name) -> str: @@ -73,31 +71,10 @@ def get_version_name_spiget(plugin_id, plugin_version_id) -> str: version_name = response["name"] return version_name - -def get_download_path(config_values) -> str: - """ - Reads the config and gets the path of the plugin folder - """ - match (config_values.connection): - case "local": - match (config_values.local_seperate_download_path): - case True: - return config_values.local_path_to_seperate_download_path - case _: - return config_values.path_to_plugin_folder - case _: - match (config_values.remote_seperate_download_path): - case True: - return config_values.remote_path_to_seperate_download_path - case _: - return config_values.remote_plugin_folder_on_server - - def download_specific_plugin_version_spiget(plugin_id, download_path, version_id="latest") -> None: """ Download a specific plugin """ - config_values = config_value() if version_id != "latest" and version_id != None: #url = f"https://spigotmc.org/resources/{plugin_id}/download?version={versionID}" rich_print_error("Sorry but specific version downloads aren't supported because of cloudflare protection. :(") @@ -144,12 +121,9 @@ def download_specific_plugin_version_spiget(plugin_id, download_path, version_id console.print(" [not bold][bright_green]Downloaded[bright_magenta] " + (str(file_size_data)).rjust(9) + \ f" KB [cyan]→ [white]{download_path}") - if config_values.connection == "sftp": - sftp_session = sftp_create_connection() - sftp_upload_file(sftp_session, download_path) - elif config_values.connection == "ftp": - ftp_session = ftp_create_connection() - ftp_upload_file(ftp_session, download_path) + handle_server.active_server.create_connection() + handle_server.active_server.upload_plugin(download_path) + return None @@ -157,12 +131,8 @@ def get_specific_plugin_spiget(plugin_id, plugin_version="latest") -> None: """ Gets the specific plugin and calls the download function """ - config_values = config_value() # use a temporary folder to store plugins until they are uploaded - if config_values.connection != "local": - download_path = create_temp_plugin_folder() - else: - download_path = get_download_path(config_values) + download_path = create_temp_plugin_folder() url = f"https://api.spiget.org/v2/resources/{plugin_id}" plugin_details = api_do_request(url) @@ -188,8 +158,7 @@ def get_specific_plugin_spiget(plugin_id, plugin_version="latest") -> None: plugin_version_id = None download_specific_plugin_version_spiget(plugin_id, download_plugin_path, plugin_version_id) - if config_values.connection != "local": - remove_temp_plugin_folder() + remove_temp_plugin_folder() return None diff --git a/src/plugin/plugin_remover.py b/src/plugin/plugin_remover.py index 8bde13e..f4ac365 100644 --- a/src/plugin/plugin_remover.py +++ b/src/plugin/plugin_remover.py @@ -6,11 +6,8 @@ import os import re from pathlib import Path from rich.console import Console - -from src.handlers.handle_config import config_value from src.utils.console_output import rich_print_error -from src.handlers.handle_sftp import sftp_create_connection, sftp_list_all -from src.handlers.handle_ftp import ftp_create_connection, ftp_list_all +from src.handlers import handle_server def delete_plugin(plugin_name: str) -> None: @@ -21,36 +18,18 @@ def delete_plugin(plugin_name: str) -> None: :returns: None """ - config_values = config_value() rich_console = Console() - match config_values.connection: - case "sftp": - connection = sftp_create_connection() - plugin_list = sftp_list_all() - case "ftp": - connection = ftp_create_connection() - plugin_list = ftp_list_all() - case "local": - plugin_list = os.listdir(config_values.path_to_plugin_folder) + handle_server.active_server.create_connection() + plugin_list = handle_server.active_server.list_plugins() for plugin_file in plugin_list: # skip all other plugins if not re.search(plugin_name, plugin_file, re.IGNORECASE): continue try: - match config_values.connection: - case "sftp": - plugin_path = f"{config_values.remote_plugin_folder_on_server}/{plugin_file}" - connection = sftp_create_connection() - connection.remove(plugin_path) - case "ftp": - plugin_path = f"{config_values.remote_plugin_folder_on_server}/{plugin_file}" - connection = ftp_create_connection() - connection.delete(plugin_path) - case "local": - pluginPath = Path(f"{config_values.path_to_plugin_folder}/{plugin_file}") - os.remove(pluginPath) + handle_server.active_server.delete_plugin(plugin_file) rich_console.print(f"[not bold][bright_green]Successfully removed: [bright_magenta]{plugin_file}") except: rich_print_error(f"[not bold]Error: Couldn't remove [bright_magenta]{plugin_file}") + handle_server.active_server.close_connection() return None diff --git a/src/plugin/plugin_updatechecker.py b/src/plugin/plugin_updatechecker.py index ed5a8e4..8934475 100644 --- a/src/plugin/plugin_updatechecker.py +++ b/src/plugin/plugin_updatechecker.py @@ -13,13 +13,10 @@ from rich.console import Console from urllib.error import HTTPError from zipfile import ZipFile -from src.handlers.handle_config import config_value -from src.handlers.handle_sftp import sftp_create_connection, sftp_download_file, sftp_validate_file_attributes, sftp_list_all -from src.handlers.handle_ftp import ftp_create_connection, ftp_download_file, ftp_validate_file_attributes, ftp_list_all -from src.plugin.plugin_downloader import get_specific_plugin_spiget, get_download_path +from src.plugin.plugin_downloader import get_specific_plugin_spiget from src.utils.console_output import rich_print_error from src.utils.utilities import api_do_request, create_temp_plugin_folder, remove_temp_plugin_folder - +from src.handlers import handle_server class Plugin(): """ @@ -215,21 +212,11 @@ def egg_cracking_jar(plugin_file_name: str) -> str: :returns: Plugin name in plugin.yml file :returns: Plugin version in plugin.yml file """ - config_values = config_value() - match config_values.connection: - case "sftp": - path_temp_plugin_folder = create_temp_plugin_folder() - connection = sftp_create_connection() - sftp_download_file(connection, plugin_file_name) - path_plugin_jar = Path(f"{path_temp_plugin_folder}/{plugin_file_name}") - case "ftp": - path_temp_plugin_folder = create_temp_plugin_folder() - connection = ftp_create_connection() - path_plugin_jar = Path(f"{path_temp_plugin_folder}/{plugin_file_name}") - ftp_download_file(connection, path_plugin_jar, plugin_file_name) - case _: - path_plugin_folder = config_values.path_to_plugin_folder - path_plugin_jar = Path(f"{path_plugin_folder}/{plugin_file_name}") + path_temp_plugin_folder = create_temp_plugin_folder() + handle_server.active_server.create_connection() + handle_server.active_server.download_plugin(plugin_file_name,path_temp_plugin_folder) + path_plugin_jar = Path(f"{path_temp_plugin_folder}/{plugin_file_name}") + # later used to escape for-loop plugin_name = plugin_version = "" @@ -255,52 +242,30 @@ def egg_cracking_jar(plugin_file_name: str) -> str: except zipfile.BadZipFile: plugin_name = plugin_version = "" - # remove temp plugin folder if plugin was downloaded from sftp/ftp server - if config_values.connection != "local": - remove_temp_plugin_folder() + # remove temp plugin folder + remove_temp_plugin_folder() return plugin_name, plugin_version -def check_update_available_installed_plugins(input_selected_object: str, config_values: config_value) -> str: +def check_update_available_installed_plugins(input_selected_object: str) -> str: """ Gets installed plugins and checks it against the apis if there are updates for the plugins available :param input_selected_object: Command line input (default: all) - :param config_values: Config values from config file :returns: Count of plugins, Count of plugins with available updates """ Plugin.create_plugin_list() - match config_values.connection: - case "sftp": - connection = sftp_create_connection() - plugin_list = sftp_list_all(connection) - case "ftp": - connection = ftp_create_connection() - plugin_list = ftp_list_all(connection) - case _: - plugin_folder_path = config_values.path_to_plugin_folder - plugin_list = os.listdir(plugin_folder_path) + handle_server.active_server.create_connection() + plugin_list = handle_server.active_server.list_plugins() plugin_count = plugins_with_udpates = 0 # create simple progress bar from rich for plugin_file in track(plugin_list, description="[cyan]Checking...", transient=True, style="bright_yellow"): - plugin_attributes = True - match config_values.connection: - case "sftp": - plugin_attributes = sftp_validate_file_attributes( - connection, f"{config_values.remote_plugin_folder_on_server}/{plugin_file}" - ) - case "ftp": - plugin_attributes = ftp_validate_file_attributes( - connection, f"{config_values.remote_plugin_folder_on_server}/{plugin_file}" - ) - case _: - if not os.path.isfile(Path(f"{plugin_folder_path}/{plugin_file}")): - plugin_attributes = False - if not re.search(r'.jar$', plugin_file): - plugin_attributes = False + + plugin_attributes = handle_server.active_server.validate_plugin(plugin_file) + # skip plugin if no attributes were found to skip not valid plugin files if plugin_attributes == False: continue @@ -337,8 +302,7 @@ def check_installed_plugins(input_selected_object : str="all", input_parameter : :returns: None """ - config_values = config_value() - plugin_count, plugins_with_udpates = check_update_available_installed_plugins(input_selected_object, config_values) + plugin_count, plugins_with_udpates = check_update_available_installed_plugins(input_selected_object) # print rich table of found plugins and result rich_table = Table(box=None) @@ -384,22 +348,19 @@ def update_installed_plugins(input_selected_object : str="all", no_confirmation :returns: None """ rich_console = Console() - config_values = config_value() - match config_values.connection: - case "sftp": - connection = sftp_create_connection() - case "ftp": - connection = ftp_create_connection() + + handle_server.active_server.create_connection() + # if INSTALLEDPLUGINLIST was not previously filled by 'check' command call the command to fill plugin list try: if len(INSTALLEDPLUGINLIST) == 0: - check_update_available_installed_plugins(input_selected_object, config_values) + check_update_available_installed_plugins(input_selected_object) except NameError: - check_update_available_installed_plugins(input_selected_object, config_values) + check_update_available_installed_plugins(input_selected_object) # if argument 'all' was given recheck all plugins to avoid having only a few plugins from previously cached checks if input_selected_object == "all" or input_selected_object == "*": - check_update_available_installed_plugins(input_selected_object, config_values) + check_update_available_installed_plugins(input_selected_object) # skip confirmation message if pluGET was called with --no-confirmation if no_confirmation == False: @@ -428,79 +389,32 @@ def update_installed_plugins(input_selected_object : str="all", no_confirmation ) plugins_updated += 1 - plugin_path = get_download_path(config_values) - match config_values.connection: - # local plugin folder - case "local": - match (plugin.plugin_repository): - case "spigot": - try: - get_specific_plugin_spiget(plugin.plugin_repository_data[0]) - except HTTPError as err: - rich_print_error(f"HTTPError: {err.code} - {err.reason}") - plugins_updated -= 1 - except TypeError: - rich_print_error( - f"Error: TypeError > Couldn't download new version. Is the file available on spigotmc?" - ) - plugins_updated -= 1 + match (plugin.plugin_repository): + case "spigot": + try: + get_specific_plugin_spiget(plugin.plugin_repository_data[0]) + except HTTPError as err: + rich_print_error(f"HTTPError: {err.code} - {err.reason}") + plugins_updated -= 1 + except TypeError: + rich_print_error( + f"Error: TypeError > Couldn't download new version. Is the file available on spigotmc?" + ) + plugins_updated -= 1 - case _: - rich_print_error("Error: Plugin repository wasn't found") - return None - # don't delete files if they are downloaded to a seperate download path - if config_values.local_seperate_download_path == False: - try: - os.remove(Path(f"{plugin_path}/{plugin.plugin_file_name}")) - rich_console.print( - " [not bold][bright_green]Deleted old plugin file [cyan]→ [white]" + - f"{plugin.plugin_file_name}" - ) - except FileNotFoundError: - rich_print_error("Error: Old plugin file couldn't be deleted") - - - - # plugin folder is on sftp or ftp server case _: - plugin_path = f"{plugin_path}/{plugin.plugin_file_name}" - match (plugin.plugin_repository): - case "spigot": - try: - get_specific_plugin_spiget(plugin.plugin_repository_data[0]) - except HTTPError as err: - rich_print_error(f"HTTPError: {err.code} - {err.reason}") - plugins_updated -= 1 - except TypeError: - rich_print_error( - f"Error: TypeError > Couldn't download new version. Is the file available on spigotmc?" - ) - plugins_updated -= 1 - - case _: - rich_print_error("Error: Plugin repository wasn't found") - return None - # don't delete old plugin files if they are downloaded to a seperate download path - if config_values.remote_seperate_download_path == False: - match config_values.connection: - case "sftp": - try: - connection.remove(plugin_path) - rich_console.print( - " [not bold][bright_green]Deleted old plugin file [cyan]→ [white]" + - f"{plugin.plugin_file_name}" - ) - except FileNotFoundError: - rich_print_error("Error: Old plugin file couldn't be deleted") - case "ftp": - try: - connection.delete(plugin_path) - rich_console.print( - " [not bold][bright_green]Deleted old plugin file [cyan]→ [white]" + - f"{plugin.plugin_file_name}" - ) - except FileNotFoundError: - rich_print_error("Error: Old plugin file couldn't be deleted") + rich_print_error("Error: Plugin repository wasn't found") + return None + # don't delete old plugin files if they are downloaded to a seperate download path + if handle_server.active_server.connection == False: + try: + handle_server.active_server.remove(plugin.plugin_file_name) + rich_console.print( + " [not bold][bright_green]Deleted old plugin file [cyan]→ [white]" + + f"{plugin.plugin_file_name}" + ) + except FileNotFoundError: + rich_print_error("Error: Old plugin file couldn't be deleted") rich_console.print( f"\n[not bold][bright_green]Plugins updated: {plugins_updated}/{(len(INSTALLEDPLUGINLIST) - plugins_skipped)}" diff --git a/src/serverjar/serverjar_paper_velocity_waterfall.py b/src/serverjar/serverjar_paper_velocity_waterfall.py index 1b97a1a..f2a5868 100644 --- a/src/serverjar/serverjar_paper_velocity_waterfall.py +++ b/src/serverjar/serverjar_paper_velocity_waterfall.py @@ -11,11 +11,12 @@ from pathlib import Path from rich.table import Table from rich.console import Console from rich.progress import Progress +from src.handlers import handle_server -from src.handlers.handle_config import config_value +# from src.handlers.handle_config import config_value from src.utils.console_output import rich_print_error -from src.handlers.handle_sftp import sftp_create_connection, sftp_upload_server_jar -from src.handlers.handle_ftp import ftp_create_connection, ftp_upload_server_jar +# from src.handlers.handle_sftp import sftp_create_connection, sftp_upload_server_jar +# from src.handlers.handle_ftp import ftp_create_connection, ftp_upload_server_jar from src.utils.utilities import \ api_do_request, create_temp_plugin_folder, remove_temp_plugin_folder, convert_file_size_down @@ -169,16 +170,8 @@ def serverjar_papermc_update( :returns: True/False if the serverjar was downloaded successfully """ - config_values = config_value() - match config_values.connection: - case "local": - path_server_root = config_values.path_to_plugin_folder - # need help_path or else TypeError will be thrown - help_path = Path('/plugins') - help_path_str = str(help_path) - path_server_root = Path(str(path_server_root).replace(help_path_str, '')) - case _: - path_server_root = create_temp_plugin_folder() + + path_server_root = create_temp_plugin_folder() # exit if the mc version can't be found if file_server_jar_full_name == None and mc_version == None: @@ -264,14 +257,9 @@ def serverjar_papermc_update( file_size_data = convert_file_size_down(convert_file_size_down(file_size)) rich_console.print(" [not bold][bright_green]Downloaded[bright_magenta] " + (str(file_size_data)).rjust(9) + \ f" MB [cyan]→ [white]{download_path}") - - if config_values.connection == "sftp": - sftp_session = sftp_create_connection() - sftp_upload_server_jar(sftp_session, download_path) - remove_temp_plugin_folder() - elif config_values.connection == "ftp": - ftp_session = ftp_create_connection() - ftp_upload_server_jar(ftp_session, download_path) - remove_temp_plugin_folder() + + handle_server.active_server.create_connection() + handle_server.active_server.upload_server_jar(download_path) + remove_temp_plugin_folder() return True diff --git a/src/serverjar/serverjar_purpur.py b/src/serverjar/serverjar_purpur.py index 3416ece..d72a995 100644 --- a/src/serverjar/serverjar_purpur.py +++ b/src/serverjar/serverjar_purpur.py @@ -10,10 +10,8 @@ from rich.table import Table from rich.console import Console from rich.progress import Progress -from src.handlers.handle_config import config_value from src.utils.console_output import rich_print_error -from src.handlers.handle_sftp import sftp_create_connection, sftp_upload_server_jar -from src.handlers.handle_ftp import ftp_create_connection, ftp_upload_server_jar +from src.handlers import handle_server from src.utils.utilities import \ api_do_request, create_temp_plugin_folder, remove_temp_plugin_folder, convert_file_size_down from src.serverjar.serverjar_paper_velocity_waterfall import \ @@ -114,16 +112,8 @@ def serverjar_purpur_update( :returns: True/False if the serverjar was downloaded successfully """ - config_values = config_value() - match config_values.connection: - case "local": - path_server_root = config_values.path_to_plugin_folder - # need help_path or else TypeError will be thrown - help_path = Path('/plugins') - help_path_str = str(help_path) - path_server_root = Path(str(path_server_root).replace(help_path_str, '')) - case _: - path_server_root = create_temp_plugin_folder() + + path_server_root = create_temp_plugin_folder() # exit if the mc version can't be found if file_server_jar_full_name == None and mc_version == None: @@ -196,13 +186,8 @@ def serverjar_purpur_update( rich_console.print(" [not bold][bright_green]Downloaded[bright_magenta] " + (str(file_size_data)).rjust(9) + \ f" MB [cyan]→ [white]{download_path}") - if config_values.connection == "sftp": - sftp_session = sftp_create_connection() - sftp_upload_server_jar(sftp_session, download_path) - remove_temp_plugin_folder() - elif config_values.connection == "ftp": - ftp_session = ftp_create_connection() - ftp_upload_server_jar(ftp_session, download_path) - remove_temp_plugin_folder() + handle_server.active_server.create_connection() + handle_server.active_server.upload_server_jar(download_path) + remove_temp_plugin_folder() return True diff --git a/src/serverjar/serverjar_updatechecker.py b/src/serverjar/serverjar_updatechecker.py index ee24143..1e30354 100644 --- a/src/serverjar/serverjar_updatechecker.py +++ b/src/serverjar/serverjar_updatechecker.py @@ -6,15 +6,13 @@ import os from pathlib import Path from rich.console import Console -from src.handlers.handle_config import config_value from src.utils.console_output import rich_print_error -from src.handlers.handle_sftp import sftp_create_connection, sftp_list_files_in_server_root -from src.handlers.handle_ftp import ftp_create_connection, ftp_list_files_in_server_root from src.serverjar.serverjar_paper_velocity_waterfall import serverjar_papermc_check_update, serverjar_papermc_update from src.serverjar.serverjar_purpur import serverjar_purpur_check_update, serverjar_purpur_update +from src.handlers import handle_server -def get_installed_server_jar_file(config_values) -> str: +def get_installed_server_jar_file() -> str: """ Gets the file name of the installed server jar @@ -22,16 +20,8 @@ def get_installed_server_jar_file(config_values) -> str: :returns: Full file name of installed server jar """ - match config_values.connection: - case "sftp": - connection = sftp_create_connection() - file_list_server_root = sftp_list_files_in_server_root(connection) - case "ftp": - connection = ftp_create_connection() - file_list_server_root = ftp_list_files_in_server_root(connection) - case _: - file_list_server_root = os.path.dirname(config_values.path_to_plugin_folder) - file_list_server_root = os.listdir(file_list_server_root) + + file_list_server_root = handle_server.active_server.list_server_root() file_server_jar_full_name = None try: @@ -54,8 +44,7 @@ def check_update_available_installed_server_jar() -> None: :returns: None """ - config_values = config_value() - file_server_jar_full_name = get_installed_server_jar_file(config_values) + file_server_jar_full_name = get_installed_server_jar_file() if file_server_jar_full_name == None: # print error and exit function rich_print_error("Error: Serverjar couldn't be found") @@ -84,24 +73,14 @@ def update_installed_server_jar(server_jar_version: str="latest") -> None: :returns: None """ - config_values = config_value() - file_server_jar_full_name = get_installed_server_jar_file(config_values) + file_server_jar_full_name = get_installed_server_jar_file() if file_server_jar_full_name == None: # print error and exit function rich_print_error("Error: Serverjar couldn't be found") return None # finding path which is used for deleting old server jar - match config_values.connection: - case "local": - path_server_root = config_values.path_to_plugin_folder - # need help_path or else TypeError will be thrown - help_path = Path('/plugins') - help_path_str = str(help_path) - path_server_root = Path(str(path_server_root).replace(help_path_str, '')) - case _: - path_server_root = config_values.remote_plugin_folder_on_server - path_server_root = str(path_server_root).replace(r'/plugins', '') + path_server_root = handle_server.active_server.root_path server_jar_path = f"{path_server_root}/{file_server_jar_full_name}" rich_console = Console() @@ -122,15 +101,7 @@ def update_installed_server_jar(server_jar_version: str="latest") -> None: # remove old serverjar when the serverjar was sucessfully updated if download_successfull is True: - match config_values.connection: - case "local": - os.remove(Path(server_jar_path)) - case "sftp": - connection = sftp_create_connection() - connection.remove(server_jar_path) - case "ftp": - connection = ftp_create_connection() - connection.delete(server_jar_path) + handle_server.active_server.delete_server_jar(server_jar_path) rich_console.print( " [not bold][bright_green]Deleted old server file [cyan]→ [white]" + f"{file_server_jar_full_name}" diff --git a/src/servers/ftp.py b/src/servers/ftp.py new file mode 100644 index 0000000..7977db0 --- /dev/null +++ b/src/servers/ftp.py @@ -0,0 +1,148 @@ +import os +import sys +import ftplib +import re +from pathlib import Path +from src.utils.console_output import rich_print_error + +class ftp_server(): + def create_connection(self): + """ + Creates a connection to the ftp server with the given values in the config + """ + try: + ftp = ftplib.FTP() + ftp.connect(self.server, self.port) + ftp.login(self.username, self.password) + self.ftp = ftp + except UnboundLocalError: + rich_print_error("Error: [SFTP]: Check your config file!") + rich_print_error("Exiting program...") + sys.exit() + + def close_connection(self): + """ + Closes the ftp connection + """ + self.ftp.close() + + def upload_plugin(self, path_item) -> None: + """ + Uploads a plugin to the plugins folder or seperate download folder + + :param path_item: Name of the item which should be uploaded + + :returns: None + """ + if self.seperate_download_path is not False: + path_upload_folder = self.seperate_download_path + else: + path_upload_folder = self.plugin_path + try: + self.ftp.cwd(path_upload_folder) + with open (path_item, 'rb') as plugin_file: + self.ftp.storbinary('STOR '+ str(path_item), plugin_file) + except FileNotFoundError: + rich_print_error("Error: [FTP]: The 'plugins' folder couldn't be found on the remote host!") + rich_print_error("Error: [FTP]: Aborting uploading.") + return None + + def upload_server_jar(self, path_item) -> None: + """ + Uploads a serverjar to the root folder of the ftp host + + :param path_item: Name of the file which should be uploaded + + :returns: None + """ + try: + self.ftp.cwd(self.root_path) + with open (path_item, 'rb') as server_jar: + self.ftp.storbinary('STOR '+ str(path_item), server_jar) + except FileNotFoundError: + rich_print_error("Error: [FTP]: The 'root' folder couldn't be found on the remote host!") + rich_print_error("Error: [FTP]: Aborting uploading.") + return None + + def list_plugins(self): + """ + Returns a list with all installed plugins in the plugin folder of the ftp host + + :returns: List of all plugins in plugin folder + """ + try: + self.ftp.cwd(self.plugin_path) + installed_plugins = self.ftp.nlst() + except FileNotFoundError: + rich_print_error("Error: [FTP]: The 'plugins' folder couldn't be found on the remote host!") + + try: + return installed_plugins + except UnboundLocalError: + rich_print_error("Error: [FTP]: No plugins were found.") + + def list_server_root(self): + """ + Returns a list with all files in the root folder of the ftp host + + :returns: List of all files in root folder + """ + try: + self.ftp.cwd(self.server_root) + filesInServerRoot = self.ftp.nlst() + except FileNotFoundError: + rich_print_error("Error: [FTP]: The 'root' folder couldn't be found on the remote host!") + + try: + return filesInServerRoot + except UnboundLocalError: + rich_print_error("Error: [FTP]: No Serverjar was found.") + + def download_plugin(self, file, dest) -> None: + """ + Downloads a plugin file from the sftp host to the dest folder + + :param file: name of the plugin file + :param dest: destination (on this system) + + :returns None + """ + self.ftp.cwd(self.plugin_path) + filedata = open(dest,'wb') + self.ftp.retrbinary('RETR '+file, filedata.write) + filedata.close() + self.ftp.quit() + return None + + def validate_file_attributes(self, file) -> bool: + """ + Check if a file is a legitimate plugin file + + :param ftp: ftp connection + :param plugin_path: Path of file to check + + :returns: If file is a plugin file or not + """ + plugin_path = f"{self.plugin_path}/{file}" + if self.ftp.nlst(plugin_path) == [plugin_path] is False: + return False + if re.search(r'.jar$', plugin_path): + return True + else: + return False + + def delete_plugin(self, file): + """ + Deletes a plugin from the plugins folder + + :param file: The name of the file to delete + """ + self.ftp.delete(f"{self.plugin_path}/{file}") + + def delete_server_jar(self, file): + """ + Deletes a plugin from the server root + + :param file: The name of the file to delete + """ + self.ftp.delete(f"{self.root_path}/{file}") diff --git a/src/servers/local.py b/src/servers/local.py new file mode 100644 index 0000000..2ac0192 --- /dev/null +++ b/src/servers/local.py @@ -0,0 +1,100 @@ +import os +import shutil +import re +from pathlib import Path + +class local_server(): + def create_connection(self): + """ + Does not do anything, placeholder for if this were a remote connection + """ + pass + + def close_connection(self): + """ + Does not do anything, placeholder for if this were a remote connection + """ + pass + + def upload_plugin(self, file): + """ + Moves a plugin to the plugins folder or seperate download folder + + :param path_item: Name of the item which should be moved + + :returns: None + """ + if self.seperate_download_path is not False: + path_upload_folder = self.seperate_download_path + else: + path_upload_folder = self.plugin_path + shutil.copy(file, path_upload_folder) + + def upload_server_jar(self, file): + """ + Moves a serverjar to the root folder of the server + + :param path_item: Name of the file which should be moved + + :returns: None + """ + shutil.copy(file, self.root_path) + + def list_plugins(self): + """ + Returns a list with all installed plugins in the plugin folder + + :returns: List of all plugins in plugin folder + """ + return os.listdir(self.plugin_path) + + def list_server_root(self): + """ + Returns a list with all files in the root folder of the server + + :returns: List of all files in root folder + """ + return os.listdir(self.root_path) + + def download_plugin(self, file, dest): + """ + Moves a plugin file from the plugins folder to the dest folder + + :param file: name of the plugin file + :param dest: destination + + :returns None + """ + shutil.copy(f"{self.plugin_path}/{file}", dest) + + def validate_plugin(self, plugin_file): + """ + Check if a file is a legitimate plugin file + + :param ftp: ftp connection + :param plugin_path: Path of file to check + + :returns: If file is a plugin file or not + """ + plugin_attributes = True + if not os.path.isfile(Path(f"{self.plugin_path}/{plugin_file}")): + plugin_attributes = False + elif not re.search(r'.jar$', plugin_file): + plugin_attributes = False + return plugin_attributes + + def delete_plugin(self, file): + """ + Deletes a plugin from the plugins folder + + :param file: The name of the file to delete + """ + os.remove(f"{self.plugin_path}/{file}") + + def delete_server_jar(self, file): + """ + Deletes a plugin from the server root + + :param file: The name of the file to delete + """ + os.remove(f"{self.root_path}/{file}") \ No newline at end of file diff --git a/src/servers/sftp.py b/src/servers/sftp.py new file mode 100644 index 0000000..464bd4f --- /dev/null +++ b/src/servers/sftp.py @@ -0,0 +1,159 @@ +import sys +import os +import pysftp +import paramiko +import stat +import re + +from pathlib import Path +from src.utils.console_output import rich_print_error + +class sftp_server(): + def create_connection(self): + """ + Creates a sftp connection with the given values in the config file + """ + cnopts = pysftp.CnOpts() + cnopts.hostkeys = None # TODO fix this + try: + sftp = pysftp.Connection(self.server, username=self.username, \ + password=self.password, port=self.port, cnopts=cnopts) + except paramiko.ssh_exception.AuthenticationException: + rich_print_error("Error: [SFTP]: Wrong Username/Password") + except paramiko.ssh_exception.SSHException: + rich_print_error("Error: [SFTP]: The SFTP server isn't available.") + try: + self.sftp = sftp + except UnboundLocalError: + rich_print_error("Error: [SFTP]: Check your config file!") + rich_print_error("Exiting program...") + sys.exit() + + def close_connection(self): + """ + Closes the sftp connection + """ + self.sftp.close() + + def upload_plugin(self, path_item) -> None: + """ + Uploads a file to the set folder from the config file + + :param path_item: The upload path with the item name + + :returns: None + """ + if self.seperate_download_path is not False: + path_upload_folder = self.seperate_download_path + else: + path_upload_folder = self.plugin_path + try: + print(path_upload_folder) + self.sftp.chdir(str(path_upload_folder)) + self.sftp.put(path_item) + except FileNotFoundError: + rich_print_error("Error: [SFTP]: The 'plugins' folder couldn't be found on the remote host!") + rich_print_error("Error: [SFTP]: Aborting uploading.") + return None + + def upload_server_jar(self, path_item) -> None: + """ + Uploads the server jar to the root folder + + :param path_item: The upload path with the item name + + :returns: None + """ + try: + self.sftp.chdir(self.root_path) + self.sftp.put(path_item) + except FileNotFoundError: + rich_print_error("Error: [SFTP]: The 'root' folder couldn't be found on the remote host!") + rich_print_error("Error: [SFTP]: Aborting uploading.") + self.sftp.close() + return None + + def list_plugins(self): + """ + List all plugins in the 'plugins' folder on the sftp host + + :return: List of plugins in plugin folder + """ + try: + self.sftp.chdir(str(self.plugin_path)) + installed_plugins = self.sftp.listdir() + except FileNotFoundError: + rich_print_error("Error: [SFTP]: The 'plugins' folder couldn't be found on the remote host!") + + try: + return installed_plugins + except UnboundLocalError: + rich_print_error("Error: [SFTP]: No plugins were found.") + + def list_files_in_server_root(self): + """ + List all files in the root folder on the sftp host + + :returns: List of files in root folder + """ + try: + self.sftp.chdir(self.root_path) + files_in_server_root = self.sftp.listdir() + except FileNotFoundError: + rich_print_error("Error: [SFTP]: The 'root' folder couldn't be found on the remote host!") + try: + return files_in_server_root + except UnboundLocalError: + rich_print_error("Error: [SFTP]: No Serverjar was found.") + + def download_plugin(self, file, dest) -> None: + """ + Downloads a plugin file from the sftp host to the dest folder + + :param file: name of the plugin file + :param dest: destination (on this system) + + :returns: None + """ + self.sftp.cwd(str(self.plugin_path)) + current_directory = os.getcwd() + os.chdir(dest) + self.sftp.get(file) + self.sftp.close() + os.chdir(current_directory) + return None + + def validate_plugin(self, file) -> bool: + """ + Check if the file is a legitimate plugin file + + :param sftp: sftp connection + param plugin_path: Path of the single plugin file + + :returns: If file is a plugin file or not + """ + self.create_connection() + plugin_path = f"{self.plugin_path}/{file}" + plugin_sftp_attribute = self.sftp.lstat(plugin_path) + if stat.S_ISDIR(plugin_sftp_attribute.st_mode): + return False + elif re.search(r'.jar$', plugin_path): + return True + else: + return False + + def delete_plugin(self, file): + """ + Deletes a plugin from the plugins folder + + :param file: The name of the file to delete + """ + self.sftp.remove(f"{self.plugin_path}/{file}") + + def delete_server_jar(self, file): + """ + Deletes a plugin from the server root + + :param file: The name of the file to delete + """ + self.sftp.remove(f"{self.root_path}/{file}") diff --git a/src/settings.py b/src/settings.py index f5c2c53..ffe9314 100644 --- a/src/settings.py +++ b/src/settings.py @@ -5,4 +5,4 @@ PLUGETVERSION = current version of pluGET """ # constant values -PLUGETVERSION = "1.7.2" +PLUGETVERSION = "1.7.3" diff --git a/src/tests/all.py b/src/tests/all.py new file mode 100644 index 0000000..b5f3881 --- /dev/null +++ b/src/tests/all.py @@ -0,0 +1,40 @@ +from src.handlers.handle_server import server_list + +class all_servers(): + def create_connection(self): + for server in server_list: + server_list[server].create_connection() + + def close_connection(self): + for server in server_list: + server_list[server].close_connection + + def upload_plugin(self, file): + for server in server_list: + server_list[server].upload_plugin(file) + + def upload_server_jar(self, file): + pass + + def list_plugins(self): + combined = [] + for server in server_list: + combined += server_list[server].list_plugins() + return combined + + def list_server_root(self): + pass + + def download_plugin(self, file, dest): + for server in server_list: + server_list[server].download_plugin(self, file, dest) + + def validate_plugin(self, plugin_file): + pass + + def delete_plugin(self, file): + for server in server_list: + server_list[server].delete_plugin(self, file) + + def delete_server_jar(self, file): + pass \ No newline at end of file diff --git a/src/utils/utilities.py b/src/utils/utilities.py index ac32ebc..0c693e9 100644 --- a/src/utils/utilities.py +++ b/src/utils/utilities.py @@ -10,11 +10,8 @@ import re from pathlib import Path from rich.console import Console from rich.table import Table -from src.handlers.handle_sftp import sftp_create_connection -from src.handlers.handle_ftp import ftp_create_connection from src.utils.console_output import rich_print_error -from src.handlers.handle_config import config_value from src.settings import PLUGETVERSION @@ -195,16 +192,15 @@ def check_local_plugin_folder(config_values) -> None: return None -def check_requirements() -> None: - """ - Check if the plugin folders are available - """ - config_values = config_value() - match config_values.connection: - case "local": - check_local_plugin_folder(config_values) - case "sftp": - sftp_create_connection() - case "ftp": - ftp_create_connection() - return None +# def check_requirements() -> None: +# """ +# Check if the plugin folders are available +# """ +# match config_values.connection: +# case "local": +# check_local_plugin_folder(config_values) +# case "sftp": +# sftp_create_connection() +# case "ftp": +# ftp_create_connection() +# return None