refactor: logger

This commit is contained in:
RedDeadDepresso
2024-07-25 16:31:54 +01:00
parent 13d47889d7
commit 844c9d368d
9 changed files with 76 additions and 96 deletions

View File

@@ -25,13 +25,10 @@ class Logger:
handler1.setFormatter(formatter) handler1.setFormatter(formatter)
self.logger.setLevel(logging.INFO) self.logger.setLevel(logging.INFO)
self.logger.addHandler(handler1) self.logger.addHandler(handler1)
self.text = ['INFO', 'SUCCESS', 'ERROR', 'SKIPPED', 'REPLACED', 'RENAMED', 'REMOVED']
# Status Text: INFO, SUCCESS, ERROR, SKIPPED, REPLACED, RENAMED, REMOVED # Status Text: INFO, SUCCESS, ERROR, SKIPPED, REPLACED, RENAMED, REMOVED
self.status = ['    INFO', '  SUCCESS', '   ERROR', self.status = ['INFO', 'SUCCESS', 'ERROR', 'WARNING', 'SKIPPED', 'REPLACED', 'RENAMED', 'REMOVED']
' SKIPPED', ' REPLACED', ' RENAMED', ' REMOVED']
# Status Color: Blue, Red, Green, Orange # Status Color: Blue, Red, Green, Orange
self.statusColor = ['#2d8cf0', '#00c12b', '#ed3f14', '#f90', '#f90', '#f90', '#f90'] self.statusColor = ['#2d8cf0', '#00c12b', '#ed3f14', '#f90', '#f90', '#f90', '#f90', '#f90']
# Status HTML: <b style="color:$color">status</b> # Status HTML: <b style="color:$color">status</b>
self.statusHtml = [ self.statusHtml = [
f'<b style="color:{_color};">{status}</b>' f'<b style="color:{_color};">{status}</b>'
@@ -58,7 +55,7 @@ class Logger:
if self.logger_signal is not None: if self.logger_signal is not None:
message = message.replace('\n', '<br>').replace(' ', '&nbsp;') message = message.replace('\n', '<br>').replace(' ', '&nbsp;')
adding = (f''' adding = (f'''
<div style="font-family: Consolas, monospace;color:{self.statusColor[level - 1]};"> <div style="font-family: Inter;color:{self.statusColor[level - 1]};">
{self.statusHtml[level - 1]} | {category} | {message} {self.statusHtml[level - 1]} | {category} | {message}
</div> </div>
''') ''')
@@ -69,10 +66,10 @@ class Logger:
def colorize(self, line): def colorize(self, line):
adding = line adding = line
for i, s in enumerate(self.text): for i, s in enumerate(self.status):
if s in line: if s in line:
adding = (f''' adding = (f'''
<div style="font-family: Consolas, monospace;color:{self.statusColor[i]};"> <div style="font-family: Inter;color:{self.statusColor[i]};">
{line} {line}
</div> </div>
@@ -113,7 +110,7 @@ class Logger:
""" """
self.__out__(category, message, 4) self.__out__(category, message, 4)
def replaced(self, category: str, message: str) -> None: def warning(self, category: str, message: str) -> None:
""" """
:param message: log message :param message: log message
@@ -121,7 +118,7 @@ class Logger:
""" """
self.__out__(category, message, 5) self.__out__(category, message, 5)
def renamed(self, category: str, message: str) -> None: def replaced(self, category: str, message: str) -> None:
""" """
:param message: log message :param message: log message
@@ -129,7 +126,7 @@ class Logger:
""" """
self.__out__(category, message, 6) self.__out__(category, message, 6)
def removed(self, category: str, message: str) -> None: def renamed(self, category: str, message: str) -> None:
""" """
:param message: log message :param message: log message
@@ -137,16 +134,27 @@ class Logger:
""" """
self.__out__(category, message, 7) self.__out__(category, message, 7)
def removed(self, category: str, message: str) -> None:
"""
:param message: log message
Output warn log
"""
self.__out__(category, message, 8)
def line(self) -> None: def line(self) -> None:
""" """
Output line Output line
""" """
# While the line print do not need wrapping, we # While the line print do not need wrapping, we
# use raw_print=True to output log to logger box # use raw_print=True to output log to logger box
self.__out__( if self.logger_signal is not None:
'<div style="font-family: Consolas, monospace;color:#2d8cf0;">--------------' self.__out__("",
'-------------------------------------------------------------' '<div style="font-family: Consolas, monospace;color:#2d8cf0;">'
'-------------------</div>', raw_print=True) '--------------------------------------------------------------------'
'</div>', raw_print=True)
else:
print('--------------------------------------------------------------------')
logger = Logger() logger = Logger()

View File

@@ -10,6 +10,7 @@ class ThreadManager:
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._script = None self._script = None
self._line = '--------------------------------------------------------------------'
def start(self): def start(self):
if self._script is not None: if self._script is not None:
@@ -28,6 +29,8 @@ class ThreadManager:
line = self._script.stdout.readline().decode('utf-8') line = self._script.stdout.readline().decode('utf-8')
if not line: if not line:
signalBus.stopSignal.emit() signalBus.stopSignal.emit()
elif line == self._line:
logger.line()
else: else:
logger.colorize(line) logger.colorize(line)

View File

@@ -2,7 +2,7 @@ import os
import re as regex import re as regex
import codecs import codecs
import shutil import shutil
from util.logger import Logger from app.common.logger import logger
class FilterConvertKKS: class FilterConvertKKS:
def __init__(self, config, file_manager): def __init__(self, config, file_manager):
@@ -33,7 +33,7 @@ class FilterConvertKKS:
card_type = 2 card_type = 2
elif data.find(b"KoiKatuCharaSun") != -1: elif data.find(b"KoiKatuCharaSun") != -1:
card_type = 3 card_type = 3
Logger.log_info(f"[{card_type}]", f"{card_path}") logger.info(f"[{card_type}]", f"{card_path}")
return card_type return card_type
def convert_kk(self, card_name, card_path, destination_path): def convert_kk(self, card_name, card_path, destination_path):
@@ -65,12 +65,12 @@ class FilterConvertKKS:
count = len(png_list) count = len(png_list)
if count > 0: if count > 0:
Logger.log_info("SCRIPT", "0: unknown / 1: kk / 2: kksp / 3: kks") logger.info("SCRIPT", "0: unknown / 1: kk / 2: kksp / 3: kks")
for png in png_list: for png in png_list:
if self.check_png(png) == 3: if self.check_png(png) == 3:
kks_card_list.append(png) kks_card_list.append(png)
else: else:
Logger.log_success("SCRIPT", f"no PNG found") logger.success("SCRIPT", f"no PNG found")
return return
count = len(kks_card_list) count = len(kks_card_list)
@@ -83,7 +83,7 @@ class FilterConvertKKS:
os.mkdir(target_folder) os.mkdir(target_folder)
if self.convert: if self.convert:
Logger.log_info("SCRIPT", f"Conversion to KK is [{self.convert}]") logger.info("SCRIPT", f"Conversion to KK is [{self.convert}]")
if not os.path.isdir(target_folder2): if not os.path.isdir(target_folder2):
os.mkdir(target_folder2) os.mkdir(target_folder2)
@@ -100,8 +100,8 @@ class FilterConvertKKS:
shutil.move(source, target) shutil.move(source, target)
if self.convert: if self.convert:
Logger.log_success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder, converted and save to [{kks_folder2}] folder") logger.success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder, converted and save to [{kks_folder2}] folder")
else: else:
Logger.log_success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder") logger.success("SCRIPT", f"[{count}] cards moved to [{kks_folder}] folder")
else: else:
Logger.log_success("SCRIPT", f"no KKS card found") logger.success("SCRIPT", f"no KKS card found")

View File

@@ -1,6 +1,6 @@
import os import os
import codecs import codecs
from util.logger import Logger from app.common.logger import logger
class InstallChara: class InstallChara:
def __init__(self, config, file_manager): def __init__(self, config, file_manager):
@@ -20,7 +20,7 @@ class InstallChara:
if data.find(b"KoiKatuChara") != -1: if data.find(b"KoiKatuChara") != -1:
if data.find(b"KoiKatuCharaSP") != -1 or data.find(b"KoiKatuCharaSun") != -1: if data.find(b"KoiKatuCharaSP") != -1 or data.find(b"KoiKatuCharaSun") != -1:
basename = os.path.basename(image_path[0]) basename = os.path.basename(image_path[0])
Logger.log_error("CHARA", f"{basename} is a KKS card") logger.error("CHARA", f"{basename} is a KKS card")
return return
self.file_manager.copy_and_paste("CHARA", image_path, self.game_path["chara"]) self.file_manager.copy_and_paste("CHARA", image_path, self.game_path["chara"])
elif data.find(b"KoiKatuClothes") != -1: elif data.find(b"KoiKatuClothes") != -1:
@@ -32,7 +32,8 @@ class InstallChara:
if folder_path is None: if folder_path is None:
folder_path = self.input_path folder_path = self.input_path
foldername = os.path.basename(folder_path) foldername = os.path.basename(folder_path)
Logger.log_msg("FOLDER", foldername) logger.line()
logger.info("FOLDER", foldername)
file_list, compressed_file_list = self.file_manager.find_all_files(folder_path) file_list, compressed_file_list = self.file_manager.find_all_files(folder_path)
for file in file_list: for file in file_list:
@@ -44,8 +45,8 @@ class InstallChara:
self.resolve_png(file) self.resolve_png(file)
case _: case _:
basename = os.path.basename(file[0]) basename = os.path.basename(file[0])
Logger.log_error("UKNOWN", f"Cannot classify {basename}") logger.error("UKNOWN", f"Cannot classify {basename}")
print("[MSG]") logger.line()
for compressed in compressed_file_list: for compressed in compressed_file_list:
extract_path = self.file_manager.extract_archive(compressed[0]) extract_path = self.file_manager.extract_archive(compressed[0])

View File

@@ -1,6 +1,7 @@
import os import os
import codecs import codecs
from util.logger import Logger from app.common.logger import logger
class RemoveChara: class RemoveChara:
def __init__(self, config, file_manager): def __init__(self, config, file_manager):
@@ -28,7 +29,7 @@ class RemoveChara:
def logic_wrapper(self): def logic_wrapper(self):
foldername = os.path.basename(self.input_path) foldername = os.path.basename(self.input_path)
Logger.log_msg("FOLDER", foldername) logger.info("FOLDER", foldername)
file_list, archive_list = self.file_manager.find_all_files(self.input_path) file_list, archive_list = self.file_manager.find_all_files(self.input_path)
for file in file_list: for file in file_list:
@@ -40,7 +41,7 @@ class RemoveChara:
self.resolve_png(file) self.resolve_png(file)
case _: case _:
pass pass
print("[MSG]") logger.line()

View File

@@ -5,7 +5,7 @@ try:
pass pass
from util.config import Config from util.config import Config
from util.logger import Logger from app.common.logger import logger
from util.file_manager import FileManager from util.file_manager import FileManager
from modules.install_chara import InstallChara from modules.install_chara import InstallChara
from modules.remove_chara import RemoveChara from modules.remove_chara import RemoveChara
@@ -21,6 +21,7 @@ try:
Args: Args:
config (Config): BAAuto Config instance config (Config): BAAuto Config instance
""" """
logger.logger_signal = None
self.config = config self.config = config
self.file_manager = file_manager self.file_manager = file_manager
self.modules = { self.modules = {
@@ -41,11 +42,11 @@ try:
def run(self): def run(self):
for task in self.config.tasks: for task in self.config.tasks:
if self.modules[task]: if self.modules[task]:
Logger.log_info("SCRIPT", f'Start Task: {task}') logger.info("SCRIPT", f'Start Task: {task}')
try: try:
self.modules[task].logic_wrapper() self.modules[task].logic_wrapper()
except: except:
Logger.log_error("SCRIPT", f'Task error: {task}. For more info, check the traceback.log file.') logger.error("SCRIPT", f'Task error: {task}. For more info, check the traceback.log file.')
with open('traceback.log', 'a') as f: with open('traceback.log', 'a') as f:
f.write(f'[{task}]\n') f.write(f'[{task}]\n')
traceback.print_exc(None, f, True) traceback.print_exc(None, f, True)

View File

@@ -1,11 +1,11 @@
import sys import sys
import json import json
import os import os
from util.logger import Logger from app.common.logger import logger
class Config: class Config:
def __init__(self, config_file): def __init__(self, config_file):
Logger.log_info("SCRIPT", "Initializing config module") logger.info("SCRIPT", "Initializing config module")
self.config_file = config_file self.config_file = config_file
self.ok = False self.ok = False
self.initialized = False self.initialized = False
@@ -20,31 +20,31 @@ class Config:
with open(self.config_file, 'r') as json_file: with open(self.config_file, 'r') as json_file:
self.config_data = json.load(json_file) self.config_data = json.load(json_file)
except FileNotFoundError: except FileNotFoundError:
Logger.log_error("SCRIPT", f"Config file '{self.config_file}' not found.") logger.error("SCRIPT", f"Config file '{self.config_file}' not found.")
sys.exit(1) sys.exit(1)
except json.JSONDecodeError: except json.JSONDecodeError:
Logger.log_error("SCRIPT", f"Invalid JSON format in '{self.config_file}'.") logger.error("SCRIPT", f"Invalid JSON format in '{self.config_file}'.")
sys.exit(1) sys.exit(1)
self.validate() self.validate()
if self.ok and not self.initialized: if self.ok and not self.initialized:
Logger.log_info("SCRIPT", "Starting KKAFIO!") logger.info("SCRIPT", "Starting KKAFIO!")
self.initialized = True self.initialized = True
self.changed = True self.changed = True
elif not self.ok and not self.initialized: elif not self.ok and not self.initialized:
Logger.log_error("SCRIPT", "Invalid config. Please check your config file.") logger.error("SCRIPT", "Invalid config. Please check your config file.")
sys.exit(1) sys.exit(1)
elif not self.ok and self.initialized: elif not self.ok and self.initialized:
Logger.log_warning("SCRIPT", "Config change detected, but with problems. Rolling back config.") logger.warning("SCRIPT", "Config change detected, but with problems. Rolling back config.")
self._rollback_config(backup_config) self._rollback_config(backup_config)
elif self.ok and self.initialized: elif self.ok and self.initialized:
if backup_config != self.__dict__: if backup_config != self.__dict__:
Logger.log_warning("SCRIPT", "Config change detected. Hot-reloading.") logger.warning("SCRIPT", "Config change detected. Hot-reloading.")
self.changed = True self.changed = True
def validate(self): def validate(self):
Logger.log_info("SCRIPT", "Validating config") logger.info("SCRIPT", "Validating config")
self.ok = True self.ok = True
self.tasks = ["CreateBackup", "FilterConvertKKS", "InstallChara", "RemoveChara"] self.tasks = ["CreateBackup", "FilterConvertKKS", "InstallChara", "RemoveChara"]
self.create_gamepath() self.create_gamepath()
@@ -56,7 +56,7 @@ class Config:
elif "OutputPath" in self.config_data[task]: elif "OutputPath" in self.config_data[task]:
path = self.config_data[task]["OutputPath"] path = self.config_data[task]["OutputPath"]
if not os.path.exists(path): if not os.path.exists(path):
Logger.log_error("SCRIPT", f"Path invalid for task {task}") logger.error("SCRIPT", f"Path invalid for task {task}")
raise Exception() raise Exception()
self.install_chara = self.config_data.get("InstallChara", {}) self.install_chara = self.config_data.get("InstallChara", {})
@@ -72,13 +72,13 @@ class Config:
"BepInEx": os.path.join(base, "BepInEx"), "BepInEx": os.path.join(base, "BepInEx"),
"mods": os.path.join(base, "mods"), "mods": os.path.join(base, "mods"),
"chara": os.path.join(base, "UserData\\chara\\female"), "chara": os.path.join(base, "UserData\\chara\\female"),
"coordinate": os.path.join(base, "UserData\coordinate"), "coordinate": os.path.join(base, "UserData\\coordinate"),
"Overlays": os.path.join(base, "UserData\Overlays") "Overlays": os.path.join(base, "UserData\\Overlays")
} }
for path in self.game_path.values(): for path in self.game_path.values():
if not os.path.exists(path): if not os.path.exists(path):
Logger.log_error("SCRIPT", "Game path not valid") logger.error("SCRIPT", "Game path not valid")
raise Exception() raise Exception()
def _deepcopy_dict(self, dictionary): def _deepcopy_dict(self, dictionary):

View File

@@ -5,7 +5,7 @@ import patoolib
import customtkinter import customtkinter
import subprocess import subprocess
import time import time
from util.logger import Logger from app.common.logger import logger
class FileManager: class FileManager:
@@ -41,11 +41,11 @@ class FileManager:
already_exists = os.path.exists(destination_path) already_exists = os.path.exists(destination_path)
if already_exists and conflicts == "Skip": if already_exists and conflicts == "Skip":
Logger.log_skipped(type, base_name) logger.skipped(type, base_name)
return return
elif already_exists and conflicts == "Replace": elif already_exists and conflicts == "Replace":
Logger.log_replaced(type, base_name) logger.replaced(type, base_name)
elif already_exists and conflicts == "Rename": elif already_exists and conflicts == "Rename":
max_retries = 3 max_retries = 3
@@ -56,7 +56,7 @@ class FileManager:
new_source_path = f"{filename}_{new_name}{file_extension}" new_source_path = f"{filename}_{new_name}{file_extension}"
os.rename(source_path, new_source_path) os.rename(source_path, new_source_path)
source_path = new_source_path source_path = new_source_path
Logger.log_renamed(type, base_name) logger.renamed(type, base_name)
filename, file_extension = os.path.splitext(destination_path) filename, file_extension = os.path.splitext(destination_path)
destination_path = f"{filename}_{new_name}{file_extension}" destination_path = f"{filename}_{new_name}{file_extension}"
@@ -65,20 +65,20 @@ class FileManager:
if attempt < max_retries - 1: if attempt < max_retries - 1:
time.sleep(1) # Wait for 1 second before retrying time.sleep(1) # Wait for 1 second before retrying
else: else:
Logger.log_error(type, f"Failed to rename {base_name} after {max_retries} attempts.") logger.error(type, f"Failed to rename {base_name} after {max_retries} attempts.")
return return
try: try:
shutil.copy(source_path, destination_path) shutil.copy(source_path, destination_path)
print(f"File copied successfully from {source_path} to {destination_path}") print(f"File copied successfully from {source_path} to {destination_path}")
if not already_exists: if not already_exists:
Logger.log_success(type, base_name) logger.success(type, base_name)
except FileNotFoundError: except FileNotFoundError:
Logger.log_error(type, f"{base_name} does not exist.") logger.error(type, f"{base_name} does not exist.")
except PermissionError: except PermissionError:
Logger.log_error(type, f"Permission denied for {base_name}") logger.error(type, f"Permission denied for {base_name}")
except Exception as e: except Exception as e:
Logger.log_error(type, f"An error occurred: {e}") logger.error(type, f"An error occurred: {e}")
def find_and_remove(self, type, source_path, destination_folder): def find_and_remove(self, type, source_path, destination_folder):
source_path = source_path[0] source_path = source_path[0]
@@ -87,15 +87,15 @@ class FileManager:
if os.path.exists(destination_path): if os.path.exists(destination_path):
try: try:
os.remove(destination_path) os.remove(destination_path)
Logger.log_removed(type, base_name) logger.removed(type, base_name)
except OSError as e: except OSError as e:
Logger.log_error(type, base_name) logger.error(type, base_name)
def create_archive(self, folders, archive_path): def create_archive(self, folders, archive_path):
# Specify the full path to the 7zip executable # Specify the full path to the 7zip executable
path_to_7zip = patoolib.util.find_program("7z") path_to_7zip = patoolib.util.find_program("7z")
if not path_to_7zip: if not path_to_7zip:
Logger.log_error("SCRIPT", "7zip not found. Unable to create backup") logger.error("SCRIPT", "7zip not found. Unable to create backup")
raise Exception() raise Exception()
if os.path.exists(archive_path+".7z"): if os.path.exists(archive_path+".7z"):
@@ -133,7 +133,7 @@ class FileManager:
# Print the output # Print the output
for line in process.stdout.decode().split('\n'): for line in process.stdout.decode().split('\n'):
if line.strip() != "": if line.strip() != "":
Logger.log_info("7-Zip", line) logger.info("7-Zip", line)
# Check the return code # Check the return code
if process.returncode not in [0, 1]: if process.returncode not in [0, 1]:
raise Exception() raise Exception()
@@ -141,7 +141,7 @@ class FileManager:
def extract_archive(self, archive_path): def extract_archive(self, archive_path):
try: try:
archive_name = os.path.basename(archive_path) archive_name = os.path.basename(archive_path)
Logger.log_info("ARCHIVE", f"Extracting {archive_name}") logger.info("ARCHIVE", f"Extracting {archive_name}")
extract_path = os.path.join(f"{os.path.splitext(archive_path)[0]}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')}") extract_path = os.path.join(f"{os.path.splitext(archive_path)[0]}_{datetime.datetime.now().strftime('%Y%m%d%H%M%S%f')}")
patoolib.extract_archive(archive_path, outdir=extract_path) patoolib.extract_archive(archive_path, outdir=extract_path)
return extract_path return extract_path
@@ -161,5 +161,5 @@ class FileManager:
except: except:
text = f"Wrong password or {archive_name} is corrupted. Please enter password again or click Cancel" text = f"Wrong password or {archive_name} is corrupted. Please enter password again or click Cancel"
Logger.log_skipped("ARCHIVE", archive_name) logger.skipped("ARCHIVE", archive_name)

View File

@@ -1,34 +0,0 @@
class Logger(object):
@classmethod
def log_msg(cls, type, msg):
print(f"[MSG][{type}] {msg}")
@classmethod
def log_success(cls, type, msg):
print(f"[SUCCESS][{type}] {msg}")
@classmethod
def log_skipped(cls, type, msg):
print(f"[SKIPPED][{type}] {msg}")
@classmethod
def log_replaced(cls, type, msg):
print(f"[REPLACED][{type}] {msg}")
@classmethod
def log_renamed(cls, type, msg):
print(f"[RENAMED][{type}] {msg}")
@classmethod
def log_removed(cls, type, msg):
print(f"[REMOVED][{type}] {msg}")
@classmethod
def log_error(cls, type, msg):
print(f"[ERROR][{type}] {msg}")
@classmethod
def log_info(cls, type, msg):
print(f"[INFO][{type}] {msg}")