Compare commits

...
14 Commits
Author SHA1 Message Date
aclist e3027fa830 Merge pull request #310 from aclist/fix/7.0.0b6-hotfixes
fix: 7.0.0b6 hotfixes
2026-05-26 04:54:48 +09:00
aclist 92699ebaa9 chore: revert delay to 3s 2026-05-26 04:42:50 +09:00
aclist ef2709561d fix: resolve #306 2026-05-26 04:40:14 +09:00
aclist 89a6996695 Merge pull request #304 from aclist/chore/prebuild-script
chore: update build tools
2026-05-26 04:01:24 +09:00
aclist 41b3ad8eca chore: clear typehinting errors 2026-05-26 03:59:11 +09:00
aclist d57277f527 fix: drop unused import 2026-05-26 03:57:13 +09:00
aclist c45678ca88 chore: add custom ScrolledWindow class 2026-05-26 03:56:35 +09:00
aclist c95ad53f6f chore: bump version 2026-05-26 03:55:51 +09:00
aclist 3e144dc7d2 fix: resolve #305 2026-05-26 03:54:30 +09:00
aclist afdfa76fdf fix: resolve #309, #307 2026-05-26 03:53:01 +09:00
aclist 00c27ad020 fix: resolve #308 2026-05-26 03:52:11 +09:00
aclist d60204b676 chore: reorder operations in entrypoint function 2026-05-26 03:51:44 +09:00
aclist 3d2e27bfe1 chore: update release script 2026-05-26 00:56:02 +09:00
aclist 8a66bafe4c chore: update build tools 2026-05-26 00:55:11 +09:00
14 changed files with 143 additions and 37 deletions

No files matched your search

+2 -1
View File
@@ -1,6 +1,7 @@
import shutil
from pathlib import Path
from typing import Any
from dzgui.const.constants import LEGACY_CONFIG_PATH, LEGACY_COLS_PATH, LEGACY_IPS_PATH
from dzgui.config.convert import rc2json
from dzgui.util._json import read_json, write_json
@@ -17,7 +18,7 @@ def has_new_config(config: Path) -> bool:
return config.exists()
def convert_cols_file(res: Path) -> dict[str, int] | None:
def convert_cols_file(res: Path) -> Any | None:
j = read_json(res)
cols = j["cols"]
# NOTE: implies prior conversion
+7 -3
View File
@@ -121,8 +121,6 @@ def main() -> None:
with open(XDG.debug, "w") as f:
f.truncate(0)
latest_release = check_updates(version)
if _is_steam_deck is False:
# TODO: sudo escalation dialog
# count = get_map_count()
@@ -130,16 +128,22 @@ def main() -> None:
if has_steam_client() is False:
EarlyAlertDialog(init.requires_steam)
is_dayz_installed(XDG.config)
# TODO: slow running procs here--needs dialog
# NOTE: clears versions file of unlinked mods
rebuild_symlinks(XDG.config)
remove_stale_signatures(XDG.config, XDG.version)
is_dayz_installed(XDG.config)
# TODO: handle IP DB failure and use coords fallback
# TODO: drop this after dialog is complete
print("Fetching geolocation data, may take some time...")
get_ipdb(XDG.ips)
local_coords = get_local_coords(XDG.ips)
use_miles = lookup(XDG.config, Preferences.DIST)
latest_release = check_updates(version)
prefs = UserPrefs(
is_steam_deck=_is_steam_deck,
is_game_mode=_is_game_mode,
+9 -3
View File
@@ -161,7 +161,7 @@ class ConnectionManager:
if len(self.missing_mods) > 0:
required_size = sum(row[2] for row in self.missing_mods)
required_mib = format_mib(required_size)
free_mib = format_mib(required_size)
free_mib = format_mib(free)
dayz_running = is_dayz_running()
@@ -222,7 +222,8 @@ class ConnectionManager:
def query_modlist_and_present(self, record: Servers.Record) -> None:
try:
mods = self._query_modlist(record)
except Exception:
except Exception as e:
print(f"{type(e).__name__}: {e}")
self.thread_man.set_cleanup_func(
StoredFunc(self._server_timeout), destroy_first=True
)
@@ -279,8 +280,13 @@ class ConnectionManager:
for title, mod, stamp, size in self.missing_mods:
# TODO: check cancel and exit events
if self.controller.get_exit_event().is_set():
return
if self.controller.get_cancel_event().is_set():
self.controller.clear_cancel_event()
return
enqueue_mod(mod, self.appid)
time.sleep(2)
time.sleep(3)
if raise_window is True:
logger.info("Bringing window to foreground")
+3 -1
View File
@@ -324,6 +324,7 @@ class ServerModelManager:
self.thread_man.set_cleanup_func(func)
return
config_man.add_saved_server(fqip)
# FIXME: this is valid if saved servers tab is already open,
# but not if app was just booted; causes single row to appear prematurely
if proxy_man.has_control_model() is False:
@@ -374,7 +375,8 @@ class ServerModelManager:
proxy = self._get_proxy_man().get_proxy_model()
self.tv.set_model(proxy)
self.emitter.emit("servers_loaded", self.enum)
if self.controller.get_active_treeview().get_enum == ServerTab.SAVED:
self.emitter.emit("servers_loaded", self.enum)
filter_man = self.tv.get_filter_man()
# NOTE: maps are set outside of thread because it triggers map changed signals
+1 -1
View File
@@ -12,7 +12,7 @@ def read_json(path: Path) -> Any:
raise e
def write_json(data: dict, path: Path) -> None:
def write_json(data: dict[str, Any], path: Path) -> None:
try:
j = json.dumps(data, indent=2)
path.write_text(j)
+10 -7
View File
@@ -43,11 +43,14 @@ def clone_symlinks(steam_path: Path) -> None:
# TODO: test these two operations
# use less time intensive logic like the above
for file in exp_path.iterdir():
if file.is_symlink():
file.unlink()
try:
for file in exp_path.iterdir():
if file.is_symlink():
file.unlink()
for file in dayz_path.iterdir():
if file.is_symlink():
uid = file.name
Path(exp_path / uid).symlink_to(dayz_path / uid)
for file in dayz_path.iterdir():
if file.is_symlink():
uid = file.name
Path(exp_path / uid).symlink_to(dayz_path / uid)
except Exception as e:
logger.critical(e)
+9
View File
@@ -0,0 +1,9 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa
class NoOverlayScrolledWindow(Gtk.ScrolledWindow):
def __init__(self) -> None:
super().__init__(overlay_scrolling=False)
+2
View File
@@ -53,3 +53,5 @@ class EarlyIgnoreDialog(EarlyAlertDialog):
# TODO: reverse order
self.add_button("Ignore", Gtk.ResponseType.CANCEL)
# TODO: if exit, sys.exit(1), else pass
+2 -1
View File
@@ -1,5 +1,6 @@
from typing import TYPE_CHECKING
from dzgui.const.constants import LOG_FILTERS
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
from dzgui.views.mixins.cursor_mixin import CursorMixin
from dzgui.views.mixins.help_menu_mixin import HelpMenuMixin
from dzgui.views.trees.tree_log import LogTreeView
@@ -21,7 +22,7 @@ class Log(CursorMixin, HelpMenuMixin, Gtk.Box): # type: ignore
NOTE: LogTreeView is kept in a separate ScrolledWindow so that
checkboxes will be flush on bottom
"""
self.scrolled = Gtk.ScrolledWindow()
self.scrolled = NoOverlayScrolledWindow()
self.treeview = LogTreeView(controller)
self.scrolled.add(self.treeview)
+3 -1
View File
@@ -1,4 +1,5 @@
from typing import Self, TYPE_CHECKING
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
from dzgui.views.trees.tree_mods import ModTreeView
import gi
@@ -10,7 +11,8 @@ if TYPE_CHECKING:
from dzgui.controllers.mc import Controller
class Mods(Gtk.ScrolledWindow):
class Mods(NoOverlayScrolledWindow):
def __init__(self, controller: "Controller") -> None:
super().__init__()
-13
View File
@@ -162,19 +162,6 @@ class ServerNotebook(Gtk.ScrolledWindow):
return tv
raise ValueError("No treeview set")
def add_notification(self) -> None:
saved = self.notebook.get_nth_page(1)
if saved is None:
return
text = self.notebook.get_tab_label_text(saved)
if text is None:
return
# TODO: strings
if "*" in text:
return
text += "*"
self.notebook.set_tab_label_text(saved, text)
def update_tab_widths(self, col: Gtk.TreeViewColumn) -> None:
# TODO: may cause pixel offsets when application is maximized
width = col.get_width()
+1 -1
View File
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
authors = [
{name = "aclist"}
]
version = "7.0.0b5"
version = "7.0.0b6"
license = "GPL-3.0-or-later"
license-files = ["LICENSE"]
readme = "README.md"
+81
View File
@@ -0,0 +1,81 @@
import os
import requests
import subprocess
import tarfile
from pathlib import Path
from urllib.parse import unquote
BUILD = "3.13.9"
DATE = "20251014"
CPYTHON_BUILD = f"cpython-{BUILD}"
root = Path(__file__).resolve().parents[1]
build_dir = root.joinpath("build")
cpython_dir = build_dir.joinpath(CPYTHON_BUILD)
def fetch(url: str, destination: str) -> None:
print(f"Fetching URL '{url}'")
res = requests.get(url)
code = res.status_code
if code != 200:
raise Exception(f"URL '{url}' returned status code {code}")
with open(build_dir.joinpath(destination), "wb") as f:
f.write(res.content)
def get_cpython() -> None:
source = f"https://github.com/astral-sh/python-build-standalone/releases/download/{DATE}/"
build = f"{CPYTHON_BUILD}%2B{DATE}-x86_64_v3-unknown-linux-gnu-install_only_stripped.tar.gz"
url = f"{source}{build}"
outfile = unquote(build)
fetch(url, outfile)
version = build.split("%")[0]
untar(outfile, "python", version)
def get_pyapp() -> None:
url = "https://github.com/ofek/pyapp/releases/latest/download/source.tar.gz"
outfile = "pyapp-latest.tar.gz"
fetch(url, outfile)
untar(outfile, "pyapp-*", "pyapp-latest")
def untar(file: str, glob: str, renamed: str) -> None:
full_path = build_dir.joinpath(file)
with tarfile.open(full_path, "r:gz") as tar:
tar.extractall(path=build_dir)
full_path.unlink()
for _dir in build_dir.glob(glob):
os.rename(_dir, build_dir.joinpath(renamed))
def install_deps() -> None:
pip = build_dir.joinpath(f"{CPYTHON_BUILD}/bin/pip")
subprocess.run([pip, "install", root])
def repackage() -> None:
print("Preparing tar archive...")
outfile = build_dir.joinpath("airgapped.tar.gz")
with tarfile.open(outfile, "w:gz") as tar:
tar.add(build_dir.joinpath(CPYTHON_BUILD), arcname="python")
def rebuild_cpython() -> None:
if cpython_dir.is_dir() is False:
get_cpython()
install_deps()
repackage()
return get_packaged_version()
def get_packaged_version() -> str:
proc = subprocess.run(
[cpython_dir.joinpath("bin/dzgui"), "-v"],
capture_output=True,
text=True,
check=True,
)
return proc.stdout.rstrip()
+13 -5
View File
@@ -5,11 +5,12 @@ import tarfile
from pathlib import Path
from prebuild import get_pyapp, rebuild_cpython
root = Path(__file__).resolve().parents[1]
output = root.joinpath("dist")
pyapp_dir = root.joinpath("pyapp-latest")
cpython = root.joinpath("build/cpython/airgapped.tar.gz")
build_dir = root.joinpath("build")
builder = build.ProjectBuilder(root)
wheel = builder.build("wheel", output_directory=output)
@@ -20,8 +21,15 @@ metadata = stem.split("-")
appname = metadata[0]
version = metadata[1]
entrypoint = "dzgui.main:main"
pyapp_dir = build_dir.joinpath("pyapp-latest")
if pyapp_dir.is_dir() is False:
get_pyapp()
packaged_version = rebuild_cpython()
assert packaged_version == version
cpython = build_dir.joinpath("airgapped.tar.gz")
entrypoint = "dzgui.main:main"
env = os.environ
env["PYAPP_PROJECT_VERSION"] = version
env["PYAPP_PROJECT_NAME"] = appname
@@ -38,7 +46,7 @@ env["PYAPP_DISTRIBUTION_PYTHON_PATH"] = "python/bin/python3"
proc = subprocess.run(["cargo", "build", "--release"], env=env, cwd=pyapp_dir)
if proc.returncode == 0:
output_exe = root.joinpath("pyapp-latest/target/release/pyapp")
output_exe = build_dir.joinpath("pyapp-latest/target/release/pyapp")
release_exe = output.joinpath(appname)
output_exe.rename(release_exe)
tarpath = output.joinpath(tarname)