diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e5aa15..66e0b1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog Backuppy +## [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 diff --git a/README.md b/README.md index fae01e5..6ee459c 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ Name: Backuppy 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` @@ -16,32 +16,32 @@ Author: Joël Schurter Licence: GPL3 -More infos: see constants and README.md +More infos: See README.md and CHANGELOG.md # ToDo - add a log-file for the rsync errors +- check user-input for validity + # Dependencies - 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 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: - pip (the python package manager) + execute `sudo pacman -S pip` on Arch/Manjaro + 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 `pip install pyside2` on Arch/Manjaro - -# IMPORTANT - -You have to remove the "backuppy" alias in your .bashrc or .zshrc before reinstall Backuppy. + execute `sudo dnf install pip` on Fedora + + execute `sudo zypper install python3-pip` on openSUSE diff --git a/install.py b/install.py index a586b0b..d6468be 100644 --- a/install.py +++ b/install.py @@ -1,343 +1,187 @@ #!/usr/bin/env python3 """ project: Backuppy -version: 0.6 +version: 0.8 file: install.py -summary: main entry python file +summary: python installer-script in CLI-mode """ # Standard library imports +import sys import os - -# Third party imports -from PySide2 import QtWidgets +import time # local imports from languages import english from languages import german # local globals -VERSION: str = "0.6" -EMAIL: str = "fotocoder@joschu.ch" -TARGET_SCRIPT: str = "Backuppy.sh" -EXCLUDE_FILE: str = "exclude.txt" -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 +# ---------------------- +VERSION: str = "0.8" +EMAIL = "fotocoder@joschu.ch" +EXCLUDE_FILE = "exclude.txt" +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): + global LANGUAGE + LANGUAGE = language + +def trace(message_txt): + """ Print a formatted message to std out. """ + print("[ OK ] " + message_txt) + def get_lang_text(search_str: str): + global LANGUAGE """ 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 trace(message_txt: str): - """ Print a formatted message to std out. """ - print("[ OK ]" + message_txt) +def main_install_cli(): + 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") -class BackuppyWizard(QtWidgets.QWizard): - def __init__(self, parent=None): - super().__init__(parent) + time.sleep(1) - self.addPage(Page01(self)) - 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) + print("\n" + get_lang_text("intromsg1") + "\n") + time.sleep(1) -class Page01(QtWidgets.QWizardPage): - def __init__(self, parent=None): - 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) + print("\n" + get_lang_text("intromsg2") + "\n") + time.sleep(1) - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.label) - layout.addWidget(self.comboBox) - self.setLayout(layout) + # which Rsync options are available and which one you want to use + print(get_lang_text("rsyncopt") + "\n") + time.sleep(1) - def validatePage(self): - global LANGUAGE - if self.comboBox.currentText() == LANG_DE: - LANGUAGE = LANG_DE - else: - LANGUAGE = LANG_EN - return True + # 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> ") + global EXCLUDE + if exclude.upper() in ("J", "Y"): + EXCLUDE = True + print(get_lang_text("excludefile2") + "\n") + else: + EXCLUDE = False + print(get_lang_text("excludefile3") + "\n") + time.sleep(1) + # Asks for the source directory which should be saved + print(get_lang_text("srcdir1")) + time.sleep(1) + sourcedir = input(get_lang_text("srcdir2") + "\n> ") -class Page02(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super().__init__(parent) - self.label1 = QtWidgets.QLabel() - self.label2 = QtWidgets.QLabel() + print(f"{get_lang_text('srcdir3_1')} {sourcedir} {get_lang_text('srcdir3_2')}") + time.sleep(1) - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.label1) - layout.addWidget(self.label2) - self.setLayout(layout) + # asks for the destination directory in which the backup should be saved + targetdir = input(get_lang_text("targetdir1") + "\n> ") + print(f"{get_lang_text('targetdir2_1')} {targetdir} {get_lang_text('targetdir2_2')}") + time.sleep(1) - def initializePage(self): - self.label1.setText(get_lang_text("languagepack")) - self.label2.setText(get_lang_text("intromsg2")) + # collects all the information needed to execute the rsync command and creates it. + print(get_lang_text("collect") + "\n") + time.sleep(1) + exclude_file = os.path.join(MYDIR, EXCLUDE_FILE) + + RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {sourcedir} {targetdir}" + print(f"{RSYNC_CMD}") + time.sleep(1) -class Page03(QtWidgets.QWizardPage): - 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() + # Outro + print(get_lang_text("outro1")) + time.sleep(2) + print(get_lang_text("outro2") + " " + EMAIL) - vbox = QtWidgets.QVBoxLayout() - vbox.addWidget(self.radio1) - vbox.addWidget(self.radio2) - vbox.addStretch(1) - self.groupbox.setLayout(vbox) + return True, EXCLUDE, RSYNC_CMD - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.label) - layout.addWidget(self.groupbox) - self.setLayout(layout) +def create_exclude_file(directory, exclude_file): + exclude_file = os.path.join(directory, exclude_file) + with open(exclude_file, "w") as fExclude: + trace(f"creating exclude-file '{exclude_file}'.") + fExclude.write("\n") - def initializePage(self): - 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 create_alias(shell, home_dir, directory, backuppy_script): + # alias entry in .bashrc or .zshrc + backuppy_script = os.path.join(directory, backuppy_script) + alias_str = f"alias backuppy='sudo {backuppy_script}'" - def validatePage(self): - global EXCLUDE - if self.radio1.isChecked(): - EXCLUDE = True - else: - EXCLUDE = False - return True - -class Page04(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super().__init__(parent) - self.label = QtWidgets.QLabel() - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.label) - 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"

{SOURCEDIR}

" - 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"

{TARGETDIR}

" - 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"

{RSYNC_CMD}

" - 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"{EMAIL}" - 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 # Check for installed ZSH - if current_shell.upper().find("ZSH") > 0: - rc_filepath = os.path.join(user_home, ".zshrc") - + if shell.upper().find("ZSH") > 0: + rc_filepath = os.path.join(home_dir, ".zshrc") # Check for installed BASH - if current_shell.upper().find("BASH") > 0: - rc_filepath = os.path.join(user_home, ".bashrc") - + 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): fileRc = open(rc_filepath, "r") # open file in read mode - backuppy_entry_exists = False - for line in fileRc: + 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}'.") + 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.write("\n# Following line was created by Backuppy\n" + alias_str + "\n") fileRc.close() - ## STEP 2: Create the exclude script if desired - if EXCLUDE: - global EXCLUDE_FILE - EXCLUDE_FILE = os.path.join(MYDIR, EXCLUDE_FILE) - with open(EXCLUDE_FILE, "w") as file2: - trace(f"creating exclude-file '{EXCLUDE_FILE}'.") - file2.writelines("\n") +def create_backuppy_script(directory, backuppy_script, rsync_cmd): + # creates the file 'Backuppy.sh' + backuppy_file = os.path.join(directory, backuppy_script) + with open(backuppy_file, "w") as fBackuppy: + trace(f"creating backuppy-file '{backuppy_file}'.") + fBackuppy.write("#!/bin/bash\n" + rsync_cmd + "\n") + + os.chmod(backuppy_file, 0o777) # make file executable - ## STEP 3: enter the rsync command in Backuppy.sh - with open(TARGET_SCRIPT, "w") as file3: - trace(f"Writing rsync-command to file '{TARGET_SCRIPT}':\n {command_str}") - file3.writelines("#!/bin/bash" + "\n") - file3.writelines(command_str + "\n") +def do_the_install(is_exclude: bool, rsync_cmd: str): + """ Creates scripts and entries based on environment variables. """ + 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(SHELL, HOME, MYDIR, BACKUPPY_SCRIPT) + +def main(argv): trace(f"Starting Backuppy install.py v{VERSION}") - app = QtWidgets.QApplication() - wizard = BackuppyWizard() - wizard.show() + is_finalized = False - 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() # 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() # 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: + do_the_install(is_exclude, rsync_cmd) trace("Ending Backuppy install.py") + +if __name__ == '__main__': + # sys.argv.append("--gui") # TODO: disable for production + sys.exit(main(sys.argv[1:])) diff --git a/install.sh b/install.sh index ba8f1da..f1e9ffd 100755 --- a/install.sh +++ b/install.sh @@ -1,107 +1,29 @@ #!/bin/bash - -# Variables -mydir=$PWD -langDE="./languages/german.py" -langEN="./languages/english.py" +# """ +# project: Backuppy +# version: 0.8 +# file: install.sh +# summary: main entry shell script +# """ # Check if graphical installer should be executed if [ "$1" == "--gui" ]; then - python3 -B install.py - exit 0 + # Check if PIP ist installed + 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 - # Intro - # language - 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 + # Launch python installer in CLI mode + python3 -B install.py fi diff --git a/install_cli.py b/install_cli.py deleted file mode 100644 index c3215e3..0000000 --- a/install_cli.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 - -# Dependencies -import os -import time - -# Variables -MYDIR = os.getcwd() -SHELL = os.environ.get("SHELL") -HOME = os.environ.get("HOME") - -# Intro -# language - -language = input("Hello, first of all, which language do you prefer: German [DE] or English [EN]?\n> ") -if language.upper() == "DE": - from languages.german import * - print("Perfekt, nun ist das deutsche Sprachpaket aktiviert. Willkommen!\n") -else: - from languages.english import * - print("Perfect, the English language package is now activated. Welcome!.\n") - -time.sleep(1) - -print("\n" + intromsg1 + "\n") -time.sleep(1) - -print("\n" + intromsg2 + "\n") -time.sleep(1) - -# Installer - -# creates the file 'Backuppy.sh' -fBackuppy = open("Backuppy.sh", "w") -fBackuppy.write("#!/bin/bash") -os.chmod("Backuppy.sh", 0o777) # make file executable - -# which Rsync options are available and which one you want to use -print(rsyncopt + "\n") -time.sleep(1) - -# asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes -exclude = input(excludefile1 + "\n> ") -if exclude.upper() in ("J", "Y"): - print(excludefile2 + "\n") - fExclude = open("exclude.txt", "w") - fExclude.close() -else: - print(excludefile3 + "\n") -time.sleep(1) - -# Asks for the source directory which should be saved -print(srcdir1) -time.sleep(1) -sourcedir = input(srcdir2 + "\n> ") - -print(f"{srcdir3_1} {sourcedir} {srcdir3_2}") -time.sleep(1) - -# asks for the destination directory in which the backup should be saved -targetdir = input(targetdir1 + "\n> ") -print(f"{targetdir2_1} {targetdir} {targetdir2_2}") -time.sleep(1) - -# alias entry in .bashrc or .zshrc -print(SHELL) - -# .zshrc case1 and case2 -if SHELL.upper().find("ZSH") >0: - # Appending to bash config file - fRc = open(os.path.join(HOME, ".zshrc"), "a") # append mode - fRc.write("\n" + f"alias backuppy='sudo {MYDIR}/Backuppy.sh'" + "\n") - fRc.close() - -# .bashrc case1 and case2 -elif SHELL.upper().find("BASH") >0: - # Appending to zsh config file - fRc = open(os.path.join(HOME, ".bashrc"), "a") # append mode - fRc.write("\n" + f"alias backuppy='sudo {MYDIR}/Backuppy.sh'" + "\n") - fRc.close() - -# collects all the information needed to execute the rsync command and creates it. -print(collect + "\n") -time.sleep(1) -print(f"rsync -aqp --exclude-from={MYDIR}/exclude.txt {sourcedir} {targetdir}\n") -time.sleep(1) - -# enter the rsync command in Backuppy.sh -fBackuppy.write("\n" + f"rsync -aqp --exclude-from={MYDIR}/exclude.txt {sourcedir} {targetdir}" + "\n") -fBackuppy.close() - -# Outro -print(outro1) -time.sleep(2) -print(outro2 + " fotocoder@joschu.ch") diff --git a/install_gui.py b/install_gui.py new file mode 100644 index 0000000..6a3dfae --- /dev/null +++ b/install_gui.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +""" +project: Backuppy +version: 0.8 +file: install_gui.py +summary: python installer-script in GUI-mode (needs PySide2) +""" + +# Standard library imports +import os + +# Third party imports +from PySide2 import QtWidgets + +# local imports +from install import * + +class BackuppyWizard(QtWidgets.QWizard): + def __init__(self, parent=None): + super().__init__(parent) + + self.setWindowTitle(get_lang_text("intromsg1")) + + self.addPage(Page01(self)) + 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.resize(640, 480) + + +class Page01(QtWidgets.QWizardPage): + def __init__(self, parent=None): + super().__init__(parent) + self.label = QtWidgets.QLabel("Hello, first of all, which language do you prefer: English or German?") + + self.comboBox = QtWidgets.QComboBox(self) + self.comboBox.addItem(LANG_EN, LANG_EN) + self.comboBox.addItem(LANG_DE, LANG_DE) + + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label) + layout.addWidget(self.comboBox) + self.setLayout(layout) + + def validatePage(self): + if self.comboBox.currentText() == LANG_DE: + set_language(LANG_DE) + + return True + + +class Page02(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.setWindowTitle(get_lang_text("intromsg1")) + + self.label1.setText(get_lang_text("languagepack")) + self.label2.setText(get_lang_text("intromsg2")) + + +class Page03(QtWidgets.QWizardPage): + 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() + vbox.addWidget(self.radio1) + vbox.addWidget(self.radio2) + vbox.addStretch(1) + self.groupbox.setLayout(vbox) + + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label) + layout.addWidget(self.groupbox) + self.setLayout(layout) + + def initializePage(self): + 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): + global EXCLUDE + if self.radio1.isChecked(): + EXCLUDE = True + else: + EXCLUDE = False + return True + + +class Page04(QtWidgets.QWizardPage): + def __init__(self, parent=None): + super().__init__(parent) + self.label = QtWidgets.QLabel() + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label) + 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.efSourceDir = QtWidgets.QLineEdit() + self.pbBrowse = QtWidgets.QPushButton("Browse") + self.pbBrowse.clicked.connect(self.on_pbBrowse_clicked) + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label1) + layout.addWidget(self.label2) + + hLayout = QtWidgets.QHBoxLayout() + hLayout.addWidget(self.efSourceDir) + hLayout.addWidget(self.pbBrowse) + + layout.addLayout(hLayout) + + self.setLayout(layout) + + def initializePage(self): + self.label1.setText(get_lang_text("srcdir1")) + 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): + global SOURCEDIR + SOURCEDIR = self.efSourceDir.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"

{SOURCEDIR}

" + 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.efTargetDir = QtWidgets.QLineEdit() + self.pbBrowse = QtWidgets.QPushButton("Browse") + self.pbBrowse.clicked.connect(self.on_pbBrowse_clicked) + layout = QtWidgets.QVBoxLayout() + layout.addWidget(self.label1) + + hLayout = QtWidgets.QHBoxLayout() + hLayout.addWidget(self.efTargetDir) + hLayout.addWidget(self.pbBrowse) + + layout.addLayout(hLayout) + + self.setLayout(layout) + + def initializePage(self): + 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): + global TARGETDIR + TARGETDIR = self.efTargetDir.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"

{TARGETDIR}

" + self.label2.setText(bold_text) + self.label3.setText(get_lang_text("targetdir2_2")) + + def validatePage(self): + global RSYNC_CMD, MYDIR, SOURCEDIR, TARGETDIR + exclude_file = os.path.join(MYDIR, EXCLUDE_FILE) + + RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {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"

{RSYNC_CMD}

" + 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"{EMAIL}" + self.label3.setText(urlLink) + self.label3.setOpenExternalLinks(True) + + def validatePage(self): + return True + + +def main_install_gui(): + app = QtWidgets.QApplication() + wizard = BackuppyWizard() + wizard.show() + + app.exec_() + + return True, EXCLUDE, RSYNC_CMD + +if __name__ == '__main__': + is_finalized, is_exclude, rsync_cmd = main_install_gui()