added permissions check

This commit is contained in:
Faraphel 2022-06-08 14:39:43 +02:00
parent 2f7f0ad5bf
commit 8d6141703b
9 changed files with 150 additions and 31 deletions

View file

@ -1,6 +1,10 @@
{ {
"name": "English", "name": "English",
"translation": { "translation": {
"INSTALLER_TITLE": "MKWF-Install" "INSTALLER_TITLE": "MKWF-Install",
"LANGUAGE_SELECTION": "Language",
"TRACK_CONFIGURATION": "Track Configuration",
"ADVANCED_CONFIGURATION": "Advanced",
"HELP": "Help"
} }
} }

View file

@ -1,6 +1,10 @@
{ {
"name": "Français", "name": "Français",
"translation": { "translation": {
"INSTALLER_TITLE": "MKWF-Install",
"LANGUAGE_SELECTION": "Langue",
"TRACK_CONFIGURATION": "Configuration des courses",
"ADVANCED_CONFIGURATION": "Avancée",
"HELP": "Aide"
} }
} }

View file

@ -1,3 +1,8 @@
from source.gui import install from source.gui import install
import sys
install.Window().mainloop() # this allows every variable to be accessible from other files, useful for the plugins
self = sys.modules[__name__]
self.window = install.Window()
self.window.run()

View file

@ -1,10 +1,22 @@
from source import event from source import event
import tkinter import tkinter
import sys
@event.on("source.gui.install.Window.__init__") @event.on("source.gui.install.Window.run_after")
def test_button(master): def test_button():
tkinter.Button(master, text="test des plugins", command=lambda: print("test")).grid( """
Test function for the plugins
:return:
"""
# get the main window from the main module
window = sys.modules["__main__"].window
# get the install button from the main window
window.button_install.config(text="installation plugins")
# add a custom button on the main window
tkinter.Button(window, text="test des plugins", command=lambda: print("test")).grid(
row=10, column=1, sticky="nsew" row=10, column=1, sticky="nsew"
) )
print("I have been called")

View file

@ -1,6 +1,6 @@
from cx_Freeze import setup, Executable from cx_Freeze import setup, Executable
import sys import sys
import json import source
include_files = [ include_files = [
"./LICENSE", "./LICENSE",
@ -25,7 +25,7 @@ options = {
setup( setup(
options=options, options=options,
name='MKWF-Install', name='MKWF-Install',
version="0.12", version=".".join(source.__version__),
url='https://github.com/Faraphel/MKWF-Install', url='https://github.com/Faraphel/MKWF-Install',
license='Apache-2.0', license='Apache-2.0',
author='Faraphel', author='Faraphel',

View file

@ -0,0 +1,12 @@
__version__ = (0, 12, 0)
__author__ = 'Faraphel'
discord_url = "https://discord.gg/HEYW5v8ZCd"
github_wiki_url = "https://github.com/Faraphel/MKWF-Install/wiki/help"
Ko = 1_000
Mo = 1_000 * Ko
Go = 1_000 * Mo
minimum_space_available = 15*Go

View file

@ -2,11 +2,11 @@ from types import FunctionType
from pathlib import Path from pathlib import Path
import sys import sys
# using this self variable allow us to keep the events in the whole module
self = sys.modules[__name__] self = sys.modules[__name__]
self.events = {} self.events = {}
# register the function to the event
def on(event_name: str): def on(event_name: str):
""" """
Register the function to be called when the event is called. Register the function to be called when the event is called.
@ -23,7 +23,6 @@ def on(event_name: str):
return decorator return decorator
# register all the events at the end of the function
def register(func: FunctionType): def register(func: FunctionType):
""" """
Register the function as an event. Register the function as an event.
@ -39,7 +38,6 @@ def register(func: FunctionType):
return wrapper return wrapper
# call all the events of the event_name
def call_event(event_name: str, *args, **kwargs) -> None: def call_event(event_name: str, *args, **kwargs) -> None:
""" """
Call all the events associated with the event_name. Call all the events associated with the event_name.
@ -47,9 +45,13 @@ def call_event(event_name: str, *args, **kwargs) -> None:
:return: :return:
""" """
for func in self.events.get(event_name, []): for func in self.events.get(event_name, []):
func(*args, **kwargs) func()
# execute all scripts in the ./plugins/ directory that don't start with an underscore def initialise_plugins() -> None:
for file in Path("./plugins/").rglob("[!_]*.py"): """
exec(file.read_text(encoding="utf8"), globals()) Execute all the scripts in the ./plugins/ directory that don't start with an underscore.
:return:
"""
for file in Path("./plugins/").rglob("[!_]*.py"):
exec(file.read_text(encoding="utf8"), globals())

View file

@ -1,16 +1,20 @@
import shutil
import tkinter import tkinter
from pathlib import Path from pathlib import Path
import json import json
from tkinter import ttk from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
import webbrowser
from source.translation import translate as _ from source.translation import translate as _
from source import event from source import event
from source import *
import os
# Main window for the installer # Main window for the installer
class Window(tkinter.Tk): class Window(tkinter.Tk):
@event.register
def __init__(self): def __init__(self):
super().__init__() super().__init__()
@ -38,6 +42,22 @@ class Window(tkinter.Tk):
self.progress_bar = ProgressBar(self) self.progress_bar = ProgressBar(self)
self.progress_bar.grid(row=5, column=1, sticky="nsew") self.progress_bar.grid(row=5, column=1, sticky="nsew")
def run(self) -> None:
"""
Run the installer
"""
event.initialise_plugins()
self.after(0, self.run_after)
self.mainloop()
@event.register
def run_after(self) -> None:
"""
Run after the installer has been initialised, can be used to add plugins
:return:
"""
return None
# Menu bar # Menu bar
class Menu(tkinter.Menu): class Menu(tkinter.Menu):
@ -54,7 +74,7 @@ class Menu(tkinter.Menu):
def __init__(self, master: tkinter.Menu): def __init__(self, master: tkinter.Menu):
super().__init__(master, tearoff=False) super().__init__(master, tearoff=False)
master.add_cascade(label="Language", menu=self) master.add_cascade(label=_("LANGUAGE_SELECTION"), menu=self)
for file in Path("./assets/language/").iterdir(): for file in Path("./assets/language/").iterdir():
self.add_command(label=json.loads(file.read_text(encoding="utf8"))["name"]) self.add_command(label=json.loads(file.read_text(encoding="utf8"))["name"])
@ -64,7 +84,7 @@ class Menu(tkinter.Menu):
def __init__(self, master: tkinter.Menu): def __init__(self, master: tkinter.Menu):
super().__init__(master, tearoff=False) super().__init__(master, tearoff=False)
master.add_cascade(label="Track Configuration", menu=self) master.add_cascade(label=_("TRACK_CONFIGURATION"), menu=self)
self.add_command(label="Change configuration") self.add_command(label="Change configuration")
# Advanced menu # Advanced menu
@ -72,7 +92,7 @@ class Menu(tkinter.Menu):
def __init__(self, master: tkinter.Menu): def __init__(self, master: tkinter.Menu):
super().__init__(master, tearoff=False) super().__init__(master, tearoff=False)
master.add_cascade(label="Advanced", menu=self) master.add_cascade(label=_("ADVANCED_CONFIGURATION"), menu=self)
self.add_command(label="Debug mode") self.add_command(label="Debug mode")
# Help menu # Help menu
@ -81,8 +101,8 @@ class Menu(tkinter.Menu):
super().__init__(master, tearoff=False) super().__init__(master, tearoff=False)
master.add_cascade(label="Help", menu=self) master.add_cascade(label="Help", menu=self)
self.add_command(label="Discord") self.add_command(label="Discord", command=lambda: webbrowser.open(discord_url))
self.add_command(label="Github Wiki") self.add_command(label="Github Wiki", command=lambda: webbrowser.open(github_wiki_url))
# Select game frame # Select game frame
@ -93,7 +113,35 @@ class SourceGame(ttk.LabelFrame):
self.entry = ttk.Entry(self, width=50) self.entry = ttk.Entry(self, width=50)
self.entry.grid(row=1, column=1, sticky="nsew") self.entry.grid(row=1, column=1, sticky="nsew")
ttk.Button(self, text="...", width=2).grid(row=1, column=2, sticky="nsew") self.button = ttk.Button(self, text="...", width=2, command=self.select)
self.button.grid(row=1, column=2, sticky="nsew")
def select(self) -> None:
"""
Select the source game
:return:
"""
path = Path(tkinter.filedialog.askopenfilename(
title=_("SELECT_SOURCE_GAME"),
filetypes=[(_("WII GAMES"), "*.iso *.wbfs *.dol")],
))
# if the user didn't select any file, return None
if not path.exists():
messagebox.showerror(_("ERROR"), _("ERROR_INVALID_SOURCE_GAME"))
return
self.set_path(path)
def set_path(self, path: Path) -> None:
"""
Set the source game path
:param path:
:return:
"""
self.entry.delete(0, tkinter.END)
self.entry.insert(0, str(path.absolute()))
self.master.destination_game.set_path(path.parent / "MKWF.iso")
# Select game destination frame # Select game destination frame
@ -104,7 +152,29 @@ class DestinationGame(ttk.LabelFrame):
self.entry = ttk.Entry(self, width=50) self.entry = ttk.Entry(self, width=50)
self.entry.grid(row=1, column=1, sticky="nsew") self.entry.grid(row=1, column=1, sticky="nsew")
ttk.Button(self, text="...", width=2).grid(row=1, column=2, sticky="nsew") self.button = ttk.Button(self, text="...", width=2, command=self.select)
self.button.grid(row=1, column=2, sticky="nsew")
def select(self) -> None:
"""
Select the source game
:return:
"""
path = Path(tkinter.filedialog.asksaveasfilename(
title=_("SELECT_DESTINATION_GAME"),
filetypes=[(_("WII GAMES"), "*.iso *.wbfs *.dol")],
))
path.parent.mkdir(mode=0o777, parents=True, exist_ok=True)
self.set_path(path)
def set_path(self, path: Path):
if not os.access(path.parent, os.W_OK):
messagebox.showwarning(_("WARNING"), _("WARNING_DESTINATION_GAME_NOT_WRITABLE"))
self.entry.delete(0, tkinter.END)
self.entry.insert(0, str(path.absolute()))
# Install button # Install button
@ -113,18 +183,23 @@ class ButtonInstall(ttk.Button):
super().__init__(master, text="Install", command=self.install) super().__init__(master, text="Install", command=self.install)
def install(self): def install(self):
... # get space remaining on the C: drive
if shutil.disk_usage(".").free < minimum_space_available:
if not messagebox.askokcancel(_("WARNING"), _("WARNING_NOT_ENOUGH_SPACE_CONTINUE")): return
# Progress bar # Progress bar
class ProgressBar(ttk.Frame): class ProgressBar(ttk.LabelFrame):
def __init__(self, master: tkinter.Tk): def __init__(self, master: tkinter.Tk):
super().__init__(master) super().__init__(master)
self.progress_bar = ttk.Progressbar(self) # make the element fill the whole frame
self.columnconfigure(1, weight=1)
self.progress_bar = ttk.Progressbar(self, orient="horizontal")
self.progress_bar.grid(row=1, column=1, sticky="nsew") self.progress_bar.grid(row=1, column=1, sticky="nsew")
self.description = tkinter.Label(self, text="test") self.description = ttk.Label(self, text="no process running", anchor="center", font=("TkDefaultFont", 10))
self.description.grid(row=2, column=1, sticky="nsew") self.description.grid(row=2, column=1, sticky="nsew")

View file

@ -5,5 +5,10 @@ from pathlib import Path
language_data = json.loads(Path("./assets/language/en.json").read_text(encoding="utf8")) language_data = json.loads(Path("./assets/language/en.json").read_text(encoding="utf8"))
def translate(*text): def translate(*text) -> str:
"""
Translate a text to the loaded language.
:param text: list of text to translate
:return: translated text
"""
return "".join([language_data["translation"].get(word, word) for word in text]) return "".join([language_data["translation"].get(word, word) for word in text])