Compare commits

...

21 commits

Author SHA1 Message Date
Paul S eb8e536617 check if user paths from user-input exists and differs
- CLI-mode: check if user paths from user-input exists
- CLI-mode: prevent identical source and target path
2021-05-11 19:08:56 +02:00
Paul S f9dc51340c check if user paths from user-input exists and differ
- CLI-mode: check if user paths from user-input exists
- CLI-mode: prevent identical source and target path
2021-05-11 19:07:21 +02:00
Paul S 543a0e59f1 Disable always gui mode for production release 2021-05-10 18:53:34 +02:00
Paul S c7180d5863 Refactoring, color-mode, :q and ESC key
## [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)
2021-05-10 18:49:30 +02:00
Paul S 87ee1f2064 Created helper scripts "utils.py" 2021-05-10 18:48:11 +02:00
Paul S edb10d9a54 Fix typos 2021-05-10 18:47:31 +02:00
Paul S 45535d7ff5 Set version to 0.8.1 2021-05-10 14:00:27 +02:00
Paul S b24dabf203 Show message on Ctrl+C
- CLI-mode: Show text "Programm interrupted by user." instead of error message when Ctrl+C was pressed.
- CLI-mode: Removed obsolete trace messages
2021-05-10 11:29:40 +02:00
Paul S 21f6b4b3ac Added install instructions for Fedora and openSUSE 2021-05-07 17:35:08 +02:00
Paul S d8e953bf05 Update CHANGELOG.md 2021-05-07 16:26:33 +02:00
Paul S a336776904 Removed note about removing alias 2021-05-07 16:12:42 +02:00
Paul S 3423502e68 Fixed typos, simplified dependencies-section 2021-05-07 13:38:08 +02:00
Paul S 5852ac6b62 Installing necessary PySide2 package for GUI-mode 2021-05-07 13:16:13 +02:00
Paul S 8e7afcedce Return values for main-function 2021-05-07 13:15:20 +02:00
Paul S 845b7e9c9a "Browse"-button on directory-selection dialogs 2021-05-07 12:08:33 +02:00
Paul S a1c5fbf7ea Reworked "install.sh" to call "install.py"
- Reworked "install.sh" to call "install.py"
- All the functionality in "install.py"
- Launches graphical installer when called with "--gui" option: "install.sh --gui"
2021-05-06 19:40:07 +02:00
Paul S a8199debc9 Added TO-DO
check user-input for validity
2021-05-06 15:47:58 +02:00
Paul S 5d367fa1a8 Write alias only if not already existing 2021-05-06 15:14:50 +02:00
Paul S 1dfe37a970 Ported shell script "install.sh" to Python 2021-05-06 12:40:12 +02:00
PhotoLinux e3bccb0715 deleted backupp.py
deleted backup.py because we don't need it anymore.
2021-05-05 19:15:25 +02:00
Paul S 00fa691116 Renamed "changelog.MD" to "CHANGELOG.md" 2021-05-05 17:54:06 +02:00
9 changed files with 417 additions and 507 deletions

View file

@ -1,6 +1,39 @@
# Changelog Backuppy # Changelog Backuppy
## [1.02.000] - 2021-05-05 ## [0.10] - 2021-05-11
### Added
- CLI-mode: check if user paths from user-input exists
- CLI-mode: prevent identical source and target path
## [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
### Added
- GUI-mode: Introduce "Browse"-button on directory-selection dialogs
- GUI-mode: Installing necessary PySide2 package if not existing
## [0.7] - 2021-05-06
### Added
- Reworked "install.sh" to call "install.py"
- Launches graphical installer when called with "--gui" option: "install.sh --gui"
## [0.6] - 2021-05-06
### Added
- Write alias to Backuppy.sh into .bashrc/.zshrc only if not already existing
## [0.5.2] - 2021-05-05
### Added ### Added
- Now fully functional as the shell version - Now fully functional as the shell version
@ -11,11 +44,11 @@
### Fixed ### Fixed
- Fixed problem with the Bash/ZSH config - Fixed problem with the Bash/ZSH config
## [1.01.001] - 2021-05-04 ## [0.5.1] - 2021-05-04
### Changed ### Changed
- Use E-MAIL constant - Use E-MAIL constant
## [1.01.000] - 2021-05-04 ## [0.5] - 2021-05-04
### Added ### Added
- Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python) - Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python)
- Changelog.MD - Changelog.MD

View file

@ -6,9 +6,9 @@ Name: Backuppy
Description: Make daily backups with Backuppy to avoid losing your data. Description: Make daily backups with Backuppy to avoid losing your data.
Installation: execute `chmod +x install.sh && .\install.sh` Installation: execute `chmod +x install.sh && ./install.sh`
Install. GUI: execute `chmod +x install.sh && .\install.sh --gui` Install. GUI: execute `chmod +x install.sh && ./install.sh --gui`
Usage: execute `backuppy` Usage: execute `backuppy`
@ -16,32 +16,32 @@ Author: Joël Schurter
Licence: GPL3 Licence: GPL3
More infos: see constants and README.md More infos: See README.md and CHANGELOG.md
# ToDo # ToDo
- add a log-file for the rsync errors - add a log-file for the rsync errors
- check user-input for validity
# Dependencies # Dependencies
- rsync (because Backuppy makes its backups with rsync) - rsync (because Backuppy makes its backups with rsync)
execute `sudo apt install rsync` on Debian/Ubuntu
execute `sudo pacman -S rsync` on Arch/Manjaro execute `sudo pacman -S rsync` on Arch/Manjaro
execute `sudo apt install rsync` on Debian/Ubuntu
execute `sudo dnf install rsync` on Fedora
execute `sudo zypper install rsync` on openSUSE
# Dependencies for the graphical installer: # Dependencies for the graphical installer:
- pip (the python package manager) - pip (the python package manager)
execute `sudo pacman -S pip` on Arch/Manjaro
execute `sudo apt install python3-pip` on Debian/Ubuntu execute `sudo apt install python3-pip` on Debian/Ubuntu
execute `sudo pacman -S pip` on Arch/Manjaro
- pip package 'PySide2'
execute `pip3 install pyside2` on Debian/Ubuntu execute `sudo dnf install pip` on Fedora
execute `pip install pyside2` on Arch/Manjaro execute `sudo zypper install python3-pip` on openSUSE
# IMPORTANT
You have to remove the "backuppy" alias in your .bashrc or .zshrc before reinstall Backuppy.

View file

@ -1,21 +0,0 @@
# Changelog Backuppy
## [1.01.001] - 2021-05-04
### Changed
- Use E-MAIL constant
## [1.01.000] - 2021-05-04
### Added
- Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python)
- Changelog.MD
### Changed
- Directory ".languages" renamed to "languages" due to python module import syntax constraints
- Files "english.txt" and "german.txt" renamed to .-py due to follow the python filename schema
# Changelog Backuppy
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

View file

@ -1,336 +1,158 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
project: Backuppy project: Backuppy
version: 1.02.000 version: 0.10
file: install.py file: install.py
summary: main entry python file summary: python installer-script in CLI-mode
""" """
# Standard library imports # Standard library imports
import sys
import os import os
# Third party imports
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtCore, QtWidgets
# local imports # local imports
from languages import english from utils import set_language, query, query_path, _print, trace, paths_are_identical
from languages import german
# local globals # local globals
VERSION: str = "1.02.000" VERSION: str = "0.10"
EMAIL: str = "fotocoder@joschu.ch" EMAIL = "fotocoder@joschu.ch"
TARGET_SCRIPT: str = "Backuppy.sh" EXCLUDE_FILE = "exclude.txt"
EXCLUDE_FILE: str = "exclude.txt" BACKUPPY_SCRIPT = "Backuppy.sh"
LANG_EN: str = "English"
LANG_DE: str = "German"
LANGUAGE: str = LANG_EN
MYDIR: str = os.environ.get("mydir")
if not MYDIR:
MYDIR = os.getcwd()
SOURCEDIR: str = None
EXCLUDE: bool = True
TARGETDIR: str = None
RSYNC_CMD: str = None
def get_lang_text(search_str: str): def main_install_cli(mydir, exclude_file):
""" Returns a string from the appropriate language file. """ language = query("welcome")
return_str: str = eval("english." + search_str) if not language:
global LANGUAGE return False, None, None
if LANGUAGE == LANG_DE: set_language(language)
return_str = eval("german." + search_str)
return return_str
def trace(message_txt: str): _print("languagepack")
""" Print a formatted message to std out. """
print(f"[ OK ]", message_txt)
class BackuppyWizard(QtWidgets.QWizard): _print("intromsg1")
def __init__(self, parent=None):
super().__init__(parent)
self.addPage(Page01(self)) _print("intromsg2")
self.addPage(Page02(self))
self.addPage(Page03(self))
self.addPage(Page04(self))
self.addPage(Page05(self))
self.addPage(Page06(self))
self.addPage(Page07(self))
self.addPage(Page08(self))
self.addPage(Page09(self))
self.addPage(Page10(self))
self.setWindowTitle(english.intromsg1)
self.resize(640, 480)
class Page01(QtWidgets.QWizardPage): # which Rsync options are available and which one you want to use
def __init__(self, parent=None): _print("rsyncopt", wait=2)
super().__init__(parent)
self.label = QtWidgets.QLabel("Hello, first of all, which language do you prefer: English or German?")
# self.comboBox = QIComboBox(self)
self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.addItem(LANG_EN, LANG_EN)
self.comboBox.addItem(LANG_DE, LANG_DE)
layout = QtWidgets.QVBoxLayout() # asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes
layout.addWidget(self.label) exclude = query("excludefile1")
layout.addWidget(self.comboBox) if not exclude:
self.setLayout(layout) return False, None, None
elif exclude.upper() in ("J", "Y"):
_print("excludefile2")
exclude = True
else:
_print("excludefile3")
exclude = False
def validatePage(self): # Asks for the source directory which should be saved
global LANGUAGE _print("srcdir1")
if self.comboBox.currentText() == LANG_DE: sourcedir = query_path("srcdir2")
LANGUAGE = LANG_DE if not sourcedir:
else: return False, None, None
LANGUAGE = LANG_EN
return True
#_print("srcdir3_1")
#print(sourcedir)
_print("srcdir3_2")
class Page02(QtWidgets.QWizardPage): # asks for the destination directory in which the backup should be saved
def __init__(self, parent=None): targetdir = query_path("targetdir1")
super().__init__(parent) while paths_are_identical(sourcedir, targetdir):
self.label1 = QtWidgets.QLabel() _print("paths_must_differ")
self.label2 = QtWidgets.QLabel() targetdir = query_path("targetdir1")
if not targetdir:
return False, None, None
layout = QtWidgets.QVBoxLayout() #_print("targetdir2_1")
layout.addWidget(self.label1) #print(targetdir)
layout.addWidget(self.label2) _print("targetdir2_2")
self.setLayout(layout)
def initializePage(self): # collects all the information needed to execute the rsync command and creates it.
self.label1.setText(get_lang_text("languagepack")) _print("collect", wait=2)
self.label2.setText(get_lang_text("intromsg2"))
rsync_cmd = f"rsync -aqp --exclude-from={os.path.join(mydir, exclude_file)} {sourcedir} {targetdir}"
class Page03(QtWidgets.QWizardPage): print(f"{rsync_cmd}")
def __init__(self, parent=None):
super().__init__(parent)
self.label = QtWidgets.QLabel()
self.groupbox = QtWidgets.QGroupBox()
self.groupbox.setFlat(True)
self.radio1 = QtWidgets.QRadioButton()
self.radio2 = QtWidgets.QRadioButton()
vbox = QtWidgets.QVBoxLayout() # Outro
vbox.addWidget(self.radio1) _print("outro1", wait=2)
vbox.addWidget(self.radio2)
vbox.addStretch(1)
self.groupbox.setLayout(vbox)
layout = QtWidgets.QVBoxLayout() _print("outro2")
layout.addWidget(self.label) print(EMAIL)
layout.addWidget(self.groupbox)
self.setLayout(layout)
def initializePage(self): return True, exclude, rsync_cmd
self.label.setText(get_lang_text("excludefile1"))
self.radio1.setText(get_lang_text("Yes"))
self.radio2.setText(get_lang_text("No"))
self.radio1.setChecked(True)
def validatePage(self): def create_exclude_file(mydir, exclude_file):
global EXCLUDE exclude_file = os.path.join(mydir, exclude_file)
if self.radio1.isChecked(): with open(exclude_file, "w") as fExclude:
EXCLUDE = True trace(f"creating exclude-file '{exclude_file}'.")
else: fExclude.write("\n")
EXCLUDE = False
return True
class Page04(QtWidgets.QWizardPage): def create_alias(mydir, backuppy_script):
def __init__(self, parent=None): shell = os.environ.get("SHELL")
super().__init__(parent) home_dir = os.environ.get("HOME")
self.label = QtWidgets.QLabel() # alias entry in .bashrc or .zshrc
layout = QtWidgets.QVBoxLayout() backuppy_script = os.path.join(mydir, backuppy_script)
layout.addWidget(self.label) alias_str = f"alias backuppy='sudo {backuppy_script}'"
self.setLayout(layout)
def initializePage(self):
global EXCLUDE
if EXCLUDE:
self.label.setText(get_lang_text("excludefile2"))
else:
self.label.setText(get_lang_text("excludefile3"))
class Page05(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.edit = QtWidgets.QLineEdit()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.label2)
layout.addWidget(self.edit)
self.setLayout(layout)
def initializePage(self):
self.label1.setText(get_lang_text("srcdir1"))
self.label2.setText(get_lang_text("srcdir2"))
def validatePage(self):
global SOURCEDIR
SOURCEDIR = self.edit.text()
return True
class Page06(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.label2)
layout.addWidget(self.label3)
self.setLayout(layout)
def initializePage(self):
self.label1.setText(get_lang_text("srcdir3_1"))
bold_text = f"<p><strong>{SOURCEDIR}</strong></p>"
self.label2.setText(bold_text)
self.label3.setText(get_lang_text("srcdir3_2"))
class Page07(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.edit = QtWidgets.QLineEdit()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.edit)
self.setLayout(layout)
def initializePage(self):
self.label1.setText(get_lang_text("targetdir1"))
def validatePage(self):
global TARGETDIR
TARGETDIR = self.edit.text()
return True
class Page08(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.label2)
layout.addWidget(self.label3)
self.setLayout(layout)
def initializePage(self):
self.label1.setText(get_lang_text("targetdir2_1"))
bold_text = f"<p><strong>{TARGETDIR}</strong></p>"
self.label2.setText(bold_text)
self.label3.setText(get_lang_text("targetdir2_2"))
def validatePage(self):
global RSYNC_CMD, MYDIR, SOURCEDIR, TARGETDIR
RSYNC_CMD = f"rsync -aqp --exclude-from={MYDIR}/exclude.txt {SOURCEDIR} {TARGETDIR}"
return True
class Page09(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.label2)
self.setLayout(layout)
def initializePage(self):
self.label1.setText(get_lang_text("collect"))
global RSYNC_CMD
#self.label2.setText(f"{RSYNC_CMD}")
bold_text = f"<p><strong>{RSYNC_CMD}</strong></p>"
self.label2.setText(bold_text)
class Page10(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1)
layout.addWidget(self.label2)
layout.addWidget(self.label3)
self.setLayout(layout)
self.setFinalPage(True)
def initializePage(self):
self.label1.setText(get_lang_text("outro1"))
self.label2.setText(get_lang_text("outro2"))
urlLink = f"<a href='mailto: {EMAIL}'>{EMAIL}</a>"
self.label3.setText(urlLink)
self.label3.setOpenExternalLinks(True)
def validatePage(self):
# create shell script with rsync command
create_shell_script(RSYNC_CMD)
return True
def create_shell_script(command_str: str):
rc_filepath: str = None
global MYDIR, EXCLUDE, TARGET_SCRIPT
TARGET_SCRIPT = os.path.join(MYDIR, TARGET_SCRIPT)
ALIAS_STR = f"alias backuppy='sudo {TARGET_SCRIPT}'"
current_shell = os.environ.get("SHELL")
user_home = os.environ.get("HOME")
## STEP 1: update shell config scripts with alias for backuppy
# .zshrc case1 and case2
if current_shell in ("/usr/bin/zsh", "/bin/zsh"):
# Appending to bash config file
rc_filepath = os.path.join(user_home, ".zshrc")
# .bashrc case1 and case2
elif current_shell in ("/usr/bin/bash", "/bin/bash"):
# Appending to zsh config file
rc_filepath = os.path.join(user_home, ".bashrc")
# Check for installed ZSH
if shell.upper().find("ZSH") > 0:
rc_filepath = os.path.join(home_dir, ".zshrc")
# Check for installed BASH
if shell.upper().find("BASH") > 0:
rc_filepath = os.path.join(home_dir, ".bashrc")
# Append our alias if not already existing
if os.path.isfile(rc_filepath): if os.path.isfile(rc_filepath):
with open(rc_filepath, 'a') as file1: fileRc = open(rc_filepath, "r") # open file in read mode
trace(f"Writing {ALIAS_STR} to config file '{rc_filepath}'.") backuppy_entry_exists = False
file1.write("\n# Following line was created by Backuppy\n" + ALIAS_STR + "\n") for line in fileRc:
if "alias backuppy=" in line:
backuppy_entry_exists = True
break
if not backuppy_entry_exists:
trace(f"Writing {alias_str} to config file '{rc_filepath}'.")
fileRc = open(rc_filepath, "a") # open file in append mode
fileRc.write("\n# Following line was created by Backuppy\n" + alias_str + "\n")
fileRc.close()
## STEP 2: Create the exclude script if desired def create_backuppy_script(directory, backuppy_script, rsync_cmd):
if EXCLUDE: # creates the file 'Backuppy.sh'
global EXCLUDE_FILE backuppy_file = os.path.join(directory, backuppy_script)
EXCLUDE_FILE = os.path.join(MYDIR, EXCLUDE_FILE) with open(backuppy_file, "w") as fBackuppy:
with open(EXCLUDE_FILE, "w") as file2: trace(f"creating backuppy-file '{backuppy_file}'.")
trace(f"creating exclude-file '{EXCLUDE_FILE}'.") fBackuppy.write("#!/bin/bash\n" + rsync_cmd + "\n")
file2.writelines("\n")
os.chmod(backuppy_file, 0o777) # make file executable
## STEP 3: enter the rsync command in Backuppy.sh def do_the_install(mydir: str, exclude_file, is_exclude: bool, backuppy_script: str, rsync_cmd: str):
with open(TARGET_SCRIPT, "w") as file3: """ Creates scripts and entries based on environment variables. """
trace(f"Writing rsync-command to file '{TARGET_SCRIPT}':\n {command_str}")
file3.writelines("#!/bin/bash" + "\n")
file3.writelines(command_str + "\n")
if is_exclude:
create_exclude_file(mydir, exclude_file)
if __name__ == '__main__': if rsync_cmd:
create_backuppy_script(mydir, backuppy_script, rsync_cmd)
create_alias(mydir, backuppy_script)
def main(argv):
trace(f"Starting Backuppy install.py v{VERSION}") trace(f"Starting Backuppy install.py v{VERSION}")
app = QtWidgets.QApplication() is_finalized = False
wizard = BackuppyWizard() mydir = os.getcwd()
wizard.show()
app.exec_() if argv and argv[0] == "--gui":
from install_gui import main_install_gui
trace("Starting GUI-version.")
is_finalized, is_exclude, rsync_cmd = main_install_gui(mydir, EXCLUDE_FILE) # collect user input via GUI and store in env. variables
else:
trace("Starting CLI-version.\n")
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:
do_the_install(mydir, EXCLUDE_FILE, is_exclude, BACKUPPY_SCRIPT, rsync_cmd)
trace("Ending Backuppy install.py") trace("Ending Backuppy install.py")
if __name__ == '__main__':
# sys.argv.append("--gui") # TODO: disable for production
sys.exit(main(sys.argv[1:]))

View file

@ -1,107 +1,29 @@
#!/bin/bash #!/bin/bash
# """
# Variables # project: Backuppy
mydir=$PWD # version: 0.10
langDE="./languages/german.py" # file: install.sh
langEN="./languages/english.py" # summary: main entry shell script
# """
# Check if graphical installer should be executed # Check if graphical installer should be executed
if [ "$1" == "--gui" ]; then if [ "$1" == "--gui" ]; then
python3 -B install.py # Check if PIP ist installed
exit 0 if ! command -v pip3> /dev/null
then
echo "Please install PIP on your system for the graphical version of Backuppy!"
exit
fi
# Check if PIP module "PySide2" is installed
if ! pip list | grep PySide2> /dev/null
then
# Install PySide2
echo -e "Installing necessary PySide2 package for GUI-mode."
pip3 install PySide2
fi
# Launch python installer in GUI mode
python3 -B install.py "$1"
else else
# Intro # Launch python installer in CLI mode
# language python3 -B install.py
echo -e "Hello, first of all, which language do you prefer: German [DE] or English [EN]?"
read language
if [ $language = "DE" ]; then
echo -e "Perfekt, nun ist das deutsche Sprachpaket aktiviert. Willkommen! \n"
. $langDE
sleep 1
fi
if [ $language = "EN" ]; then
echo -e "Perfect, the English language package is now activated. Welcome!. \n"
. $langEN
sleep 1
fi
echo -e "\n$intromsg1 \n"
sleep 1
echo -e " \n$intromsg2\n"
sleep 1
# Installer
# creates the file 'Backuppy.sh'
touch Backuppy.sh
echo "#!/bin/bash" >> Backuppy.sh
chmod +x Backuppy.sh
# which Rsync options are available and which one you want to use
echo -e "$rsyncopt \n"
sleep 1
# asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes
echo -e "$excludefile1"
read exclude
if [ $exclude = "J" ]; then
echo -e "$excludefile2 \n"
touch exclude.txt
sleep 1
elif [ $exclude = "Y" ]; then
echo -e "$excludefile2 \n"
touch exclude.txt
sleep 1
fi
if [ $exclude = "N" ]; then
echo -e "$excludefile3 \n"
sleep 1
fi
# Asks for the source directory which should be saved
echo -e "$srcdir1"
sleep 1
echo -e "$srcdir2"
read sourcedir
echo -e "$srcdir3_1 $sourcedir $srcdir3_2"
sleep 1
# asks for the destination directory in which the backup should be saved
echo -e "$targetdir1"
read targetdir
echo -e "$targetdir2_1 $targetdir $targetdir2_2"
sleep 1
# alias entry in .bashrc or .zshrc
# .zshrc case 1
echo $SHELL
if [ $SHELL = "/usr/bin/zsh" ]; then
echo "alias backuppy='sudo $mydir/Backuppy.sh'" >> ~/.zshrc
fi
# zshrc case 2
echo $SHELL
if [ $SHELL = "/bin/zsh" ]; then
echo "alias backuppy='sudo $mydir/Backuppy.sh'" >> ~/.zshrc
fi
#bashrc case 1
if [ $SHELL = "/usr/bin/bash" ]; then
echo "alias backuppy='sudo $mydir/Backuppy.sh'" >> ~/.bashrc
fi
# bashrc case 2
if [ $SHELL = "/bin/bash" ]; then
echo "alias backuppy='sudo $mydir/Backuppy.sh'" >> ~/.bashrc
fi
# collects all the information needed to execute the rsync command and creates it.
echo -e "$collect \n"
sleep 1
echo -e "rsync -aqp --exclude-from=$mydir/exclude.txt $sourcedir $targetdir \n"
sleep 1
# enter the rsync command in Backuppy.sh
echo "rsync -aqp --exclude-from=$mydir/exclude.txt $sourcedir $targetdir" >> Backuppy.sh
# Outro
echo -e "$outro1"
sleep 2
echo "$outro2"
exit 0
fi fi

View file

@ -1,46 +1,35 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
project: Backuppy project: Backuppy
version: 1.01.001 version: 0.9
file: backup.py file: install_gui.py
summary: main entry python file summary: python installer-script in GUI-mode (needs PySide2)
""" """
# Standard library imports # Standard library imports
import os import os
# Third party imports # Third party imports
from PySide2 import QtCore from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore, QtWidgets
# local imports # local imports
from languages import english from install import EXCLUDE_FILE, EMAIL
from languages import german from utils import set_language, get_lang_text, LANG_EN, LANG_DE
# local globals
VERSION: str = "1.01.001"
EMAIL: str = "fotocoder@joschu.ch"
LANG_EN: str = "English"
LANG_DE: str = "German"
LANGUAGE: str = LANG_EN
MYDIR: str = os.getcwd()
SOURCEDIR: str = None
EXCLUDE: bool = True
TARGETDIR: str = None
def get_lang_text(search_str: str):
return_str: str = eval("english." + search_str)
global LANGUAGE
if LANGUAGE == LANG_DE:
return_str = eval("german." + search_str)
return return_str
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.addPage(Page01(self)) self.addPage(Page01(self))
self.addPage(Page02(self)) self.addPage(Page02(self))
self.addPage(Page03(self)) self.addPage(Page03(self))
@ -51,18 +40,18 @@ class BackuppyWizard(QtWidgets.QWizard):
self.addPage(Page08(self)) self.addPage(Page08(self))
self.addPage(Page09(self)) self.addPage(Page09(self))
self.addPage(Page10(self)) self.addPage(Page10(self))
self.setWindowTitle(english.intromsg1)
self.resize(640, 480) self.resize(640, 480)
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 = QIComboBox(self)
self.comboBox = QtWidgets.QComboBox(self) self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.addItem("English", LANG_DE) self.comboBox.addItem(LANG_EN)
self.comboBox.addItem("German", LANG_EN) self.comboBox.addItem(LANG_DE)
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label) layout.addWidget(self.label)
@ -70,11 +59,8 @@ class Page01(QtWidgets.QWizardPage):
self.setLayout(layout) self.setLayout(layout)
def validatePage(self): def validatePage(self):
global LANGUAGE set_language(self.comboBox.currentText())
if self.comboBox.currentText() == LANG_DE:
LANGUAGE = LANG_DE
else:
LANGUAGE = LANG_EN
return True return True
@ -90,6 +76,8 @@ class Page02(QtWidgets.QWizardPage):
self.setLayout(layout) self.setLayout(layout)
def initializePage(self): def initializePage(self):
self.setWindowTitle(get_lang_text("intromsg1"))
self.label1.setText(get_lang_text("languagepack")) self.label1.setText(get_lang_text("languagepack"))
self.label2.setText(get_lang_text("intromsg2")) self.label2.setText(get_lang_text("intromsg2"))
@ -97,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)
@ -121,24 +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"))
@ -146,22 +139,37 @@ 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.edit = QtWidgets.QLineEdit() self.efSourceDir = QtWidgets.QLineEdit()
self.pbBrowse = QtWidgets.QPushButton("Browse")
self.pbBrowse.clicked.connect(self.on_pbBrowse_clicked)
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1) layout.addWidget(self.label1)
layout.addWidget(self.label2) layout.addWidget(self.label2)
layout.addWidget(self.edit)
hLayout = QtWidgets.QHBoxLayout()
hLayout.addWidget(self.efSourceDir)
hLayout.addWidget(self.pbBrowse)
layout.addLayout(hLayout)
self.setLayout(layout) self.setLayout(layout)
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("srcdir1")) self.label1.setText(get_lang_text("srcdir1"))
self.label2.setText(get_lang_text("srcdir2")) self.label2.setText(get_lang_text("srcdir2"))
def on_pbBrowse_clicked(self):
options = QtWidgets.QFileDialog.Options() | QtWidgets.QFileDialog.ShowDirsOnly
dirName = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Directory", None, options)
self.efSourceDir.setText(dirName)
def validatePage(self): def validatePage(self):
global SOURCEDIR self.parent.sourcedir = self.efSourceDir.text()
SOURCEDIR = self.edit.text()
return True return True
@ -169,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()
@ -180,26 +191,42 @@ 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"))
self.label2.setText(SOURCEDIR) bold_text = f"<p><strong>{self.parent.sourcedir}</strong></p>"
self.label2.setText(bold_text)
self.label3.setText(get_lang_text("srcdir3_2")) self.label3.setText(get_lang_text("srcdir3_2"))
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.edit = QtWidgets.QLineEdit() self.efTargetDir = QtWidgets.QLineEdit()
self.pbBrowse = QtWidgets.QPushButton("Browse")
self.pbBrowse.clicked.connect(self.on_pbBrowse_clicked)
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label1) layout.addWidget(self.label1)
layout.addWidget(self.edit)
hLayout = QtWidgets.QHBoxLayout()
hLayout.addWidget(self.efTargetDir)
hLayout.addWidget(self.pbBrowse)
layout.addLayout(hLayout)
self.setLayout(layout) self.setLayout(layout)
def initializePage(self): def initializePage(self):
self.label1.setText(get_lang_text("targetdir1")) self.label1.setText(get_lang_text("targetdir1"))
def on_pbBrowse_clicked(self):
options = QtWidgets.QFileDialog.Options() | QtWidgets.QFileDialog.ShowDirsOnly
dirName = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Directory", None, options)
self.efTargetDir.setText(dirName)
def validatePage(self): def validatePage(self):
global TARGETDIR self.parent.targetdir = self.efTargetDir.text()
TARGETDIR = self.edit.text()
return True return True
@ -207,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()
@ -218,13 +248,24 @@ 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"))
self.label2.setText(TARGETDIR) bold_text = f"<p><strong>{self.parent.targetdir}</strong></p>"
self.label2.setText(bold_text)
self.label3.setText(get_lang_text("targetdir2_2")) self.label3.setText(get_lang_text("targetdir2_2"))
def validatePage(self):
exclude_file = os.path.join(self.parent.mydir, self.parent.exclude_file)
self.parent.rsync_cmd = f"rsync -aqp --exclude-from={exclude_file} {self.parent.sourcedir} {self.parent.targetdir}"
return True
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()
@ -234,8 +275,8 @@ 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 SOURCEDIR, TARGETDIR bold_text = f"<p><strong>{self.parent.rsync_cmd}</strong></p>"
self.label2.setText(f"rsync -aqp --exclude-from={MYDIR}/exclude.txt {SOURCEDIR} {TARGETDIR}") self.label2.setText(bold_text)
class Page10(QtWidgets.QWizardPage): class Page10(QtWidgets.QWizardPage):
@ -249,20 +290,29 @@ class Page10(QtWidgets.QWizardPage):
layout.addWidget(self.label2) layout.addWidget(self.label2)
layout.addWidget(self.label3) layout.addWidget(self.label3)
self.setLayout(layout) self.setLayout(layout)
self.setFinalPage(True) self.setFinalPage(True)
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)
def validatePage(self):
return True
def main_install_gui(mydir, exclude_file):
app = QtWidgets.QApplication()
wizard = BackuppyWizard(parent=None, mydir=mydir, exclude_file=exclude_file)
wizard.show()
app.exec_()
return True, wizard.exclude, wizard.rsync_cmd
if __name__ == '__main__': if __name__ == '__main__':
print(f"Starting backup.py v{VERSION}") is_finalized, is_exclude, rsync_cmd = main_install_gui(mydir=os.getcwd(), exclude_file=EXCLUDE_FILE)
app = QtWidgets.QApplication()
wizard = BackuppyWizard()
wizard.show()
app.exec_()
print("Ending backup.py")

View file

@ -9,15 +9,21 @@ Yes="Yes"
No="No" No="No"
welcome="Hello, first of all, which language do you prefer: German or English [de/EN]?"
path_not_existing="Specified directory does not exist!"
paths_must_differ="Source dir and target dir must differ!"
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!"
intromsg2="The installer will now ask you a few things to adapt your backup script to your requirements." intromsg2="The installer will now ask you a few things to adapt your backup script to your requirements."
rsyncopt="rsync offers various options, but to simplify the installation process, I have activated the options -a, -q and -p. \n If you want to set more options, you can do thjat in the file 'Backuppy.sh'." rsyncopt="rsync offers various options, but to simplify the installation process, I have activated the options -a, -q and -p.\nIf you want to set more options, you can do that in the file 'Backuppy.sh'."
excludefile1="Now I need to know if you want to exclude one or more files/directories from your backups.\nThen you can adjust this in the 'exclude.txt'.\nThere you can exclude directories and files in the format '/directory' '/file.txt'.\nDo you want to exclude files/directories or not? [Y/N]" excludefile1="Now I need to know if you want to exclude one or more files/directories from your backups.\nThen you can adjust this in the 'exclude.txt'.\nThere you can exclude directories and files in the format '/directory' '/file.txt'.\nDo you want to exclude files/directories or not? [y/N]"
excludefile2="Perfect, then you can enter your files/directories to be excluded in the file 'exclude.txt' after completing the installation of Backuppy." excludefile2="Perfect, then you can enter your files/directories to be excluded in the file 'exclude.txt' after completing the installation of Backuppy."
@ -28,12 +34,12 @@ srcdir1="Now we come to one of the most important parts of installing Backuppy:"
srcdir2="Which directory do you want to save (e.g. the home directory)? Please enter an absolute path (e.g. '/home/username/')." srcdir2="Which directory do you want to save (e.g. the home directory)? Please enter an absolute path (e.g. '/home/username/')."
srcdir3_1="you have typed in the following source path: " srcdir3_1="you have typed in the following source path: "
srcdir3_2="if this path is not correct, adjust it in the file 'Backuppy.sh'." srcdir3_2="(You may adjust this any time 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="(You may adjust this any time 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

@ -9,15 +9,19 @@ Yes="Ja"
No="Nein" No="Nein"
path_not_existing="Der angegebene Pfad existiert nicht!"
paths_must_differ="Quell- and Zielpfad dürfen nicht identisch sein!"
languagepack="Perfekt, nun ist das deutsche Sprachpaket aktiviert. Willkommen!" languagepack="Perfekt, nun ist das deutsche Sprachpaket aktiviert. Willkommen!"
intromsg1="Danke, dass du Backuppy nutzt, um deine Backups zu erstellen!" intromsg1="Danke, dass du Backuppy nutzt, um deine Backups zu erstellen!"
intromsg2="Der Installer wird dich nun einige Dinge abfragen, um dein Backup-Skript an deine Anforderungen anzupassen." intromsg2="Der Installer wird dich nun einige Dinge abfragen, um dein Backup-Skript an deine Anforderungen anzupassen."
rsyncopt="rsync bietet verschiedene Optionen an, um das Ganze jedoch zu vereinfachen, habe ich die Optionen -a, -q und -p aktiviert. \n Wenn du mehr einstellen willst, kannst du das in der Datei 'Backuppy.sh' machen." rsyncopt="rsync bietet verschiedene Optionen an, um das Ganze jedoch zu vereinfachen, habe ich die Optionen -a, -q und -p aktiviert.\nWenn du mehr einstellen willst, kannst du das in der Datei 'Backuppy.sh' machen."
excludefile1="Nun muss ich noch wissen, ob du ein oder mehrere Dateien/Verzeichnisse vom Backup ausschliessen möchtest.\nDann kannst du das in der 'exclude.txt' anpassen.\nDort kannst du dann im Format '/Verzeichnis' '/Datei.txt' Verzeichnisse und Dateien ausschliessen.\nMöchtest du Dateien/Verzeichnisse ausschliessen oder nicht? [J/N]" excludefile1="Nun muss ich noch wissen, ob du ein oder mehrere Dateien/Verzeichnisse vom Backup ausschliessen möchtest.\nDann kannst du das in der 'exclude.txt' anpassen.\nDort kannst du dann im Format '/Verzeichnis' '/Datei.txt' Verzeichnisse und Dateien ausschliessen.\nMöchtest du Dateien/Verzeichnisse ausschliessen oder nicht? [j/N]"
excludefile2="Perfekt, dann kannst du nach der Fertigstellung der Installation von Backuppy deine auszuschliessenden\nDateien/Verzeichnisse in der Datei 'exclude.txt eintragen." excludefile2="Perfekt, dann kannst du nach der Fertigstellung der Installation von Backuppy deine auszuschliessenden\nDateien/Verzeichnisse in der Datei 'exclude.txt eintragen."
@ -28,12 +32,12 @@ srcdir1="Nun kommen wir zu einem der wichtigesten Teile der Installation von Bac
srcdir2="Welches Verzeichnis möchtest du sichern (z.B. das Homeverzeichnis)? Bitte gib einen absoluten Pfad (z.B. '/home/username/') an." srcdir2="Welches Verzeichnis möchtest du sichern (z.B. das Homeverzeichnis)? Bitte gib einen absoluten Pfad (z.B. '/home/username/') an."
srcdir3_1="du hast folgenden Quellpfad eingetippt: " srcdir3_1="du hast folgenden Quellpfad eingetippt: "
srcdir3_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'Backuppy.sh' an." srcdir3_2="(Der Pfad kann jederzeit in der Datei 'Backuppy.sh' angepasst werden.)"
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="(Der Pfad kann jederzeit in der Datei 'Backuppy.sh' angepasst werden.)"
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."

94
utils.py Normal file
View file

@ -0,0 +1,94 @@
#!/usr/bin/env python3
"""
project: Backuppy
version: 0.9
file: utils.py
summary: utilities script
"""
# Standard library imports
import time
import os
# 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, wait: int=1):
print("\n" + get_lang_text(message_txt) + "\n")
time.sleep(wait)
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 paths_are_identical(path1: str, path2: str):
if os.path.isdir(path1):
if path1 == path2:
return True
return False
def query_path(question_txt: str):
path = query(question_txt)
while not os.path.isdir(path):
_print("path_not_existing")
#path = input("Please retype an existing directory.\n> ")
path = query(question_txt)
return path
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