mirror of
https://github.com/aclist/dztui.git
synced 2026-10-28 13:42:42 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3027fa830 | ||
|
|
92699ebaa9 | ||
|
|
ef2709561d | ||
|
|
89a6996695 | ||
|
|
41b3ad8eca | ||
|
|
d57277f527 | ||
|
|
c45678ca88 | ||
|
|
c95ad53f6f | ||
|
|
3e144dc7d2 | ||
|
|
afdfa76fdf | ||
|
|
00c27ad020 | ||
|
|
d60204b676 | ||
|
|
3d2e27bfe1 | ||
|
|
8a66bafe4c |
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
from dzgui.const.constants import LEGACY_CONFIG_PATH, LEGACY_COLS_PATH, LEGACY_IPS_PATH
|
from dzgui.const.constants import LEGACY_CONFIG_PATH, LEGACY_COLS_PATH, LEGACY_IPS_PATH
|
||||||
from dzgui.config.convert import rc2json
|
from dzgui.config.convert import rc2json
|
||||||
from dzgui.util._json import read_json, write_json
|
from dzgui.util._json import read_json, write_json
|
||||||
@@ -17,7 +18,7 @@ def has_new_config(config: Path) -> bool:
|
|||||||
return config.exists()
|
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)
|
j = read_json(res)
|
||||||
cols = j["cols"]
|
cols = j["cols"]
|
||||||
# NOTE: implies prior conversion
|
# NOTE: implies prior conversion
|
||||||
|
|||||||
+7
-3
@@ -121,8 +121,6 @@ def main() -> None:
|
|||||||
with open(XDG.debug, "w") as f:
|
with open(XDG.debug, "w") as f:
|
||||||
f.truncate(0)
|
f.truncate(0)
|
||||||
|
|
||||||
latest_release = check_updates(version)
|
|
||||||
|
|
||||||
if _is_steam_deck is False:
|
if _is_steam_deck is False:
|
||||||
# TODO: sudo escalation dialog
|
# TODO: sudo escalation dialog
|
||||||
# count = get_map_count()
|
# count = get_map_count()
|
||||||
@@ -130,16 +128,22 @@ def main() -> None:
|
|||||||
if has_steam_client() is False:
|
if has_steam_client() is False:
|
||||||
EarlyAlertDialog(init.requires_steam)
|
EarlyAlertDialog(init.requires_steam)
|
||||||
|
|
||||||
|
is_dayz_installed(XDG.config)
|
||||||
|
|
||||||
|
# TODO: slow running procs here--needs dialog
|
||||||
# NOTE: clears versions file of unlinked mods
|
# NOTE: clears versions file of unlinked mods
|
||||||
rebuild_symlinks(XDG.config)
|
rebuild_symlinks(XDG.config)
|
||||||
remove_stale_signatures(XDG.config, XDG.version)
|
remove_stale_signatures(XDG.config, XDG.version)
|
||||||
|
|
||||||
is_dayz_installed(XDG.config)
|
|
||||||
# TODO: handle IP DB failure and use coords fallback
|
# 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)
|
get_ipdb(XDG.ips)
|
||||||
local_coords = get_local_coords(XDG.ips)
|
local_coords = get_local_coords(XDG.ips)
|
||||||
use_miles = lookup(XDG.config, Preferences.DIST)
|
use_miles = lookup(XDG.config, Preferences.DIST)
|
||||||
|
|
||||||
|
latest_release = check_updates(version)
|
||||||
|
|
||||||
prefs = UserPrefs(
|
prefs = UserPrefs(
|
||||||
is_steam_deck=_is_steam_deck,
|
is_steam_deck=_is_steam_deck,
|
||||||
is_game_mode=_is_game_mode,
|
is_game_mode=_is_game_mode,
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ class ConnectionManager:
|
|||||||
if len(self.missing_mods) > 0:
|
if len(self.missing_mods) > 0:
|
||||||
required_size = sum(row[2] for row in self.missing_mods)
|
required_size = sum(row[2] for row in self.missing_mods)
|
||||||
required_mib = format_mib(required_size)
|
required_mib = format_mib(required_size)
|
||||||
free_mib = format_mib(required_size)
|
free_mib = format_mib(free)
|
||||||
|
|
||||||
dayz_running = is_dayz_running()
|
dayz_running = is_dayz_running()
|
||||||
|
|
||||||
@@ -222,7 +222,8 @@ class ConnectionManager:
|
|||||||
def query_modlist_and_present(self, record: Servers.Record) -> None:
|
def query_modlist_and_present(self, record: Servers.Record) -> None:
|
||||||
try:
|
try:
|
||||||
mods = self._query_modlist(record)
|
mods = self._query_modlist(record)
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
print(f"{type(e).__name__}: {e}")
|
||||||
self.thread_man.set_cleanup_func(
|
self.thread_man.set_cleanup_func(
|
||||||
StoredFunc(self._server_timeout), destroy_first=True
|
StoredFunc(self._server_timeout), destroy_first=True
|
||||||
)
|
)
|
||||||
@@ -279,8 +280,13 @@ class ConnectionManager:
|
|||||||
|
|
||||||
for title, mod, stamp, size in self.missing_mods:
|
for title, mod, stamp, size in self.missing_mods:
|
||||||
# TODO: check cancel and exit events
|
# 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)
|
enqueue_mod(mod, self.appid)
|
||||||
time.sleep(2)
|
time.sleep(3)
|
||||||
|
|
||||||
if raise_window is True:
|
if raise_window is True:
|
||||||
logger.info("Bringing window to foreground")
|
logger.info("Bringing window to foreground")
|
||||||
|
|||||||
@@ -324,6 +324,7 @@ class ServerModelManager:
|
|||||||
self.thread_man.set_cleanup_func(func)
|
self.thread_man.set_cleanup_func(func)
|
||||||
return
|
return
|
||||||
config_man.add_saved_server(fqip)
|
config_man.add_saved_server(fqip)
|
||||||
|
|
||||||
# FIXME: this is valid if saved servers tab is already open,
|
# FIXME: this is valid if saved servers tab is already open,
|
||||||
# but not if app was just booted; causes single row to appear prematurely
|
# but not if app was just booted; causes single row to appear prematurely
|
||||||
if proxy_man.has_control_model() is False:
|
if proxy_man.has_control_model() is False:
|
||||||
@@ -374,7 +375,8 @@ class ServerModelManager:
|
|||||||
proxy = self._get_proxy_man().get_proxy_model()
|
proxy = self._get_proxy_man().get_proxy_model()
|
||||||
self.tv.set_model(proxy)
|
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()
|
filter_man = self.tv.get_filter_man()
|
||||||
# NOTE: maps are set outside of thread because it triggers map changed signals
|
# NOTE: maps are set outside of thread because it triggers map changed signals
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ def read_json(path: Path) -> Any:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
def write_json(data: dict, path: Path) -> None:
|
def write_json(data: dict[str, Any], path: Path) -> None:
|
||||||
try:
|
try:
|
||||||
j = json.dumps(data, indent=2)
|
j = json.dumps(data, indent=2)
|
||||||
path.write_text(j)
|
path.write_text(j)
|
||||||
|
|||||||
+10
-7
@@ -43,11 +43,14 @@ def clone_symlinks(steam_path: Path) -> None:
|
|||||||
|
|
||||||
# TODO: test these two operations
|
# TODO: test these two operations
|
||||||
# use less time intensive logic like the above
|
# use less time intensive logic like the above
|
||||||
for file in exp_path.iterdir():
|
try:
|
||||||
if file.is_symlink():
|
for file in exp_path.iterdir():
|
||||||
file.unlink()
|
if file.is_symlink():
|
||||||
|
file.unlink()
|
||||||
|
|
||||||
for file in dayz_path.iterdir():
|
for file in dayz_path.iterdir():
|
||||||
if file.is_symlink():
|
if file.is_symlink():
|
||||||
uid = file.name
|
uid = file.name
|
||||||
Path(exp_path / uid).symlink_to(dayz_path / uid)
|
Path(exp_path / uid).symlink_to(dayz_path / uid)
|
||||||
|
except Exception as e:
|
||||||
|
logger.critical(e)
|
||||||
@@ -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)
|
||||||
@@ -53,3 +53,5 @@ class EarlyIgnoreDialog(EarlyAlertDialog):
|
|||||||
|
|
||||||
# TODO: reverse order
|
# TODO: reverse order
|
||||||
self.add_button("Ignore", Gtk.ResponseType.CANCEL)
|
self.add_button("Ignore", Gtk.ResponseType.CANCEL)
|
||||||
|
|
||||||
|
# TODO: if exit, sys.exit(1), else pass
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
from dzgui.const.constants import LOG_FILTERS
|
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.cursor_mixin import CursorMixin
|
||||||
from dzgui.views.mixins.help_menu_mixin import HelpMenuMixin
|
from dzgui.views.mixins.help_menu_mixin import HelpMenuMixin
|
||||||
from dzgui.views.trees.tree_log import LogTreeView
|
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
|
NOTE: LogTreeView is kept in a separate ScrolledWindow so that
|
||||||
checkboxes will be flush on bottom
|
checkboxes will be flush on bottom
|
||||||
"""
|
"""
|
||||||
self.scrolled = Gtk.ScrolledWindow()
|
self.scrolled = NoOverlayScrolledWindow()
|
||||||
self.treeview = LogTreeView(controller)
|
self.treeview = LogTreeView(controller)
|
||||||
self.scrolled.add(self.treeview)
|
self.scrolled.add(self.treeview)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from typing import Self, TYPE_CHECKING
|
from typing import Self, TYPE_CHECKING
|
||||||
|
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
|
||||||
from dzgui.views.trees.tree_mods import ModTreeView
|
from dzgui.views.trees.tree_mods import ModTreeView
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@@ -10,7 +11,8 @@ if TYPE_CHECKING:
|
|||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|
||||||
|
|
||||||
class Mods(Gtk.ScrolledWindow):
|
|
||||||
|
class Mods(NoOverlayScrolledWindow):
|
||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
|||||||
@@ -162,19 +162,6 @@ class ServerNotebook(Gtk.ScrolledWindow):
|
|||||||
return tv
|
return tv
|
||||||
raise ValueError("No treeview set")
|
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:
|
def update_tab_widths(self, col: Gtk.TreeViewColumn) -> None:
|
||||||
# TODO: may cause pixel offsets when application is maximized
|
# TODO: may cause pixel offsets when application is maximized
|
||||||
width = col.get_width()
|
width = col.get_width()
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
|
|||||||
authors = [
|
authors = [
|
||||||
{name = "aclist"}
|
{name = "aclist"}
|
||||||
]
|
]
|
||||||
version = "7.0.0b5"
|
version = "7.0.0b6"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
@@ -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
@@ -5,11 +5,12 @@ import tarfile
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from prebuild import get_pyapp, rebuild_cpython
|
||||||
|
|
||||||
|
|
||||||
root = Path(__file__).resolve().parents[1]
|
root = Path(__file__).resolve().parents[1]
|
||||||
output = root.joinpath("dist")
|
output = root.joinpath("dist")
|
||||||
|
build_dir = root.joinpath("build")
|
||||||
pyapp_dir = root.joinpath("pyapp-latest")
|
|
||||||
cpython = root.joinpath("build/cpython/airgapped.tar.gz")
|
|
||||||
|
|
||||||
builder = build.ProjectBuilder(root)
|
builder = build.ProjectBuilder(root)
|
||||||
wheel = builder.build("wheel", output_directory=output)
|
wheel = builder.build("wheel", output_directory=output)
|
||||||
@@ -20,8 +21,15 @@ metadata = stem.split("-")
|
|||||||
appname = metadata[0]
|
appname = metadata[0]
|
||||||
version = metadata[1]
|
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 = os.environ
|
||||||
env["PYAPP_PROJECT_VERSION"] = version
|
env["PYAPP_PROJECT_VERSION"] = version
|
||||||
env["PYAPP_PROJECT_NAME"] = appname
|
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)
|
proc = subprocess.run(["cargo", "build", "--release"], env=env, cwd=pyapp_dir)
|
||||||
if proc.returncode == 0:
|
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)
|
release_exe = output.joinpath(appname)
|
||||||
output_exe.rename(release_exe)
|
output_exe.rename(release_exe)
|
||||||
tarpath = output.joinpath(tarname)
|
tarpath = output.joinpath(tarname)
|
||||||
|
|||||||
Reference in new issue
Block a user