mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-03-12 10:31:50 +01:00
feat: integrate XDG paths into bot core (#776)
## ℹ️ Description Wire XDG path resolution into main bot components. - Link to the related issue(s): N/A (new feature) - Integrates installation mode detection into bot core ## 📋 Changes Summary - Added `finalize_installation_mode()` method for mode detection - UpdateChecker, AdExtractor now respect installation mode - Dynamic browser profile defaults (resolved at runtime) - German translations for installation mode messages - Comprehensive tests for installation mode integration **Part 2 of 3 for XDG support** - Depends on: PR #775 (must be merged first) - Will rebase on main after merge of previous PR ### ⚙️ Type of Change - [x] ✨ New feature (adds new functionality without breaking existing usage) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Support for portable and XDG (system-wide) installation modes with automatic detection and interactive first-run setup. * Config and paths standardized so app stores config, downloads, logs, and browser profiles in appropriate locations per mode. * Update checker improved for more reliable version/commit detection. * **Chores** * Moved dependency to runtime: platformdirs added to main dependencies. * **Tests** * Added comprehensive tests for installation modes, path utilities, and related behaviors. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -7,7 +7,6 @@ from __future__ import annotations
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from gettext import gettext as _
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import colorama
|
||||
@@ -22,6 +21,7 @@ except ImportError:
|
||||
__version__ = "unknown"
|
||||
|
||||
from kleinanzeigen_bot.model.update_check_state import UpdateCheckState
|
||||
from kleinanzeigen_bot.utils import xdg_paths
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -31,15 +31,16 @@ colorama.init()
|
||||
class UpdateChecker:
|
||||
"""Checks for updates to the bot."""
|
||||
|
||||
def __init__(self, config:"Config") -> None:
|
||||
def __init__(self, config: "Config", installation_mode: str | xdg_paths.InstallationMode = "portable") -> None:
|
||||
"""Initialize the update checker.
|
||||
|
||||
Args:
|
||||
config: The bot configuration.
|
||||
installation_mode: Installation mode (portable/xdg).
|
||||
"""
|
||||
self.config = config
|
||||
self.state_file = Path(".temp") / "update_check_state.json"
|
||||
self.state_file.parent.mkdir(exist_ok = True) # Ensure .temp directory exists
|
||||
self.state_file = xdg_paths.get_update_check_state_path(installation_mode)
|
||||
# Note: xdg_paths handles directory creation
|
||||
self.state = UpdateCheckState.load(self.state_file)
|
||||
|
||||
def get_local_version(self) -> str | None:
|
||||
@@ -54,7 +55,7 @@ class UpdateChecker:
|
||||
"""Return the effective timeout for HTTP calls."""
|
||||
return self.config.timeouts.effective("update_check")
|
||||
|
||||
def _get_commit_hash(self, version:str) -> str | None:
|
||||
def _get_commit_hash(self, version: str) -> str | None:
|
||||
"""Extract the commit hash from a version string.
|
||||
|
||||
Args:
|
||||
@@ -67,7 +68,7 @@ class UpdateChecker:
|
||||
return version.split("+")[1]
|
||||
return None
|
||||
|
||||
def _resolve_commitish(self, commitish:str) -> tuple[str | None, datetime | None]:
|
||||
def _resolve_commitish(self, commitish: str) -> tuple[str | None, datetime | None]:
|
||||
"""Resolve a commit-ish to a full commit hash and date.
|
||||
|
||||
Args:
|
||||
@@ -79,7 +80,7 @@ class UpdateChecker:
|
||||
try:
|
||||
response = requests.get(
|
||||
f"https://api.github.com/repos/Second-Hand-Friends/kleinanzeigen-bot/commits/{commitish}",
|
||||
timeout = self._request_timeout()
|
||||
timeout=self._request_timeout(),
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
@@ -95,7 +96,7 @@ class UpdateChecker:
|
||||
logger.warning(_("Could not resolve commit '%s': %s"), commitish, e)
|
||||
return None, None
|
||||
|
||||
def _get_short_commit_hash(self, commit:str) -> str:
|
||||
def _get_short_commit_hash(self, commit: str) -> str:
|
||||
"""Get the short version of a commit hash.
|
||||
|
||||
Args:
|
||||
@@ -106,7 +107,7 @@ class UpdateChecker:
|
||||
"""
|
||||
return commit[:7]
|
||||
|
||||
def _commits_match(self, local_commit:str, release_commit:str) -> bool:
|
||||
def _commits_match(self, local_commit: str, release_commit: str) -> bool:
|
||||
"""Determine whether two commits refer to the same hash.
|
||||
|
||||
This accounts for short vs. full hashes (e.g. 7 chars vs. 40 chars).
|
||||
@@ -119,7 +120,7 @@ class UpdateChecker:
|
||||
return True
|
||||
return len(release_commit) < len(local_commit) and local_commit.startswith(release_commit)
|
||||
|
||||
def check_for_updates(self, *, skip_interval_check:bool = False) -> None:
|
||||
def check_for_updates(self, *, skip_interval_check: bool = False) -> None:
|
||||
"""Check for updates to the bot.
|
||||
|
||||
Args:
|
||||
@@ -146,24 +147,16 @@ class UpdateChecker:
|
||||
try:
|
||||
if self.config.update_check.channel == "latest":
|
||||
# Use /releases/latest endpoint for stable releases
|
||||
response = requests.get(
|
||||
"https://api.github.com/repos/Second-Hand-Friends/kleinanzeigen-bot/releases/latest",
|
||||
timeout = self._request_timeout()
|
||||
)
|
||||
response = requests.get("https://api.github.com/repos/Second-Hand-Friends/kleinanzeigen-bot/releases/latest", timeout=self._request_timeout())
|
||||
response.raise_for_status()
|
||||
release = response.json()
|
||||
# Defensive: ensure it's not a prerelease
|
||||
if release.get("prerelease", False):
|
||||
logger.warning(
|
||||
_("Latest release from GitHub is a prerelease, but 'latest' channel expects a stable release.")
|
||||
)
|
||||
logger.warning(_("Latest release from GitHub is a prerelease, but 'latest' channel expects a stable release."))
|
||||
return
|
||||
elif self.config.update_check.channel == "preview":
|
||||
# Use /releases endpoint and select the most recent prerelease
|
||||
response = requests.get(
|
||||
"https://api.github.com/repos/Second-Hand-Friends/kleinanzeigen-bot/releases",
|
||||
timeout = self._request_timeout()
|
||||
)
|
||||
response = requests.get("https://api.github.com/repos/Second-Hand-Friends/kleinanzeigen-bot/releases", timeout=self._request_timeout())
|
||||
response.raise_for_status()
|
||||
releases = response.json()
|
||||
# Find the most recent prerelease
|
||||
@@ -199,7 +192,7 @@ class UpdateChecker:
|
||||
_("You are on the latest version: %s (compared to %s in channel %s)"),
|
||||
local_version,
|
||||
self._get_short_commit_hash(release_commit),
|
||||
self.config.update_check.channel
|
||||
self.config.update_check.channel,
|
||||
)
|
||||
self.state.update_last_check()
|
||||
self.state.save(self.state_file)
|
||||
@@ -212,7 +205,7 @@ class UpdateChecker:
|
||||
release_commit_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
local_version,
|
||||
local_commit_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
self.config.update_check.channel
|
||||
self.config.update_check.channel,
|
||||
)
|
||||
if release.get("body"):
|
||||
logger.info(_("Release notes:\n%s"), release["body"])
|
||||
@@ -227,7 +220,7 @@ class UpdateChecker:
|
||||
self._get_short_commit_hash(local_commit),
|
||||
local_commit_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
self._get_short_commit_hash(release_commit),
|
||||
release_commit_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
release_commit_date.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
)
|
||||
|
||||
# Update the last check time
|
||||
|
||||
Reference in New Issue
Block a user