每次构建自动卸载旧版并安装新版:本机只保留 /Applications 一个 OpenStats

This commit is contained in:
gentpan committed 2026-09-14 23:37:43 +05:00
1 parent 92d09169fd
commit dce6ab2a79
4 files changed
+72 -25

No files matched your search

+8 -5
View File
@@ -32,17 +32,20 @@ hosting SwiftUI, no third-party dependencies. The Xcode project is generated fro
```bash
brew install xcodegen
make build # Debug
make install # Release into /Applications
make build # Release build, then replace /Applications/OpenStats.app and relaunch
make test # swift test in the package
```
Versions read `0.2.0 (0003)`: `MARKETING_VERSION` changes only when releasing
(`make bump-patch` for small releases, `make bump-minor` for larger ones), and the four-digit
`CURRENT_PROJECT_VERSION` goes up by one on every `make build` (`BUMP=0` skips it). Build numbers
never reset, so every package has a larger `CFBundleVersion` than the one before. Build products are
unregistered from Launch Services so only `/Applications/OpenStats.app` shows up in Spotlight and the
widget gallery.
never reset, so every package has a larger `CFBundleVersion` than the one before. Every `make build` runs
`Scripts/install_local.sh`: it ends the running app (the helper restores fans and sleep when the
connection drops), deletes the old `/Applications/OpenStats.app`, *moves* the new bundle there so no
copy stays in the build folder, re-registers it with Launch Services, and relaunches. Only one
OpenStats ever exists on the machine, so Spotlight and the widget gallery never show duplicates.
`INSTALL=0` compiles without installing; `Scripts/release.sh` uses it and installs the notarized
build at the end.
`project.yml` defaults to ad-hoc signing so the project opens anywhere. The Makefile passes
the first Developer ID Application identity from the keychain (and `--timestamp` for Release)
+10 -19
View File
@@ -1,6 +1,7 @@
PROJECT := OpenStats.xcodeproj
SCHEME := OpenStats
CONFIG ?= Debug
# 每次构建都会安装到 /Applications,默认用 Release
CONFIG ?= Release
DERIVED := build/DerivedData
APP := $(DERIVED)/Build/Products/$(CONFIG)/OpenStats.app
LSREGISTER := /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
@@ -21,29 +22,19 @@ endif
generate:
xcodegen generate --quiet
## 编译 App(含辅助工具);每次构建号加一,BUMP=0 时不加
## 编译 App(含辅助工具)并安装:卸载旧版、装上新版、启动,本机始终只有 /Applications 一份。
## 每次构建号加一(BUMP=0 不加);INSTALL=0 只编译不安装(发布脚本使用)
build:
@if [ "$(BUMP)" != "0" ]; then ./Scripts/version.sh build; fi
@$(MAKE) --no-print-directory compile
@if [ "$(INSTALL)" != "0" ]; then ./Scripts/install_local.sh $(APP); fi
compile: generate
xcodebuild -project $(PROJECT) -scheme $(SCHEME) -configuration $(CONFIG) \
-derivedDataPath $(DERIVED) -destination 'platform=macOS' -quiet $(SIGN_FLAGS) build
@# 编译产物不登记到启动服务,系统里只保留 /Applications 那一份(聚焦搜索、打开方式、小组件列表不重复)
@$(LSREGISTER) -u $(APP) >/dev/null 2>&1 || true
## 编译并启动(会先结束正在运行的 OpenStats)
run: build stop
open $(APP)
## 以 Release 构建安装到 /Applications 并启动(覆盖旧版本,保留偏好设置)
install:
$(MAKE) build CONFIG=Release
-pkill -x OpenStats
rm -rf /Applications/OpenStats.app
ditto $(DERIVED)/Build/Products/Release/OpenStats.app /Applications/OpenStats.app
$(LSREGISTER) -f /Applications/OpenStats.app
open /Applications/OpenStats.app
## 与 build 相同,保留旧名字
run install: build
## 发布:签名、公证、装订、打包 DMG,生成 Homebrew cask(见 Scripts/release.sh)
release:
@@ -69,9 +60,9 @@ bump-major:
test:
cd Packages/OpenStatsKit && swift test
## 用本机实时数据渲染各页面截图到 build/snapshots
snapshot: build
$(APP)/Contents/MacOS/OpenStats --snapshot build/snapshots
## 用本机实时数据渲染各页面截图到 build/snapshots(使用已安装的应用,不重新构建)
snapshot:
/Applications/OpenStats.app/Contents/MacOS/OpenStats --snapshot build/snapshots
open: generate
open $(PROJECT)
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
# 本机只保留一个 OpenStats:退出正在运行的旧版 → 删除 /Applications 里的旧版 → 把刚编译的新版移进去 → 启动。
# 用移动而不是复制,编译目录里不留第二份;其他位置被系统登记的同名应用会取消登记并提示。
#
# Scripts/install_local.sh build/DerivedData/Build/Products/Release/OpenStats.app
set -euo pipefail
cd "$(dirname "$0")/.."
SOURCE="${1:?用法:Scripts/install_local.sh <OpenStats.app>}"
TARGET="/Applications/OpenStats.app"
BUNDLE_ID="com.openstats.app"
LSREGISTER=/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister
[ -d "$SOURCE" ] || { echo "error: 找不到 $SOURCE" >&2; exit 1; }
codesign --verify --deep --strict "$SOURCE"
# 结束旧版。辅助工具在连接断开时会自动恢复风扇与睡眠设置,所以直接结束是安全的
# (不用 AppleScript 退出,免得弹出“自动化”权限请求)
if pgrep -x OpenStats >/dev/null; then
pkill -x OpenStats 2>/dev/null || true
for _ in $(seq 1 25); do pgrep -x OpenStats >/dev/null || break; sleep 0.2; done
fi
if [ -d "$TARGET" ]; then
"$LSREGISTER" -u "$TARGET" >/dev/null 2>&1 || true
rm -rf "$TARGET"
fi
mv "$SOURCE" "$TARGET"
"$LSREGISTER" -f "$TARGET"
# 编译目录里残留的旧产物(Debug / Release 另一种配置)也清掉
for stale in build/DerivedData/Build/Products/*/OpenStats.app; do
[ -d "$stale" ] || continue
"$LSREGISTER" -u "$stale" >/dev/null 2>&1 || true
rm -rf "$stale"
done
# 其他位置的同名应用只取消登记并提示,不擅自删除
others="$(mdfind "kMDItemCFBundleIdentifier == '$BUNDLE_ID'" 2>/dev/null | grep -vx "$TARGET" | grep -v '^/Volumes/' || true)"
if [ -n "$others" ]; then
echo "⚠️ 其他位置还有 OpenStats(已取消系统登记,如不需要请手动删除):"
while IFS= read -r path; do
"$LSREGISTER" -u "$path" >/dev/null 2>&1 || true
echo " $path"
done <<< "$others"
fi
open "$TARGET"
version="$(defaults read "$TARGET/Contents/Info" CFBundleShortVersionString) ($(defaults read "$TARGET/Contents/Info" CFBundleVersion))"
echo "✅ 已安装并启动 OpenStats $version:$TARGET"
+4 -1
View File
@@ -37,7 +37,7 @@ echo "版本 ${VERSION} · 签名身份:${SIGN_ID}"
# ---- 构建 --------------------------------------------------------------------
make build CONFIG=Release SIGN_ID="$SIGN_ID"
make build CONFIG=Release INSTALL=0 SIGN_ID="$SIGN_ID"
codesign --verify --deep --strict --verbose=2 "$APP"
for binary in "$APP" "$APP/Contents/MacOS/OpenStatsHelper" "$APP/Contents/PlugIns/OpenStatsWidget.appex"; do
@@ -122,6 +122,9 @@ cask "openstats" do
end
CASK
# 本机只保留一份:把刚公证的发布版装到 /Applications,编译目录里不留副本
./Scripts/install_local.sh "$APP"
echo
echo "✅ ${DIST}/${DMG_NAME}"
echo " SHA-256 ${SHA256}"