Compare commits

...
10 changed files with 36 additions and 16 deletions

No files matched your search

+14
View File
@@ -70,6 +70,9 @@ jobs:
- os: macos-latest
script: dist
files: app/dist/*.dmg app/dist/*.zip
- os: macos-15-intel
script: dist:mac:x64
files: app/dist/*.dmg app/dist/*.zip
- os: windows-latest
script: dist:win
files: app/dist/*.exe app/dist/*.zip
@@ -110,6 +113,17 @@ jobs:
run: npm ci && npm run ${{ matrix.script }}
env:
CSC_IDENTITY_AUTO_DISCOVERY: "false"
- name: Check the Mac bundle matches its runner
if: runner.os == 'macOS'
shell: bash
run: |
bundle=$(find app/dist -maxdepth 2 -name 'Frame Control.app' -type d -print -quit)
test -n "$bundle"
resources="$bundle/Contents/Resources"
for binary in "$bundle/Contents/MacOS/Frame Control" "$resources/python/bin/python3" "$resources/tools/adb" "$resources/mac/bin/frame-mac-view"; do
lipo "$binary" -verify_arch "$(uname -m)"
done
"$resources/python/bin/python3" -I -B -c 'import http.server, ssl, sqlite3; print(ssl.OPENSSL_VERSION)'
- name: Launch the built Linux AppImage
if: matrix.os == 'ubuntu-latest'
run: python3 scripts/check-appimage-launch.py app/dist/Frame-Control-linux-x86_64.AppImage
+2 -1
View File
@@ -4,7 +4,7 @@
// copies into the app's resources. Also KDE Connect for the Frame (the same arm64
// packages for every build), into ../frame/kdeconnect/packages as listed in
// ../frame/kdeconnect/packages.json. Everything is pinned by version and SHA-256.
// node build/fetch-deps.js mac arm64 | win x64 | linux x64 arm64
// node build/fetch-deps.js mac arm64 x64 | win x64 | linux x64 arm64
const crypto = require("crypto");
const fs = require("fs");
const https = require("https");
@@ -15,6 +15,7 @@ const PY = "3.12.14+20260924";
const PY_URL = (triple) => "https://github.com/astral-sh/python-build-standalone/releases/download/"
+ `${PY.split("+")[1]}/cpython-${PY}-${triple}-install_only_stripped.tar.gz`;
const PYTHON = {
"mac-x64": ["x86_64-apple-darwin", "7ea9761b9069c10b9a20531d568645849d604c59e9c7f11f6659f1e1790c968e"],
"mac-arm64": ["aarch64-apple-darwin", "c2edb321cd32ec2b170df208db0446dccc4398db602ca27cf2079098fb1f7d9d"],
"win-x64": ["x86_64-pc-windows-msvc", "c5bf8edfe858c1df9891be498b5bbc8761d383df5b9790658b088fea4870433a"],
"linux-x64": ["x86_64-unknown-linux-gnu", "269b2c99e4db15b242bf01832f4fea1e8f1a664f273cff519393f296e9820b41"],
+4 -3
View File
@@ -9,10 +9,11 @@
"scripts": {
"start": "env -u ELECTRON_RUN_AS_NODE electron .",
"icon": "env -u ELECTRON_RUN_AS_NODE electron build/make-icon.js",
"dist": "sh ../mac/frame-mac-view/build.sh && node build/fetch-deps.js mac arm64 && electron-builder --mac --arm64 --publish never",
"dist:dir": "sh ../mac/frame-mac-view/build.sh && node build/fetch-deps.js mac arm64 && electron-builder --mac --arm64 --dir",
"dist": "FRAME_MAC_ARCH=arm64 sh ../mac/frame-mac-view/build.sh && node build/fetch-deps.js mac arm64 && electron-builder --mac --arm64 --publish never",
"dist:dir": "FRAME_MAC_ARCH=arm64 sh ../mac/frame-mac-view/build.sh && node build/fetch-deps.js mac arm64 && electron-builder --mac --arm64 --dir",
"dist:linux": "node build/fetch-deps.js linux x64 arm64 && electron-builder --linux --x64 --arm64 --publish never",
"dist:win": "node build/fetch-deps.js win x64 && electron-builder --win --x64 --publish never"
"dist:win": "node build/fetch-deps.js win x64 && electron-builder --win --x64 --publish never",
"dist:mac:x64": "FRAME_MAC_ARCH=x86_64 sh ../mac/frame-mac-view/build.sh && node build/fetch-deps.js mac x64 && electron-builder --mac --x64 --publish never"
},
"devDependencies": {
"electron": "^44.4.5",
+3 -3
View File
@@ -13,7 +13,7 @@ count. So a build reaches people only when you publish it, after testing it.
```
`.github/workflows/release.yml` builds macOS, Windows and Linux, and
attaches everything to a **draft** release for that tag. After all eight
attaches everything to a **draft** release for that tag. After all ten
installers upload, the workflow also attaches `SHA256SUMS` built from
GitHub's SHA-256 digests of those uploaded bytes. Nobody is
offered a draft. Editing a draft while installers are uploading can make
@@ -39,9 +39,9 @@ count. So a build reaches people only when you publish it, after testing it.
scripts/publish-release.sh v0.4.0
```
The script checks that the tag is on GitHub and that all eight installers
The script checks that the tag is on GitHub and that all ten installers
are attached, each with the SHA-256 digest GitHub records. It also checks
that the uploaded `SHA256SUMS` digest matches a fresh list of those eight
that the uploaded `SHA256SUMS` digest matches a fresh list of those ten
installer digests. It attaches
`update.json` (the version, the notes, the release page and each
installer's digest), then publishes the release and marks it latest. It
+1 -1
View File
@@ -249,7 +249,7 @@ final class WebSocket {
var payload = Data(buffer[(start + off)..<(start + off + len)])
if masked {
let mask = [UInt8](buffer[(start + maskOff)..<(start + maskOff + 4)])
payload.withUnsafeMutableBytes { p in
payload.withUnsafeMutableBytes { (p: UnsafeMutableRawBufferPointer) in
for i in 0..<len { p[i] ^= mask[i & 3] }
}
}
+4 -2
View File
@@ -1,11 +1,13 @@
#!/bin/sh
# Builds the Mac streaming agent into mac/bin/frame-mac-view (arm64, macOS 14+).
# Builds the Mac streaming agent into mac/bin/frame-mac-view (arm64 or x86_64, macOS 14+).
# Frame Control runs it for "Mac in the headset"; the Electron app bundles it.
set -eu
here=$(cd "$(dirname "$0")" && pwd)
out=${1:-$here/../bin/frame-mac-view}
arch=${FRAME_MAC_ARCH:-$(uname -m)}
case "$arch" in arm64|x86_64) ;; *) echo "unsupported Mac architecture: $arch" >&2; exit 1 ;; esac
mkdir -p "$(dirname "$out")"
xcrun swiftc -O -swift-version 5 -target arm64-apple-macos14.0 \
xcrun swiftc -O -swift-version 5 -target "$arch-apple-macos14.0" \
-import-objc-header "$here/Sources/CGVirtualDisplay.h" \
-o "$out" "$here"/Sources/*.swift
echo "built $out"
+3 -3
View File
@@ -15,7 +15,7 @@ dry=""
[ "${1:-}" = "--dry-run" ] && { dry=1; shift; }
tag="${1:?usage: $0 [--dry-run] vX.Y.Z}"
repo=saphid/frame-control
expected="Frame-Control-mac-arm64.dmg Frame-Control-mac-arm64.zip Frame-Control-Setup-x64.exe
expected="Frame-Control-mac-arm64.dmg Frame-Control-mac-arm64.zip Frame-Control-mac-x64.dmg Frame-Control-mac-x64.zip Frame-Control-Setup-x64.exe
Frame-Control-win-x64.zip Frame-Control-linux-x86_64.AppImage Frame-Control-linux-arm64.AppImage
Frame-Control-linux-amd64.deb Frame-Control-linux-arm64.deb"
page="https://github.com/$repo/releases/tag/$tag"
@@ -70,7 +70,7 @@ print(next((a.get("digest") or "" for a in d["assets"] if a["name"]==n), "absent
done
[ -z "$missing" ] || { echo "not publishing: fix the assets above" >&2; exit 1; }
# The workflow uploads this only after all eight platform builds complete.
# The workflow uploads this only after all ten platform builds complete.
# Regenerate it from GitHub's installer digests and compare its own GitHub
# digest, so a stale or partial checksum file cannot pass the release gate.
python3 "$(dirname "$0")/release-checksums.py" < "$tmp/release.json" > "$tmp/SHA256SUMS"
@@ -79,7 +79,7 @@ checksum_digest=$(python3 -c 'import json,sys
d=json.load(open(sys.argv[1])); matches=[a.get("digest") for a in d["assets"] if a["name"]=="SHA256SUMS"]
print(matches[0] if len(matches)==1 else "absent")' "$tmp/release.json")
[ "$checksum_digest" = "sha256:$expected_sum" ] || {
echo "not publishing: SHA256SUMS is absent or does not match the eight installer digests" >&2; exit 1;
echo "not publishing: SHA256SUMS is absent or does not match the ten installer digests" >&2; exit 1;
}
echo "ok SHA256SUMS"
+2 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Print SHA256SUMS for the eight release installers from GitHub asset metadata.
"""Print SHA256SUMS for the ten release installers from GitHub asset metadata.
GitHub computes each asset digest from its uploaded bytes. The workflow runs
this only after all platform builds finish; publish-release.sh checks that the
@@ -13,6 +13,7 @@ import sys
INSTALLERS = (
"Frame-Control-mac-arm64.dmg",
"Frame-Control-mac-arm64.zip",
"Frame-Control-mac-x64.dmg", "Frame-Control-mac-x64.zip",
"Frame-Control-Setup-x64.exe",
"Frame-Control-win-x64.zip",
"Frame-Control-linux-x86_64.AppImage",
+2 -1
View File
@@ -17,7 +17,8 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SCRIPT = ROOT / "scripts" / "publish-release.sh"
FAKEGH = ROOT / "tests" / "fakegh"
INSTALLERS = ["Frame-Control-mac-arm64.dmg", "Frame-Control-mac-arm64.zip", "Frame-Control-Setup-x64.exe",
INSTALLERS = ["Frame-Control-mac-arm64.dmg", "Frame-Control-mac-arm64.zip",
"Frame-Control-mac-x64.dmg", "Frame-Control-mac-x64.zip", "Frame-Control-Setup-x64.exe",
"Frame-Control-win-x64.zip", "Frame-Control-linux-x86_64.AppImage",
"Frame-Control-linux-arm64.AppImage", "Frame-Control-linux-amd64.deb",
"Frame-Control-linux-arm64.deb"]
+1 -1
View File
@@ -17,7 +17,7 @@ class Checksums(unittest.TestCase):
for i, name in enumerate(module.INSTALLERS):
assets.append({"name": name, "digest": "sha256:" + hashlib.sha256(str(i).encode()).hexdigest()})
actual = module.checksums({"assets": assets})
self.assertEqual(len(actual.splitlines()), 8)
self.assertEqual(len(actual.splitlines()), 10)
self.assertEqual(actual.splitlines()[0], hashlib.sha256(b"0").hexdigest() + " " + module.INSTALLERS[0])
def test_missing_duplicate_and_bad_digest_fail(self):