adds --logs-folder-path as cli option

This commit is contained in:
prash3r 2022-09-12 21:54:51 +02:00
parent 4952861a58
commit c56d7ccc51
5 changed files with 56 additions and 38 deletions

View file

@ -9,6 +9,7 @@ import os
import pkgutil import pkgutil
import shutil import shutil
import click import click
import pathlib
from subprocess import call from subprocess import call
from colorama import Fore, Back, Style from colorama import Fore, Back, Style
import importlib import importlib
@ -16,6 +17,7 @@ from importlib_metadata import metadata
from tabulate import tabulate from tabulate import tabulate
from PyInquirer import prompt, print_json from PyInquirer import prompt, print_json
import platform import platform
import subprocess
class CraftBeerPiCli(): class CraftBeerPiCli():
def __init__(self, config) -> None: def __init__(self, config) -> None:
@ -226,24 +228,37 @@ class CraftBeerPiCli():
@click.group() @click.group()
@click.pass_context @click.pass_context
@click.option('--config-folder-path', '-c', default="./config", type=click.Path(), help="Specify where the config folder is located. Defaults to './config'.") @click.option('--config-folder-path', '-c', default="./config", type=click.Path(), help="Specify where the config folder is located. Defaults to './config'.")
def main(context, config_folder_path): @click.option('--logs-folder-path', '-l', default="", type=click.Path(), help="Specify where the log folder is located. Defaults to '../logs' relative from the config folder.")
@click.option('--debug-log-level', '-d', default="30", type=int, help="Specify the log level you want to write to all logs. 0=ALL, 10=DEBUG, 20=INFO 30(default)=WARNING, 40=ERROR, 50=CRITICAL")
def main(context, config_folder_path, logs_folder_path, debug_log_level):
print("---------------------") print("---------------------")
print("Welcome to CBPi") print("Welcome to CBPi")
print("---------------------") print("---------------------")
level = logging.INFO if logs_folder_path == "":
logger = logging.getLogger() logs_folder_path = os.path.join(Path(config_folder_path).absolute().parent, 'logs')
logger.setLevel(level)
try:
logger.addHandler(logging.handlers.RotatingFileHandler(os.path.join(Path(config_folder_path).parent, 'logs', f"cbpi.log"), maxBytes=1000000, backupCount=3))
except:
print("there seems to be no log folder - continueing without (maybe you should run 'cbpi setup')")
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s') formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(name)s - %(message)s')
for handler in logger.handlers: logging.basicConfig(format=formatter,level=debug_log_level, stream=logging.StreamHandler())
handler.setLevel(level) logger = logging.getLogger()
handler.setFormatter(formatter) try:
cbpi_cli = CraftBeerPiCli(ConfigFolder(config_folder_path)) result = subprocess.run(['journalctl', '--since', '2 hours ago', '-u', 'craftbeerpi.service' ], stdout=subprocess.PIPE)
# journalctl is present, we assume we are running in production.
# We therefore omit the timestamp from the stdout log handler formatter because timestamps are added to the logs by journalctl anyway
logger.handlers[0].setFormatter('%(levelname)s - %(name)s - %(message)s')
except:
# journalctl command seems to not be present.
# We assume we are in the dev container and keep writing timestampts to stdout for vscode terminal output
logger.warning("journalctl command error - assuming dev container execution and writing timestamps to stdout")
try:
if not os.path.isdir(logs_folder_path):
logger.info(f"logs folder '{logs_folder_path}' doesnt exist and we are trying to create it")
pathlib.Path(logs_folder_path).mkdir(parents=True, exist_ok=True)
logger.info(f"logs folder '{logs_folder_path}' successfully created")
logger.addHandler(logging.handlers.RotatingFileHandler(os.path.join(logs_folder_path, f"cbpi.log"), maxBytes=1000000, backupCount=3))
except Exception as e:
logger.warning("log folder or log file could not be created or accessed. check folder and file permissions or create the logs folder somewhere you have access with a start option like '--log-folder-path=./logs'")
logging.critical(e, exc_info=True)
cbpi_cli = CraftBeerPiCli(ConfigFolder(config_folder_path, logs_folder_path))
context.obj = cbpi_cli context.obj = cbpi_cli
pass
@main.command() @main.command()
@click.pass_context @click.pass_context

View file

@ -6,36 +6,39 @@ import pathlib
import platform import platform
import shutil import shutil
import zipfile import zipfile
from pathlib import Path
import glob import glob
class ConfigFolder: class ConfigFolder:
def __init__(self, configFolderPath): def __init__(self, configFolderPath, logsFolderPath):
self._rawPath = configFolderPath self.configFolderPath = configFolderPath
self.logsFolderPath = logsFolderPath
self.logger.info("Config folder path : " + os.path.join(Path(self.cbpi.config_folder.configFolderPath).absolute()))
def config_file_exists(self, path): def config_file_exists(self, path):
return os.path.exists(self.get_file_path(path)) return os.path.exists(self.get_file_path(path))
def get_file_path(self, file): def get_file_path(self, file):
return os.path.join(self._rawPath, file) return os.path.join(self.configFolderPath, file)
def get_upload_file(self, file): def get_upload_file(self, file):
return os.path.join(self._rawPath, 'upload', file) return os.path.join(self.configFolderPath, 'upload', file)
def get_recipe_file_by_id(self, recipe_id): def get_recipe_file_by_id(self, recipe_id):
return os.path.join(self._rawPath, 'recipes', "{}.yaml".format(recipe_id)) return os.path.join(self.configFolderPath, 'recipes', "{}.yaml".format(recipe_id))
def get_fermenter_recipe_by_id(self, recipe_id): def get_fermenter_recipe_by_id(self, recipe_id):
return os.path.join(self._rawPath, 'fermenterrecipes', "{}.yaml".format(recipe_id)) return os.path.join(self.configFolderPath, 'fermenterrecipes', "{}.yaml".format(recipe_id))
def get_all_fermenter_recipes(self): def get_all_fermenter_recipes(self):
fermenter_recipes_folder = os.path.join(self._rawPath, 'fermenterrecipes') fermenter_recipes_folder = os.path.join(self.configFolderPath, 'fermenterrecipes')
fermenter_recipe_ids = [os.path.splitext(f)[0] for f in listdir(fermenter_recipes_folder) if isfile(join(fermenter_recipes_folder, f)) and f.endswith(".yaml")] fermenter_recipe_ids = [os.path.splitext(f)[0] for f in listdir(fermenter_recipes_folder) if isfile(join(fermenter_recipes_folder, f)) and f.endswith(".yaml")]
return fermenter_recipe_ids return fermenter_recipe_ids
def check_for_setup(self): def check_for_setup(self):
# is there a restored_config.zip file? if yes restore it first then delte the 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") backupfile = os.path.join(self.configFolderPath, "restored_config.zip")
if os.path.exists(os.path.join(backupfile)) is True: if os.path.exists(os.path.join(backupfile)) is True:
print("***************************************************") print("***************************************************")
print("Found backup of config. Starting restore") print("Found backup of config. Starting restore")
@ -52,7 +55,7 @@ class ConfigFolder:
if zip_content == True: if zip_content == True:
print("Found correct content. Starting Restore process") print("Found correct content. Starting Restore process")
output_path = pathlib.Path(self._rawPath) output_path = pathlib.Path(self.configFolderPath)
system = platform.system() system = platform.system()
print(system) print(system)
if system != "Windows": if system != "Windows":
@ -73,7 +76,7 @@ class ConfigFolder:
print("Wrong Content in zip file. No restore possible") print("Wrong Content in zip file. No restore possible")
print("renaming zip file so it will be ignored on the next start") print("renaming zip file so it will be ignored on the next start")
try: try:
os.rename(backupfile, os.path.join(self._rawPath, "UNRESTORABLE_restored_config.zip")) os.rename(backupfile, os.path.join(self.configFolderPath, "UNRESTORABLE_restored_config.zip"))
except: except:
print("renamed file does exist - deleting instead") print("renamed file does exist - deleting instead")
os.remove(backupfile) os.remove(backupfile)
@ -98,11 +101,11 @@ class ConfigFolder:
['upload', 'folder'] ['upload', 'folder']
] ]
for checking in required_config_content: 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])): if self.inform_missing_content(self.check_for_file_or_folder(os.path.join(self.configFolderPath, checking[0]), checking[1])):
# since there is no complete config we now check if the config folde rmay be completely empty to show hints: # 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 : if len(os.listdir(os.path.join(self.configFolderPath))) == 0 :
print("***************************************************") print("***************************************************")
print(f"the config folder '{self._rawPath}' seems to be completely empty") print(f"the config folder '{self.configFolderPath}' seems to be completely empty")
print("you might want to run 'cbpi setup'.print") print("you might want to run 'cbpi setup'.print")
print("but you could also place your zipped config backup named") print("but you could also place your zipped config backup named")
print("'restored_config.zip' inside the mentioned config folder for") print("'restored_config.zip' inside the mentioned config folder for")
@ -142,7 +145,7 @@ class ConfigFolder:
def copyDefaultFileIfNotExists(self, file): def copyDefaultFileIfNotExists(self, file):
if self.config_file_exists(file) is False: if self.config_file_exists(file) is False:
srcfile = os.path.join(os.path.dirname(__file__), "config", file) srcfile = os.path.join(os.path.dirname(__file__), "config", file)
destfile = os.path.join(self._rawPath, file) destfile = os.path.join(self.configFolderPath, file)
shutil.copy(srcfile, destfile) shutil.copy(srcfile, destfile)
def create_config_file(self): def create_config_file(self):
@ -156,9 +159,9 @@ class ConfigFolder:
self.copyDefaultFileIfNotExists("craftbeerpi.service") self.copyDefaultFileIfNotExists("craftbeerpi.service")
self.copyDefaultFileIfNotExists("chromium.desktop") self.copyDefaultFileIfNotExists("chromium.desktop")
if os.path.exists(os.path.join(self._rawPath, "dashboard", "cbpi_dashboard_1.json")) is False: if os.path.exists(os.path.join(self.configFolderPath, "dashboard", "cbpi_dashboard_1.json")) is False:
srcfile = os.path.join(os.path.dirname(__file__), "config", "dashboard", "cbpi_dashboard_1.json") srcfile = os.path.join(os.path.dirname(__file__), "config", "dashboard", "cbpi_dashboard_1.json")
destfile = os.path.join(self._rawPath, "dashboard") destfile = os.path.join(self.configFolderPath, "dashboard")
shutil.copy(srcfile, destfile) shutil.copy(srcfile, destfile)
print("Config Folder created") print("Config Folder created")
@ -168,12 +171,12 @@ class ConfigFolder:
print("Folder created") print("Folder created")
def create_folders(self): def create_folders(self):
pathlib.Path(self._rawPath).mkdir(parents=True, exist_ok=True) pathlib.Path(self.configFolderPath).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.configFolderPath, 'dashboard', 'widgets')).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(self._rawPath, '..','logs')).mkdir(parents=True, exist_ok=True) #pathlib.Path(os.path.join(self.configFolderPath, '..','logs')).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.configFolderPath, '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.configFolderPath, 'fermenterrecipes')).mkdir(parents=True, exist_ok=True)
pathlib.Path(os.path.join(self._rawPath, 'upload')).mkdir(parents=True, exist_ok=True) pathlib.Path(os.path.join(self.configFolderPath, 'upload')).mkdir(parents=True, exist_ok=True)
def recursive_chown(self, path, owner, group): def recursive_chown(self, path, owner, group):
try: try:

View file

@ -17,7 +17,7 @@ class ConfigController:
self.cbpi.register(self) self.cbpi.register(self)
self.path = cbpi.config_folder.get_file_path("config.json") self.path = cbpi.config_folder.get_file_path("config.json")
self.path_static = cbpi.config_folder.get_file_path("config.yaml") self.path_static = cbpi.config_folder.get_file_path("config.yaml")
self.logger.info("Config folder path : " + os.path.join(Path(self.cbpi.config_folder._rawPath).absolute())) self.logger.info("Config folder path : " + os.path.join(Path(self.cbpi.config_folder.configFolderPath).absolute()))
def get_state(self): def get_state(self):

View file

@ -26,7 +26,7 @@ class LogController:
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.configuration = False self.configuration = False
self.datalogger = {} self.datalogger = {}
self.logsFolderPath = os.path.join(Path(self.cbpi.config_folder._rawPath).parent.absolute(), 'logs') self.logsFolderPath = self.cbpi.config_folder.logsFolderPath
self.logger.info("Log folder path : " + self.logsFolderPath) self.logger.info("Log folder path : " + self.logsFolderPath)
def log_data(self, name: str, value: str) -> None: def log_data(self, name: str, value: str) -> None:

View file

@ -116,7 +116,7 @@ class SystemController:
try: try:
content = backup_file.read() content = backup_file.read()
if backup_file and self.allowed_file(filename, 'zip'): if backup_file and self.allowed_file(filename, 'zip'):
self.path = os.path.join(self.cbpi.config_folder._rawPath, "restored_config.zip") self.path = os.path.join(self.cbpi.config_folder.configFolderPath, "restored_config.zip")
f=open(self.path, "wb") f=open(self.path, "wb")
f.write(content) f.write(content)