feat: update Windows installer to include WixUtilExtension and close running application
chore: bump version to 0.6.2 fix: improve update manager logic for caching and fetching releases
This commit is contained in:
parent
cbd1f3f77c
commit
88d9f200ab
9 changed files with 2947 additions and 2917 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Application
|
# Application
|
||||||
APP_NAME=WebDrop Bridge
|
APP_NAME=WebDrop Bridge
|
||||||
APP_VERSION=0.6.0
|
APP_VERSION=0.6.2
|
||||||
|
|
||||||
# Web App
|
# Web App
|
||||||
WEBAPP_URL=file:///./webapp/index.html
|
WEBAPP_URL=file:///./webapp/index.html
|
||||||
|
|
|
||||||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -1,3 +1,19 @@
|
||||||
|
## [0.6.2] - 2026-02-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
## [0.6.1] - 2026-02-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
## [0.6.0] - 2026-02-20
|
## [0.6.0] - 2026-02-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +1,8 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||||
xmlns:ui="http://schemas.microsoft.com/wix/2010/ui">
|
xmlns:ui="http://schemas.microsoft.com/wix/2010/ui"
|
||||||
<Product Id="*" Name="WebDrop Bridge" Language="1033" Version="0.6.0"
|
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||||
|
<Product Id="*" Name="WebDrop Bridge" Language="1033" Version="0.6.1"
|
||||||
Manufacturer="HIM-Tools"
|
Manufacturer="HIM-Tools"
|
||||||
UpgradeCode="12345678-1234-1234-1234-123456789012">
|
UpgradeCode="12345678-1234-1234-1234-123456789012">
|
||||||
|
|
||||||
|
|
@ -23,6 +24,13 @@
|
||||||
<UIRef Id="WixUI_InstallDir" />
|
<UIRef Id="WixUI_InstallDir" />
|
||||||
<UIRef Id="WixUI_ErrorProgressText" />
|
<UIRef Id="WixUI_ErrorProgressText" />
|
||||||
|
|
||||||
|
<!-- Close running application before installation -->
|
||||||
|
<util:CloseApplication
|
||||||
|
Target="WebDropBridge.exe"
|
||||||
|
CloseMessage="yes"
|
||||||
|
RebootPrompt="no"
|
||||||
|
ElevatedCloseMessage="no" />
|
||||||
|
|
||||||
<Feature Id="ProductFeature" Title="WebDrop Bridge" Level="1">
|
<Feature Id="ProductFeature" Title="WebDrop Bridge" Level="1">
|
||||||
<ComponentGroupRef Id="AppFiles" />
|
<ComponentGroupRef Id="AppFiles" />
|
||||||
<ComponentRef Id="ProgramMenuShortcut" />
|
<ComponentRef Id="ProgramMenuShortcut" />
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -299,6 +299,7 @@ class WindowsBuilder:
|
||||||
candle_cmd = [
|
candle_cmd = [
|
||||||
str(candle_exe),
|
str(candle_exe),
|
||||||
"-ext", "WixUIExtension",
|
"-ext", "WixUIExtension",
|
||||||
|
"-ext", "WixUtilExtension",
|
||||||
f"-dDistDir={self.dist_dir}",
|
f"-dDistDir={self.dist_dir}",
|
||||||
f"-dSourceDir={self.dist_dir}\\WebDropBridge", # Set SourceDir for Heat-generated files
|
f"-dSourceDir={self.dist_dir}\\WebDropBridge", # Set SourceDir for Heat-generated files
|
||||||
f"-dResourcesDir={self.project_root}\\resources", # Set ResourcesDir for branding assets
|
f"-dResourcesDir={self.project_root}\\resources", # Set ResourcesDir for branding assets
|
||||||
|
|
@ -319,6 +320,7 @@ class WindowsBuilder:
|
||||||
light_cmd = [
|
light_cmd = [
|
||||||
str(light_exe),
|
str(light_exe),
|
||||||
"-ext", "WixUIExtension",
|
"-ext", "WixUIExtension",
|
||||||
|
"-ext", "WixUtilExtension",
|
||||||
"-b", str(self.dist_dir / "WebDropBridge"), # Base path for source files
|
"-b", str(self.dist_dir / "WebDropBridge"), # Base path for source files
|
||||||
"-o", str(msi_output),
|
"-o", str(msi_output),
|
||||||
str(wix_obj),
|
str(wix_obj),
|
||||||
|
|
@ -355,7 +357,8 @@ class WindowsBuilder:
|
||||||
"""
|
"""
|
||||||
wix_content = f'''<?xml version="1.0" encoding="UTF-8"?>
|
wix_content = f'''<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
||||||
xmlns:ui="http://schemas.microsoft.com/wix/2010/ui">
|
xmlns:ui="http://schemas.microsoft.com/wix/2010/ui"
|
||||||
|
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||||
<Product Id="*" Name="WebDrop Bridge" Language="1033" Version="{self.version}"
|
<Product Id="*" Name="WebDrop Bridge" Language="1033" Version="{self.version}"
|
||||||
Manufacturer="HIM-Tools"
|
Manufacturer="HIM-Tools"
|
||||||
UpgradeCode="12345678-1234-1234-1234-123456789012">
|
UpgradeCode="12345678-1234-1234-1234-123456789012">
|
||||||
|
|
@ -378,6 +381,13 @@ class WindowsBuilder:
|
||||||
<UIRef Id="WixUI_InstallDir" />
|
<UIRef Id="WixUI_InstallDir" />
|
||||||
<UIRef Id="WixUI_ErrorProgressText" />
|
<UIRef Id="WixUI_ErrorProgressText" />
|
||||||
|
|
||||||
|
<!-- Close running application before installation -->
|
||||||
|
<util:CloseApplication
|
||||||
|
Target="WebDropBridge.exe"
|
||||||
|
CloseMessage="yes"
|
||||||
|
RebootPrompt="no"
|
||||||
|
ElevatedCloseMessage="no" />
|
||||||
|
|
||||||
<Feature Id="ProductFeature" Title="WebDrop Bridge" Level="1">
|
<Feature Id="ProductFeature" Title="WebDrop Bridge" Level="1">
|
||||||
<ComponentGroupRef Id="AppFiles" />
|
<ComponentGroupRef Id="AppFiles" />
|
||||||
<ComponentRef Id="ProgramMenuShortcut" />
|
<ComponentRef Id="ProgramMenuShortcut" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""WebDrop Bridge - Qt-based desktop application for intelligent drag-and-drop file handling."""
|
"""WebDrop Bridge - Qt-based desktop application for intelligent drag-and-drop file handling."""
|
||||||
|
|
||||||
__version__ = "0.6.0"
|
__version__ = "0.6.2"
|
||||||
__author__ = "WebDrop Team"
|
__author__ = "WebDrop Team"
|
||||||
__license__ = "MIT"
|
__license__ = "MIT"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,7 @@ class UpdateManager:
|
||||||
self.current_version = current_version
|
self.current_version = current_version
|
||||||
self.forgejo_url = "https://git.him-tools.de"
|
self.forgejo_url = "https://git.him-tools.de"
|
||||||
self.repo = "HIM-public/webdrop-bridge"
|
self.repo = "HIM-public/webdrop-bridge"
|
||||||
self.api_endpoint = (
|
self.api_endpoint = f"{self.forgejo_url}/api/v1/repos/{self.repo}/releases/latest"
|
||||||
f"{self.forgejo_url}/api/v1/repos/{self.repo}/releases/latest"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Cache management
|
# Cache management
|
||||||
self.cache_dir = config_dir or Path.home() / ".webdrop-bridge"
|
self.cache_dir = config_dir or Path.home() / ".webdrop-bridge"
|
||||||
|
|
@ -147,43 +145,44 @@ class UpdateManager:
|
||||||
"""
|
"""
|
||||||
logger.debug(f"check_for_updates() called, current version: {self.current_version}")
|
logger.debug(f"check_for_updates() called, current version: {self.current_version}")
|
||||||
|
|
||||||
# Try cache first
|
# Only use cache when a pending update was already found (avoids
|
||||||
logger.debug("Checking cache...")
|
# showing the update dialog on every start). "No update" is never
|
||||||
|
# cached so that a freshly published release is visible immediately.
|
||||||
|
logger.debug("Checking cache for pending update...")
|
||||||
cached = self._load_cache()
|
cached = self._load_cache()
|
||||||
if cached:
|
if cached:
|
||||||
logger.debug("Found cached release")
|
|
||||||
release_data = cached.get("release")
|
release_data = cached.get("release")
|
||||||
if release_data:
|
if release_data:
|
||||||
version = release_data["tag_name"].lstrip("v")
|
version = release_data["tag_name"].lstrip("v")
|
||||||
if not self._is_newer_version(version):
|
logger.debug(f"Cached pending update version: {version}")
|
||||||
logger.info("No newer version available (cached)")
|
if self._is_newer_version(version):
|
||||||
return None
|
logger.info(f"Returning cached pending update: {version}")
|
||||||
return Release(**release_data)
|
return Release(**release_data)
|
||||||
|
else:
|
||||||
|
# Current version is >= cached release (e.g. already updated)
|
||||||
|
logger.debug("Cached release is no longer newer — discarding cache")
|
||||||
|
self.cache_file.unlink(missing_ok=True)
|
||||||
|
|
||||||
# Fetch from API
|
# Always fetch fresh from API so new releases are seen immediately
|
||||||
logger.debug("Fetching from API...")
|
logger.debug("Fetching from API...")
|
||||||
try:
|
try:
|
||||||
logger.info(f"Checking for updates from {self.api_endpoint}")
|
logger.info(f"Checking for updates from {self.api_endpoint}")
|
||||||
|
|
||||||
# Run in thread pool with aggressive timeout
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
response = await asyncio.wait_for(
|
response = await asyncio.wait_for(
|
||||||
loop.run_in_executor(
|
loop.run_in_executor(None, self._fetch_release),
|
||||||
None, self._fetch_release
|
timeout=8,
|
||||||
),
|
|
||||||
timeout=8 # Timeout after network call also has timeout
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if not response:
|
if not response:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check if newer version
|
|
||||||
version = response["tag_name"].lstrip("v")
|
version = response["tag_name"].lstrip("v")
|
||||||
if not self._is_newer_version(version):
|
if not self._is_newer_version(version):
|
||||||
logger.info(f"Latest version {version} is not newer than {self.current_version}")
|
logger.info(f"Latest version {version} is not newer than {self.current_version}")
|
||||||
self._save_cache(response)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Cache the found update so repeated starts don't hammer the API
|
||||||
logger.info(f"New version available: {version}")
|
logger.info(f"New version available: {version}")
|
||||||
release = Release(**response)
|
release = Release(**response)
|
||||||
self._save_cache(response)
|
self._save_cache(response)
|
||||||
|
|
@ -234,6 +233,7 @@ class UpdateManager:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to fetch release: {type(e).__name__}: {e}")
|
logger.error(f"Failed to fetch release: {type(e).__name__}: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
logger.debug(traceback.format_exc())
|
logger.debug(traceback.format_exc())
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
@ -280,7 +280,7 @@ class UpdateManager:
|
||||||
installer_asset["browser_download_url"],
|
installer_asset["browser_download_url"],
|
||||||
output_file,
|
output_file,
|
||||||
),
|
),
|
||||||
timeout=300
|
timeout=300,
|
||||||
)
|
)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
|
@ -320,9 +320,7 @@ class UpdateManager:
|
||||||
logger.error(f"Download failed: {e}")
|
logger.error(f"Download failed: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def verify_checksum(
|
async def verify_checksum(self, file_path: Path, release: Release) -> bool:
|
||||||
self, file_path: Path, release: Release
|
|
||||||
) -> bool:
|
|
||||||
"""Verify file checksum against release checksum file.
|
"""Verify file checksum against release checksum file.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -354,7 +352,7 @@ class UpdateManager:
|
||||||
self._download_checksum,
|
self._download_checksum,
|
||||||
checksum_asset["browser_download_url"],
|
checksum_asset["browser_download_url"],
|
||||||
),
|
),
|
||||||
timeout=30
|
timeout=30,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not checksum_content:
|
if not checksum_content:
|
||||||
|
|
@ -374,9 +372,7 @@ class UpdateManager:
|
||||||
logger.info("Checksum verification passed")
|
logger.info("Checksum verification passed")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.error(
|
logger.error(f"Checksum mismatch: {file_checksum} != {expected_checksum}")
|
||||||
f"Checksum mismatch: {file_checksum} != {expected_checksum}"
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue