initial version of graphical installer
- Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python)
This commit is contained in:
parent
64a01a9985
commit
9cf4ca47a1
7 changed files with 343 additions and 15 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
__pycache__/
|
23
README.md
23
README.md
|
@ -6,7 +6,9 @@ Name: Backuppy
|
|||
|
||||
Description: Make daily backups with Backuppy to avoid losing your data.
|
||||
|
||||
Usage: start it with: 'backuppy'
|
||||
Usage:
|
||||
- start it with: `backuppy`
|
||||
- start gui version with: `python backup.py` (install pip package 'PySide2' first)
|
||||
|
||||
Author: Joël Schurter
|
||||
|
||||
|
@ -16,12 +18,27 @@ More infos: see constants and readme.md
|
|||
|
||||
# ToDo
|
||||
|
||||
- make a graphical installer & Tool
|
||||
- add a log-file for the rsync errors
|
||||
|
||||
# Dependencies
|
||||
- rsync (because Backuppy makes its backups with rsync)
|
||||
|
||||
rsync - 'sudo apt install' rsync or 'sudo pacman -S rsync' # because Backuppy makes its bakups with rsync
|
||||
execute `sudo apt install rsync` on Debian/Ubuntu
|
||||
|
||||
execute `sudo pacman -S rsync` on Arch/Manjaro
|
||||
|
||||
# Dependencies for the graphical installer:
|
||||
- pip (the python package manager)
|
||||
|
||||
execute `sudo apt install python3-pip` on Debian/Ubuntu
|
||||
|
||||
execute `sudo pacman -S pip` on Arch/Manjaro
|
||||
|
||||
- pip package 'PySide2'
|
||||
|
||||
execute `pip3 install pyside2` on Debian/Ubuntu
|
||||
|
||||
execute `pip install pyside2` on Arch/Manjaro
|
||||
|
||||
# IMPORTANT
|
||||
|
||||
|
|
268
backup.py
Normal file
268
backup.py
Normal file
|
@ -0,0 +1,268 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
project: Backuppy
|
||||
version: 1.01.000
|
||||
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.000"
|
||||
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 = "<a href='mailto: " + EMAIL + "'>fotocoder@joschu.ch</a>"
|
||||
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")
|
16
changelog.MD
Normal file
16
changelog.MD
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Changelog Backuppy
|
||||
|
||||
## [1.01.000] - 2021-05-04
|
||||
### Added
|
||||
- Graphical installer based on Python3 with PySide2 GUI framework (Qt-bindings for Python)
|
||||
|
||||
### 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).
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
# Variables
|
||||
mydir=$PWD
|
||||
langDE=".languages/german.txt"
|
||||
langEN=".languages/english.txt"
|
||||
langDE="languages/german.py"
|
||||
langEN="languages/english.py"
|
||||
|
||||
# Intro
|
||||
# language
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
project: Backuppy
|
||||
file: languages/english.py
|
||||
summary: english language file
|
||||
"""
|
||||
|
||||
Yes="Yes"
|
||||
|
||||
No="No"
|
||||
|
||||
languagepack="Perfect, the English language package is now activated. Welcome!"
|
||||
|
||||
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'."
|
||||
|
||||
excludefile1="Now I need to know if you want to exclude one or more files/directories from your backups. Then you can adjust this in the 'exclude.txt'. \There you can exclude directories and files in the format '/directory' '/file.txt'.\n Do 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?"
|
||||
|
||||
excludefile2="Perfect, then you can enter your files/directories to be excluded in the file 'exclude.txt' after completing the installation of Backuppy."
|
||||
|
||||
|
@ -26,4 +39,4 @@ collect="Now we have almost reached the end of the installer. I will now create
|
|||
|
||||
outro1="Now we have reached the end. Now you can start Backuppy in the terminal with the command 'backuppy'. You may then have to type in your password so that Backuppy can work properly."
|
||||
|
||||
outro2="Backuppy is now installed, have fun with it! If you have any questions, just write to me: fotocoder@joschu.ch"
|
||||
outro2="Backuppy is now installed, have fun with it! If you have any questions, just write to me."
|
|
@ -1,12 +1,25 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
project: Backuppy
|
||||
file: languages/german.py
|
||||
summary: german language file
|
||||
"""
|
||||
|
||||
Yes="Ja"
|
||||
|
||||
No="Nein"
|
||||
|
||||
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."
|
||||
|
||||
excludefile1="Nun muss ich noch wissen, ob du ein oder mehrere Dateien/Verzeichnisse vom Backup ausschliessen möchtest. Dann kannst du das in der 'exclude.txt' anpassen. \n Dort kannst du dann im Format '/Verzeichnis' '/Datei.txt' Verzeichnisse und Dateien ausschliessen.\n Mö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?"
|
||||
|
||||
excludefile2="Perfekt, dann kannst du nach der Fertigstellung der Installation von Backuppy deine auszuschliessenden Dateien/Verzeichnisse in der Datei 'exclude.txt eintragen."
|
||||
excludefile2="Perfekt, dann kannst du nach der Fertigstellung der Installation von Backuppy deine auszuschliessenden\nDateien/Verzeichnisse in der Datei 'exclude.txt eintragen."
|
||||
|
||||
excludefile3="Gut, dann erstelle ich die Datei 'exclude.txt' gar nicht erst, da du sie ja nicht brauchst."
|
||||
|
||||
|
@ -22,8 +35,8 @@ targetdir1="Nun muss ich noch wissen, wo Backuppy dein Backup ablegen soll, das
|
|||
targetdir2_1="du hast folgenden Zielpfad eingetippt:"
|
||||
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 dir nachher nochmal. \n Wenn dir da etwas auffallen sollte, brich den Installer einfach ab und fange nochmal von Vorne an. \n Achtung: ich empfehle dir, Backuppy in diesem Fall nochmal komplett neu zu installieren."
|
||||
collect="Nun sind wir fast am Ende des Installers angelangt. Ich erstelle nun den rsync-Befehl für dich und zeige ihn\ndir nachher nochmal.\nWenn dir da etwas auffallen sollte, brich den Installer einfach ab und fange nochmal von Vorne an.\nAchtung: ich empfehle dir, Backuppy in diesem Fall nochmal komplett neu zu installieren."
|
||||
|
||||
outro1="Perfekt, jetzt sind wir fertig. Nun kannst du Backuppy im Terminal mit dem Befehl 'backuppy' starten. Möglicherweise musst du dann noch dein Passwort eintippen, damit Backuppy ordnungsgemäss arbeiten kann."
|
||||
outro1="Perfekt, jetzt sind wir fertig. Nun kannst du Backuppy im Terminal mit dem Befehl 'backuppy' starten.\nMöglicherweise musst du dann noch dein Passwort eintippen, damit Backuppy ordnungsgemäss arbeiten kann."
|
||||
|
||||
outro2="Backuppy ist nun installiert, viel Spass damit! Bei Fragen schreib mir einfach: fotocoder@joschu.ch"
|
||||
outro2="Backuppy ist nun installiert, viel Spass damit! Bei Fragen schreib mir einfach."
|
Loading…
Reference in a new issue