Merge branch 'development' into main

This commit is contained in:
PhotoLinux 2021-05-11 09:14:39 +02:00
commit a7bf152485
6 changed files with 207 additions and 120 deletions

View file

@ -1,5 +1,19 @@
# Changelog Backuppy # Changelog Backuppy
## [0.9] - 2021-05-10
### Added
- CLI-mode: It's now possible to end the program anytime with ":q" (or ESC-key) and pressing ENTER.
- CLI-mode: Colored output on traces
- New helper script "utils.py"
### Changed
- Code refactoring (get rid of global variables and constants, instead pass as arguments)
## [0.8.1] - 2021-05-10
### Fixed
- CLI-mode: Show text "Programm interrupted by user." instead of error message when Ctrl+C was pressed.
- CLI-mode: Removed obsolete trace messages
## [0.8] - 2021-05-07 ## [0.8] - 2021-05-07
### Added ### Added
- GUI-mode: Introduce "Browse"-button on directory-selection dialogs - GUI-mode: Introduce "Browse"-button on directory-selection dialogs

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
project: Backuppy project: Backuppy
version: 0.8 version: 0.9
file: install.py file: install.py
summary: python installer-script in CLI-mode summary: python installer-script in CLI-mode
""" """
@ -9,114 +9,87 @@ summary: python installer-script in CLI-mode
# Standard library imports # Standard library imports
import sys import sys
import os import os
import time
# local imports # local imports
from languages import english from utils import set_language, query, _print, trace
from languages import german
# local globals # local globals
# ---------------------- VERSION: str = "0.9"
VERSION: str = "0.8"
EMAIL = "fotocoder@joschu.ch" EMAIL = "fotocoder@joschu.ch"
EXCLUDE_FILE = "exclude.txt" EXCLUDE_FILE = "exclude.txt"
BACKUPPY_SCRIPT = "Backuppy.sh" BACKUPPY_SCRIPT = "Backuppy.sh"
# ----------------------
MYDIR = os.getcwd()
EXCLUDE: bool = False
SHELL = os.environ.get("SHELL")
HOME = os.environ.get("HOME")
LANG_EN = "English"
LANG_DE = "German"
LANGUAGE = LANG_EN
RSYNC_CMD: str = None
def set_language(language): def main_install_cli(mydir, exclude_file):
global LANGUAGE language = query("welcome")
LANGUAGE = language if not language:
return False, None, None
set_language(language)
def trace(message_txt): _print("languagepack")
""" Print a formatted message to std out. """
print("[ OK ] " + message_txt)
def get_lang_text(search_str: str): _print("intromsg1")
global LANGUAGE
""" Returns a string from the appropriate language file. """
return_str: str = eval("english." + search_str)
if LANGUAGE == LANG_DE:
return_str = eval("german." + search_str)
return return_str
def main_install_cli(): _print("intromsg2")
language = input("Hello, first of all, which language do you prefer: German [DE] or English [EN]?\n> ")
if language.upper() == "DE":
set_language(LANG_DE)
print("Perfekt, nun ist das deutsche Sprachpaket aktiviert. Willkommen!\n")
else:
print("Perfect, the English language package is now activated. Welcome!.\n")
time.sleep(1)
print("\n" + get_lang_text("intromsg1") + "\n")
time.sleep(1)
print("\n" + get_lang_text("intromsg2") + "\n")
time.sleep(1)
# which Rsync options are available and which one you want to use # which Rsync options are available and which one you want to use
print(get_lang_text("rsyncopt") + "\n") _print("rsyncopt")
time.sleep(1)
# asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes # asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes
exclude = input(get_lang_text("excludefile1") + "\n> ") exclude = query("excludefile1")
global EXCLUDE if not exclude:
if exclude.upper() in ("J", "Y"): return False, None, None
EXCLUDE = True elif exclude.upper() in ("J", "Y"):
print(get_lang_text("excludefile2") + "\n") _print("excludefile2")
exclude = True
else: else:
EXCLUDE = False _print("excludefile3")
print(get_lang_text("excludefile3") + "\n") exclude = False
time.sleep(1)
# Asks for the source directory which should be saved # Asks for the source directory which should be saved
print(get_lang_text("srcdir1")) _print("srcdir1")
time.sleep(1) sourcedir = query("srcdir2")
sourcedir = input(get_lang_text("srcdir2") + "\n> ") if not sourcedir:
return False, None, None
print(f"{get_lang_text('srcdir3_1')} {sourcedir} {get_lang_text('srcdir3_2')}") _print("srcdir3_1")
time.sleep(1) print(sourcedir)
_print("srcdir3_2")
# asks for the destination directory in which the backup should be saved # asks for the destination directory in which the backup should be saved
targetdir = input(get_lang_text("targetdir1") + "\n> ") targetdir = query("targetdir1")
print(f"{get_lang_text('targetdir2_1')} {targetdir} {get_lang_text('targetdir2_2')}") if not targetdir:
time.sleep(1) return False, None, None
_print("targetdir2_1")
print(targetdir)
_print("targetdir2_2")
# collects all the information needed to execute the rsync command and creates it. # collects all the information needed to execute the rsync command and creates it.
print(get_lang_text("collect") + "\n") _print("collect")
time.sleep(1)
exclude_file = os.path.join(MYDIR, EXCLUDE_FILE)
RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {sourcedir} {targetdir}" rsync_cmd = f"rsync -aqp --exclude-from={os.path.join(mydir, exclude_file)} {sourcedir} {targetdir}"
print(f"{RSYNC_CMD}") print(f"{rsync_cmd}")
time.sleep(1)
# Outro # Outro
print(get_lang_text("outro1")) _print("outro1")
time.sleep(2)
print(get_lang_text("outro2") + " " + EMAIL)
return True, EXCLUDE, RSYNC_CMD _print("outro2")
print(EMAIL)
def create_exclude_file(directory, exclude_file): return True, exclude, rsync_cmd
exclude_file = os.path.join(directory, exclude_file)
def create_exclude_file(mydir, exclude_file):
exclude_file = os.path.join(mydir, exclude_file)
with open(exclude_file, "w") as fExclude: with open(exclude_file, "w") as fExclude:
trace(f"creating exclude-file '{exclude_file}'.") trace(f"creating exclude-file '{exclude_file}'.")
fExclude.write("\n") fExclude.write("\n")
def create_alias(shell, home_dir, directory, backuppy_script): def create_alias(mydir, backuppy_script):
shell = os.environ.get("SHELL")
home_dir = os.environ.get("HOME")
# alias entry in .bashrc or .zshrc # alias entry in .bashrc or .zshrc
backuppy_script = os.path.join(directory, backuppy_script) backuppy_script = os.path.join(mydir, backuppy_script)
alias_str = f"alias backuppy='sudo {backuppy_script}'" alias_str = f"alias backuppy='sudo {backuppy_script}'"
# Check for installed ZSH # Check for installed ZSH
@ -148,37 +121,32 @@ def create_backuppy_script(directory, backuppy_script, rsync_cmd):
os.chmod(backuppy_file, 0o777) # make file executable os.chmod(backuppy_file, 0o777) # make file executable
def do_the_install(is_exclude: bool, rsync_cmd: str): def do_the_install(mydir: str, exclude_file, is_exclude: bool, backuppy_script: str, rsync_cmd: str):
""" Creates scripts and entries based on environment variables. """ """ Creates scripts and entries based on environment variables. """
if is_exclude: if is_exclude:
create_exclude_file(MYDIR, EXCLUDE_FILE) create_exclude_file(mydir, exclude_file)
if rsync_cmd: if rsync_cmd:
create_backuppy_script(MYDIR, BACKUPPY_SCRIPT, rsync_cmd) create_backuppy_script(mydir, backuppy_script, rsync_cmd)
create_alias(SHELL, HOME, MYDIR, BACKUPPY_SCRIPT) create_alias(mydir, backuppy_script)
def main(argv): def main(argv):
trace(f"Starting Backuppy install.py v{VERSION}") trace(f"Starting Backuppy install.py v{VERSION}")
is_finalized = False is_finalized = False
mydir = os.getcwd()
if argv and argv[0] == "--gui": if argv and argv[0] == "--gui":
from install_gui import main_install_gui from install_gui import main_install_gui
trace("Starting GUI-version.") trace("Starting GUI-version.")
is_finalized, is_exclude, rsync_cmd = main_install_gui() # collect user input via GUI and store in env. variables is_finalized, is_exclude, rsync_cmd = main_install_gui(mydir, EXCLUDE_FILE) # collect user input via GUI and store in env. variables
else: else:
trace("Starting CLI-version.\n") trace("Starting CLI-version.\n")
is_finalized, is_exclude, rsync_cmd = main_install_cli() # collect user input via CLI and store in env. variables is_finalized, is_exclude, rsync_cmd = main_install_cli(mydir, EXCLUDE_FILE) # collect user input via CLI and store in env. variables
if is_finalized:
print("CLI finalized.")
if is_exclude:
print("exclude is true.")
if rsync_cmd:
print("rsync command returned: " + rsync_cmd)
if is_finalized: if is_finalized:
do_the_install(is_exclude, rsync_cmd) do_the_install(mydir, EXCLUDE_FILE, is_exclude, BACKUPPY_SCRIPT, rsync_cmd)
trace("Ending Backuppy install.py") trace("Ending Backuppy install.py")

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
project: Backuppy project: Backuppy
version: 0.8 version: 0.9
file: install_gui.py file: install_gui.py
summary: python installer-script in GUI-mode (needs PySide2) summary: python installer-script in GUI-mode (needs PySide2)
""" """
@ -13,12 +13,21 @@ import os
from PySide2 import QtWidgets from PySide2 import QtWidgets
# local imports # local imports
from install import * from install import EXCLUDE_FILE, EMAIL
from utils import set_language, get_lang_text, LANG_EN, LANG_DE
class BackuppyWizard(QtWidgets.QWizard): class BackuppyWizard(QtWidgets.QWizard):
def __init__(self, parent=None): def __init__(self, parent=None, mydir=os.getcwd(), exclude_file=EXCLUDE_FILE):
super().__init__(parent) super().__init__(parent)
# init instance variables
self.mydir = mydir
self.exclude_file = exclude_file
self.exclude = None
self.sourcedir = None
self.targetdir = None
self.rsync_cmd = None
self.setWindowTitle(get_lang_text("intromsg1")) self.setWindowTitle(get_lang_text("intromsg1"))
self.addPage(Page01(self)) self.addPage(Page01(self))
@ -38,11 +47,11 @@ class BackuppyWizard(QtWidgets.QWizard):
class Page01(QtWidgets.QWizardPage): class Page01(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.label = QtWidgets.QLabel("Hello, first of all, which language do you prefer: English or German?") self.label = QtWidgets.QLabel(get_lang_text("welcome"))
self.comboBox = QtWidgets.QComboBox(self) self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.addItem(LANG_EN, LANG_EN) self.comboBox.addItem(LANG_EN)
self.comboBox.addItem(LANG_DE, LANG_DE) self.comboBox.addItem(LANG_DE)
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label) layout.addWidget(self.label)
@ -50,8 +59,7 @@ class Page01(QtWidgets.QWizardPage):
self.setLayout(layout) self.setLayout(layout)
def validatePage(self): def validatePage(self):
if self.comboBox.currentText() == LANG_DE: set_language(self.comboBox.currentText())
set_language(LANG_DE)
return True return True
@ -77,6 +85,9 @@ class Page02(QtWidgets.QWizardPage):
class Page03(QtWidgets.QWizardPage): class Page03(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label = QtWidgets.QLabel() self.label = QtWidgets.QLabel()
self.groupbox = QtWidgets.QGroupBox() self.groupbox = QtWidgets.QGroupBox()
self.groupbox.setFlat(True) self.groupbox.setFlat(True)
@ -101,25 +112,26 @@ class Page03(QtWidgets.QWizardPage):
self.radio1.setChecked(True) self.radio1.setChecked(True)
def validatePage(self): def validatePage(self):
global EXCLUDE
if self.radio1.isChecked(): if self.radio1.isChecked():
EXCLUDE = True self.parent.exclude = True
else: else:
EXCLUDE = False self.parent.exclude = False
return True return True
class Page04(QtWidgets.QWizardPage): class Page04(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label = QtWidgets.QLabel() self.label = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label) layout.addWidget(self.label)
self.setLayout(layout) self.setLayout(layout)
def initializePage(self): def initializePage(self):
global EXCLUDE if self.parent.exclude:
if EXCLUDE:
self.label.setText(get_lang_text("excludefile2")) self.label.setText(get_lang_text("excludefile2"))
else: else:
self.label.setText(get_lang_text("excludefile3")) self.label.setText(get_lang_text("excludefile3"))
@ -127,6 +139,9 @@ class Page04(QtWidgets.QWizardPage):
class Page05(QtWidgets.QWizardPage): class Page05(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label1 = QtWidgets.QLabel() self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel() self.label2 = QtWidgets.QLabel()
self.efSourceDir = QtWidgets.QLineEdit() self.efSourceDir = QtWidgets.QLineEdit()
@ -154,8 +169,7 @@ class Page05(QtWidgets.QWizardPage):
self.efSourceDir.setText(dirName) self.efSourceDir.setText(dirName)
def validatePage(self): def validatePage(self):
global SOURCEDIR self.parent.sourcedir = self.efSourceDir.text()
SOURCEDIR = self.efSourceDir.text()
return True return True
@ -163,6 +177,9 @@ class Page05(QtWidgets.QWizardPage):
class Page06(QtWidgets.QWizardPage): class Page06(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label1 = QtWidgets.QLabel() self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel() self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel() self.label3 = QtWidgets.QLabel()
@ -174,7 +191,7 @@ class Page06(QtWidgets.QWizardPage):
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("srcdir3_1")) self.label1.setText(get_lang_text("srcdir3_1"))
bold_text = f"<p><strong>{SOURCEDIR}</strong></p>" bold_text = f"<p><strong>{self.parent.sourcedir}</strong></p>"
self.label2.setText(bold_text) self.label2.setText(bold_text)
self.label3.setText(get_lang_text("srcdir3_2")) self.label3.setText(get_lang_text("srcdir3_2"))
@ -182,6 +199,9 @@ class Page06(QtWidgets.QWizardPage):
class Page07(QtWidgets.QWizardPage): class Page07(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label1 = QtWidgets.QLabel() self.label1 = QtWidgets.QLabel()
self.efTargetDir = QtWidgets.QLineEdit() self.efTargetDir = QtWidgets.QLineEdit()
self.pbBrowse = QtWidgets.QPushButton("Browse") self.pbBrowse = QtWidgets.QPushButton("Browse")
@ -206,8 +226,7 @@ class Page07(QtWidgets.QWizardPage):
self.efTargetDir.setText(dirName) self.efTargetDir.setText(dirName)
def validatePage(self): def validatePage(self):
global TARGETDIR self.parent.targetdir = self.efTargetDir.text()
TARGETDIR = self.efTargetDir.text()
return True return True
@ -215,6 +234,9 @@ class Page07(QtWidgets.QWizardPage):
class Page08(QtWidgets.QWizardPage): class Page08(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label1 = QtWidgets.QLabel() self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel() self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel() self.label3 = QtWidgets.QLabel()
@ -226,15 +248,14 @@ class Page08(QtWidgets.QWizardPage):
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("targetdir2_1")) self.label1.setText(get_lang_text("targetdir2_1"))
bold_text = f"<p><strong>{TARGETDIR}</strong></p>" bold_text = f"<p><strong>{self.parent.targetdir}</strong></p>"
self.label2.setText(bold_text) self.label2.setText(bold_text)
self.label3.setText(get_lang_text("targetdir2_2")) self.label3.setText(get_lang_text("targetdir2_2"))
def validatePage(self): def validatePage(self):
global RSYNC_CMD, MYDIR, SOURCEDIR, TARGETDIR exclude_file = os.path.join(self.parent.mydir, self.parent.exclude_file)
exclude_file = os.path.join(MYDIR, EXCLUDE_FILE)
RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {SOURCEDIR} {TARGETDIR}" self.parent.rsync_cmd = f"rsync -aqp --exclude-from={exclude_file} {self.parent.sourcedir} {self.parent.targetdir}"
return True return True
@ -242,6 +263,9 @@ class Page08(QtWidgets.QWizardPage):
class Page09(QtWidgets.QWizardPage): class Page09(QtWidgets.QWizardPage):
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self.parent = parent
self.label1 = QtWidgets.QLabel() self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel() self.label2 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
@ -251,9 +275,7 @@ class Page09(QtWidgets.QWizardPage):
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("collect")) self.label1.setText(get_lang_text("collect"))
global RSYNC_CMD bold_text = f"<p><strong>{self.parent.rsync_cmd}</strong></p>"
#self.label2.setText(f"{RSYNC_CMD}")
bold_text = f"<p><strong>{RSYNC_CMD}</strong></p>"
self.label2.setText(bold_text) self.label2.setText(bold_text)
@ -274,6 +296,7 @@ class Page10(QtWidgets.QWizardPage):
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("outro1")) self.label1.setText(get_lang_text("outro1"))
self.label2.setText(get_lang_text("outro2")) self.label2.setText(get_lang_text("outro2"))
global EMAIL
urlLink = f"<a href='mailto: {EMAIL}'>{EMAIL}</a>" urlLink = f"<a href='mailto: {EMAIL}'>{EMAIL}</a>"
self.label3.setText(urlLink) self.label3.setText(urlLink)
self.label3.setOpenExternalLinks(True) self.label3.setOpenExternalLinks(True)
@ -282,14 +305,14 @@ class Page10(QtWidgets.QWizardPage):
return True return True
def main_install_gui(): def main_install_gui(mydir, exclude_file):
app = QtWidgets.QApplication() app = QtWidgets.QApplication()
wizard = BackuppyWizard() wizard = BackuppyWizard(parent=None, mydir=mydir, exclude_file=exclude_file)
wizard.show() wizard.show()
app.exec_() app.exec_()
return True, EXCLUDE, RSYNC_CMD return True, wizard.exclude, wizard.rsync_cmd
if __name__ == '__main__': if __name__ == '__main__':
is_finalized, is_exclude, rsync_cmd = main_install_gui() is_finalized, is_exclude, rsync_cmd = main_install_gui(mydir=os.getcwd(), exclude_file=EXCLUDE_FILE)

View file

@ -9,6 +9,8 @@ Yes="Yes"
No="No" No="No"
welcome="Hello, first of all, which language do you prefer: German [DE] or English [EN]?"
languagepack="Perfect, the English language package is now activated. Welcome!" languagepack="Perfect, the English language package is now activated. Welcome!"
intromsg1="Thanks for using Backuppy to make your backups!" intromsg1="Thanks for using Backuppy to make your backups!"
@ -33,7 +35,7 @@ srcdir3_2="if this path is not correct, adjust it in the file 'Backuppy.sh'."
targetdir1="Now I need to know where Backuppy should save your backups, i.e. the target directory. \n Please enter this carefully and in the same way as for the source directory." targetdir1="Now I need to know where Backuppy should save your backups, i.e. the target directory. \n Please enter this carefully and in the same way as for the source directory."
targetdir2_1="you have typed in the following destination path:" targetdir2_1="you have typed in the following destination path:"
targetdir2_2="if this path is not correct, adjust it in the file 'backuppy.sh'." targetdir2_2="if this path is not correct, adjust it in the file 'Backuppy.sh'."
collect="Now we have almost reached the end of the installer. I will now create the rsync command for you and show it to you.\n If you notice a mistake, just cancel the installer and start again from the beginning.\nNote: I recommend that you download Backuppy completely again in this case." collect="Now we have almost reached the end of the installer. I will now create the rsync command for you and show it to you.\n If you notice a mistake, just cancel the installer and start again from the beginning.\nNote: I recommend that you download Backuppy completely again in this case."

View file

@ -33,7 +33,7 @@ srcdir3_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'B
targetdir1="Nun muss ich noch wissen, wo Backuppy dein Backup ablegen soll, das Zielverzeichnis also.\nBitte tippe dieses gewissenhaft und auf die Weise wie beim Quellverzeichnis ein." targetdir1="Nun muss ich noch wissen, wo Backuppy dein Backup ablegen soll, das Zielverzeichnis also.\nBitte tippe dieses gewissenhaft und auf die Weise wie beim Quellverzeichnis ein."
targetdir2_1="du hast folgenden Zielpfad eingetippt:" targetdir2_1="du hast folgenden Zielpfad eingetippt:"
targetdir2_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'backuppy.sh' an." targetdir2_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'Backuppy.sh' an."
collect="Nun sind wir fast am Ende des Installers angelangt. Ich erstelle nun den rsync-Befehl für dich und zeige ihn\ndir nachher nochmal.\nWenn dir da etwas auffallen sollte, brich den Installer einfach ab und fange nochmal von Vorne an.\nAchtung: ich empfehle dir, Backuppy in diesem Fall nochmal komplett neu zu installieren." collect="Nun sind wir fast am Ende des Installers angelangt. Ich erstelle nun den rsync-Befehl für dich und zeige ihn\ndir nachher nochmal.\nWenn dir da etwas auffallen sollte, brich den Installer einfach ab und fange nochmal von Vorne an.\nAchtung: ich empfehle dir, Backuppy in diesem Fall nochmal komplett neu zu installieren."

80
utils.py Normal file
View file

@ -0,0 +1,80 @@
#!/usr/bin/env python3
"""
project: Backuppy
version: 0.9
file: utils.py
summary: utilities script
"""
# Standard library imports
import time
# local imports
from languages import english
from languages import german
# local globals
LANG_EN = "EN"
LANG_DE = "DE"
LANGUAGE = LANG_EN
class bcolors:
""" Define colors for the std. output to console. """
OK = '\033[92m' #GREEN
WARNING = '\033[93m' #YELLOW
ERROR = '\033[91m' #RED
RESET = '\033[0m' #RESET COLOR
def trace(message_txt, prefix_crlf=False, err=False):
""" Print a formatted message to std out.
:param "message_txt" [in] The message text that should be displayed.
:param "prefix_crlf" [in] If True, a carriage return/line feed will be done prior to the message text.
"""
if prefix_crlf:
print("\n")
if err:
print("[ " + bcolors.ERROR + "ERR" + bcolors.RESET + " ] " + message_txt)
else:
print("[ " + bcolors.OK + "OK" + bcolors.RESET + " ] " + message_txt)
def get_lang_text(search_str: str):
""" Returns a string from the appropriate language file. """
return_str: str = eval("english." + search_str)
global LANGUAGE
if LANGUAGE == LANG_DE:
return_str = eval("german." + search_str)
return return_str
def _print(message_txt: str):
print("\n" + get_lang_text(message_txt) + "\n")
time.sleep(1)
def set_language(language):
""" Set global constant "LANGUAGE" to given language ("EN"/"DE"). """
global LANGUAGE, LANG_DE, LANG_EN
if str(language) and language.upper() == LANG_DE:
LANGUAGE = LANG_DE
else:
LANGUAGE = LANG_EN
def query(question_txt: str):
try:
answer_txt = input(get_lang_text(question_txt) + "\n> ")
if not answer_txt:
answer_txt = "''"
if answer_txt.upper() == ":Q" or answer_txt == chr(27):
trace("Program exited by user-input.")
return None
except KeyboardInterrupt:
trace("Program interrupted by user.", prefix_crlf=True, err=True)
return None
return answer_txt