forked from FotoCoder/Backuppy
Compare commits
8 commits
developmen
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
eb8e536617 | |||
f9dc51340c | |||
543a0e59f1 | |||
c7180d5863 | |||
87ee1f2064 | |||
edb10d9a54 | |||
45535d7ff5 | |||
b24dabf203 |
7 changed files with 244 additions and 127 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
@ -1,5 +1,24 @@
|
||||||
# Changelog Backuppy
|
# Changelog Backuppy
|
||||||
|
|
||||||
|
## [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
|
## [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
|
||||||
|
|
147
install.py
147
install.py
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
project: Backuppy
|
project: Backuppy
|
||||||
version: 0.8
|
version: 0.10
|
||||||
file: install.py
|
file: install.py
|
||||||
summary: python installer-script in CLI-mode
|
summary: python installer-script in CLI-mode
|
||||||
"""
|
"""
|
||||||
|
@ -9,114 +9,90 @@ 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, query_path, _print, trace, paths_are_identical
|
||||||
from languages import german
|
|
||||||
|
|
||||||
# local globals
|
# local globals
|
||||||
# ----------------------
|
VERSION: str = "0.10"
|
||||||
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", wait=2)
|
||||||
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_path("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_path("targetdir1")
|
||||||
print(f"{get_lang_text('targetdir2_1')} {targetdir} {get_lang_text('targetdir2_2')}")
|
while paths_are_identical(sourcedir, targetdir):
|
||||||
time.sleep(1)
|
_print("paths_must_differ")
|
||||||
|
targetdir = query_path("targetdir1")
|
||||||
|
if not targetdir:
|
||||||
|
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", wait=2)
|
||||||
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", wait=2)
|
||||||
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 +124,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")
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# """
|
# """
|
||||||
# project: Backuppy
|
# project: Backuppy
|
||||||
# version: 0.8
|
# version: 0.10
|
||||||
# file: install.sh
|
# file: install.sh
|
||||||
# summary: main entry shell script
|
# summary: main entry shell script
|
||||||
# """
|
# """
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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."
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ 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!"
|
||||||
|
@ -17,7 +21,7 @@ intromsg2="Der Installer wird dich nun einige Dinge abfragen, um dein Backup-Skr
|
||||||
|
|
||||||
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."
|
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
94
utils.py
Normal 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
|
Loading…
Reference in a new issue