Created
May 18, 2021 09:35
-
-
Save zach2good/f6ae54967c834c25b42968eae08a0af2 to your computer and use it in GitHub Desktop.
LandSandBoat Configurator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# =================== | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program. If not, see <https://www.gnu.org/licenses/>. | |
# =================== | |
# =================== | |
# LandSandBoat Server Configurator | |
# =================== | |
# Usage: | |
# As a GUI: | |
# python3 main.py | |
# | |
# From the commandline: | |
# python3 main.py arg0 arg1 arg2 | |
# | |
# =================== | |
# =================== | |
# Internal Deps | |
# =================== | |
import os | |
import subprocess | |
import sys | |
import re | |
import time | |
import fileinput | |
import distutils.spawn | |
# =================== | |
# Low-level Helpers | |
# =================== | |
def preflight_exit(): | |
# If double clicked on Windows: pause with an input so the user can read the error... | |
if os.name == 'nt' and 'PROMPT' not in os.environ: | |
input('Press ENTER to continue...') | |
exit(-1) | |
def check_for_git_executable(): | |
success = True | |
try: | |
subprocess.call(["git"], stdout=subprocess.PIPE) | |
except: | |
success = False | |
return success | |
def run_from_right_dir(): | |
return os.path.isfile("./main.py") | |
def is_git_repo(): | |
return subprocess.call(['git', '-C', ".", 'status'], stderr=subprocess.STDOUT, stdout = open(os.devnull, 'w')) == 0 | |
def config_files_setup_correctly(): | |
conf_files = [ | |
"../conf/map.conf", | |
"../conf/login.conf", | |
"../conf/search_server.conf", | |
"../conf/version.conf", | |
] | |
success = True | |
for file in conf_files: | |
if not os.path.isfile(file): | |
success = False | |
return success | |
# =================== | |
# Pre-flight Checks | |
# =================== | |
if not check_for_git_executable(): | |
print("ERROR: Make sure git.exe is available in your system's PATH environment variable.") | |
preflight_exit() | |
if not run_from_right_dir(): | |
print("ERROR: main.py is designed to be run from <root>/tools folder, not <root>. Please run from the tools folder.") | |
preflight_exit() | |
if not is_git_repo(): | |
print("ERROR: The project must be checked out as a git repo (using git clone, or similar).") | |
preflight_exit() | |
# =================== | |
# External Deps (requirements.txt) | |
# =================== | |
try: | |
import mysql.connector | |
from mysql.connector import Error, errorcode | |
from git import Repo | |
import yaml | |
import colorama | |
from colorama import Fore, Style | |
from tkinter import * | |
from tkinter.ttk import * | |
# brew install tcl-tk | |
except Exception as e: | |
print("ERROR: Exception occured while importing external dependencies:") | |
print(e) | |
preflight_exit() | |
# =================== | |
# MySQL Config & Connection | |
# =================== | |
class DatabaseConnection: | |
def __init__(self, host, database, port, login, password): | |
self.host = host | |
self.database = database | |
self.port = port | |
self.login = login | |
self.password = password | |
self.is_connected = False | |
self.db = None | |
self.cur = None | |
def connect(self): | |
success = True | |
if self.db is not None and self.cur is not None: | |
return success | |
try: | |
self.db = mysql.connector.connect( | |
host=self.host, | |
user=self.login, | |
passwd=self.password, | |
db=self.database, | |
port=self.port, | |
use_pure=True) | |
self.cur = self.db.cursor() | |
except Exception as e: | |
print("ERROR: DatabaseConnection.connect():") | |
print(e) | |
success = False | |
self.is_connected = success | |
return success | |
def query(self, query_string): | |
if not self.connect(): | |
return False | |
self.cur.execute(query_string) | |
return True | |
# Convenience statements | |
def show_tables(self): | |
return self.query("SHOW TABLES;") | |
def checks_off(self): | |
return self.query("SET unique_checks=0; SET foreign_key_checks=0;") | |
def checks_on(self): | |
return self.query("SET unique_checks=1; SET foreign_key_checks=1;") | |
def autocommit_off(self): | |
return self.query("SET autocommit=0;") | |
def autocommit_on(self): | |
return self.query("SET autocommit=1;") | |
def commit(self): | |
return self.query("COMMIT;") | |
def source(self, filename): | |
return self.query("source {};".format(filename)) | |
# =================== | |
# Window | |
# =================== | |
class Window: | |
def __init__(self): | |
self.window = Tk() | |
self.window.title("LandSandBoat Configurator") | |
self.window.geometry("800x600") | |
self.window.resizable(False, False) | |
self.window.bind("<Escape>", lambda x: self.window.destroy()) | |
# Setup Database | |
self.db = DatabaseConnection("localhost", "xidb", 3306, "login", "password") | |
self.build_ui() | |
self.present() | |
def build_setup_ui(self): | |
frame = Frame(self.notebook) | |
checks = [ | |
("Git Executable", check_for_git_executable), | |
("Run from right dir", run_from_right_dir), | |
("Checked out as git repo", is_git_repo), | |
("Config files setup correctly", config_files_setup_correctly), | |
("Connect to database", self.db.connect), | |
("Check database tables", self.db.show_tables), | |
] | |
self.health_checks_passed = True | |
row_counter = 0 | |
for check in checks: | |
success = check[1]() | |
Label(frame, text = check[0]).grid(row=row_counter, column=0, sticky=W, pady=5, padx=5) | |
colour = "green" if success else "red" | |
Label(frame, text = u'\u2B24', foreground=colour).grid(row=row_counter, column=1, sticky=W, pady=5, padx=5) | |
row_counter = row_counter + 1 | |
if not success: | |
Label(frame, text = "Setup checks failed. Configurator won't operate until the problems are fixed.", foreground="red").grid(row=row_counter, column=0, sticky=W, pady=5, padx=5) | |
self.health_checks_passed = False | |
break | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='Setup') | |
def build_status_ui(self): | |
frame = Frame(self.notebook) | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='Status', state="normal" if self.health_checks_passed else "disabled") | |
def build_configuration_ui(self): | |
frame = Frame(self.notebook) | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='Configuration', state="normal" if self.health_checks_passed else "disabled") | |
def build_maintenance_ui(self): | |
frame = Frame(self.notebook) | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='Maintenance', state="normal" if self.health_checks_passed else "disabled") | |
def build_database_ui(self): | |
frame = Frame(self.notebook) | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='Database', state="normal" if self.health_checks_passed else "disabled") | |
def build_gm_tools_ui(self): | |
frame = Frame(self.notebook) | |
frame.pack(fill='both', expand=True) | |
self.notebook.add(frame, text='GM Tools', state="normal" if self.health_checks_passed else "disabled") | |
def build_ui(self): | |
self.notebook = Notebook(self.window) | |
self.notebook.pack(fill='both', expand=True) | |
# If any checks in here fail, all other tabs will be greyed out | |
self.build_setup_ui() | |
# Other tabs: | |
self.build_configuration_ui() | |
self.build_maintenance_ui() | |
self.build_database_ui() | |
self.build_status_ui() | |
self.build_gm_tools_ui() | |
self.notebook.tab(1) | |
def present(self): | |
self.window.mainloop() | |
def main(): | |
w = Window() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment