mirror of
https://github.com/aclist/dztui.git
synced 2026-11-06 18:10:58 +01:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ba6b6c040 | ||
|
|
d3b9ba031d | ||
|
|
8bfcb6c8fe | ||
|
|
353b10ebfc | ||
|
|
698150645d | ||
|
|
87f347870f | ||
|
|
74bf4b5cfc | ||
|
|
896799f904 | ||
|
|
0f591e658c | ||
|
|
f9083b33ef | ||
|
|
89fcfcb5d6 | ||
|
|
fc7f1d7815 | ||
|
|
fb36425083 | ||
|
|
c5d8afbc4d | ||
|
|
17f732fafe | ||
|
|
676a7ea9eb | ||
|
|
d3f64c1ba5 | ||
|
|
5da3397a29 | ||
|
|
eca6df90d4 | ||
|
|
2d58df1c89 | ||
|
|
de4521a366 | ||
|
|
fe9f488e10 | ||
|
|
7b5d99c34b | ||
|
|
0a84c20d1d | ||
|
|
d5309c1ddf | ||
|
|
418c0f026d | ||
|
|
af3a9cfa77 | ||
|
|
1b20969c30 | ||
|
|
7f1125432e | ||
|
|
c063059c19 |
No files matched your search
@@ -0,0 +1,3 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: aclist
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
name: Bug report
|
||||||
|
description: Submit bugs that affect functionality here
|
||||||
|
title: "[BUG] Your title here"
|
||||||
|
labels: ["bug"]
|
||||||
|
assignees:
|
||||||
|
- aclist
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
### WARNING: When posting log/config data, redact any sensitive information like API keys.
|
||||||
|
- type: checkboxes
|
||||||
|
id: kb
|
||||||
|
attributes:
|
||||||
|
label: Did you check if this issue already exists?
|
||||||
|
options:
|
||||||
|
- label: I have checked the [Knowledge Base](https://aclist.github.io/dzgui/kb.html) and searched through [past issues](https://github.com/aclist/dztui/issues?q=is%3Aissue+is%3Aclosed) and did not find my issue there.
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: Device type
|
||||||
|
options:
|
||||||
|
- Desktop PC
|
||||||
|
- Steam Deck
|
||||||
|
default: 0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: DZGUI version
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "5.6.0"
|
||||||
|
- type: input
|
||||||
|
id: distro
|
||||||
|
attributes:
|
||||||
|
label: Linux distribution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "Arch Linux"
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: Describe the bug
|
||||||
|
description: What did you expect to happen?
|
||||||
|
placeholder: "E.g., When doing X, Y occurred. Include as much detail as possible."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Additional log output
|
||||||
|
description: Attach the file `$HOME/.local/state/dzgui/DZGUI_DEBUG.log` by clicking this area to highlight it and then dragging the file in.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
name: Feature suggestion
|
||||||
|
description: Submit requests for new features here
|
||||||
|
title: "[FEAT] Your title here"
|
||||||
|
labels: ["enhancement"]
|
||||||
|
assignees:
|
||||||
|
- aclist
|
||||||
|
body:
|
||||||
|
- type: dropdown
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: Device type
|
||||||
|
options:
|
||||||
|
- Desktop PC
|
||||||
|
- Steam Deck
|
||||||
|
default: 0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: DZGUI version
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "5.6.0"
|
||||||
|
- type: input
|
||||||
|
id: distro
|
||||||
|
attributes:
|
||||||
|
label: Linux distribution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "Arch Linux"
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: Describe the feature
|
||||||
|
description: A clear and detailed description
|
||||||
|
placeholder: "E.g., Add a dialog to the Options menu that automatically lets the user do Y"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: why
|
||||||
|
attributes:
|
||||||
|
label: Describe the benefit
|
||||||
|
description: How will this feature benefit large numbers of users?
|
||||||
|
placeholder: "E.g., Currently, users have to manually do X to achieve Y. Implementing this feature would achieve A, B, and C."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: Troubleshooting
|
||||||
|
description: Submit user error/troubleshooting questions here
|
||||||
|
title: "[HELP] Your title here"
|
||||||
|
labels: ["troubleshooting"]
|
||||||
|
assignees:
|
||||||
|
- aclist
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
### WARNING: When posting log/config data, redact any sensitive information like API keys.
|
||||||
|
- type: dropdown
|
||||||
|
id: device
|
||||||
|
attributes:
|
||||||
|
label: Device type
|
||||||
|
options:
|
||||||
|
- Desktop PC
|
||||||
|
- Steam Deck
|
||||||
|
default: 0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: DZGUI version
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "5.6.0"
|
||||||
|
- type: input
|
||||||
|
id: distro
|
||||||
|
attributes:
|
||||||
|
label: Linux distribution
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
placeholder: "Arch Linux"
|
||||||
|
- type: textarea
|
||||||
|
id: what-happened
|
||||||
|
attributes:
|
||||||
|
label: Describe the issue
|
||||||
|
description: A detailed description. What did you expect to happen?
|
||||||
|
placeholder: "Include as much detail as possible and state the steps leading up to the problem. E.g., First I do this, then I do this, then this happens."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Additional log output
|
||||||
|
description: Attach the file `$HOME/.local/state/dzgui/DZGUI_DEBUG.log` by clicking this area to highlight it and then dragging the file in.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
name: Mirror to Codeberg
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mirror-to-codeberg:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: pixta-dev/repository-mirroring-action@v1
|
||||||
|
if: ${{ vars.GIT_REMOTE != '' }}
|
||||||
|
with:
|
||||||
|
target_repo_url: ${{ vars.GIT_REMOTE }}
|
||||||
|
ssh_private_key: ${{ secrets.GIT_SSH_PRIVATE_KEY }}
|
||||||
@@ -65,7 +65,6 @@
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
- Load offline mods
|
- Load offline mods
|
||||||
- Choose to jump into splash screen instead of server
|
- Choose to jump into splash screen instead of server
|
||||||
- Setup wizard
|
|
||||||
- Local documentation
|
- Local documentation
|
||||||
- Raw debug command in context menu
|
- Raw debug command in context menu
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -14,5 +14,10 @@ sphinx-build -M html source build -a
|
|||||||
|
|
||||||
# Building standalone DZGUI release binaries
|
# Building standalone DZGUI release binaries
|
||||||
1. Run `./scripts/dl_pyapp.sh`
|
1. Run `./scripts/dl_pyapp.sh`
|
||||||
2. Run `python3 scripts/release.py`
|
# TODO: secondary script that packs this archive
|
||||||
3. Generate a release and tag against the bundled `dzgui` executable
|
2. Download cpython 3.13, linux, gnu, v3
|
||||||
|
https://github.com/astral-sh/python-build-standalone/releases/download/20251014/cpython-3.13.9%2B20251014-x86_64_v3-unknown-linux-gnu-install_only_stripped.tar.gz
|
||||||
|
3. Explicitly install dependencies into site-packages
|
||||||
|
4. Pack back into a tarball
|
||||||
|
5. Run `python3 scripts/release.py`
|
||||||
|
6. Generate a release and tag against the bundled `dzgui` executable
|
||||||
@@ -106,7 +106,7 @@ class A2SInfo:
|
|||||||
|
|
||||||
def get_netmask() -> str:
|
def get_netmask() -> str:
|
||||||
hostname = os.uname()[1]
|
hostname = os.uname()[1]
|
||||||
i = socket.gethostbyname(hostname)
|
i = socket.gethostbyname(f"{hostname}.local")
|
||||||
netmask = i.rsplit(".", 1)[0]
|
netmask = i.rsplit(".", 1)[0]
|
||||||
return netmask
|
return netmask
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,5 @@ class UserPrefs:
|
|||||||
coords: Union["Coords", None]
|
coords: Union["Coords", None]
|
||||||
version: str
|
version: str
|
||||||
paths: "Xdg"
|
paths: "Xdg"
|
||||||
update_available: bool
|
latest_release: str | None
|
||||||
use_miles: bool
|
use_miles: bool
|
||||||
@@ -73,3 +73,7 @@ UBUNTU_STEAM_PATH = ".steam/steam"
|
|||||||
DEBIAN_STEAM_PATH = ".steam/debian-installation"
|
DEBIAN_STEAM_PATH = ".steam/debian-installation"
|
||||||
|
|
||||||
LOG_FILTERS = ("CRITICAL", "WARNING", "INFO", "DEBUG")
|
LOG_FILTERS = ("CRITICAL", "WARNING", "INFO", "DEBUG")
|
||||||
|
|
||||||
|
TMP_PATH = "/tmp"
|
||||||
|
TMP_TARBALL = "/tmp/dzgui.tar.gz"
|
||||||
|
TMP_EXE = "/tmp/dzgui"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
"""
|
||||||
|
This file is intended to be patched by package maintainers
|
||||||
|
repackaging DZGUI for use in different distributions.
|
||||||
|
|
||||||
|
If DZGUI is going to be installed globally via a package manager
|
||||||
|
or other means and will reside in an immutable location, or needs to be
|
||||||
|
explicitly bound to a certain version, set the flag below to False.
|
||||||
|
|
||||||
|
This will disable the ability for the application to self-manage and
|
||||||
|
will suppress the "Updates available" button in the gutter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALLOW_UPDATES = True
|
||||||
@@ -65,7 +65,6 @@
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
- Load offline mods
|
- Load offline mods
|
||||||
- Choose to jump into splash screen instead of server
|
- Choose to jump into splash screen instead of server
|
||||||
- Setup wizard
|
|
||||||
- Local documentation
|
- Local documentation
|
||||||
- Raw debug command in context menu
|
- Raw debug command in context menu
|
||||||
|
|
||||||
|
|||||||
+11
-8
@@ -2,6 +2,7 @@ import logging
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from packaging.version import Version
|
from packaging.version import Version
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from dzgui.const.constants import APP_NAME, REQUEST_TIMEOUT
|
from dzgui.const.constants import APP_NAME, REQUEST_TIMEOUT
|
||||||
from dzgui.const.endpoints import GITHUB_RELEASES, CODEBERG_RELEASES
|
from dzgui.const.endpoints import GITHUB_RELEASES, CODEBERG_RELEASES
|
||||||
@@ -9,28 +10,30 @@ from dzgui.const.endpoints import GITHUB_RELEASES, CODEBERG_RELEASES
|
|||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
def get_latest_release() -> str | None:
|
def get_latest_release() -> tuple[Any, Any] | tuple[None, None]:
|
||||||
tag = None
|
tag = None
|
||||||
|
url = None
|
||||||
# TODO: check order; github often has gateway errors
|
# TODO: check order; github often has gateway errors
|
||||||
for url in [GITHUB_RELEASES, CODEBERG_RELEASES]:
|
for url in [GITHUB_RELEASES, CODEBERG_RELEASES]:
|
||||||
try:
|
try:
|
||||||
res = requests.get(url, timeout=REQUEST_TIMEOUT)
|
res = requests.get(url, timeout=REQUEST_TIMEOUT)
|
||||||
if res.status_code == 200:
|
if res.status_code == 200:
|
||||||
tag = res.json()["tag_name"]
|
tag = res.json()["tag_name"]
|
||||||
|
url = res.json()["assets"][0]["browser_download_url"]
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
continue
|
continue
|
||||||
return tag
|
return tag, url
|
||||||
|
|
||||||
|
|
||||||
def check_updates(version: str) -> bool:
|
def check_updates(version: str) -> str | None:
|
||||||
try:
|
try:
|
||||||
latest = get_latest_release()
|
latest, url = get_latest_release()
|
||||||
if latest is None:
|
if latest is None:
|
||||||
return False
|
return None
|
||||||
if Version(version) >= Version(latest):
|
if Version(version) >= Version(latest):
|
||||||
return False
|
return None
|
||||||
return True
|
return url
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return None
|
||||||
+8
-3
@@ -89,6 +89,8 @@ def main() -> None:
|
|||||||
version = get_version()
|
version = get_version()
|
||||||
set_locale()
|
set_locale()
|
||||||
|
|
||||||
|
print(f"{APP_NAME} {version}")
|
||||||
|
|
||||||
# NOTE: consider aborting this check if steam deck
|
# NOTE: consider aborting this check if steam deck
|
||||||
xdg_paths = get_xdg_paths()
|
xdg_paths = get_xdg_paths()
|
||||||
XDG = parse_filepaths(xdg_paths)
|
XDG = parse_filepaths(xdg_paths)
|
||||||
@@ -110,13 +112,16 @@ def main() -> None:
|
|||||||
copy_state_files(xdg_paths["XDG_STATE_HOME"])
|
copy_state_files(xdg_paths["XDG_STATE_HOME"])
|
||||||
# TODO: add logging inside wizard
|
# TODO: add logging inside wizard
|
||||||
SetupWizard(_is_steam_deck, XDG.config)
|
SetupWizard(_is_steam_deck, XDG.config)
|
||||||
|
|
||||||
|
# NOTE: implies that setup wizard failed or was closed
|
||||||
|
if has_new_config(XDG.config) is False:
|
||||||
return
|
return
|
||||||
|
|
||||||
setup_logger(XDG.debug)
|
setup_logger(XDG.debug)
|
||||||
with open(XDG.debug, "w") as f:
|
with open(XDG.debug, "w") as f:
|
||||||
f.truncate(0)
|
f.truncate(0)
|
||||||
|
|
||||||
update_available = check_updates(version)
|
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
|
||||||
@@ -125,7 +130,7 @@ def main() -> None:
|
|||||||
if has_steam_client() is False:
|
if has_steam_client() is False:
|
||||||
EarlyAlertDialog(init.requires_steam)
|
EarlyAlertDialog(init.requires_steam)
|
||||||
|
|
||||||
# NOTE: clear 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)
|
||||||
|
|
||||||
@@ -142,7 +147,7 @@ def main() -> None:
|
|||||||
coords=local_coords,
|
coords=local_coords,
|
||||||
version=version,
|
version=version,
|
||||||
paths=XDG,
|
paths=XDG,
|
||||||
update_available=update_available,
|
latest_release=latest_release,
|
||||||
use_miles=use_miles,
|
use_miles=use_miles,
|
||||||
)
|
)
|
||||||
print(boot.all_ok)
|
print(boot.all_ok)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import gi
|
|||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository.Gtk import main_quit # noqa E402
|
from gi.repository.Gtk import main_quit # noqa E402
|
||||||
|
|
||||||
# import dzgui.api.servers as Servers
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.config.userprefs import UserPrefs
|
from dzgui.config.userprefs import UserPrefs
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ logger = logging.getLogger(APP_NAME)
|
|||||||
class NoteManager:
|
class NoteManager:
|
||||||
def __init__(self, controller: "Controller", path: "Path") -> None:
|
def __init__(self, controller: "Controller", path: "Path") -> None:
|
||||||
self.notes_path = path
|
self.notes_path = path
|
||||||
self.cache: dict[str, str] = read_json(self.notes_path)
|
try:
|
||||||
|
self.cache: dict[str, str] = read_json(self.notes_path)
|
||||||
|
except Exception:
|
||||||
|
self.cache = {}
|
||||||
|
|
||||||
def add_note(self, server: str, note: str) -> None:
|
def add_note(self, server: str, note: str) -> None:
|
||||||
self.cache[server] = note
|
self.cache[server] = note
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def call_on_thread(
|
|||||||
self = args[0]
|
self = args[0]
|
||||||
stored = StoredFunc(func, *args, **kwargs)
|
stored = StoredFunc(func, *args, **kwargs)
|
||||||
if not hasattr(self, "thread_man"):
|
if not hasattr(self, "thread_man"):
|
||||||
raise AttributeError
|
raise AttributeError(f"Object '{self}' has no attribute 'thread_man'")
|
||||||
if type(self.thread_man) is not ThreadingManager:
|
if type(self.thread_man) is not ThreadingManager:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
"Attribute 'thread_man' must be of type 'ThreadingManager'"
|
"Attribute 'thread_man' must be of type 'ThreadingManager'"
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ class ServerModelManager:
|
|||||||
|
|
||||||
@call_on_thread(dialog.scanning)
|
@call_on_thread(dialog.scanning)
|
||||||
def dump_lan(self, port: int, early_abort: bool) -> None:
|
def dump_lan(self, port: int, early_abort: bool) -> None:
|
||||||
|
self.first_iteration = True
|
||||||
|
|
||||||
servers = []
|
servers = []
|
||||||
ports = range(1, 256)
|
ports = range(1, 256)
|
||||||
failure_func = StoredFunc(self._cleanup_on_failure)
|
failure_func = StoredFunc(self._cleanup_on_failure)
|
||||||
@@ -139,15 +141,11 @@ class ServerModelManager:
|
|||||||
res = future.result(timeout=LAN_TIMEOUT)
|
res = future.result(timeout=LAN_TIMEOUT)
|
||||||
if res is None:
|
if res is None:
|
||||||
continue
|
continue
|
||||||
|
servers.append(res)
|
||||||
if early_abort is True:
|
if early_abort is True:
|
||||||
# NOTE: on first non-empty hit, flag pending threads to close
|
# NOTE: on first non-empty hit, flag pending threads to close
|
||||||
event.set()
|
event.set()
|
||||||
servers.append(res)
|
break
|
||||||
self.thread_man.set_cleanup_func(
|
|
||||||
StoredFunc(self._cleanup_on_success)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
servers.append(res)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
waiting_for_launch = "Waiting for DayZ to launch"
|
waiting_for_launch = "Waiting for DayZ to launch"
|
||||||
waiting_for_mods = "Waiting for Steam to update mods"
|
waiting_for_mods = "Waiting for Steam to update mods"
|
||||||
|
|
||||||
|
fetching_update = "Fetching update"
|
||||||
|
failed_to_update = "Failed to update DZGUI executable"
|
||||||
|
update_success = "Updated successfully. Please exit and relaunch."
|
||||||
@@ -67,4 +67,4 @@ label_client = "Steam client"
|
|||||||
|
|
||||||
### Completion page
|
### Completion page
|
||||||
heading_completion = "Setup complete"
|
heading_completion = "Setup complete"
|
||||||
blurb_completion = "Configuration completed successfully. Please exit and restart DZGUI to apply changes."
|
blurb_completion = "Configuration completed successfully. Click 'Close' to close this dialog and launch DZGUI."
|
||||||
+4
-6
@@ -2,15 +2,13 @@ import json
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
def read_json(path: Path) -> Any:
|
def read_json(path: Path) -> Any:
|
||||||
try:
|
try:
|
||||||
with open(path, "r") as infile:
|
with open(path, "r") as infile:
|
||||||
try:
|
data = json.load(infile)
|
||||||
data = json.load(infile)
|
return data
|
||||||
return data
|
except Exception as e:
|
||||||
except json.decoder.JSONDecodeError as e:
|
|
||||||
raise e
|
|
||||||
except OSError as e:
|
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ input_required = "User input required"
|
|||||||
confirm = "Confirmation"
|
confirm = "Confirmation"
|
||||||
notice = "Notice"
|
notice = "Notice"
|
||||||
wait = "Please wait"
|
wait = "Please wait"
|
||||||
|
restart_required = "App relaunch required"
|
||||||
|
|
||||||
# Wait dialogs
|
# Wait dialogs
|
||||||
ping = "Ping"
|
ping = "Ping"
|
||||||
@@ -100,7 +101,7 @@ build_corrupted = (
|
|||||||
"Steam settings or DayZ installation may be corrupted. Try restarting Steam."
|
"Steam settings or DayZ installation may be corrupted. Try restarting Steam."
|
||||||
)
|
)
|
||||||
api_warn_msg = """No servers returned. Please wait and try again.
|
api_warn_msg = """No servers returned. Please wait and try again.
|
||||||
If this issue persists, your API key may be defunct or your network is blocking requests.
|
This usually indicates a transitory network timeout. If this issue persists, your API key or network may be malfunctioning.
|
||||||
"""
|
"""
|
||||||
server_timeout = "Timed out when querying server, check IP or try again later."
|
server_timeout = "Timed out when querying server, check IP or try again later."
|
||||||
server_error = (
|
server_error = (
|
||||||
|
|||||||
+1
-1
@@ -262,8 +262,8 @@ class Grid(Gtk.Grid):
|
|||||||
|
|
||||||
self.emitter.connect("server_page_toggled", self.toggle_filter_panels)
|
self.emitter.connect("server_page_toggled", self.toggle_filter_panels)
|
||||||
|
|
||||||
|
# TODO: drop, use map/signal
|
||||||
def hide_widgets_on_init(self) -> None:
|
def hide_widgets_on_init(self) -> None:
|
||||||
self.conpan.set_lan_visible(False)
|
|
||||||
self.right_panel.sel_panel.hide()
|
self.right_panel.sel_panel.hide()
|
||||||
|
|
||||||
def toggle_filter_panels(self, emitter: "Emitter", state: bool) -> None:
|
def toggle_filter_panels(self, emitter: "Emitter", state: bool) -> None:
|
||||||
|
|||||||
@@ -278,9 +278,7 @@ class ConnectPanel(Gtk.Box):
|
|||||||
|
|
||||||
for el in self.lan, self.fav, self.add_panel:
|
for el in self.lan, self.fav, self.add_panel:
|
||||||
self.add(el)
|
self.add(el)
|
||||||
|
self.lan.set_visible(False)
|
||||||
def set_lan_visible(self, state: bool) -> None:
|
|
||||||
self.lan.set_visible(state)
|
|
||||||
|
|
||||||
def _on_lan_tab_toggled(self, emitter: "Emitter", state: bool) -> None:
|
def _on_lan_tab_toggled(self, emitter: "Emitter", state: bool) -> None:
|
||||||
self.set_lan_visible(state)
|
self.lan.set_visible(state)
|
||||||
@@ -1,14 +1,32 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tarfile
|
||||||
|
|
||||||
from typing import Literal, TYPE_CHECKING
|
from typing import Literal, TYPE_CHECKING
|
||||||
|
|
||||||
from dzgui.const.constants import NO_EXPAND, NO_FILL, FILL, NO_PADDING
|
from dzgui.const.constants import (
|
||||||
from dzgui.const.endpoints import GITHUB_USER_RELEASES
|
APP_NAME,
|
||||||
|
NO_EXPAND,
|
||||||
|
NO_FILL,
|
||||||
|
FILL,
|
||||||
|
NO_PADDING,
|
||||||
|
TMP_EXE,
|
||||||
|
TMP_PATH,
|
||||||
|
TMP_TARBALL,
|
||||||
|
)
|
||||||
|
from dzgui.const.update import ALLOW_UPDATES
|
||||||
from dzgui.const.enum import ServerTab
|
from dzgui.const.enum import ServerTab
|
||||||
|
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
|
||||||
|
from dzgui.strings import dialogs
|
||||||
from dzgui.util.clip import copy_clipboard
|
from dzgui.util.clip import copy_clipboard
|
||||||
from dzgui.util.open_links import open_link_by_url
|
|
||||||
from dzgui.views.components.buttonbox import ButtonBox
|
from dzgui.views.components.buttonbox import ButtonBox
|
||||||
from dzgui.views.components.filter_panel import FilterPanel
|
from dzgui.views.components.filter_panel import FilterPanel
|
||||||
from dzgui.views.components.mod_panel import ModSelectionPanel
|
from dzgui.views.components.mod_panel import ModSelectionPanel
|
||||||
from dzgui.views.components.buttons import IconTextButton, RefreshButton, KeysButton
|
from dzgui.views.components.buttons import IconTextButton, RefreshButton, KeysButton
|
||||||
|
from dzgui.views.dialogs.generic import ExceptionDialog, QuitDialog
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
@@ -20,11 +38,14 @@ if TYPE_CHECKING:
|
|||||||
from dzgui.controllers.emitter import Emitter
|
from dzgui.controllers.emitter import Emitter
|
||||||
from dzgui.views.trees.tree_servers import ServerTreeView
|
from dzgui.views.trees.tree_servers import ServerTreeView
|
||||||
|
|
||||||
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
class RightPanel(Gtk.Box):
|
class RightPanel(Gtk.Box):
|
||||||
def __init__(self, controller: "Controller"):
|
def __init__(self, controller: "Controller"):
|
||||||
super().__init__(spacing=6, orientation=Gtk.Orientation.VERTICAL)
|
super().__init__(spacing=6, orientation=Gtk.Orientation.VERTICAL)
|
||||||
|
|
||||||
|
self.thread_man = ThreadingManager(controller)
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.controller.register_widget("right_panel", self)
|
self.controller.register_widget("right_panel", self)
|
||||||
|
|
||||||
@@ -44,7 +65,7 @@ class RightPanel(Gtk.Box):
|
|||||||
|
|
||||||
prefs = self.controller.get_prefs()
|
prefs = self.controller.get_prefs()
|
||||||
version = prefs.version
|
version = prefs.version
|
||||||
update = prefs.update_available
|
update = prefs.latest_release
|
||||||
|
|
||||||
self.version_label = Gtk.Label(
|
self.version_label = Gtk.Label(
|
||||||
label=version,
|
label=version,
|
||||||
@@ -64,7 +85,7 @@ class RightPanel(Gtk.Box):
|
|||||||
|
|
||||||
self.pack_start(self.sel_panel, NO_EXPAND, NO_FILL, NO_PADDING)
|
self.pack_start(self.sel_panel, NO_EXPAND, NO_FILL, NO_PADDING)
|
||||||
|
|
||||||
self.version_button = IconTextButton(
|
self.update_button = IconTextButton(
|
||||||
"dialog-information-symbolic", label="Updates available"
|
"dialog-information-symbolic", label="Updates available"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,15 +95,54 @@ class RightPanel(Gtk.Box):
|
|||||||
valign=Gtk.Align.END,
|
valign=Gtk.Align.END,
|
||||||
spacing=10,
|
spacing=10,
|
||||||
)
|
)
|
||||||
if update:
|
if ALLOW_UPDATES and update is not None:
|
||||||
self.version_button.set_halign(Gtk.Align.END)
|
self.update_button.set_halign(Gtk.Align.END)
|
||||||
self.gutter_box.add(self.version_button)
|
self.gutter_box.add(self.update_button)
|
||||||
self.version_button.connect("clicked", self._on_version_button_clicked)
|
self.update_button.connect(
|
||||||
|
"clicked", self._on_update_button_clicked, update
|
||||||
|
)
|
||||||
self.gutter_box.add(eb)
|
self.gutter_box.add(eb)
|
||||||
self.pack_start(self.gutter_box, NO_EXPAND, FILL, NO_PADDING)
|
self.pack_start(self.gutter_box, NO_EXPAND, FILL, NO_PADDING)
|
||||||
|
|
||||||
def _on_version_button_clicked(self, button: Gtk.Button) -> None:
|
def _on_update_success(self) -> None:
|
||||||
open_link_by_url(GITHUB_USER_RELEASES)
|
msg = dialogs.update_success
|
||||||
|
dialog = QuitDialog(self.controller, msg)
|
||||||
|
dialog.run()
|
||||||
|
|
||||||
|
def _on_update_failure(self, msg: str) -> None:
|
||||||
|
dialog = ExceptionDialog(self.controller, msg)
|
||||||
|
dialog.run()
|
||||||
|
|
||||||
|
@call_on_thread(dialogs.fetching_update)
|
||||||
|
def _on_update_button_clicked(self, button: Gtk.Button, url: str) -> None:
|
||||||
|
try:
|
||||||
|
res = requests.get(url)
|
||||||
|
if res.status_code == 200:
|
||||||
|
with open(TMP_TARBALL, "wb") as file:
|
||||||
|
file.write(res.content)
|
||||||
|
with tarfile.open(TMP_TARBALL) as tar:
|
||||||
|
tar.extractall(TMP_PATH)
|
||||||
|
|
||||||
|
exe_path = os.getenv("PYAPP")
|
||||||
|
if exe_path is None:
|
||||||
|
msg = dialogs.failed_to_update
|
||||||
|
func = StoredFunc(self._on_update_failure, msg)
|
||||||
|
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
||||||
|
return
|
||||||
|
shutil.move(TMP_EXE, exe_path)
|
||||||
|
|
||||||
|
proc = subprocess.run([exe_path, "self", "restore"])
|
||||||
|
if proc.returncode == 0:
|
||||||
|
func = StoredFunc(self._on_update_success)
|
||||||
|
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
||||||
|
else:
|
||||||
|
msg = dialogs.failed_to_update
|
||||||
|
func = StoredFunc(self._on_update_failure, msg)
|
||||||
|
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
||||||
|
except Exception as e:
|
||||||
|
func = StoredFunc(self._on_update_failure, e)
|
||||||
|
self.thread_man.set_cleanup_func(func, destroy_first=True)
|
||||||
|
logger.warning(e)
|
||||||
|
|
||||||
def _on_server_page_changed(
|
def _on_server_page_changed(
|
||||||
self, emitter: "Emitter", page: "ServerTreeView"
|
self, emitter: "Emitter", page: "ServerTreeView"
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class NotifyDialog(GenericDialog):
|
|||||||
controller=controller,
|
controller=controller,
|
||||||
text=strings.notice,
|
text=strings.notice,
|
||||||
mtype=Gtk.MessageType.INFO,
|
mtype=Gtk.MessageType.INFO,
|
||||||
buttons=Gtk.ButtonsType.OK_CANCEL,
|
buttons=Gtk.ButtonsType.OK,
|
||||||
secondary=secondary,
|
secondary=secondary,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ class QuitDialog(GenericDialog):
|
|||||||
def __init__(self, controller: "Controller", secondary: str):
|
def __init__(self, controller: "Controller", secondary: str):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
controller=controller,
|
controller=controller,
|
||||||
text=strings.wait,
|
text=strings.restart_required,
|
||||||
mtype=Gtk.MessageType.INFO,
|
mtype=Gtk.MessageType.INFO,
|
||||||
buttons=Gtk.ButtonsType.NONE,
|
buttons=Gtk.ButtonsType.NONE,
|
||||||
secondary=secondary,
|
secondary=secondary,
|
||||||
|
|||||||
@@ -11,5 +11,5 @@ class ModsMixin:
|
|||||||
self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
|
self, tree: TreeView, path: Gtk.TreePath, column: Gtk.TreeViewColumn
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
path = self.get_focused_row_path() # type: ignore
|
mod = self.get_value_at_index(2)
|
||||||
self.controller.open_mod_page(path) # type: ignore
|
self.controller.open_workshop_page(mod) # type: ignore
|
||||||
@@ -17,7 +17,7 @@ from dzgui.views.trees.tree_server_mods import ServerModTreeView
|
|||||||
import gi
|
import gi
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gdk, Gtk # type: ignore # noqa E402
|
from gi.repository import Gdk, Gtk # noqa E402
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|||||||
@@ -162,8 +162,8 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore
|
|||||||
|
|
||||||
def _on_map(self, widget: Self) -> None:
|
def _on_map(self, widget: Self) -> None:
|
||||||
# TODO: disable filter panel if current model is None
|
# TODO: disable filter panel if current model is None
|
||||||
if self.get_enum() is ServerTab.LAN:
|
state = self.get_enum() is ServerTab.LAN
|
||||||
self.emitter.emit("lan_tab_toggled", True)
|
self.emitter.emit("lan_tab_toggled", state)
|
||||||
|
|
||||||
store = self.filter_man.get_map_store()
|
store = self.filter_man.get_map_store()
|
||||||
|
|
||||||
@@ -178,8 +178,6 @@ class ServerTreeView(ContextMixin, TreeView): # type: ignore
|
|||||||
# NOTE: removes queue checker for this tab
|
# NOTE: removes queue checker for this tab
|
||||||
GLib.Source.remove(self.queue_id)
|
GLib.Source.remove(self.queue_id)
|
||||||
self.emitter.disconnect(self.handler_id)
|
self.emitter.disconnect(self.handler_id)
|
||||||
if self.get_enum() is ServerTab.LAN:
|
|
||||||
self.emitter.emit("lan_tab_toggled", False)
|
|
||||||
|
|
||||||
def _on_col_width_changed(
|
def _on_col_width_changed(
|
||||||
self, col: Gtk.TreeViewColumn, width: GObject.ParamSpecInt
|
self, col: Gtk.TreeViewColumn, width: GObject.ParamSpecInt
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
|
|||||||
authors = [
|
authors = [
|
||||||
{name = "aclist"}
|
{name = "aclist"}
|
||||||
]
|
]
|
||||||
version = "7.0.0b1"
|
version = "7.0.0b3"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
+19
-16
@@ -3,43 +3,46 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
from importlib import metadata
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dzgui.const.constants import APP_NAME_LOWER
|
|
||||||
|
|
||||||
root = Path(__file__).resolve().parents[1]
|
root = Path(__file__).resolve().parents[1]
|
||||||
output = root.joinpath("dist")
|
output = root.joinpath("dist")
|
||||||
|
|
||||||
pyapp_dir = root.joinpath("pyapp-latest")
|
pyapp_dir = root.joinpath("pyapp-latest")
|
||||||
|
cpython = root.joinpath("build/cpython/airgapped.tar.gz")
|
||||||
|
|
||||||
builder = build.ProjectBuilder(root)
|
builder = build.ProjectBuilder(root)
|
||||||
builder.build("wheel", output_directory=output)
|
wheel = builder.build("wheel", output_directory=output)
|
||||||
|
stem = Path(wheel).stem
|
||||||
|
tarname = f"{stem}.tar.gz"
|
||||||
|
|
||||||
interpreter = "py3"
|
metadata = stem.split("-")
|
||||||
arch = "none"
|
appname = metadata[0]
|
||||||
target = "any"
|
version = metadata[1]
|
||||||
version = metadata.version(APP_NAME_LOWER)
|
|
||||||
filename = f"{APP_NAME_LOWER}-{version}-{interpreter}-{arch}-{target}.whl"
|
|
||||||
|
|
||||||
wheel = str(output.joinpath(filename))
|
|
||||||
entrypoint = "dzgui.main:main"
|
entrypoint = "dzgui.main:main"
|
||||||
|
|
||||||
env = os.environ
|
env = os.environ
|
||||||
env["PYAPP_PROJECT_VERSION"] = version
|
env["PYAPP_PROJECT_VERSION"] = version
|
||||||
env["PYAPP_PROJECT_NAME"] = APP_NAME_LOWER
|
env["PYAPP_PROJECT_NAME"] = appname
|
||||||
env["PYAPP_EXEC_SPEC"] = entrypoint
|
env["PYAPP_EXEC_SPEC"] = entrypoint
|
||||||
env["PYAPP_PROJECT_PATH"] = wheel
|
env["PYAPP_PROJECT_PATH"] = wheel
|
||||||
env["PYAPP_DISTRIBUTION_EMBED"] = "1"
|
env["PYAPP_PASS_LOCATION"] = "true"
|
||||||
env["PYAPP_PYTHON_VERSION"] = "3.13"
|
# env["PYAPP_PYTHON_VERSION"] = "3.13"
|
||||||
|
|
||||||
|
# NOTE: explicitly install all dependencies into distribution
|
||||||
|
env["PYAPP_SKIP_INSTALL"] = "true"
|
||||||
|
env["PYAPP_DISTRIBUTION_EMBED"] = "true"
|
||||||
|
env["PYAPP_FULL_ISOLATION"] = "true"
|
||||||
|
env["PYAPP_DISTRIBUTION_PATH"] = str(cpython)
|
||||||
|
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 = root.joinpath("pyapp-latest/target/release/pyapp")
|
||||||
release_exe = output.joinpath(APP_NAME_LOWER)
|
release_exe = output.joinpath(appname)
|
||||||
output_exe.rename(release_exe)
|
output_exe.rename(release_exe)
|
||||||
tarname = APP_NAME_LOWER + ".tar.gz"
|
|
||||||
tarpath = output.joinpath(tarname)
|
tarpath = output.joinpath(tarname)
|
||||||
with tarfile.open(tarpath, "w:gz") as tar:
|
with tarfile.open(tarpath, "w:gz") as tar:
|
||||||
tar.add(release_exe)
|
tar.add(release_exe, arcname=appname)
|
||||||
print(f"Wrote tarfile to '{tarpath}'")
|
print(f"Wrote tarfile to '{tarpath}'")
|
||||||
Reference in new issue
Block a user