Compare commits

..
Author SHA1 Message Date
aclist 96d50ffafa chore: resolve pytest errors 2026-10-18 07:44:31 +09:00
aclist 6c801ffec5 chore: update tests 2026-10-18 07:44:14 +09:00
aclist 5eb70a1eb8 fix: support changes to VDF format 2026-10-18 07:35:17 +09:00
aclist 7dd14804aa Merge pull request #491 from aclist/fix/dword-parse
Mirror to Codeberg / mirror-to-codeberg (push) Canceled after 0s
fix: dword parse
2026-10-16 00:09:26 +09:00
aclist 1cc1ba2864 chore: bump version 2026-10-16 00:06:54 +09:00
aclist 8c4d0aecdc fix: parse alternate VS_FIXEDFILEINFO structure 2026-10-16 00:06:37 +09:00
aclist 616f18452a Merge pull request #489 from aclist/fix/badlands
Mirror to Codeberg / mirror-to-codeberg (push) Canceled after 0s
fix: badlands
2026-10-15 19:26:43 +09:00
aclist 1064f7a9d6 chore: clear typehinting errors 2026-10-15 19:23:42 +09:00
aclist b0e85f0e35 fix: update Badlands flag 2026-10-15 19:22:44 +09:00
aclist 4d02604bcf Merge pull request #485 from aclist/fix/gint-warning
Mirror to Codeberg / mirror-to-codeberg (push) Canceled after 0s
fix: use more stable GObject signal
2026-10-15 00:32:28 +09:00
aclist 61860f6aee Merge pull request #482 from aclist/fix/duplicate-warnings
Fix/duplicate warnings
2026-10-14 23:12:18 +09:00
14 changed files with 59 additions and 73 deletions

No files matched your search

+20 -8
View File
@@ -255,16 +255,28 @@ class PeFileError(Exception):
pass
def parse_version_number(data: BinaryIO) -> FileVersion:
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
minor = struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF
major = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
build = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
# NOTE: 0-pad revision number
revision = str(struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF)
offset = 3 - len(revision)
padded = "0" * offset + revision
return FileVersion(major, minor, build, padded)
"""
Note: structure differs from standard VS_FIXEDFILEINFO
Major: lower 16 bits of first DWORD
Minor: upper 16 bits of first DWORD
Build: lower 16 bits of third DWORD
Revision: upper 16 bits of second DWORD, zero-padded
Lower 16 bits of revision DWORD appear unused.
"""
major_minor = struct.unpack("<I", data.read(4))[0]
revision_pair = struct.unpack("<I", data.read(4))[0]
build_dword = struct.unpack("<I", data.read(4))[0]
major = major_minor & 0xFFFF
minor = (major_minor >> 16) & 0xFFFF
build = build_dword & 0xFFFF
revision = (revision_pair >> 16) & 0xFFFF
revision = f"{revision:03d}"
return FileVersion(major, minor, build, revision)
def seek_to_hex(address: str, data: BinaryIO) -> None:
+1 -1
View File
@@ -346,7 +346,7 @@ def get_details(record: Record) -> Details | None:
dlc = strings.dlc_none
case 2:
dlc = strings.dlc_frostline
case 3:
case 4:
dlc = strings.dlc_badlands
case _:
dlc = strings.unspecified
+6 -6
View File
@@ -11,7 +11,7 @@ from typing import Any, Union
from warnings import deprecated
from dzgui.api.acf import ACF
from dzgui.init.prereqs import has_any_client
from dzgui.init.prereqs import has_steam_client
from dzgui.const.constants import (
APPID_DAYZ,
APPID_DAYZ_EXP,
@@ -59,7 +59,7 @@ class VDFLoadError(Exception):
def get_steam_paths() -> list[tuple[Path, str]]:
paths = []
if has_any_client():
if has_steam_client():
HOME = Path.home()
env = os.environ.get("XDG_DATA_HOME")
if env is not None:
@@ -245,9 +245,9 @@ def find_user_id(path: Path) -> str | None:
last_user = str(next(iter(users)))
if len(users) == 1:
return last_user
last_stamp = int(users[last_user]["Timestamp"])
last_stamp = int(users[last_user]["timestamp"])
for user in users:
stamp = int(users[user]["Timestamp"])
stamp = int(users[user]["timestamp"])
if stamp > last_stamp:
last_stamp = stamp
last_user = user
@@ -265,12 +265,12 @@ def find_user_id_32(path: Path) -> int:
class SteamAPIKeyError(Exception):
def __init__(self, msg: str | None = None) -> None:
def __init__(self, msg: str | None = None):
super().__init__(msg or api_validation_error)
class SteamWorkshopEndpointError(Exception):
def __init__(self, msg: str | None = None) -> None:
def __init__(self, msg: str | None = None):
super().__init__(msg or workshop_endpoint_error)
+2 -2
View File
@@ -15,7 +15,7 @@ from dzgui.init.migrate import (
migrate_cols_file,
)
from dzgui.init.flock import lock_acquire
from dzgui.init.prereqs import has_any_client
from dzgui.init.prereqs import has_steam_client
from dzgui.strings import boot
from dzgui.util.deck import is_steam_deck, is_game_mode
@@ -136,7 +136,7 @@ def load_gui(version: str, is_debug: bool) -> None:
# TODO: sudo escalation dialog
# count = get_map_count()
# TODO: move into module
if has_any_client() is False:
if has_steam_client() is False:
EarlyAlertDialog(init.requires_steam)
bootwin = BootWindow(XDG, version)
+7 -20
View File
@@ -7,32 +7,19 @@ from dzgui.const.constants import APP_NAME, FLATPAK_APPID, FLATPAK_CMD, STEAM_CM
logger = logging.getLogger(APP_NAME)
def has_flatpak_client() -> bool:
def has_steam_client() -> bool:
if shutil.which(STEAM_CMD):
return True
if not shutil.which(FLATPAK_CMD):
return False
try:
res = subprocess.run(
[FLATPAK_CMD, "list", "--columns=application"],
capture_output=True,
text=True,
check=True,
[FLATPAK_CMD, "list"], capture_output=True, text=True, check=True
)
if FLATPAK_APPID in res.stdout:
return True
else:
return False
except Exception as e:
except subprocess.CalledProcessError as e:
logger.critical(e)
return False
def has_steam_client() -> bool:
if shutil.which(STEAM_CMD):
return True
return False
def has_any_client() -> bool:
if shutil.which(STEAM_CMD):
return True
if not shutil.which(FLATPAK_CMD):
return False
return has_flatpak_client()
+2 -23
View File
@@ -3,8 +3,6 @@ from dzgui.strings import options
from dzgui.views.components.box import HBox
from dzgui.views.components.buttons import Icon
from typing import Self
from dzgui.init.prereqs import has_steam_client, has_flatpak_client
import gi
@@ -16,55 +14,36 @@ class ClientCombo(Gtk.ComboBox):
def __init__(self) -> None:
super().__init__()
has_steam = has_steam_client()
has_flatpak = has_flatpak_client()
self.client_store = Gtk.ListStore(str, str, bool)
self.client_store = Gtk.ListStore(str, str)
self.clients = (
(
options.steam_combo,
STEAM_CMD,
has_steam,
),
(
options.flatpak_combo,
FLATPAK_RUN_CMD,
has_flatpak,
),
(
options.flatpak_container_combo,
FLATPAK_SANDBOX,
has_flatpak,
),
)
for client in self.clients:
self.client_store.append(client)
self.set_model(self.client_store)
renderer_text = Gtk.CellRendererText()
self.pack_start(renderer_text, True)
self.add_attribute(renderer_text, "text", 0)
self.set_active(0)
self.set_cell_data_func(self.get_cells()[0], self.data_func)
def data_func(
self,
combo: Self,
cell: Gtk.CellRendererText,
model: Gtk.ListStore,
_iter: Gtk.TreeIter,
) -> None:
sens = model[_iter][2]
cell.set_property("sensitive", sens)
def get_client_human_readable(self, cmd: str) -> str:
for client in self.clients:
human, command, sens = client
human, command = client
if command == cmd:
return human
raise TypeError("Not a valid Steam client selection")
class ErrorPopover(Gtk.Popover):
def __init__(self, relative_to: Gtk.Widget, position: Gtk.PositionType) -> None:
super().__init__(relative_to=relative_to, position=position)
+1 -1
View File
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
authors = [
{name = "aclist"}
]
version = "7.0.0b26"
version = "7.0.0b28"
license = "GPL-3.0-or-later"
license-files = ["LICENSE"]
readme = "README.md"
+1 -1
View File
@@ -8,6 +8,6 @@
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "0"
"timestamp" "0"
}
}
+2 -2
View File
@@ -8,7 +8,7 @@
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "1787904411"
"timestamp" "1787904411"
}
"1"
{
@@ -18,6 +18,6 @@
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "1787904647"
"timestamp" "1787904647"
}
}
+2 -2
View File
@@ -8,7 +8,7 @@
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "1797904411"
"timestamp" "1797904411"
}
"1"
{
@@ -18,6 +18,6 @@
"WantsOfflineMode" "0"
"SkipOfflineModeWarning" "0"
"AutoLogin" "1"
"Timestamp" "1787904647"
"timestamp" "1787904647"
}
}
+1 -1
View File
@@ -9,6 +9,6 @@
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "1"
"Timestamp" "0"
"timestamp" "0"
}
}
+2 -2
View File
@@ -9,7 +9,7 @@
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "0"
"Timestamp" "0"
"timestamp" "0"
}
"1"
{
@@ -20,6 +20,6 @@
"SkipOfflineModeWarning" "0"
"AllowAutoLogin" "1"
"MostRecent" "1"
"Timestamp" "10"
"timestamp" "10"
}
}
+3 -4
View File
@@ -10,7 +10,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio, GLib # noqa
class TestWidget(ColorAwareApp, Gtk.Button):
class DummyWidget(ColorAwareApp, Gtk.Button):
def __init__(self) -> None:
super().__init__()
@@ -22,11 +22,10 @@ class TestWidget(ColorAwareApp, Gtk.Button):
@pytest.fixture
def widget() -> TestWidget:
return TestWidget()
def widget() -> DummyWidget:
return DummyWidget()
@pytest.mark.integration
@pytest.mark.parametrize("key, expect", [("default", False), ("prefer-dark", True)])
def test_light_mode(widget, key: str, expect: bool) -> None:
local_pref = subprocess.run(
+9
View File
@@ -3,6 +3,7 @@ import pytest
from pathlib import Path
from dzgui.api.steam import find_user_id
from dzgui.const.constants import DEFAULT_STEAM_PATH
from tests.fixtures import fixture_path
pytestmark = pytest.mark.apitest
@@ -25,3 +26,11 @@ def test_loginusers(monkeypatch, fixture: str, expect: int) -> None:
monkeypatch.setattr("dzgui.api.steam.find_loginusers", mock_loginusers)
uid = find_user_id(Path(""))
assert int(uid) == expect
@pytest.mark.realconfig
def test_live_loginusers() -> None:
"""Added on 2026-10-17 following changes to VDF keys"""
steam = Path.home().joinpath(DEFAULT_STEAM_PATH)
uid = find_user_id(steam)
assert uid is not None