From 00fa691116315ba093e1e2a7143f8b13e519ca41 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Wed, 5 May 2021 17:54:06 +0200
Subject: [PATCH 01/21] Renamed "changelog.MD" to "CHANGELOG.md"
---
changelog.MD | 21 ---------------------
1 file changed, 21 deletions(-)
delete mode 100644 changelog.MD
diff --git a/changelog.MD b/changelog.MD
deleted file mode 100644
index 51721aa..0000000
--- a/changelog.MD
+++ /dev/null
@@ -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).
From e3bccb0715c5b34688c6fb6210d8b659824752bc Mon Sep 17 00:00:00 2001
From: PhotoLinux
Date: Wed, 5 May 2021 19:15:25 +0200
Subject: [PATCH 02/21] deleted backupp.py
deleted backup.py because we don't need it anymore.
---
backup.py | 268 ------------------------------------------------------
1 file changed, 268 deletions(-)
delete mode 100644 backup.py
diff --git a/backup.py b/backup.py
deleted file mode 100644
index 266dc56..0000000
--- a/backup.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/env python3
-"""
-project: Backuppy
-version: 1.01.001
-file: backup.py
-summary: main entry python file
-"""
-
-# Standard library imports
-import os
-
-# Third party imports
-from PySide2 import QtCore
-from PySide2 import QtGui
-from PySide2 import QtCore, QtWidgets
-
-# local imports
-from languages import english
-from languages import german
-
-# 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):
- def __init__(self, parent=None):
- super().__init__(parent)
-
- 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)
-
-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("English", LANG_DE)
- self.comboBox.addItem("German", LANG_EN)
-
- layout = QtWidgets.QVBoxLayout()
- layout.addWidget(self.label)
- layout.addWidget(self.comboBox)
- self.setLayout(layout)
-
- def validatePage(self):
- global LANGUAGE
- if self.comboBox.currentText() == LANG_DE:
- LANGUAGE = LANG_DE
- else:
- LANGUAGE = LANG_EN
- 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.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.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"))
- self.label2.setText(SOURCEDIR)
- 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"))
- self.label2.setText(TARGETDIR)
- self.label3.setText(get_lang_text("targetdir2_2"))
-
-
-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 SOURCEDIR, TARGETDIR
- self.label2.setText(f"rsync -aqp --exclude-from={MYDIR}/exclude.txt {SOURCEDIR} {TARGETDIR}")
-
-
-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)
-
-
-if __name__ == '__main__':
- print(f"Starting backup.py v{VERSION}")
- app = QtWidgets.QApplication()
- wizard = BackuppyWizard()
- wizard.show()
- app.exec_()
- print("Ending backup.py")
From 1dfe37a97086c80878219405e13c4bc33fc2ccd7 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Thu, 6 May 2021 12:40:12 +0200
Subject: [PATCH 03/21] Ported shell script "install.sh" to Python
---
install_cli.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 install_cli.py
diff --git a/install_cli.py b/install_cli.py
new file mode 100644
index 0000000..c3215e3
--- /dev/null
+++ b/install_cli.py
@@ -0,0 +1,95 @@
+#!/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")
From 5d367fa1a89376e265fd3616c57cb28232794284 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Thu, 6 May 2021 15:14:50 +0200
Subject: [PATCH 04/21] Write alias only if not already existing
---
CHANGELOG.md | 10 +++++++---
install.py | 35 +++++++++++++++++++++--------------
2 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e975aa4..7e5aa15 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
# Changelog Backuppy
-## [1.02.000] - 2021-05-05
+## [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
- Now fully functional as the shell version
@@ -11,11 +15,11 @@
### Fixed
- Fixed problem with the Bash/ZSH config
-## [1.01.001] - 2021-05-04
+## [0.5.1] - 2021-05-04
### Changed
- Use E-MAIL constant
-## [1.01.000] - 2021-05-04
+## [0.5] - 2021-05-04
### Added
- Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python)
- Changelog.MD
diff --git a/install.py b/install.py
index e99284f..a586b0b 100644
--- a/install.py
+++ b/install.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 1.02.000
+version: 0.6
file: install.py
summary: main entry python file
"""
@@ -10,16 +10,14 @@ summary: main entry python file
import os
# Third party imports
-from PySide2 import QtCore
-from PySide2 import QtGui
-from PySide2 import QtCore, QtWidgets
+from PySide2 import QtWidgets
# local imports
from languages import english
from languages import german
# local globals
-VERSION: str = "1.02.000"
+VERSION: str = "0.6"
EMAIL: str = "fotocoder@joschu.ch"
TARGET_SCRIPT: str = "Backuppy.sh"
EXCLUDE_FILE: str = "exclude.txt"
@@ -44,7 +42,7 @@ def get_lang_text(search_str: str):
def trace(message_txt: str):
""" Print a formatted message to std out. """
- print(f"[ OK ]", message_txt)
+ print("[ OK ]" + message_txt)
class BackuppyWizard(QtWidgets.QWizard):
def __init__(self, parent=None):
@@ -295,20 +293,29 @@ def create_shell_script(command_str: str):
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
+ # Check for installed ZSH
+ if current_shell.upper().find("ZSH") > 0:
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
+ # Check for installed BASH
+ if current_shell.upper().find("BASH") > 0:
rc_filepath = os.path.join(user_home, ".bashrc")
+ # Append our alias if not already existing
if os.path.isfile(rc_filepath):
- with open(rc_filepath, 'a') as file1:
+ fileRc = open(rc_filepath, "r") # open file in read mode
+
+ backuppy_entry_exists = False
+ 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}'.")
- file1.write("\n# Following line was created by Backuppy\n" + ALIAS_STR + "\n")
+ 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
if EXCLUDE:
From a8199debc99c4fa11fa27296361a753be3b7dbe7 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Thu, 6 May 2021 15:47:58 +0200
Subject: [PATCH 05/21] Added TO-DO
check user-input for validity
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index fae01e5..e5f4308 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,8 @@ More infos: see constants and README.md
- add a log-file for the rsync errors
+- check user-input for validity
+
# Dependencies
- rsync (because Backuppy makes its backups with rsync)
From a1c5fbf7eaa33dd9998f3331d10110fc9af7d1f7 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Thu, 6 May 2021 19:40:07 +0200
Subject: [PATCH 06/21] 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"
---
CHANGELOG.md | 5 +
install.py | 401 +++++++++++++++----------------------------------
install.sh | 109 +-------------
install_cli.py | 95 ------------
install_gui.py | 260 ++++++++++++++++++++++++++++++++
5 files changed, 390 insertions(+), 480 deletions(-)
delete mode 100644 install_cli.py
create mode 100644 install_gui.py
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e5aa15..2167c76 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog Backuppy
+## [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/install.py b/install.py
index a586b0b..ac7ace4 100644
--- a/install.py
+++ b/install.py
@@ -1,343 +1,176 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.6
+version: 0.7
file: install.py
summary: main entry python file
"""
# 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"
+# ----------------------
+VERSION: str = "0.7"
+# ----------------------
+MYDIR = os.getcwd()
+EXCLUDE_FILE = "exclude.txt"
+BACKUPPY_SCRIPT = "Backuppy.sh"
+SHELL = os.environ.get("SHELL")
+HOME = os.environ.get("HOME")
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
+LANGUAGE: str = None
RSYNC_CMD: str = None
+EMAIL: str = "fotocoder@joschu.ch"
+
+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 install_cli_main():
+ 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> ")
+ if exclude.upper() in ("J", "Y"):
+ print(get_lang_text("excludefile2") + "\n")
+ os.environ["BUPY_CREATE_EXCLUDE"] = "True"
+ else:
+ 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}"
+ os.environ["BUPY_RSYNC_CMD"] = RSYNC_CMD
+ print(f"{RSYNC_CMD}")
+ time.sleep(1)
+ # Outro
+ print(get_lang_text("outro1"))
+ time.sleep(2)
+ print(get_lang_text("outro2") + " " + EMAIL)
-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()
+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")
- vbox = QtWidgets.QVBoxLayout()
- vbox.addWidget(self.radio1)
- vbox.addWidget(self.radio2)
- vbox.addStretch(1)
- self.groupbox.setLayout(vbox)
+ return exclude_file
- layout = QtWidgets.QVBoxLayout()
- layout.addWidget(self.label)
- layout.addWidget(self.groupbox)
- self.setLayout(layout)
+def create_alias(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 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.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, ".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, ".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():
+ """ Does the things with our environment variables. """
+ is_exclude = os.environ.get("BUPY_CREATE_EXCLUDE")
+ rsync_cmd = os.environ.get("BUPY_RSYNC_CMD")
+
+ if is_exclude == "True":
+ exclude_file = create_exclude_file(MYDIR, EXCLUDE_FILE)
+ create_alias(MYDIR, BACKUPPY_SCRIPT)
+ create_backuppy_script(MYDIR, BACKUPPY_SCRIPT, rsync_cmd)
-if __name__ == '__main__':
+def main(argv):
trace(f"Starting Backuppy install.py v{VERSION}")
- app = QtWidgets.QApplication()
- wizard = BackuppyWizard()
- wizard.show()
- app.exec_()
+ if argv and argv[0] == "--gui":
+ import install_gui
+ trace("Starting GUI-version.\n")
+ install_gui.main() # collect user input via GUI and store in env. variables
+ else:
+ trace("Starting CLI-version.\n")
+ install_cli_main() # collect user input via CLI and store in env. variables
+
+ do_the_install()
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..9711dd6 100755
--- a/install.sh
+++ b/install.sh
@@ -1,107 +1,14 @@
#!/bin/bash
-# Variables
-mydir=$PWD
-langDE="./languages/german.py"
-langEN="./languages/english.py"
-
# Check if graphical installer should be executed
if [ "$1" == "--gui" ]; then
- python3 -B install.py
- exit 0
+ if ! command -v pip3> /dev/null
+ then
+ echo "Please install PIP on your system for the graphical version of Backuppy!"
+ exit
+ fi
+ pip3 install pyside2
+ 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
+ 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..88ab993
--- /dev/null
+++ b/install_gui.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python3
+"""
+project: Backuppy
+version: 0.7
+file: install_gui.py
+summary: main entry python file
+"""
+
+# 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.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)
+
+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)
+
+ 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.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"))
+ os.environ["BUPY_CREATE_EXCLUDE"] = "True"
+ 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
+ exclude_file = os.path.join(MYDIR, EXCLUDE_FILE)
+
+ RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {SOURCEDIR} {TARGETDIR}"
+ os.environ["BUPY_RSYNC_CMD"] = RSYNC_CMD
+
+ 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 main():
+ app = QtWidgets.QApplication()
+ wizard = BackuppyWizard()
+ wizard.show()
+
+ app.exec_()
+
+if __name__ == '__main__':
+ main()
From 845b7e9c9a339d8a6d6c37f9999d692614778391 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 12:08:33 +0200
Subject: [PATCH 07/21] "Browse"-button on directory-selection dialogs
---
CHANGELOG.md | 4 +++
install.py | 78 +++++++++++++++++++++++++++++---------------------
install.sh | 16 ++++++++++-
install_gui.py | 68 +++++++++++++++++++++++++++++++------------
4 files changed, 115 insertions(+), 51 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2167c76..dc9236c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changelog Backuppy
+## [0.8] - 2021-05-07
+### Added
+- Introduce "Browse"-button on directory-selection dialogs
+
## [0.7] - 2021-05-06
### Added
- Reworked "install.sh" to call "install.py"
diff --git a/install.py b/install.py
index ac7ace4..40bde02 100644
--- a/install.py
+++ b/install.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.7
+version: 0.8
file: install.py
-summary: main entry python file
+summary: python installer-script in CLI-mode
"""
# Standard library imports
@@ -17,23 +17,28 @@ from languages import german
# local globals
# ----------------------
-VERSION: str = "0.7"
-# ----------------------
-MYDIR = os.getcwd()
+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: str = "English"
-LANG_DE: str = "German"
-LANGUAGE: str = None
+LANG_EN = "English"
+LANG_DE = "German"
+LANGUAGE = LANG_EN
RSYNC_CMD: str = None
-EMAIL: str = "fotocoder@joschu.ch"
def set_language(language):
global LANGUAGE
LANGUAGE = language
+def set_exclude(exclude_flag):
+ global EXCLUDE
+ EXCLUDE = exclude_flag
+
def trace(message_txt):
""" Print a formatted message to std out. """
print("[ OK ] " + message_txt)
@@ -46,7 +51,7 @@ def get_lang_text(search_str: str):
return_str = eval("german." + search_str)
return return_str
-def install_cli_main():
+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)
@@ -69,9 +74,10 @@ def install_cli_main():
# 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> ")
if exclude.upper() in ("J", "Y"):
+ set_exclude(True)
print(get_lang_text("excludefile2") + "\n")
- os.environ["BUPY_CREATE_EXCLUDE"] = "True"
else:
+ set_exclude(False)
print(get_lang_text("excludefile3") + "\n")
time.sleep(1)
@@ -94,7 +100,7 @@ def install_cli_main():
exclude_file = os.path.join(MYDIR, EXCLUDE_FILE)
RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {sourcedir} {targetdir}"
- os.environ["BUPY_RSYNC_CMD"] = RSYNC_CMD
+
print(f"{RSYNC_CMD}")
time.sleep(1)
@@ -103,25 +109,25 @@ def install_cli_main():
time.sleep(2)
print(get_lang_text("outro2") + " " + EMAIL)
+ return True, EXCLUDE, RSYNC_CMD
+
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")
- return exclude_file
-
-def create_alias(directory, backuppy_script):
+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}'"
# Check for installed ZSH
- if SHELL.upper().find("ZSH") > 0:
- rc_filepath = os.path.join(HOME, ".zshrc")
+ 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, ".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
@@ -145,29 +151,37 @@ def create_backuppy_script(directory, backuppy_script, rsync_cmd):
os.chmod(backuppy_file, 0o777) # make file executable
-def do_the_install():
- """ Does the things with our environment variables. """
+def do_the_install(is_exclude: bool, rsync_cmd: str):
+ """ Creates scripts and entries based on environment variables. """
- is_exclude = os.environ.get("BUPY_CREATE_EXCLUDE")
- rsync_cmd = os.environ.get("BUPY_RSYNC_CMD")
-
- if is_exclude == "True":
- exclude_file = create_exclude_file(MYDIR, EXCLUDE_FILE)
- create_alias(MYDIR, BACKUPPY_SCRIPT)
- create_backuppy_script(MYDIR, BACKUPPY_SCRIPT, rsync_cmd)
+ if is_exclude:
+ create_exclude_file(MYDIR, EXCLUDE_FILE)
+
+ 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}")
+ is_finalized = False
if argv and argv[0] == "--gui":
- import install_gui
+ from install_gui import main_install_gui
trace("Starting GUI-version.\n")
- install_gui.main() # collect user input via GUI and store in env. variables
+ 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")
- install_cli_main() # collect user input via CLI and store in env. variables
+ 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)
- do_the_install()
+ if is_finalized:
+ do_the_install(is_exclude, rsync_cmd)
trace("Ending Backuppy install.py")
diff --git a/install.sh b/install.sh
index 9711dd6..08fe784 100755
--- a/install.sh
+++ b/install.sh
@@ -1,14 +1,28 @@
#!/bin/bash
+# """
+# project: Backuppy
+# version: 0.8
+# file: install.sh
+# summary: main entry shell script
+# """
# Check if graphical installer should be executed
if [ "$1" == "--gui" ]; then
+ # 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
- pip3 install pyside2
+ # Check if PIP module "PySide2" is installed
+ if ! pip list | grep PySide2> /dev/null
+ then
+ # Install PySide2
+ pip3 install PySide2
+ fi
+ # Launch python installer in GUI mode
python3 -B install.py "$1"
else
+ # Launch python installer in CLI mode
python3 -B install.py
fi
diff --git a/install_gui.py b/install_gui.py
index 88ab993..538fe1c 100644
--- a/install_gui.py
+++ b/install_gui.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.7
+version: 0.8
file: install_gui.py
-summary: main entry python file
+summary: python installer-script in GUI-mode (needs PySide2)
"""
# Standard library imports
@@ -19,6 +19,8 @@ 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))
@@ -29,15 +31,15 @@ class BackuppyWizard(QtWidgets.QWizard):
self.addPage(Page08(self))
self.addPage(Page09(self))
self.addPage(Page10(self))
-
- self.setWindowTitle(english.intromsg1)
+
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 = QIComboBox(self)
+
self.comboBox = QtWidgets.QComboBox(self)
self.comboBox.addItem(LANG_EN, LANG_EN)
self.comboBox.addItem(LANG_DE, LANG_DE)
@@ -66,6 +68,8 @@ class Page02(QtWidgets.QWizardPage):
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"))
@@ -97,13 +101,13 @@ class Page03(QtWidgets.QWizardPage):
self.radio1.setChecked(True)
def validatePage(self):
- global EXCLUDE
if self.radio1.isChecked():
- EXCLUDE = True
+ set_exclude(True)
else:
- EXCLUDE = False
+ set_exclude(False)
return True
+
class Page04(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
@@ -116,7 +120,6 @@ class Page04(QtWidgets.QWizardPage):
global EXCLUDE
if EXCLUDE:
self.label.setText(get_lang_text("excludefile2"))
- os.environ["BUPY_CREATE_EXCLUDE"] = "True"
else:
self.label.setText(get_lang_text("excludefile3"))
@@ -125,20 +128,33 @@ class Page05(QtWidgets.QWizardPage):
super().__init__(parent)
self.label1 = 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.addWidget(self.label1)
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)
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.edit.text()
+ SOURCEDIR = self.efSourceDir.text()
return True
@@ -166,18 +182,31 @@ class Page07(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
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.addWidget(self.label1)
- layout.addWidget(self.edit)
+
+ 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.edit.text()
+ TARGETDIR = self.efTargetDir.text()
return True
@@ -205,7 +234,6 @@ class Page08(QtWidgets.QWizardPage):
exclude_file = os.path.join(MYDIR, EXCLUDE_FILE)
RSYNC_CMD = f"rsync -aqp --exclude-from={exclude_file} {SOURCEDIR} {TARGETDIR}"
- os.environ["BUPY_RSYNC_CMD"] = RSYNC_CMD
return True
@@ -239,6 +267,7 @@ class Page10(QtWidgets.QWizardPage):
layout.addWidget(self.label2)
layout.addWidget(self.label3)
self.setLayout(layout)
+
self.setFinalPage(True)
def initializePage(self):
@@ -248,8 +277,11 @@ class Page10(QtWidgets.QWizardPage):
self.label3.setText(urlLink)
self.label3.setOpenExternalLinks(True)
+ def validatePage(self):
+ return True, EXCLUDE, RSYNC_CMD
-def main():
+
+def main_install_gui():
app = QtWidgets.QApplication()
wizard = BackuppyWizard()
wizard.show()
@@ -257,4 +289,4 @@ def main():
app.exec_()
if __name__ == '__main__':
- main()
+ main_install_gui()
From 8e7afcedcee747cd1a93ff578ddef010a3ea4ba1 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 13:15:20 +0200
Subject: [PATCH 08/21] Return values for main-function
---
install_gui.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/install_gui.py b/install_gui.py
index 538fe1c..6a3dfae 100644
--- a/install_gui.py
+++ b/install_gui.py
@@ -101,10 +101,11 @@ class Page03(QtWidgets.QWizardPage):
self.radio1.setChecked(True)
def validatePage(self):
+ global EXCLUDE
if self.radio1.isChecked():
- set_exclude(True)
+ EXCLUDE = True
else:
- set_exclude(False)
+ EXCLUDE = False
return True
@@ -278,7 +279,7 @@ class Page10(QtWidgets.QWizardPage):
self.label3.setOpenExternalLinks(True)
def validatePage(self):
- return True, EXCLUDE, RSYNC_CMD
+ return True
def main_install_gui():
@@ -288,5 +289,7 @@ def main_install_gui():
app.exec_()
+ return True, EXCLUDE, RSYNC_CMD
+
if __name__ == '__main__':
- main_install_gui()
+ is_finalized, is_exclude, rsync_cmd = main_install_gui()
From 5852ac6b625e15518737ce70686c91b1a93dfb1b Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 13:16:13 +0200
Subject: [PATCH 09/21] Installing necessary PySide2 package for GUI-mode
---
CHANGELOG.md | 1 +
install.py | 11 ++++-------
install.sh | 1 +
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dc9236c..6c33f16 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
## [0.8] - 2021-05-07
### Added
- Introduce "Browse"-button on directory-selection dialogs
+- Installing necessary PySide2 package for GUI-mode if not existing
## [0.7] - 2021-05-06
### Added
diff --git a/install.py b/install.py
index 40bde02..d6468be 100644
--- a/install.py
+++ b/install.py
@@ -35,10 +35,6 @@ def set_language(language):
global LANGUAGE
LANGUAGE = language
-def set_exclude(exclude_flag):
- global EXCLUDE
- EXCLUDE = exclude_flag
-
def trace(message_txt):
""" Print a formatted message to std out. """
print("[ OK ] " + message_txt)
@@ -73,11 +69,12 @@ def main_install_cli():
# 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"):
- set_exclude(True)
+ EXCLUDE = True
print(get_lang_text("excludefile2") + "\n")
else:
- set_exclude(False)
+ EXCLUDE = False
print(get_lang_text("excludefile3") + "\n")
time.sleep(1)
@@ -167,7 +164,7 @@ def main(argv):
if argv and argv[0] == "--gui":
from install_gui import main_install_gui
- trace("Starting GUI-version.\n")
+ trace("Starting GUI-version.")
is_finalized, is_exclude, rsync_cmd = main_install_gui() # collect user input via GUI and store in env. variables
else:
diff --git a/install.sh b/install.sh
index 08fe784..f1e9ffd 100755
--- a/install.sh
+++ b/install.sh
@@ -18,6 +18,7 @@ if [ "$1" == "--gui" ]; then
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
From 3423502e68dfccb94ef8377956e75a026039d1e0 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 13:38:08 +0200
Subject: [PATCH 10/21] Fixed typos, simplified dependencies-section
---
README.md | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index e5f4308..95cacf2 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,7 +16,7 @@ Author: Joël Schurter
Licence: GPL3
-More infos: see constants and README.md
+More infos: See README.md and CHANGELOG.md
# ToDo
@@ -38,12 +38,6 @@ More infos: see constants and README.md
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.
+You have to remove the "backuppy" alias in your .bashrc or .zshrc before reinstalling Backuppy.
From a336776904091f17b4a8cdf239dd80316c5ef43d Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 16:12:42 +0200
Subject: [PATCH 11/21] Removed note about removing alias
---
README.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/README.md b/README.md
index 95cacf2..cf272a9 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,3 @@ More infos: See README.md and CHANGELOG.md
execute `sudo apt install python3-pip` on Debian/Ubuntu
execute `sudo pacman -S pip` on Arch/Manjaro
-
-# IMPORTANT
-
-You have to remove the "backuppy" alias in your .bashrc or .zshrc before reinstalling Backuppy.
From d8e953bf057c4b2bd12833265864e18235bfa610 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 16:26:33 +0200
Subject: [PATCH 12/21] Update CHANGELOG.md
---
CHANGELOG.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6c33f16..66e0b1d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,8 +2,8 @@
## [0.8] - 2021-05-07
### Added
-- Introduce "Browse"-button on directory-selection dialogs
-- Installing necessary PySide2 package for GUI-mode if not existing
+- GUI-mode: Introduce "Browse"-button on directory-selection dialogs
+- GUI-mode: Installing necessary PySide2 package if not existing
## [0.7] - 2021-05-06
### Added
From 21f6b4b3ac41aab6d09e0626d3eb162424e7c3b7 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Fri, 7 May 2021 17:35:08 +0200
Subject: [PATCH 13/21] Added install instructions for Fedora and openSUSE
---
README.md | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index cf272a9..6ee459c 100644
--- a/README.md
+++ b/README.md
@@ -27,13 +27,21 @@ More infos: See README.md and CHANGELOG.md
# 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
+
+ execute `sudo dnf install pip` on Fedora
+
+ execute `sudo zypper install python3-pip` on openSUSE
From b24dabf2036b2f8170fbcbeb26f26ef9fa1ed7f7 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 11:29:40 +0200
Subject: [PATCH 14/21] 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
---
CHANGELOG.md | 5 +++
install.py | 118 +++++++++++++++++++++++++++------------------------
2 files changed, 68 insertions(+), 55 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 66e0b1d..7031763 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog Backuppy
+## [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
diff --git a/install.py b/install.py
index d6468be..34b04ac 100644
--- a/install.py
+++ b/install.py
@@ -35,8 +35,16 @@ def set_language(language):
global LANGUAGE
LANGUAGE = language
-def trace(message_txt):
- """ Print a formatted message to std out. """
+def trace(message_txt, prefix_crlf=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")
print("[ OK ] " + message_txt)
def get_lang_text(search_str: str):
@@ -48,65 +56,71 @@ def get_lang_text(search_str: str):
return return_str
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")
+ try:
+ 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)
+ time.sleep(1)
- print("\n" + get_lang_text("intromsg1") + "\n")
- time.sleep(1)
+ print("\n" + get_lang_text("intromsg1") + "\n")
+ time.sleep(1)
- print("\n" + get_lang_text("intromsg2") + "\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
- print(get_lang_text("rsyncopt") + "\n")
- time.sleep(1)
+ # which Rsync options are available and which one you want to use
+ print(get_lang_text("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(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 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> ")
+ # Asks for the source directory which should be saved
+ print(get_lang_text("srcdir1"))
+ time.sleep(1)
+ sourcedir = input(get_lang_text("srcdir2") + "\n> ")
- print(f"{get_lang_text('srcdir3_1')} {sourcedir} {get_lang_text('srcdir3_2')}")
- time.sleep(1)
+ print(f"{get_lang_text('srcdir3_1')} {sourcedir} {get_lang_text('srcdir3_2')}")
+ time.sleep(1)
- # 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)
+ # 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)
- # 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}"
+ # 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)
+ print(f"{RSYNC_CMD}")
+ time.sleep(1)
- # Outro
- print(get_lang_text("outro1"))
- time.sleep(2)
- print(get_lang_text("outro2") + " " + EMAIL)
+ # Outro
+ print(get_lang_text("outro1"))
+ time.sleep(2)
+ print(get_lang_text("outro2") + " " + EMAIL)
+
+ return True, EXCLUDE, RSYNC_CMD
+
+ except KeyboardInterrupt:
+ trace("Programm interrupted by user.", prefix_crlf=True)
+ return False, None, None
- return True, EXCLUDE, RSYNC_CMD
def create_exclude_file(directory, exclude_file):
exclude_file = os.path.join(directory, exclude_file)
@@ -170,12 +184,6 @@ def main(argv):
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)
From 45535d7ff5d631b97c709abe8bf768b7941b84d4 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 14:00:27 +0200
Subject: [PATCH 15/21] Set version to 0.8.1
---
install.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/install.py b/install.py
index 34b04ac..ef672f6 100644
--- a/install.py
+++ b/install.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.8
+version: 0.8.1
file: install.py
summary: python installer-script in CLI-mode
"""
@@ -17,7 +17,7 @@ from languages import german
# local globals
# ----------------------
-VERSION: str = "0.8"
+VERSION: str = "0.8.1"
EMAIL = "fotocoder@joschu.ch"
EXCLUDE_FILE = "exclude.txt"
BACKUPPY_SCRIPT = "Backuppy.sh"
From edb10d9a54204ad149d8005f479b72877e1f7b7d Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 18:47:31 +0200
Subject: [PATCH 16/21] Fix typos
---
languages/english.py | 4 +++-
languages/german.py | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/languages/english.py b/languages/english.py
index e04cfe2..367e77a 100644
--- a/languages/english.py
+++ b/languages/english.py
@@ -9,6 +9,8 @@ Yes="Yes"
No="No"
+welcome="Hello, first of all, which language do you prefer: German [DE] or English [EN]?"
+
languagepack="Perfect, the English language package is now activated. Welcome!"
intromsg1="Thanks for using Backuppy to make your backups!"
@@ -33,7 +35,7 @@ srcdir3_2="if this path is not correct, adjust it in the file 'Backuppy.sh'."
targetdir1="Now I need to know where Backuppy should save your backups, i.e. the target directory. \n Please enter this carefully and in the same way as for the source directory."
targetdir2_1="you have typed in the following destination path:"
-targetdir2_2="if this path is not correct, adjust it in the file 'backuppy.sh'."
+targetdir2_2="if this path is not correct, adjust it in the file 'Backuppy.sh'."
collect="Now we have almost reached the end of the installer. I will now create the rsync command for you and show it to you.\n If you notice a mistake, just cancel the installer and start again from the beginning.\nNote: I recommend that you download Backuppy completely again in this case."
diff --git a/languages/german.py b/languages/german.py
index 07508c9..8836f19 100644
--- a/languages/german.py
+++ b/languages/german.py
@@ -33,7 +33,7 @@ srcdir3_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'B
targetdir1="Nun muss ich noch wissen, wo Backuppy dein Backup ablegen soll, das Zielverzeichnis also.\nBitte tippe dieses gewissenhaft und auf die Weise wie beim Quellverzeichnis ein."
targetdir2_1="du hast folgenden Zielpfad eingetippt:"
-targetdir2_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'backuppy.sh' an."
+targetdir2_2="wenn dieser Pfad nicht stimmen sollte, dann passe ihn in der Datei 'Backuppy.sh' an."
collect="Nun sind wir fast am Ende des Installers angelangt. Ich erstelle nun den rsync-Befehl für dich und zeige ihn\ndir nachher nochmal.\nWenn dir da etwas auffallen sollte, brich den Installer einfach ab und fange nochmal von Vorne an.\nAchtung: ich empfehle dir, Backuppy in diesem Fall nochmal komplett neu zu installieren."
From 87ee1f2064dd864c5ca58e665cf878fc5f960701 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 18:48:11 +0200
Subject: [PATCH 17/21] Created helper scripts "utils.py"
---
utils.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
create mode 100644 utils.py
diff --git a/utils.py b/utils.py
new file mode 100644
index 0000000..ce6df85
--- /dev/null
+++ b/utils.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+"""
+project: Backuppy
+version: 0.9
+file: utils.py
+summary: utilities script
+"""
+
+# Standard library imports
+import time
+
+# local imports
+from languages import english
+from languages import german
+
+# local globals
+LANG_EN = "EN"
+LANG_DE = "DE"
+LANGUAGE = LANG_EN
+class bcolors:
+ """ Define colors for the std. output to console. """
+
+ OK = '\033[92m' #GREEN
+ WARNING = '\033[93m' #YELLOW
+ ERROR = '\033[91m' #RED
+ RESET = '\033[0m' #RESET COLOR
+
+
+def trace(message_txt, prefix_crlf=False, err=False):
+ """ Print a formatted message to std out.
+
+ :param "message_txt" [in] The message text that should be displayed.
+ :param "prefix_crlf" [in] If True, a carriage return/line feed will be done prior to the message text.
+
+ """
+
+ if prefix_crlf:
+ print("\n")
+ if err:
+ print("[ " + bcolors.ERROR + "ERR" + bcolors.RESET + " ] " + message_txt)
+ else:
+ print("[ " + bcolors.OK + "OK" + bcolors.RESET + " ] " + message_txt)
+
+def get_lang_text(search_str: str):
+ """ Returns a string from the appropriate language file. """
+ return_str: str = eval("english." + search_str)
+ global LANGUAGE
+ if LANGUAGE == LANG_DE:
+ return_str = eval("german." + search_str)
+ return return_str
+
+def _print(message_txt: str):
+ print("\n" + get_lang_text(message_txt) + "\n")
+ time.sleep(1)
+
+def set_language(language):
+ """ Set global constant "LANGUAGE" to given language ("EN"/"DE"). """
+ global LANGUAGE, LANG_DE, LANG_EN
+
+ if str(language) and language.upper() == LANG_DE:
+ LANGUAGE = LANG_DE
+ else:
+ LANGUAGE = LANG_EN
+
+def query(question_txt: str):
+ try:
+ answer_txt = input(get_lang_text(question_txt) + "\n> ")
+
+ if not answer_txt:
+ answer_txt = "''"
+
+ if answer_txt.upper() == ":Q" or answer_txt == chr(27):
+ trace("Program exited by user-input.")
+ return None
+
+ except KeyboardInterrupt:
+ trace("Program interrupted by user.", prefix_crlf=True, err=True)
+ return None
+
+ return answer_txt
From c7180d586368c98b6de7e6a4cf144695f9abaa96 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 18:49:30 +0200
Subject: [PATCH 18/21] 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)
---
CHANGELOG.md | 9 +++
install.py | 178 +++++++++++++++++++------------------------------
install_gui.py | 81 ++++++++++++++--------
3 files changed, 130 insertions(+), 138 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7031763..e3bd4f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog Backuppy
+## [0.9] - 2021-05-10
+### Added
+- CLI-mode: It's now possible to end the program anytime with ":q" (or ESC-key) and pressing ENTER.
+- CLI-mode: Colored output on traces
+- New helper script "utils.py"
+
+### Changed
+- Code refactoring (get rid of global variables and constants, instead pass as arguments)
+
## [0.8.1] - 2021-05-10
### Fixed
- CLI-mode: Show text "Programm interrupted by user." instead of error message when Ctrl+C was pressed.
diff --git a/install.py b/install.py
index ef672f6..4cc80fb 100644
--- a/install.py
+++ b/install.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.8.1
+version: 0.9
file: install.py
summary: python installer-script in CLI-mode
"""
@@ -9,128 +9,87 @@ summary: python installer-script in CLI-mode
# Standard library imports
import sys
import os
-import time
# local imports
-from languages import english
-from languages import german
+from utils import set_language, query, _print, trace
# local globals
-# ----------------------
-VERSION: str = "0.8.1"
+VERSION: str = "0.9"
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 main_install_cli(mydir, exclude_file):
+ language = query("welcome")
+ if not language:
+ return False, None, None
+ set_language(language)
-def trace(message_txt, prefix_crlf=False):
- """ Print a formatted message to std out.
+ _print("languagepack")
- :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.
-
- """
+ _print("intromsg1")
- if prefix_crlf:
- print("\n")
- print("[ OK ] " + message_txt)
+ _print("intromsg2")
-def get_lang_text(search_str: str):
- 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
+ # which Rsync options are available and which one you want to use
+ _print("rsyncopt")
-def main_install_cli():
- try:
- 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")
+ # asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes
+ exclude = query("excludefile1")
+ if not exclude:
+ return False, None, None
+ elif exclude.upper() in ("J", "Y"):
+ _print("excludefile2")
+ exclude = True
+ else:
+ _print("excludefile3")
+ exclude = False
- 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
- print(get_lang_text("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(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> ")
-
- print(f"{get_lang_text('srcdir3_1')} {sourcedir} {get_lang_text('srcdir3_2')}")
- time.sleep(1)
-
- # 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)
-
- # 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)
-
- # Outro
- print(get_lang_text("outro1"))
- time.sleep(2)
- print(get_lang_text("outro2") + " " + EMAIL)
-
- return True, EXCLUDE, RSYNC_CMD
-
- except KeyboardInterrupt:
- trace("Programm interrupted by user.", prefix_crlf=True)
+ # Asks for the source directory which should be saved
+ _print("srcdir1")
+ sourcedir = query("srcdir2")
+ if not sourcedir:
return False, None, None
+ _print("srcdir3_1")
+ print(sourcedir)
+ _print("srcdir3_2")
-def create_exclude_file(directory, exclude_file):
- exclude_file = os.path.join(directory, exclude_file)
+ # asks for the destination directory in which the backup should be saved
+ targetdir = query("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.
+ _print("collect")
+
+ rsync_cmd = f"rsync -aqp --exclude-from={os.path.join(mydir, exclude_file)} {sourcedir} {targetdir}"
+
+ print(f"{rsync_cmd}")
+
+ # Outro
+ _print("outro1")
+
+ _print("outro2")
+ print(EMAIL)
+
+ return True, exclude, rsync_cmd
+
+def create_exclude_file(mydir, exclude_file):
+ exclude_file = os.path.join(mydir, exclude_file)
with open(exclude_file, "w") as fExclude:
trace(f"creating exclude-file '{exclude_file}'.")
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
- backuppy_script = os.path.join(directory, backuppy_script)
+ backuppy_script = os.path.join(mydir, backuppy_script)
alias_str = f"alias backuppy='sudo {backuppy_script}'"
# Check for installed ZSH
@@ -162,34 +121,35 @@ def create_backuppy_script(directory, backuppy_script, rsync_cmd):
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. """
if is_exclude:
- create_exclude_file(MYDIR, EXCLUDE_FILE)
+ create_exclude_file(mydir, exclude_file)
if rsync_cmd:
- create_backuppy_script(MYDIR, BACKUPPY_SCRIPT, rsync_cmd)
- create_alias(SHELL, HOME, MYDIR, BACKUPPY_SCRIPT)
+ create_backuppy_script(mydir, backuppy_script, rsync_cmd)
+ create_alias(mydir, backuppy_script)
def main(argv):
trace(f"Starting Backuppy install.py v{VERSION}")
is_finalized = False
+ mydir = os.getcwd()
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
+ 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() # 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:
- do_the_install(is_exclude, rsync_cmd)
+ do_the_install(mydir, EXCLUDE_FILE, is_exclude, BACKUPPY_SCRIPT, rsync_cmd)
trace("Ending Backuppy install.py")
if __name__ == '__main__':
- # sys.argv.append("--gui") # TODO: disable for production
+ sys.argv.append("--gui") # TODO: disable for production
sys.exit(main(sys.argv[1:]))
diff --git a/install_gui.py b/install_gui.py
index 6a3dfae..6d9e1fd 100644
--- a/install_gui.py
+++ b/install_gui.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.8
+version: 0.9
file: install_gui.py
summary: python installer-script in GUI-mode (needs PySide2)
"""
@@ -13,12 +13,21 @@ import os
from PySide2 import QtWidgets
# 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):
- def __init__(self, parent=None):
+ def __init__(self, parent=None, mydir=os.getcwd(), exclude_file=EXCLUDE_FILE):
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))
@@ -38,11 +47,11 @@ class BackuppyWizard(QtWidgets.QWizard):
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.label = QtWidgets.QLabel(get_lang_text("welcome"))
self.comboBox = QtWidgets.QComboBox(self)
- self.comboBox.addItem(LANG_EN, LANG_EN)
- self.comboBox.addItem(LANG_DE, LANG_DE)
+ self.comboBox.addItem(LANG_EN)
+ self.comboBox.addItem(LANG_DE)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label)
@@ -50,8 +59,7 @@ class Page01(QtWidgets.QWizardPage):
self.setLayout(layout)
def validatePage(self):
- if self.comboBox.currentText() == LANG_DE:
- set_language(LANG_DE)
+ set_language(self.comboBox.currentText())
return True
@@ -77,6 +85,9 @@ class Page02(QtWidgets.QWizardPage):
class Page03(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label = QtWidgets.QLabel()
self.groupbox = QtWidgets.QGroupBox()
self.groupbox.setFlat(True)
@@ -101,25 +112,26 @@ class Page03(QtWidgets.QWizardPage):
self.radio1.setChecked(True)
def validatePage(self):
- global EXCLUDE
if self.radio1.isChecked():
- EXCLUDE = True
+ self.parent.exclude = True
else:
- EXCLUDE = False
+ self.parent.exclude = False
return True
class Page04(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.label)
self.setLayout(layout)
def initializePage(self):
- global EXCLUDE
- if EXCLUDE:
+ if self.parent.exclude:
self.label.setText(get_lang_text("excludefile2"))
else:
self.label.setText(get_lang_text("excludefile3"))
@@ -127,6 +139,9 @@ class Page04(QtWidgets.QWizardPage):
class Page05(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.efSourceDir = QtWidgets.QLineEdit()
@@ -154,8 +169,7 @@ class Page05(QtWidgets.QWizardPage):
self.efSourceDir.setText(dirName)
def validatePage(self):
- global SOURCEDIR
- SOURCEDIR = self.efSourceDir.text()
+ self.parent.sourcedir = self.efSourceDir.text()
return True
@@ -163,6 +177,9 @@ class Page05(QtWidgets.QWizardPage):
class Page06(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel()
@@ -174,7 +191,7 @@ class Page06(QtWidgets.QWizardPage):
def initializePage(self):
self.label1.setText(get_lang_text("srcdir3_1"))
- bold_text = f"{SOURCEDIR}
"
+ bold_text = f"{self.parent.sourcedir}
"
self.label2.setText(bold_text)
self.label3.setText(get_lang_text("srcdir3_2"))
@@ -182,6 +199,9 @@ class Page06(QtWidgets.QWizardPage):
class Page07(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label1 = QtWidgets.QLabel()
self.efTargetDir = QtWidgets.QLineEdit()
self.pbBrowse = QtWidgets.QPushButton("Browse")
@@ -206,8 +226,7 @@ class Page07(QtWidgets.QWizardPage):
self.efTargetDir.setText(dirName)
def validatePage(self):
- global TARGETDIR
- TARGETDIR = self.efTargetDir.text()
+ self.parent.targetdir = self.efTargetDir.text()
return True
@@ -215,6 +234,9 @@ class Page07(QtWidgets.QWizardPage):
class Page08(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
self.label3 = QtWidgets.QLabel()
@@ -226,15 +248,14 @@ class Page08(QtWidgets.QWizardPage):
def initializePage(self):
self.label1.setText(get_lang_text("targetdir2_1"))
- bold_text = f"{TARGETDIR}
"
+ bold_text = f"{self.parent.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)
+ exclude_file = os.path.join(self.parent.mydir, self.parent.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
@@ -242,6 +263,9 @@ class Page08(QtWidgets.QWizardPage):
class Page09(QtWidgets.QWizardPage):
def __init__(self, parent=None):
super().__init__(parent)
+
+ self.parent = parent
+
self.label1 = QtWidgets.QLabel()
self.label2 = QtWidgets.QLabel()
layout = QtWidgets.QVBoxLayout()
@@ -251,9 +275,7 @@ class Page09(QtWidgets.QWizardPage):
def initializePage(self):
self.label1.setText(get_lang_text("collect"))
- global RSYNC_CMD
- #self.label2.setText(f"{RSYNC_CMD}")
- bold_text = f"{RSYNC_CMD}
"
+ bold_text = f"{self.parent.rsync_cmd}
"
self.label2.setText(bold_text)
@@ -274,6 +296,7 @@ class Page10(QtWidgets.QWizardPage):
def initializePage(self):
self.label1.setText(get_lang_text("outro1"))
self.label2.setText(get_lang_text("outro2"))
+ global EMAIL
urlLink = f"{EMAIL}"
self.label3.setText(urlLink)
self.label3.setOpenExternalLinks(True)
@@ -282,14 +305,14 @@ class Page10(QtWidgets.QWizardPage):
return True
-def main_install_gui():
+def main_install_gui(mydir, exclude_file):
app = QtWidgets.QApplication()
- wizard = BackuppyWizard()
+ wizard = BackuppyWizard(parent=None, mydir=mydir, exclude_file=exclude_file)
wizard.show()
app.exec_()
- return True, EXCLUDE, RSYNC_CMD
+ return True, wizard.exclude, wizard.rsync_cmd
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)
From 543a0e59f15cc2cfb00208ad44efb327ff2f3c03 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Mon, 10 May 2021 18:53:34 +0200
Subject: [PATCH 19/21] Disable always gui mode for production release
---
install.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/install.py b/install.py
index 4cc80fb..490916b 100644
--- a/install.py
+++ b/install.py
@@ -151,5 +151,5 @@ def main(argv):
trace("Ending Backuppy install.py")
if __name__ == '__main__':
- sys.argv.append("--gui") # TODO: disable for production
+ # sys.argv.append("--gui") # TODO: disable for production
sys.exit(main(sys.argv[1:]))
From f9dc51340cbccf2ab7f215167555462894526a0d Mon Sep 17 00:00:00 2001
From: Paul S
Date: Tue, 11 May 2021 19:07:21 +0200
Subject: [PATCH 20/21] 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
---
CHANGELOG.md | 5 +++++
install.sh | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e3bd4f3..8912add 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# 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.
diff --git a/install.sh b/install.sh
index f1e9ffd..7a8c145 100755
--- a/install.sh
+++ b/install.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# """
# project: Backuppy
-# version: 0.8
+# version: 0.10
# file: install.sh
# summary: main entry shell script
# """
From eb8e536617e916fd801e02db79c79a910066bf58 Mon Sep 17 00:00:00 2001
From: Paul S
Date: Tue, 11 May 2021 19:08:56 +0200
Subject: [PATCH 21/21] 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
---
install.py | 29 ++++++++++++++++-------------
languages/english.py | 14 +++++++++-----
languages/german.py | 12 ++++++++----
utils.py | 20 +++++++++++++++++---
4 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/install.py b/install.py
index 490916b..9113aba 100644
--- a/install.py
+++ b/install.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
"""
project: Backuppy
-version: 0.9
+version: 0.10
file: install.py
summary: python installer-script in CLI-mode
"""
@@ -11,10 +11,10 @@ import sys
import os
# local imports
-from utils import set_language, query, _print, trace
+from utils import set_language, query, query_path, _print, trace, paths_are_identical
# local globals
-VERSION: str = "0.9"
+VERSION: str = "0.10"
EMAIL = "fotocoder@joschu.ch"
EXCLUDE_FILE = "exclude.txt"
BACKUPPY_SCRIPT = "Backuppy.sh"
@@ -32,7 +32,7 @@ def main_install_cli(mydir, exclude_file):
_print("intromsg2")
# which Rsync options are available and which one you want to use
- _print("rsyncopt")
+ _print("rsyncopt", wait=2)
# asks if you want to exclude files/directories from backup and creates an exclude file in case of Yes
exclude = query("excludefile1")
@@ -47,32 +47,35 @@ def main_install_cli(mydir, exclude_file):
# Asks for the source directory which should be saved
_print("srcdir1")
- sourcedir = query("srcdir2")
+ sourcedir = query_path("srcdir2")
if not sourcedir:
return False, None, None
- _print("srcdir3_1")
- print(sourcedir)
+ #_print("srcdir3_1")
+ #print(sourcedir)
_print("srcdir3_2")
# asks for the destination directory in which the backup should be saved
- targetdir = query("targetdir1")
+ targetdir = query_path("targetdir1")
+ while paths_are_identical(sourcedir, targetdir):
+ _print("paths_must_differ")
+ targetdir = query_path("targetdir1")
if not targetdir:
- return False, None, None
+ return False, None, None
- _print("targetdir2_1")
- print(targetdir)
+ #_print("targetdir2_1")
+ #print(targetdir)
_print("targetdir2_2")
# collects all the information needed to execute the rsync command and creates it.
- _print("collect")
+ _print("collect", wait=2)
rsync_cmd = f"rsync -aqp --exclude-from={os.path.join(mydir, exclude_file)} {sourcedir} {targetdir}"
print(f"{rsync_cmd}")
# Outro
- _print("outro1")
+ _print("outro1", wait=2)
_print("outro2")
print(EMAIL)
diff --git a/languages/english.py b/languages/english.py
index 367e77a..d903678 100644
--- a/languages/english.py
+++ b/languages/english.py
@@ -9,7 +9,11 @@ Yes="Yes"
No="No"
-welcome="Hello, first of all, which language do you prefer: German [DE] or English [EN]?"
+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!"
@@ -17,9 +21,9 @@ 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."
-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."
@@ -30,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/')."
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."
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."
diff --git a/languages/german.py b/languages/german.py
index 8836f19..acf978e 100644
--- a/languages/german.py
+++ b/languages/german.py
@@ -9,15 +9,19 @@ Yes="Ja"
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!"
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."
-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."
@@ -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."
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."
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."
diff --git a/utils.py b/utils.py
index ce6df85..4a8dea6 100644
--- a/utils.py
+++ b/utils.py
@@ -8,6 +8,7 @@ summary: utilities script
# Standard library imports
import time
+import os
# local imports
from languages import english
@@ -25,7 +26,6 @@ class bcolors:
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.
@@ -49,9 +49,9 @@ def get_lang_text(search_str: str):
return_str = eval("german." + search_str)
return return_str
-def _print(message_txt: str):
+def _print(message_txt: str, wait: int=1):
print("\n" + get_lang_text(message_txt) + "\n")
- time.sleep(1)
+ time.sleep(wait)
def set_language(language):
""" Set global constant "LANGUAGE" to given language ("EN"/"DE"). """
@@ -62,6 +62,20 @@ def set_language(language):
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> ")