Feature/updater can now update from gitlab
Added update function, update function does not work inside git folder.
This commit is contained in:
parent
f8419c6d01
commit
7e8a68e73e
3 changed files with 125 additions and 15 deletions
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 0.3.1
|
||||||
|
Fixed that online version always was newer. Changed some small layouts from the menu.
|
||||||
|
|
||||||
|
## 0.3.0
|
||||||
|
Adding an update function. Checks the latest_version.txt file from gitlab and can pull the newest ftl-savemanager.py file and replace the local version.
|
||||||
|
If .gitignore file is found in the same folder update is denied, it also ask if the user wants to update before doing so.
|
||||||
|
|
||||||
|
## 0.2.1
|
||||||
|
Switching to Semantic versioning, MAJOR.MINOR.PATCH
|
||||||
|
|
||||||
|
## 0.2
|
||||||
|
Reorgenized: The functions have been reorganized into two classes, Backup and UI.
|
||||||
|
|
||||||
|
## 0.1
|
||||||
|
Initial working script
|
|
@ -1,11 +1,15 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import sys
|
||||||
|
import requests
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
version = "0.3.1"
|
||||||
|
gitlab_url = "https://gitlab.com/python_projects3802849/ftl-save-manager/-/raw/main"
|
||||||
|
settings_location = "settings.txt"
|
||||||
|
|
||||||
class BackupApp:
|
class BackupApp:
|
||||||
""""Backup class, copy FTL continue file to backup location and restores it."""
|
""""Backup class, copy FTL continue file to backup location and restores it."""
|
||||||
def __init__(self, settings_file_path):
|
def __init__(self, settings_file_path):
|
||||||
self.version = 0.1
|
|
||||||
self.backup_files = {"1": "initiating"} # initiating variable
|
self.backup_files = {"1": "initiating"} # initiating variable
|
||||||
self.settings_path = settings_file_path
|
self.settings_path = settings_file_path
|
||||||
self.settings = self.read_settings()
|
self.settings = self.read_settings()
|
||||||
|
@ -17,7 +21,7 @@ class BackupApp:
|
||||||
self.game_path, self.backup_path = self.ask_for_path()
|
self.game_path, self.backup_path = self.ask_for_path()
|
||||||
self.write_settings([self.game_path, self.backup_path])
|
self.write_settings([self.game_path, self.backup_path])
|
||||||
|
|
||||||
print(f"Game location: {self.game_path}.\nSave location: {self.backup_path}\n")
|
print(f"Game location: {self.game_path}.\nSave location: {self.backup_path}")
|
||||||
|
|
||||||
def read_settings(self):
|
def read_settings(self):
|
||||||
"""Reading the settings file."""
|
"""Reading the settings file."""
|
||||||
|
@ -29,15 +33,15 @@ class BackupApp:
|
||||||
return(data)
|
return(data)
|
||||||
else:
|
else:
|
||||||
print("settings file does not exit.")
|
print("settings file does not exit.")
|
||||||
return 0
|
return False
|
||||||
|
|
||||||
def ask_for_path(self):
|
def ask_for_path(self):
|
||||||
"""Uses get_path to request path from the user."""
|
"""Uses get_path to request path from the user."""
|
||||||
game_path = self.get_path("Game save path", 1)
|
game_path = self.get_path("Game save path", True)
|
||||||
backup_path = self.get_path("Backup path")
|
backup_path = self.get_path("Backup path")
|
||||||
return(game_path, backup_path)
|
return(game_path, backup_path)
|
||||||
|
|
||||||
def get_path(self, str, ftl = 0):
|
def get_path(self, str, ftl = False):
|
||||||
"""Get path from user and check if exists."""
|
"""Get path from user and check if exists."""
|
||||||
while True:
|
while True:
|
||||||
path = input(f"please enter {str}: ")
|
path = input(f"please enter {str}: ")
|
||||||
|
@ -88,7 +92,7 @@ class BackupApp:
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
formatted_now = now.strftime("%Y-%m-%d_%H-%M")
|
formatted_now = now.strftime("%Y-%m-%d_%H-%M")
|
||||||
self.copy_file(f"{self.game_path}/continue.sav", f"{self.backup_path}/{formatted_now}.bkup")
|
self.copy_file(f"{self.game_path}/continue.sav", f"{self.backup_path}/{formatted_now}.bkup")
|
||||||
time.sleep(1)
|
time.sleep(0.5)
|
||||||
|
|
||||||
def restore(self):
|
def restore(self):
|
||||||
"""Copies a selected backup file to the game folder and renames it."""
|
"""Copies a selected backup file to the game folder and renames it."""
|
||||||
|
@ -99,7 +103,7 @@ class BackupApp:
|
||||||
if choice in self.backup_files:
|
if choice in self.backup_files:
|
||||||
self.copy_file(f"{self.backup_path}/{self.backup_files[choice]}", f"{self.game_path}/continue.sav")
|
self.copy_file(f"{self.backup_path}/{self.backup_files[choice]}", f"{self.game_path}/continue.sav")
|
||||||
print(f"{self.backup_files[choice]} restored.")
|
print(f"{self.backup_files[choice]} restored.")
|
||||||
time.sleep(1)
|
time.sleep(0.5)
|
||||||
break
|
break
|
||||||
elif choice == "b":
|
elif choice == "b":
|
||||||
break
|
break
|
||||||
|
@ -116,21 +120,21 @@ class BackupApp:
|
||||||
try:
|
try:
|
||||||
print(f"Deleting {file}.")
|
print(f"Deleting {file}.")
|
||||||
os.remove(f"{self.backup_path}/{file}")
|
os.remove(f"{self.backup_path}/{file}")
|
||||||
time.sleep(0.1)
|
time.sleep(0.3)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to delete {file}. Reason: {e}.")
|
print(f"Failed to delete {file}. Reason: {e}.")
|
||||||
time.sleep(2)
|
#time.sleep(2)
|
||||||
|
|
||||||
def yes_no(self, str):
|
def yes_no(self, str):
|
||||||
"""Ask user y/n question regaring deletion of a string."""
|
"""Ask user y/n question regaring deletion of a string."""
|
||||||
while True:
|
while True:
|
||||||
choice = input(f"Are you sure you want to delete all {str} files? (y/n)")
|
choice = input(f"Are you sure you want to delete all {str} files? (y/n)")
|
||||||
if choice == "y":
|
if choice == "y":
|
||||||
return 1
|
return True
|
||||||
elif choice == "n":
|
elif choice == "n":
|
||||||
print(f"Deleting {str} files aborted")
|
print(f"Deleting {str} files aborted")
|
||||||
time.sleep(1)
|
#time.sleep(1)
|
||||||
return 0
|
return False
|
||||||
else:
|
else:
|
||||||
print("Not a valid option, try again")
|
print("Not a valid option, try again")
|
||||||
|
|
||||||
|
@ -144,7 +148,8 @@ class SimpleUI:
|
||||||
""""Use dict to select an option (function)."""
|
""""Use dict to select an option (function)."""
|
||||||
self.print_menu()
|
self.print_menu()
|
||||||
while True:
|
while True:
|
||||||
choice = input("Selection Option: ")
|
choice = input("Select Option: ")
|
||||||
|
print("\n")
|
||||||
if choice in self.options:
|
if choice in self.options:
|
||||||
self.options[choice]()
|
self.options[choice]()
|
||||||
self.print_menu()
|
self.print_menu()
|
||||||
|
@ -153,26 +158,113 @@ class SimpleUI:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def print_menu(self):
|
def print_menu(self):
|
||||||
print("\033[H\033[J", end="")
|
#print("\033[H\033[J", end="")
|
||||||
print("Menu options")
|
print("Menu options")
|
||||||
for key in self.options:
|
for key in self.options:
|
||||||
print(f"{key}: {self.names[key]}")
|
print(f"{key}: {self.names[key]}")
|
||||||
|
|
||||||
app = BackupApp("local_files/settings.txt")
|
class Updater:
|
||||||
|
"""Update local version from gitlab repo."""
|
||||||
|
def __init__(self, version, update_url, local_file):
|
||||||
|
self.current_version = version
|
||||||
|
self.update_url = update_url
|
||||||
|
self.local_file = local_file
|
||||||
|
self.git = os.path.exists(".gitignore") # Checking if the program inside git env
|
||||||
|
|
||||||
|
def check_for_update(self):
|
||||||
|
"""Check if a new version is available."""
|
||||||
|
try:
|
||||||
|
print("Checking for updates...")
|
||||||
|
response = requests.get(f"{self.update_url}/latest_version.txt")
|
||||||
|
response.raise_for_status()
|
||||||
|
latest_version = response.text.strip()
|
||||||
|
|
||||||
|
if self.compare_SemVer(latest_version):
|
||||||
|
print(f"New version {latest_version} available.\nCurrent version: {self.current_version}")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("You are already on the latest version.")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error checking for updates: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def compare_SemVer(self, latest_version):
|
||||||
|
"""Compare two Semantic versioning strings."""
|
||||||
|
local_version = self.convert_str_list_to_int(self.current_version.split("."))
|
||||||
|
online_version = self.convert_str_list_to_int(latest_version.split("."))
|
||||||
|
return local_version < online_version
|
||||||
|
|
||||||
|
def convert_str_list_to_int(self, list_str):
|
||||||
|
"""Converts a list with strings to a list with intengers."""
|
||||||
|
return [int(i) for i in list_str]
|
||||||
|
|
||||||
|
def download_update(self, latest_version):
|
||||||
|
"""Download the new version and overwrite the current file."""
|
||||||
|
try:
|
||||||
|
print(f"Downloading version {latest_version}...")
|
||||||
|
response = requests.get(f"{self.update_url}/{self.local_file}")
|
||||||
|
response.raise_for_status()
|
||||||
|
with open(self.local_file, "wb") as file:
|
||||||
|
file.write(response.content)
|
||||||
|
print("Update downloaded.")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error downloading update: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def restart_program(self):
|
||||||
|
"""Restart the current program."""
|
||||||
|
print("Restarting the program...")
|
||||||
|
os.execv(sys.executable, ["python"] + sys.argv)
|
||||||
|
|
||||||
|
def run_update(self):
|
||||||
|
"""Main method to check, update, and restart."""
|
||||||
|
if self.git:
|
||||||
|
print("Updating only works outside git env.")
|
||||||
|
else:
|
||||||
|
latest_version = self.check_for_update()
|
||||||
|
if latest_version:
|
||||||
|
if self.yes_no("Do you want to update the program?"):
|
||||||
|
success = self.download_update(latest_version)
|
||||||
|
if success:
|
||||||
|
self.restart_program()
|
||||||
|
else:
|
||||||
|
print("Update cancelled")
|
||||||
|
return
|
||||||
|
|
||||||
|
def yes_no(self, str):
|
||||||
|
"""Ask user y/n question"""
|
||||||
|
while True:
|
||||||
|
choice = input(f"{str} (y/n)")
|
||||||
|
if choice == "y":
|
||||||
|
return True
|
||||||
|
elif choice == "n":
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print("Not a valid option, try again")
|
||||||
|
|
||||||
|
up = Updater(version, gitlab_url, "ftl-savemanager.py")
|
||||||
|
app = BackupApp(settings_location)
|
||||||
|
|
||||||
|
# Designing the menu options from the backupapp and the layout
|
||||||
menu_options = {
|
menu_options = {
|
||||||
"b": app.backup,
|
"b": app.backup,
|
||||||
"r": app.restore,
|
"r": app.restore,
|
||||||
"d": app.delete_backup_file,
|
"d": app.delete_backup_file,
|
||||||
|
"u": up.run_update,
|
||||||
"q": exit
|
"q": exit
|
||||||
}
|
}
|
||||||
menu_names = {
|
menu_names = {
|
||||||
"b": "Backup now",
|
"b": "Backup now",
|
||||||
"r": "Restore backup",
|
"r": "Restore backup",
|
||||||
"d": "Delete backup files",
|
"d": "Delete backup files",
|
||||||
|
"u": "Update",
|
||||||
"q": "Exit"
|
"q": "Exit"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Loading the ui and the options
|
||||||
sui = SimpleUI(menu_options, menu_names)
|
sui = SimpleUI(menu_options, menu_names)
|
||||||
|
|
||||||
|
# starting the ui i.e. program
|
||||||
sui.menu()
|
sui.menu()
|
||||||
|
|
1
latest_version.txt
Normal file
1
latest_version.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0.3.1
|
Loading…
Add table
Add a link
Reference in a new issue