Skip to content

Commit

Permalink
Config now exists in a way better place
Browse files Browse the repository at this point in the history
- And will also be migrated there.
- Also, config files that are not an object at root will no longer cause an uncontrolled error
  • Loading branch information
Square789 committed Jul 7, 2022
1 parent 9f7f7e7 commit 9fcc756
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 34 deletions.
8 changes: 8 additions & 0 deletions demomgr/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def __init__(self, passed_cfg):
Will merge the supplied dict with a copy of the default
config and run a Schema validation on the supplied dict, so a
SchemaError may be raised.
May also raise TypeError if the passed object was not of type
dict.
Will perform some backwards-compatibility operations on the
supplied arguments, notably `hlae_path`, `last_path`, `rcon_pwd`
Expand All @@ -161,6 +163,12 @@ def __init__(self, passed_cfg):
for the system.
"""

if not isinstance(passed_cfg, dict):
raise TypeError(
f"Bad type for passed config object. Expected dict, was "
f"{type(passed_cfg).__name__}"
)

cfg = deepcopy(DEFAULT)
deepupdate_dict(cfg, _rename_fields(passed_cfg))
cfg = _SCHEMA.validate(cfg)
Expand Down
24 changes: 20 additions & 4 deletions demomgr/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,65 +17,81 @@ def get_display_name(self):
elif self is self.JSON:
return ".json"


class FILE_MANAGER_MODE(IntEnum):
WINDOWS_EXPLORER = 0
USER_DEFINED = 1


class BULK_OPERATION(IntEnum):
MOVE = 0
COPY = 1
DELETE = 2

CFG_FOLDER = ".demomgr"
CFG_NAME = "config.cfg"

WELCOME = (
"Hi and Thank You for using Demomgr!\n\nA config file has been "
"created.\n\nThis program is able to delete files if you tell it to.\n"
"Hi and Thank You for using Demomgr!\n\n"
"This program is able to delete files if you tell it to.\n"
"I can't guarantee that Demomgr is 100% safe or reliable and will not take any "
"responsibility for lost data, damaged drives and/or destroyed hopes and dreams.\n"
"(Look, I use it personally, it's probably fine.)\n\n"
"This program is licensed via the BSD 3-Clause License."
)

EVENT_FILE = "_events.txt"

DATE_FORMATS = (
"%d.%m.%Y %H:%M:%S",
"%d.%m.%Y",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y",
)

EVENTFILE_FILENAMEFORMAT = "(?<= \\(\").+(?=\" at)" #regex
EVENTFILE_BOOKMARK = "Bookmark"
EVENTFILE_KILLSTREAK = "Killstreak"

STATUSBARDEFAULT = "Ready."

TF2_HEAD_PATH = "steamapps/common/Team Fortress 2/"
TF2_FS_ROOT_TAIL_PATH = "tf/"
TF2_EXE_TAIL_PATH = "hl2.exe"
TF2_LAUNCHARGS = ["-steam", "-game", "tf"]
TF2_GAME_ID = "440"
APPLAUNCH_ARGS = ["-applaunch", TF2_GAME_ID]

HLAE_EXE = "hlae.exe"
HLAE_HOOK_DLL = "AfxHookSource.dll"
HLAE_LAUNCHARGS0 = ["-customLoader", "-noGui", "-autoStart", "-hookDllPath"]
HLAE_LAUNCHARGS1 = ["-programPath"]
HLAE_LAUNCHARGS2 = ["-cmdLine"]
HLAE_ADD_TF2_ARGS = ["-insecure", "+sv_lan", "1"]

LIBRARYFOLDER_VDF = "steamapps/libraryfolders.vdf"

STEAM_CFG_PATH0 = "userdata/"
STEAM_CFG_PATH1 = "config/localconfig.vdf"

STEAM_EXE = "steam.exe"
STEAM_SH = "steam.sh"

REPLACEMENT_CHAR = "\uFFFD"

STEAM_CFG_LAUNCH_OPTIONS = (
"UserLocalConfigStore", "Software", "Valve", "Steam", "Apps", TF2_GAME_ID, "LaunchOptions",
)
STEAM_CFG_USER_NAME = ("UserLocalConfigStore", "friends", "PersonaName")
# Setting this to lower values might lock the UI, use with care.

GUI_UPDATE_WAIT = 30

THEME_SUBDIR = "ui_themes"

# 0: tcl file, 1: theme name, 2: resource dir name
THEME_PACKAGES = {
"Dark": ("dark.tcl", "demomgr_dark", "dark"),
}

HEADER_HUMAN_NAMES = {
"hostname": "Hostname", "clientid": "Playername",
"map_name": "Map", "playtime": "Playtime",
Expand Down
60 changes: 33 additions & 27 deletions demomgr/main_app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import json
import shutil
import subprocess
import tkinter as tk
import tkinter.ttk as ttk
Expand Down Expand Up @@ -87,40 +88,44 @@ def __init__(self):
self.threadgroups["filter"].build_cb_method(self._after_callback_filter)

# startup routine
is_firstrun = False
if os.path.exists(self.cfgpath):
self.cfg = self.getcfg()
if self.cfg is None: # Quit
return
if self.cfg.first_run:
is_firstrun = True
else:
try:
os.makedirs(
os.path.dirname(self.cfgpath), # self.cfgpath ends in a file, should be ok
exist_ok = True
)
except OSError as exc:
tk_msg.showerror(
"Demomgr - Error", f"The following error occurred during startup: {exc}"
)
self.quit_app(False)
return
self.cfg = Config.get_default()
self.writecfg()
is_firstrun = True
# see if an old (pre-1.10.1) config exists and migrate it
old_cfgpath = platforming.get_old_cfg_storage_path()
if os.path.exists(old_cfgpath):
try:
os.makedirs(os.path.dirname(self.cfgpath), exist_ok = True)
shutil.move(old_cfgpath, self.cfgpath)
except OSError as exc:
tk_msg.showerror("Demomgr - Error", f"Error migrating config: {exc}")
self.quit_app(False)
return
try:
os.rmdir(os.path.dirname(old_cfgpath))
except OSError:
# Weird, since it may mean the dir is not empty. Just ignore it then.
# The dir will be left like that forever but, as a wise man once said,
# that's showbiz.
pass
self.cfg = self.getcfg()
else:
self.cfg = Config.get_default()

if self.cfg is None:
return

# load style (For FirstRun)
self.ttkstyle = ttk.Style() # Used later-on too.
# Fallback that is different depending on the platform.
self._DEFAULT_THEME = self.ttkstyle.theme_use()
self._applytheme()

if is_firstrun:
if self.cfg.first_run:
fr_dialog = FirstRun(self.root)
fr_dialog.show()
if fr_dialog.result.state != DIAGSIG.SUCCESS:
self.quit_app()
self.quit_app(False)
return
self.cfg.first_run = False

Expand Down Expand Up @@ -338,6 +343,7 @@ def quit_app(self, save_cfg = True):
# Without the stuff below, the root.destroy method will produce
# strange errors on closing, due to some dark magic regarding after
# commands.
# Begin section heavily copied from tkinter's __init__.py
for c in list(self.root.children.values()):
try:
c.destroy()
Expand All @@ -347,11 +353,7 @@ def quit_app(self, save_cfg = True):
tk.Misc.destroy(self.root)
if tk._support_default_root and tk._default_root is self.root:
tk._default_root = None
# Above section copied from tkinter's __init__.py
try:
self.root.destroy()
except tk.TclError:
pass
# End section copied from tkinter's __init__.py
self.root.quit()

def _opensettings(self):
Expand Down Expand Up @@ -836,8 +838,12 @@ def writecfg(self):
fixed.
"""
write_ok = False
cfg_dir = os.path.dirname(self.cfgpath) # self.cfgpath ends in a file, should be ok
while not write_ok:
try:
if not os.path.exists(cfg_dir):
# exist_ok is unnecessary but as long as it gets created, whatever
os.makedirs(cfg_dir, exist_ok = True)
with open(self.cfgpath, "w") as handle:
handle.write(self.cfg.to_json())
write_ok = True
Expand All @@ -863,7 +869,7 @@ def getcfg(self):
while cfg is None:
try:
cfg = Config.load_and_validate(self.cfgpath)
except (OSError, json.decoder.JSONDecodeError, SchemaError) as exc:
except (OSError, json.decoder.JSONDecodeError, SchemaError, TypeError) as exc:
dialog = CfgError(self.root, cfgpath = self.cfgpath, error = exc, mode = 0)
dialog.show()
if dialog.result.data == 0: # Retry
Expand Down
19 changes: 16 additions & 3 deletions demomgr/platforming.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,32 @@ class BY_HANDLE_FILE_INFORMATION(Structure):
# quote = shlex.quote


def get_cfg_storage_path():
# Poor decisions. Why did i not want to roam a config file?
# Also the `.demomgr` sticks out like a sore thumb alongside all other dirs in `.config`
# that are not prefixed with a dot
def get_old_cfg_storage_path():
if _system == "windows":
appdata_path = Path(os.environ["APPDATA"])
if (
str(appdata_path.parent.name).lower() == "appdata" and
appdata_path.name.lower() == "roaming"
):
appdata_path = appdata_path.parent
return str(Path(appdata_path, "Local", CNST.CFG_FOLDER, CNST.CFG_NAME))
return str(Path(appdata_path, "Local", ".demomgr", "config.cfg"))
else:
return str(Path("~/.config", CNST.CFG_FOLDER, CNST.CFG_NAME).expanduser())
return str(Path("~/.config", ".demomgr", "config.cfg").expanduser())
# No clue if this works, especially on apple.

def get_cfg_storage_path():
if _system == "windows":
return str(Path(os.environ["APPDATA"], "Demomgr", "config.json"))
else:
cfg_dir = os.getenv("XDG_CONFIG_HOME", os.path.join(os.environ["HOME"], ".config/"))
return str(Path(cfg_dir, "Demomgr", "config.json"))
# Still unsure about this on darwin, since there's also a Library/Application Support/ dir
# there but A: i don't really care about that platform and B: i have no way of testing
# this as a direct consequence of A.

def get_contextmenu_btn():
"""
Returns the name of the contextmenu button, dependent on the system.
Expand Down

0 comments on commit 9fcc756

Please sign in to comment.