Make mac release rebuilds incremental and drop debug builds
This commit is contained in:
@@ -6,7 +6,7 @@ These are requirements, not preferences. Changing one needs the owner's agreemen
|
|||||||
|
|
||||||
- Never deploy unless the owner asks for it in the current turn. A finished change is reported undeployed; the owner deploys it, or asks you to. Never run `go install ./cmd/byre` or restart the service on your own initiative, not even to check that a change works.
|
- Never deploy unless the owner asks for it in the current turn. A finished change is reported undeployed; the owner deploys it, or asks you to. Never run `go install ./cmd/byre` or restart the service on your own initiative, not even to check that a change works.
|
||||||
- `docs/operations.md` describes the layout, data, service and APIs; keep it current with every change.
|
- `docs/operations.md` describes the layout, data, service and APIs; keep it current with every change.
|
||||||
- Never add tests. byre has no test suite; check a change with `go vet ./...`, `go generate ./web` (which type-checks the UI) and, when `mac/` changed, `swift build --package-path mac`.
|
- Never add tests. byre has no test suite; check a change with `go vet ./...`, `go generate ./web` (which type-checks the UI) and, when `mac/` changed, `mac/bundle.sh` (release only; debug builds are refused).
|
||||||
- The web UI (`web/src/`) and the macOS app (`mac/Sources/Byre/`) are two clients of the same views. A change to what a client shows or does, such as Markdown rendering, goes into both in the same task; never leave one client behind.
|
- The web UI (`web/src/`) and the macOS app (`mac/Sources/Byre/`) are two clients of the same views. A change to what a client shows or does, such as Markdown rendering, goes into both in the same task; never leave one client behind.
|
||||||
|
|
||||||
## Deploying
|
## Deploying
|
||||||
|
|||||||
+5
-3
@@ -18,7 +18,9 @@ The first version copies the web client: the same two equal panes, tabs, labels,
|
|||||||
- `UserNotifications` for notifications.
|
- `UserNotifications` for notifications.
|
||||||
- Third-party code: Apple's `swift-openapi-generator` (with `swift-openapi-runtime` and `swift-openapi-urlsession`) for the API types and client, and SwiftTerm for the terminal.
|
- Third-party code: Apple's `swift-openapi-generator` (with `swift-openapi-runtime` and `swift-openapi-urlsession`) for the API types and client, and SwiftTerm for the terminal.
|
||||||
|
|
||||||
The host has the Command Line Tools and no Xcode (`xcode-select --print-path` prints which), so the project is a Swift package under `mac/`, built with `swift build`, not an Xcode project. `mac/bundle.sh` builds the release configuration and assembles `mac/.build/byre.app` (the executable, `mac/Info.plist` with the fixed bundle identifier `run.fc.byre.mac`, the `web/fonts/` files and an `.icns` rendered from `web/favicon-tile.svg`) and signs it ad hoc; notification permission needs the bundle identifier. The app keeps its server origin in the `byre.server` default (`defaults read run.fc.byre.mac byre.server` prints it).
|
The project is a Swift package under `mac/`, built with `swift build`, not an Xcode project. It builds with Xcode's toolchain: `xcode-select --print-path` must print `/Applications/Xcode.app/Contents/Developer`. With the Command Line Tools selected while Xcode is installed, Swift Build finds two toolchains for the Command Line Tools path and picks one at random on each run; the pick is part of the build request, so every change of pick rebuilds every target. `mac/bundle.sh` builds the release configuration and assembles `mac/.build/byre.app` (the executable, `mac/Info.plist` with the fixed bundle identifier `run.fc.byre.mac`, the `web/fonts/` files and an `.icns` rendered from `web/favicon-tile.svg`, cached as `mac/.build/byre.icns` until the SVG changes) and signs it ad hoc; notification permission needs the bundle identifier.
|
||||||
|
|
||||||
|
Only the release configuration is built. A debug build stops at an `#error` in `ByreApp.swift`, and even a failed one leaves the next release build recompiling every target, since the two configurations share `mac/.build`. The generated API client is its own target, `ByreAPI`, so an edit to the app recompiles only the `Byre` target. SwiftPM builds release targets whole-module, so that is one compile of the whole `Byre` target, and a one-file change still costs that. The app keeps its server origin in the `byre.server` default (`defaults read run.fc.byre.mac byre.server` prints it).
|
||||||
|
|
||||||
SwiftUI's own macros don't build here: the SDK declares `@State`, `@Entry`, `@Animatable` and the rest as macros implemented in the `SwiftUIMacros` plugin, which ships with Xcode and not with the Command Line Tools (`ls /Library/Developer/CommandLineTools/usr/lib/swift/host/plugins` lists the plugins there). `@State` is reached through its property-wrapper type instead, as `typealias ViewState = State` and `@ViewState var …`; other SwiftUI macros aren't used. `@Observable` and `@Bindable` (Observation's plugin, which the Command Line Tools have), `@Environment` and `@FocusState` work as usual.
|
SwiftUI's own macros don't build here: the SDK declares `@State`, `@Entry`, `@Animatable` and the rest as macros implemented in the `SwiftUIMacros` plugin, which ships with Xcode and not with the Command Line Tools (`ls /Library/Developer/CommandLineTools/usr/lib/swift/host/plugins` lists the plugins there). `@State` is reached through its property-wrapper type instead, as `typealias ViewState = State` and `@ViewState var …`; other SwiftUI macros aren't used. `@Observable` and `@Bindable` (Observation's plugin, which the Command Line Tools have), `@Environment` and `@FocusState` work as usual.
|
||||||
|
|
||||||
@@ -28,7 +30,7 @@ Values the web client defines are generated into Swift, never copied by hand, so
|
|||||||
|
|
||||||
| Value | Source | Swift |
|
| Value | Source | Swift |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| API types and client | `api/openapi.yaml` | Generated at build time by the `swift-openapi-generator` plugin (`mac/Sources/Byre/openapi-generator-config.yaml`, idiomatic naming: `display_name` is `displayName`) from the symlink `mac/Sources/Byre/openapi.yaml` to the spec. The output lands in `mac/.build/plugins/outputs/`, not in git |
|
| API types and client | `api/openapi.yaml` | Generated at build time into the `ByreAPI` target by the `swift-openapi-generator` plugin (`mac/Sources/ByreAPI/openapi-generator-config.yaml`, public access, idiomatic naming: `display_name` is `displayName`) from the symlink `mac/Sources/ByreAPI/openapi.yaml` to the spec. App files that use it `import ByreAPI`. The output lands in `mac/.build/plugins/outputs/`, not in git |
|
||||||
| Palette, light and dark | Custom properties at the top of `web/style.css` (`:root` and its `prefers-color-scheme: dark` block) | `go generate ./mac` (`mac/palette`) writes `Palette.swift`: one dynamic `Color` per hex property, `--accent-tint` as `Palette.accentTint`, resolving light or dark with the window's appearance. Properties that aren't a hex colour (`--task`, `--shadow`, `--font`) are left out. The file is committed, so `swift build` needs no Go; a property missing from either block fails the generator |
|
| Palette, light and dark | Custom properties at the top of `web/style.css` (`:root` and its `prefers-color-scheme: dark` block) | `go generate ./mac` (`mac/palette`) writes `Palette.swift`: one dynamic `Color` per hex property, `--accent-tint` as `Palette.accentTint`, resolving light or dark with the window's appearance. Properties that aren't a hex colour (`--task`, `--shadow`, `--font`) are left out. The file is committed, so `swift build` needs no Go; a property missing from either block fails the generator |
|
||||||
| Font | `web/fonts/` | The build script copies the woff2 files into the bundle; the app loads each with `CTFontManagerCreateFontDescriptorsFromURL` (see "Gaps in SwiftUI") |
|
| Font | `web/fonts/` | The build script copies the woff2 files into the bundle; the app loads each with `CTFontManagerCreateFontDescriptorsFromURL` (see "Gaps in SwiftUI") |
|
||||||
| App icon | `web/favicon-tile.svg` | The build script renders it to an `.icns` with `rsvg-convert` and `iconutil` |
|
| App icon | `web/favicon-tile.svg` | The build script renders it to an `.icns` with `rsvg-convert` and `iconutil` |
|
||||||
@@ -188,7 +190,7 @@ Platform differences the copy can't avoid, each with what the web client does an
|
|||||||
|
|
||||||
## Building and checking
|
## Building and checking
|
||||||
|
|
||||||
`swift build --package-path mac` is the compile check for changes under `mac/`, alongside the checks `AGENTS.md` already names. No tests are added. Installing the app is a separate action from deploying the byre service.
|
`mac/bundle.sh` is the compile check for changes under `mac/`, alongside the checks `AGENTS.md` already names. No tests are added. Installing the app is a separate action from deploying the byre service.
|
||||||
|
|
||||||
## Not in version one
|
## Not in version one
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -11,14 +11,21 @@ let package = Package(
|
|||||||
.package(url: "https://github.com/apple/swift-openapi-urlsession", from: "1.1.0"),
|
.package(url: "https://github.com/apple/swift-openapi-urlsession", from: "1.1.0"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.executableTarget(
|
.target(
|
||||||
name: "Byre",
|
name: "ByreAPI",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "SwiftTerm", package: "SwiftTerm"),
|
|
||||||
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||||
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
|
||||||
],
|
],
|
||||||
plugins: [.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")]
|
plugins: [.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")]
|
||||||
),
|
),
|
||||||
|
.executableTarget(
|
||||||
|
name: "Byre",
|
||||||
|
dependencies: [
|
||||||
|
"ByreAPI",
|
||||||
|
.product(name: "SwiftTerm", package: "SwiftTerm"),
|
||||||
|
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
|
||||||
|
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
|
||||||
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import Foundation
|
import Foundation
|
||||||
import HTTPTypes
|
import HTTPTypes
|
||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#error("debug builds are unsupported: build with mac/bundle.sh")
|
||||||
|
#endif
|
||||||
|
|
||||||
typealias ViewState = State
|
typealias ViewState = State
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias TaskChanges = Components.Schemas.TaskChanges
|
typealias TaskChanges = Components.Schemas.TaskChanges
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
enum ChatKind: Equatable {
|
enum ChatKind: Equatable {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UniformTypeIdentifiers
|
import UniformTypeIdentifiers
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias DirListing = Components.Schemas.DirListing
|
typealias DirListing = Components.Schemas.DirListing
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import OpenAPIRuntime
|
import OpenAPIRuntime
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias Participant = Components.Schemas.Participant
|
typealias Participant = Components.Schemas.Participant
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
enum TabBadge {
|
enum TabBadge {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias Todo = Components.Schemas.Todo
|
typealias Todo = Components.Schemas.Todo
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias FindingState = Components.Schemas.FindingState
|
typealias FindingState = Components.Schemas.FindingState
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias AgentProcess = Components.Schemas.AgentProcess
|
typealias AgentProcess = Components.Schemas.AgentProcess
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias WorkflowSummary = Components.Schemas.WorkflowSummary
|
typealias WorkflowSummary = Components.Schemas.WorkflowSummary
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import ByreAPI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias WorkflowRun = Components.Schemas.WorkflowRun
|
typealias WorkflowRun = Components.Schemas.WorkflowRun
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
import OpenAPIRuntime
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
generate:
|
generate:
|
||||||
- types
|
- types
|
||||||
- client
|
- client
|
||||||
accessModifier: internal
|
accessModifier: public
|
||||||
namingStrategy: idiomatic
|
namingStrategy: idiomatic
|
||||||
+13
-9
@@ -4,20 +4,24 @@ mac=$(cd "$(dirname "$0")" && pwd)
|
|||||||
root=$(dirname "$mac")
|
root=$(dirname "$mac")
|
||||||
build=$mac/.build
|
build=$mac/.build
|
||||||
app=$build/byre.app
|
app=$build/byre.app
|
||||||
|
svg=$root/web/favicon-tile.svg
|
||||||
|
icns=$build/byre.icns
|
||||||
swift build --package-path "$mac" --configuration release
|
swift build --package-path "$mac" --configuration release
|
||||||
bin=$(swift build --package-path "$mac" --configuration release --show-bin-path)
|
if [ ! "$icns" -nt "$svg" ]; then
|
||||||
rm -rf "$app"
|
|
||||||
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources/fonts"
|
|
||||||
cp "$bin/Byre" "$app/Contents/MacOS/Byre"
|
|
||||||
cp "$mac/Info.plist" "$app/Contents/Info.plist"
|
|
||||||
cp "$root"/web/fonts/*.woff2 "$app/Contents/Resources/fonts/"
|
|
||||||
iconset=$build/byre.iconset
|
iconset=$build/byre.iconset
|
||||||
rm -rf "$iconset"
|
rm -rf "$iconset"
|
||||||
mkdir -p "$iconset"
|
mkdir -p "$iconset"
|
||||||
for size in 16 32 128 256 512; do
|
for size in 16 32 128 256 512; do
|
||||||
rsvg-convert --width $size --height $size --output "$iconset/icon_${size}x${size}.png" "$root/web/favicon-tile.svg"
|
rsvg-convert --width $size --height $size --output "$iconset/icon_${size}x${size}.png" "$svg"
|
||||||
rsvg-convert --width $((size * 2)) --height $((size * 2)) --output "$iconset/icon_${size}x${size}@2x.png" "$root/web/favicon-tile.svg"
|
rsvg-convert --width $((size * 2)) --height $((size * 2)) --output "$iconset/icon_${size}x${size}@2x.png" "$svg"
|
||||||
done
|
done
|
||||||
iconutil --convert icns --output "$app/Contents/Resources/byre.icns" "$iconset"
|
iconutil --convert icns --output "$icns" "$iconset"
|
||||||
|
fi
|
||||||
|
rm -rf "$app"
|
||||||
|
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources/fonts"
|
||||||
|
cp "$build/release/Byre" "$app/Contents/MacOS/Byre"
|
||||||
|
cp "$mac/Info.plist" "$app/Contents/Info.plist"
|
||||||
|
cp "$root"/web/fonts/*.woff2 "$app/Contents/Resources/fonts/"
|
||||||
|
cp "$icns" "$app/Contents/Resources/byre.icns"
|
||||||
codesign --force --sign - "$app"
|
codesign --force --sign - "$app"
|
||||||
echo "$app"
|
echo "$app"
|
||||||
|
|||||||
Reference in New Issue
Block a user