From 61f90d60167ca721510841295ff1995448225c58 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sat, 27 Jun 2026 23:51:20 +0900 Subject: [PATCH 1/4] fix: copy bare config files to named directory (#375) --- dzgui/app_init.py | 33 ++++++++++++++++++++++++++++++- dzgui/config/xdg.py | 9 +++++---- tests/test_bare_conf_files.py | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 tests/test_bare_conf_files.py diff --git a/dzgui/app_init.py b/dzgui/app_init.py index 078f1f3..2535f0e 100644 --- a/dzgui/app_init.py +++ b/dzgui/app_init.py @@ -1,9 +1,10 @@ import logging import os +import shutil from typing import TYPE_CHECKING -from dzgui.const.constants import APP_NAME +from dzgui.const.constants import APP_NAME, APP_NAME_LOWER from dzgui.const.enum import Preferences from dzgui.config.query import lookup from dzgui.config.userprefs import UserPrefs @@ -50,6 +51,34 @@ def setup_logger(log_path: "Path") -> None: logger.addHandler(fh) + +def copy_bare_configs(config: "Path", resolution: "Path") -> None: + # NOTE: temporary workaround for #375 + conf = "config.json" + state = [ + "dzg.history", + "dzg.versions", + "dzg.res.json", + "dzg.filters.json", + "dzg.columns.json", + "dzg.notes.json", + "ips.csv", + ".month" + ] + if APP_NAME_LOWER not in str(config): + new_file = config.parent / APP_NAME_LOWER / conf + make_parents(new_file) + if config.is_file(): + shutil.copy(config, new_file) + if APP_NAME_LOWER not in str(resolution): + state_path = resolution.parent + for state_file in state: + old_file = state_path / state_file + if old_file.is_file(): + new_file = state_path / APP_NAME_LOWER / state_file + make_parents(new_file) + shutil.copy(old_file, new_file) + def load_gui(version: str, is_debug: bool) -> None: lock = lock_acquire() # noqa @@ -58,6 +87,8 @@ def load_gui(version: str, is_debug: bool) -> None: xdg_paths = get_xdg_paths() XDG = parse_filepaths(xdg_paths) + copy_bare_configs(XDG.config, XDG.resolution) + if XDG.resolution.parent.is_dir() is False: make_parents(XDG.resolution) diff --git a/dzgui/config/xdg.py b/dzgui/config/xdg.py index 2748c8f..8494bae 100644 --- a/dzgui/config/xdg.py +++ b/dzgui/config/xdg.py @@ -55,11 +55,12 @@ def get_xdg_paths() -> dict: resolved_paths = {} for path in xdg_paths: - rp = os.environ.get(path) - if rp is not None and is_writeable(rp): - resolved_paths[path] = Path(rp) + real_path = os.environ.get(path) + if real_path is not None and is_writeable(real_path): + new_path = Path(real_path) else: - resolved_paths[path] = xdg_paths[path] / APP_NAME_LOWER + new_path = xdg_paths[path] + resolved_paths[path] = new_path / APP_NAME_LOWER return resolved_paths diff --git a/tests/test_bare_conf_files.py b/tests/test_bare_conf_files.py new file mode 100644 index 0000000..4dffa6b --- /dev/null +++ b/tests/test_bare_conf_files.py @@ -0,0 +1,37 @@ +import pytest +import tempfile + +from dzgui.app_init import copy_bare_configs +from pathlib import Path + +@pytest.mark.mods +def test_bare_file_import(): + conf_string = "DZGUI_CONF\n" + state_string = "DZGUI_STATE\n" + state = [ + "dzg.history", + "dzg.versions", + "dzg.res.json", + "dzg.filters.json", + "dzg.columns.json", + "dzg.notes.json", + "ips.csv", + ".month" + ] + + tmp = tempfile.TemporaryDirectory() + tmp2 = tempfile.TemporaryDirectory() + tmp_conf = Path(tmp.name) + tmp_state = Path(tmp2.name) + + tmp_conf_file = tmp_conf / "config.json" + tmp_conf_file.write_text(conf_string) + for file in state: + tmp_state.joinpath(file).write_text(state_string) + + tmp_state_file = tmp_state / "dzg.res.json" + copy_bare_configs(tmp_conf_file, tmp_state_file) + + assert (tmp_conf / "dzgui/config.json").read_text() == conf_string + for file in state: + assert (tmp_state / "dzgui" / file).read_text() == state_string From 4c31cd7ecd53aef9893de01a4c11dedd7bc35cef Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sun, 28 Jun 2026 00:07:51 +0900 Subject: [PATCH 2/4] chore: add test for no import case --- dzgui/app_init.py | 13 ++++++---- tests/test_bare_conf_files.py | 45 +++++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/dzgui/app_init.py b/dzgui/app_init.py index 2535f0e..3bd1f0d 100644 --- a/dzgui/app_init.py +++ b/dzgui/app_init.py @@ -51,8 +51,7 @@ def setup_logger(log_path: "Path") -> None: logger.addHandler(fh) - -def copy_bare_configs(config: "Path", resolution: "Path") -> None: +def copy_bare_configs(config: "Path", resolution: "Path") -> tuple[bool, bool]: # NOTE: temporary workaround for #375 conf = "config.json" state = [ @@ -63,13 +62,16 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> None: "dzg.columns.json", "dzg.notes.json", "ips.csv", - ".month" + ".month", ] + config_changed = False + state_changed = False if APP_NAME_LOWER not in str(config): new_file = config.parent / APP_NAME_LOWER / conf - make_parents(new_file) if config.is_file(): + make_parents(new_file) shutil.copy(config, new_file) + config_changed = True if APP_NAME_LOWER not in str(resolution): state_path = resolution.parent for state_file in state: @@ -78,6 +80,9 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> None: new_file = state_path / APP_NAME_LOWER / state_file make_parents(new_file) shutil.copy(old_file, new_file) + state_changed = True + return (config_changed, state_changed) + def load_gui(version: str, is_debug: bool) -> None: lock = lock_acquire() # noqa diff --git a/tests/test_bare_conf_files.py b/tests/test_bare_conf_files.py index 4dffa6b..1eb58a6 100644 --- a/tests/test_bare_conf_files.py +++ b/tests/test_bare_conf_files.py @@ -4,10 +4,8 @@ import tempfile from dzgui.app_init import copy_bare_configs from pathlib import Path -@pytest.mark.mods -def test_bare_file_import(): - conf_string = "DZGUI_CONF\n" - state_string = "DZGUI_STATE\n" +@pytest.fixture +def state_files(): state = [ "dzg.history", "dzg.versions", @@ -18,6 +16,12 @@ def test_bare_file_import(): "ips.csv", ".month" ] + return state + +@pytest.mark.mods +def test_config_file_import(state_files): + conf_string = "DZGUI_CONF\n" + state_string = "DZGUI_STATE\n" tmp = tempfile.TemporaryDirectory() tmp2 = tempfile.TemporaryDirectory() @@ -26,12 +30,39 @@ def test_bare_file_import(): tmp_conf_file = tmp_conf / "config.json" tmp_conf_file.write_text(conf_string) - for file in state: + for file in state_files: tmp_state.joinpath(file).write_text(state_string) tmp_state_file = tmp_state / "dzg.res.json" - copy_bare_configs(tmp_conf_file, tmp_state_file) + config_changed, state_changed = copy_bare_configs(tmp_conf_file, tmp_state_file) assert (tmp_conf / "dzgui/config.json").read_text() == conf_string - for file in state: + for file in state_files: assert (tmp_state / "dzgui" / file).read_text() == state_string + + assert config_changed is True + assert state_changed is True + +@pytest.mark.mods +def test_config_file_no_import(state_files): + conf_string = "DZGUI_CONF\n" + state_string = "DZGUI_STATE\n" + + tmp = tempfile.TemporaryDirectory() + tmp2 = tempfile.TemporaryDirectory() + tmp_conf = Path(tmp.name) + tmp_state = Path(tmp2.name) + + for d in tmp_conf, tmp_state: + subdir = d / "dzgui" + subdir.mkdir() + + tmp_conf_file = tmp_conf / "dzgui/config.json" + tmp_conf_file.write_text(conf_string) + + for file in state_files: + tmp_state.joinpath("dzgui").joinpath(file).write_text(state_string) + tmp_state_file = tmp_state / "dzgui/dzg.res.json" + config_changed, state_changed = copy_bare_configs(tmp_conf_file, tmp_state_file) + assert config_changed is False + assert state_changed is False From 4de5147899a20e6dbb27d0bad29898c9605d2f15 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Sun, 28 Jun 2026 23:52:13 +0900 Subject: [PATCH 3/4] fix: parse parent directory --- dzgui/app_init.py | 15 +++---- dzgui/config/xdg.py | 2 +- dzgui/views/dialogs/boot.py | 1 + tests/test_bare_conf_files.py | 73 ++++++++++++++++++++--------------- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/dzgui/app_init.py b/dzgui/app_init.py index 3bd1f0d..fc86e52 100644 --- a/dzgui/app_init.py +++ b/dzgui/app_init.py @@ -66,18 +66,19 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> tuple[bool, bool]: ] config_changed = False state_changed = False - if APP_NAME_LOWER not in str(config): - new_file = config.parent / APP_NAME_LOWER / conf - if config.is_file(): + if config.parent.exists() is False: + new_file = config + old_file = config.parent.parent / conf + if old_file.is_file(): make_parents(new_file) - shutil.copy(config, new_file) + shutil.copy(old_file, new_file) config_changed = True - if APP_NAME_LOWER not in str(resolution): + if resolution.parent.exists() is False: state_path = resolution.parent for state_file in state: - old_file = state_path / state_file + old_file = state_path.parent / state_file if old_file.is_file(): - new_file = state_path / APP_NAME_LOWER / state_file + new_file = state_path / state_file make_parents(new_file) shutil.copy(old_file, new_file) state_changed = True diff --git a/dzgui/config/xdg.py b/dzgui/config/xdg.py index 8494bae..5b78423 100644 --- a/dzgui/config/xdg.py +++ b/dzgui/config/xdg.py @@ -29,9 +29,9 @@ def is_writeable(path_str: str) -> bool: if not path.exists(): try: path.mkdir(parents=True) + path.unlink() except OSError: return False - path.unlink() return True try: diff --git a/dzgui/views/dialogs/boot.py b/dzgui/views/dialogs/boot.py index 8491530..f2b275d 100644 --- a/dzgui/views/dialogs/boot.py +++ b/dzgui/views/dialogs/boot.py @@ -121,6 +121,7 @@ class BootDialog(Gtk.Dialog): self.error_box.hide() + print(self.xdg.ips) steps = [ (StoredFunc(is_dayz_installed, self.xdg.config), preboot.dayz, False), (StoredFunc(rebuild_symlinks, self.xdg.config), preboot.symlinks, False), diff --git a/tests/test_bare_conf_files.py b/tests/test_bare_conf_files.py index 1eb58a6..8153e05 100644 --- a/tests/test_bare_conf_files.py +++ b/tests/test_bare_conf_files.py @@ -1,9 +1,15 @@ import pytest import tempfile +import os from dzgui.app_init import copy_bare_configs +from dzgui.config.xdg import get_xdg_paths, parse_filepaths from pathlib import Path + +CONF_STRING = "DZGUI_CONF\n" +STATE_STRING = "DZGUI_STATE\n" + @pytest.fixture def state_files(): state = [ @@ -14,55 +20,58 @@ def state_files(): "dzg.columns.json", "dzg.notes.json", "ips.csv", - ".month" + ".month", ] return state + +@pytest.fixture +def xdg_paths(): + paths = [] + routes = {"XDG_CONFIG_HOME": "", "XDG_STATE_HOME": "", "XDG_DATA_HOME": "", "XDG_CACHE_HOME": ""} + for route in routes: + tmp = tempfile.TemporaryDirectory(delete=False) + routes[route] = tmp.name + for k, v in routes.items(): + os.environ[k] = v + env = get_xdg_paths() + return parse_filepaths(env) + @pytest.mark.mods -def test_config_file_import(state_files): - conf_string = "DZGUI_CONF\n" - state_string = "DZGUI_STATE\n" +def test_config_file_import(xdg_paths, state_files): - tmp = tempfile.TemporaryDirectory() - tmp2 = tempfile.TemporaryDirectory() - tmp_conf = Path(tmp.name) - tmp_state = Path(tmp2.name) + tmp_conf = xdg_paths.config.parent.parent + tmp_conf_file = tmp_conf / xdg_paths.config.name + tmp_conf_file.write_text(CONF_STRING) + + tmp_state = xdg_paths.resolution.parent.parent + tmp_state_file = tmp_state / xdg_paths.resolution.name - tmp_conf_file = tmp_conf / "config.json" - tmp_conf_file.write_text(conf_string) for file in state_files: - tmp_state.joinpath(file).write_text(state_string) + tmp_state.joinpath(file).write_text(STATE_STRING) + config_changed, state_changed = copy_bare_configs(xdg_paths.config, xdg_paths.resolution) - tmp_state_file = tmp_state / "dzg.res.json" - config_changed, state_changed = copy_bare_configs(tmp_conf_file, tmp_state_file) - - assert (tmp_conf / "dzgui/config.json").read_text() == conf_string + assert (tmp_conf / xdg_paths.config.name).read_text() == CONF_STRING for file in state_files: - assert (tmp_state / "dzgui" / file).read_text() == state_string + assert (tmp_state / file).read_text() == STATE_STRING assert config_changed is True assert state_changed is True + @pytest.mark.mods -def test_config_file_no_import(state_files): - conf_string = "DZGUI_CONF\n" - state_string = "DZGUI_STATE\n" - - tmp = tempfile.TemporaryDirectory() - tmp2 = tempfile.TemporaryDirectory() - tmp_conf = Path(tmp.name) - tmp_state = Path(tmp2.name) - - for d in tmp_conf, tmp_state: - subdir = d / "dzgui" +def test_config_file_no_import(xdg_paths, state_files): + for subdir in xdg_paths.config.parent, xdg_paths.resolution.parent: subdir.mkdir() - tmp_conf_file = tmp_conf / "dzgui/config.json" - tmp_conf_file.write_text(conf_string) + tmp_conf_file = xdg_paths.config + tmp_conf_file.write_text(CONF_STRING) + + tmp_state_file = xdg_paths.resolution for file in state_files: - tmp_state.joinpath("dzgui").joinpath(file).write_text(state_string) - tmp_state_file = tmp_state / "dzgui/dzg.res.json" - config_changed, state_changed = copy_bare_configs(tmp_conf_file, tmp_state_file) + xdg_paths.resolution.parent.joinpath(file).write_text(STATE_STRING) + + config_changed, state_changed = copy_bare_configs(xdg_paths.config, xdg_paths.resolution) assert config_changed is False assert state_changed is False From 2b87272b529cf8146e15be80fc89359ea57c194c Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Mon, 29 Jun 2026 07:28:35 +0900 Subject: [PATCH 4/4] chore: update test conditions --- dzgui/app_init.py | 20 +++++++++++++------- dzgui/views/dialogs/boot.py | 1 - tests/test_bare_conf_files.py | 28 +++++++++++++++++++--------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/dzgui/app_init.py b/dzgui/app_init.py index fc86e52..3ed89d2 100644 --- a/dzgui/app_init.py +++ b/dzgui/app_init.py @@ -70,18 +70,24 @@ def copy_bare_configs(config: "Path", resolution: "Path") -> tuple[bool, bool]: new_file = config old_file = config.parent.parent / conf if old_file.is_file(): - make_parents(new_file) - shutil.copy(old_file, new_file) - config_changed = True + try: + make_parents(new_file) + shutil.copy(old_file, new_file) + config_changed = True + except Exception as e: + logger.critical(e) if resolution.parent.exists() is False: state_path = resolution.parent for state_file in state: old_file = state_path.parent / state_file if old_file.is_file(): - new_file = state_path / state_file - make_parents(new_file) - shutil.copy(old_file, new_file) - state_changed = True + try: + new_file = state_path / state_file + make_parents(new_file) + shutil.copy(old_file, new_file) + state_changed = True + except Exception as e: + logger.critical(e) return (config_changed, state_changed) diff --git a/dzgui/views/dialogs/boot.py b/dzgui/views/dialogs/boot.py index f2b275d..8491530 100644 --- a/dzgui/views/dialogs/boot.py +++ b/dzgui/views/dialogs/boot.py @@ -121,7 +121,6 @@ class BootDialog(Gtk.Dialog): self.error_box.hide() - print(self.xdg.ips) steps = [ (StoredFunc(is_dayz_installed, self.xdg.config), preboot.dayz, False), (StoredFunc(rebuild_symlinks, self.xdg.config), preboot.symlinks, False), diff --git a/tests/test_bare_conf_files.py b/tests/test_bare_conf_files.py index 8153e05..9235390 100644 --- a/tests/test_bare_conf_files.py +++ b/tests/test_bare_conf_files.py @@ -10,6 +10,7 @@ from pathlib import Path CONF_STRING = "DZGUI_CONF\n" STATE_STRING = "DZGUI_STATE\n" + @pytest.fixture def state_files(): state = [ @@ -28,7 +29,12 @@ def state_files(): @pytest.fixture def xdg_paths(): paths = [] - routes = {"XDG_CONFIG_HOME": "", "XDG_STATE_HOME": "", "XDG_DATA_HOME": "", "XDG_CACHE_HOME": ""} + routes = { + "XDG_CONFIG_HOME": "", + "XDG_STATE_HOME": "", + "XDG_DATA_HOME": "", + "XDG_CACHE_HOME": "", + } for route in routes: tmp = tempfile.TemporaryDirectory(delete=False) routes[route] = tmp.name @@ -37,23 +43,27 @@ def xdg_paths(): env = get_xdg_paths() return parse_filepaths(env) + @pytest.mark.mods def test_config_file_import(xdg_paths, state_files): + # NOTE: write bare files in root tmp_conf = xdg_paths.config.parent.parent tmp_conf_file = tmp_conf / xdg_paths.config.name tmp_conf_file.write_text(CONF_STRING) tmp_state = xdg_paths.resolution.parent.parent - tmp_state_file = tmp_state / xdg_paths.resolution.name - for file in state_files: tmp_state.joinpath(file).write_text(STATE_STRING) - config_changed, state_changed = copy_bare_configs(xdg_paths.config, xdg_paths.resolution) + # NOTE: function should move files into "dzgui" subdirectory + config_changed, state_changed = copy_bare_configs( + xdg_paths.config, xdg_paths.resolution + ) - assert (tmp_conf / xdg_paths.config.name).read_text() == CONF_STRING + assert xdg_paths.config.read_text() == CONF_STRING for file in state_files: - assert (tmp_state / file).read_text() == STATE_STRING + expected = xdg_paths.resolution.parent.joinpath(file) + assert expected.read_text() == STATE_STRING assert config_changed is True assert state_changed is True @@ -67,11 +77,11 @@ def test_config_file_no_import(xdg_paths, state_files): tmp_conf_file = xdg_paths.config tmp_conf_file.write_text(CONF_STRING) - tmp_state_file = xdg_paths.resolution - for file in state_files: xdg_paths.resolution.parent.joinpath(file).write_text(STATE_STRING) - config_changed, state_changed = copy_bare_configs(xdg_paths.config, xdg_paths.resolution) + config_changed, state_changed = copy_bare_configs( + xdg_paths.config, xdg_paths.resolution + ) assert config_changed is False assert state_changed is False