Skip to content

Instantly share code, notes, and snippets.

@zach2good
Created May 18, 2021 09:35
Show Gist options
  • Save zach2good/f6ae54967c834c25b42968eae08a0af2 to your computer and use it in GitHub Desktop.
Save zach2good/f6ae54967c834c25b42968eae08a0af2 to your computer and use it in GitHub Desktop.
LandSandBoat Configurator
# ===================
# 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