From 2f085965c780c5baa9a475f7ae1aa668320828df Mon Sep 17 00:00:00 2001 From: prash3r Date: Fri, 2 Sep 2022 17:00:50 +0200 Subject: [PATCH] extends cbpi-dev-config to be a complete set. cbpi requires empty folders inside the config folder to fully function, and this commit adds them. There are also some more extensive checks on missing files and folders newly implemented. As well as checking for restored_config.zip is now done before checking for config.yaml. On unsuccessfull restore the zip file is renamed instead of deleted. --- .../{_widgets_are_placed_here => .gitkeep} | 0 .../.gitkeep} | 0 .../cbpi-dev-config/logs/sensors/.gitkeep | 0 .../cbpi-dev-config/recipes/.gitkeep | 0 .devcontainer/cbpi-dev-config/upload/.gitkeep | 0 .gitignore | 3 +- .vscode/launch.json | 10 +- cbpi/configFolder.py | 114 +++++++++++++----- 8 files changed, 97 insertions(+), 30 deletions(-) rename .devcontainer/cbpi-dev-config/dashboard/widgets/{_widgets_are_placed_here => .gitkeep} (100%) rename .devcontainer/cbpi-dev-config/{upload/_uploads_are_placed_here => fermenterrecipes/.gitkeep} (100%) create mode 100644 .devcontainer/cbpi-dev-config/logs/sensors/.gitkeep create mode 100644 .devcontainer/cbpi-dev-config/recipes/.gitkeep create mode 100644 .devcontainer/cbpi-dev-config/upload/.gitkeep diff --git a/.devcontainer/cbpi-dev-config/dashboard/widgets/_widgets_are_placed_here b/.devcontainer/cbpi-dev-config/dashboard/widgets/.gitkeep similarity index 100% rename from .devcontainer/cbpi-dev-config/dashboard/widgets/_widgets_are_placed_here rename to .devcontainer/cbpi-dev-config/dashboard/widgets/.gitkeep diff --git a/.devcontainer/cbpi-dev-config/upload/_uploads_are_placed_here b/.devcontainer/cbpi-dev-config/fermenterrecipes/.gitkeep similarity index 100% rename from .devcontainer/cbpi-dev-config/upload/_uploads_are_placed_here rename to .devcontainer/cbpi-dev-config/fermenterrecipes/.gitkeep diff --git a/.devcontainer/cbpi-dev-config/logs/sensors/.gitkeep b/.devcontainer/cbpi-dev-config/logs/sensors/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.devcontainer/cbpi-dev-config/recipes/.gitkeep b/.devcontainer/cbpi-dev-config/recipes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.devcontainer/cbpi-dev-config/upload/.gitkeep b/.devcontainer/cbpi-dev-config/upload/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index bb723ac..20ad518 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ node_modules .DS_Store config/* logs/ -.coverage \ No newline at end of file +.coverage +.devcontainer/cbpi-dev-config/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index c2f9637..feff4f1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,15 @@ "configurations": [ { - "name": "Run CraftBeerPi4", + "name": "setup CraftBeerPi4: create config folder structure", + "type": "python", + "request": "launch", + "module": "run", + "args": ["--config-folder-path=./.devcontainer/cbpi-dev-config", "setup"] + }, + + { + "name": "run CraftBeerPi4", "type": "python", "request": "launch", "module": "run", diff --git a/cbpi/configFolder.py b/cbpi/configFolder.py index 5741d4f..8926a91 100644 --- a/cbpi/configFolder.py +++ b/cbpi/configFolder.py @@ -1,3 +1,4 @@ +from ast import If, Try import os from os import listdir from os.path import isfile, join @@ -33,25 +34,8 @@ class ConfigFolder: return fermenter_recipe_ids def check_for_setup(self): - if self.config_file_exists("config.yaml") is False: - print("***************************************************") - print("CraftBeerPi Config File not found: %s" % self.get_file_path("config.yaml")) - print("Please run 'cbpi setup' before starting the server ") - print("***************************************************") - return False - if self.config_file_exists("upload") is False: - print("***************************************************") - print("CraftBeerPi upload folder not found: %s" % self.get_file_path("upload")) - print("Please run 'cbpi setup' before starting the server ") - print("***************************************************") - return False - # if os.path.exists(os.path.join(".", "config", "fermenterrecipes")) is False: - # print("***************************************************") - # print("CraftBeerPi fermenterrecipes folder not found: %s" % os.path.join(".", "config/fermenterrecipes")) - # print("Please run 'cbpi setup' before starting the server ") - # print("***************************************************") - # return False - backupfile = os.path.join(".", "restored_config.zip") + # is there a restored_config.zip file? if yes restore it first then delte the zip. + backupfile = os.path.join(self._rawPath, "restored_config.zip") if os.path.exists(os.path.join(backupfile)) is True: print("***************************************************") print("Found backup of config. Starting restore") @@ -75,7 +59,7 @@ class ConfigFolder: owner = output_path.owner() group = output_path.group() print("Removing old config folder") - shutil.rmtree(output_path, ignore_errors=True) + shutil.rmtree(output_path, ignore_errors=True) print("Extracting zip file to config folder") zip.extractall(output_path) zip.close() @@ -83,12 +67,79 @@ class ConfigFolder: print(f"Changing owner and group of config folder recursively to {owner}:{group}") self.recursive_chown(output_path, owner, group) print("Removing backup file") - os.remove(backupfile) + print("contents of restored_config.zip file have been restored.") + print("in case of a partial backup you will still be prompted to run 'cbpi setup'.") + # os.remove(backupfile) # since the zip was inside the config folder and the config folder was deleted 10 lines ago this file doesnt exist anymore else: print("Wrong Content in zip file. No restore possible") - print("Removing zip file") - os.remove(backupfile) + print("renaming zip file so it will be ignored on the next start") + try: + os.rename(backupfile, os.path.join(self._rawPath, "UNRESTORABLE_restored_config.zip")) + except: + print("renamed file does exist - deleting instead") + os.remove(backupfile) print("***************************************************") + # possible restored_config.zip has been handeled now lets check if files and folders exist + required_config_content = [ + ['config.yaml', 'file'], + ['actor.json', 'file'], + ['sensor.json', 'file'], + ['kettle.json', 'file'], + ['fermenter_data.json', 'file'], + ['step_data.json', 'file'], + ['config.json', 'file'], + ['craftbeerpi.service', 'file'], + ['chromium.desktop', 'file'], + ['dashboard/cbpi_dashboard_1.json', 'file'], + ['dashboard', 'folder'], + ['dashboard/widgets', 'folder'], + ['fermenterrecipes', 'folder'], + ['logs', 'folder'], + ['logs/sensors', 'folder'], + ['recipes', 'folder'], + ['upload', 'folder'] + ] + for checking in required_config_content: + if self.inform_missing_content(self.check_for_file_or_folder(os.path.join(self._rawPath, checking[0]), checking[1])): + # since there is no complete config we now check if the config folde rmay be completely empty to show hints: + if len(os.listdir(os.path.join(self._rawPath))) == 0 : + print("***************************************************") + print(f"the config folder '{self._rawPath}' seems to be completely empty") + print("you might want to run 'cbpi setup'.print") + print("but you could also place your zipped config backup named") + print("'restored_config.zip' inside the mentioned config folder for") + print("cbpi4 to automatically unpack it") + print("of course you can also place your config files manually") + print("***************************************************") + return False + + def inform_missing_content(self, whatsmissing : str): + if whatsmissing == "": + return False + print("***************************************************") + print(f"CraftBeerPi config content not found: {whatsmissing}") + print("Please run 'cbpi setup' before starting the server ") + print("***************************************************") + return True + + + def check_for_file_or_folder(self, path : str, file_or_folder : str = ""): # file_or_folder should be "file" or "folder" or "" if both is ok + if (file_or_folder == ""): # file and folder is ok + if os.path.exists(path): + return "" + else: + return "file or folder missing: " + path + if (file_or_folder == "file"): # only file is ok + if (os.path.isfile(path)): + return "" + else: + return "file missing: " + path + if (file_or_folder == "folder"): # oly folder is ok + if (os.path.isdir(path)): + return "" + else: + return "folder missing: " + path + return "usage of check_file_or_folder() function wrong. second Argument must either be 'file' or 'folder' or an empty string" def copyDefaultFileIfNotExists(self, file): if self.config_file_exists(file) is False: @@ -115,7 +166,7 @@ class ConfigFolder: print("Config Folder created") def create_home_folder_structure(configFolder): - pathlib.Path(os.path.join(".", 'logs/sensors')).mkdir(parents=True, exist_ok=True) + # pathlib.Path(os.path.join(".", 'logs/sensors')).mkdir(parents=True, exist_ok=True) configFolder.create_folders() print("Folder created") @@ -123,11 +174,18 @@ class ConfigFolder: def create_folders(self): pathlib.Path(self._rawPath).mkdir(parents=True, exist_ok=True) pathlib.Path(os.path.join(self._rawPath, 'dashboard', 'widgets')).mkdir(parents=True, exist_ok=True) + pathlib.Path(os.path.join(self._rawPath, 'logs', 'sensors')).mkdir(parents=True, exist_ok=True) pathlib.Path(os.path.join(self._rawPath, 'recipes')).mkdir(parents=True, exist_ok=True) + pathlib.Path(os.path.join(self._rawPath, 'fermenterrecipes')).mkdir(parents=True, exist_ok=True) pathlib.Path(os.path.join(self._rawPath, 'upload')).mkdir(parents=True, exist_ok=True) def recursive_chown(self, path, owner, group): - for dirpath, dirnames, filenames in os.walk(path): - shutil.chown(dirpath, owner, group) - for filename in filenames: - shutil.chown(os.path.join(dirpath, filename), owner, group) \ No newline at end of file + try: + for dirpath, dirnames, filenames in os.walk(path): + shutil.chown(dirpath, owner, group) + for filename in filenames: + shutil.chown(os.path.join(dirpath, filename), owner, group) + except: + print("problems assigning file or folder permissions") + print("if this happend on windows its fine") + print("if this happend in the dev container running inside windows its also fine but you might have to rebuild the container if you run into further problems")