Embed installer icons and remove external assets from archives

This commit is contained in:
toorux committed 2026-10-04 23:51:37 +08:00
1 parent e54689bff6
commit c4f672cba7
4 files changed
+15 -6

No files matched your search

+2
View File
@@ -66,6 +66,8 @@ Actions builds Linux x64/ARM64, Windows x64, and macOS Intel/Apple Silicon. macO
The titlebar and application icons share the pixel logo. Windows builds embed the ICO in the EXE; macOS packaging uses the system `iconutil` to generate and configure `.icns`. On Linux, run `bash install-desktop-entry.sh` from the extracted archive to register an icon-bearing entry in the current user's application menu. The entry points to that directory; rerun the script after moving it.
Installer archives do not include a separate `assets` directory. The UI logo is embedded in the executable; the Linux registration script embeds its menu icon, while macOS keeps its application icon inside the `.app` bundle.
Automated tests and Actions builds validate software and artifacts. Discovery, login, permissions, update, rollback, and uninstall still need acceptance testing on actual computers and Frame hardware.
Discovery queries `frame.local` mDNS address records directly. It does not require an advertised SSH service or system DNS support for `.local`. Run the same discovery logic independently for diagnosis:
+2
View File
@@ -66,6 +66,8 @@ Actions 构建 Linux x64/ARM64、Windows x64、macOS Intel/Apple Silicon。macOS
安装器标题栏和应用图标使用统一的像素 Logo。Windows 构建将 ICO 嵌入 EXE,macOS 打包使用系统 `iconutil` 生成并配置 `.icns`。Linux 解压后可在解压目录执行 `bash install-desktop-entry.sh`,把带图标的入口注册到当前用户的应用菜单;入口指向该目录,移动后需重新执行脚本。
安装器压缩包不包含独立的 `assets` 目录。界面 Logo 内嵌在可执行文件中,Linux 注册脚本内嵌菜单图标,macOS 的应用图标保存在 `.app` 内部。
所有自动测试和 Actions 构建只能验证软件及产物;仍需在真实电脑和 Frame 上完成扫描、登录、权限、升级回滚及卸载验收。
扫描会直接查询 `frame.local` 的 mDNS 地址记录,不要求设备广播 SSH 服务,也不依赖电脑的系统 DNS 支持 `.local`。可单独运行与界面相同的发现逻辑进行诊断:
+5 -2
View File
@@ -3,7 +3,7 @@
set -euo pipefail
base=$(cd -- "$(dirname -- "$0")" && pwd)
python3 - "$base" <<'PY'
import os, pathlib, shutil
import os, pathlib
base = pathlib.Path(__import__('sys').argv[1])
binary = base / 'framely-installer'
if not binary.is_file():
@@ -13,7 +13,10 @@ apps = data / 'applications'
icons = data / 'icons/hicolor/scalable/apps'
apps.mkdir(parents=True, exist_ok=True)
icons.mkdir(parents=True, exist_ok=True)
shutil.copy2(base / 'assets/branding/framely-app-icon.svg', icons / 'org.framely.installer.svg')
icon = None # Embedded by tools/package-installer.py.
if icon is None:
icon = (base.parent / 'assets/branding/framely-app-icon.svg').read_bytes()
(icons / 'org.framely.installer.svg').write_bytes(icon)
# Desktop entries parse backslash escapes before parsing the quoted Exec value.
quoted = str(binary).replace('%', '%%').replace('\\', '\\\\')
for character in ('"', '`', '$'):
+6 -4
View File
@@ -39,11 +39,13 @@ with __import__('tempfile').TemporaryDirectory() as temp:
shutil.copy2(binary, stage / exe)
if not platform.startswith('windows'):
(stage / exe).chmod(0o755)
shutil.copy2(root / 'installer/install-desktop-entry.sh', stage / 'install-desktop-entry.sh')
desktop_script = (root / 'installer/install-desktop-entry.sh').read_text()
marker = 'icon = None # Embedded by tools/package-installer.py.'
if desktop_script.count(marker) != 1:
raise ValueError('Desktop registration script is missing its icon marker')
icon = (root / 'assets/branding/framely-app-icon.svg').read_bytes()
(stage / 'install-desktop-entry.sh').write_text(desktop_script.replace(marker, f'icon = {icon!r}'))
(stage / 'install-desktop-entry.sh').chmod(0o755)
(stage / 'assets/branding').mkdir(parents=True)
for asset in ('framely-logo.svg', 'framely-logo-light.svg', 'framely-app-icon.svg', 'framely-app-icon.png', 'framely.ico'):
shutil.copy2(root / 'assets/branding' / asset, stage / 'assets/branding' / asset)
shutil.copy2(root / 'installer/README.md', stage / 'README.md')
shutil.copy2(root / 'installer/README.zh-CN.md', stage / 'README.zh-CN.md')
shutil.copy2(root / 'LICENSE', stage / 'LICENSE')