Skip to content

chore: require macOS 15, move to grpc-swift v2 and bump dependencies - #280

Draft
ethanndickson wants to merge 3 commits into
fix/xcode-27from
chore/bump-swift-deps
Draft

ethanndickson wants to merge 3 commits into
fix/xcode-27from
chore/bump-swift-deps

Conversation

@ethanndickson

@ethanndickson ethanndickson commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

This started as bumping the protoc plugins in the flake. They come from a third-party grpc-swift flake that hasn't been touched since December 2024, and since #276 it needs its own ancient nixpkgs pin just to evaluate on Darwin. nixpkgs doesn't package protoc-gen-grpc-swift, and grpc-swift stopped attaching prebuilt plugins to v1 releases, so keeping v1 meant maintaining our own Nix package for it.

Instead, this PR requires macOS 15 so we can move to grpc-swift v2. Its build tool plugin generates the Swift code for the .proto files at build time, building protoc and both plugins from the resolved packages. The generated code can't drift from the runtime anymore, and the committed .pb.swift/.grpc.swift files, make proto, and all of the protoc tooling in the flake are gone. Clean builds do compile protoc from source once.

The protos now live in a local Swift package, Coder-Desktop/Proto, with a VPNProto target for vpn.proto and a MutagenProto target for the Mutagen protos and their gRPC clients. Attached to an Xcode target, the plugin only sees files in a build phase, which meant putting every .proto and .json in the sources phase and adding no-op build rules to stop Xcode warning about them. In a package it just picks up the files in the target directory. VPNLib imports MutagenProto with internal import, so the Mutagen types stay out of its public API, and anything using the Vpn_ types now imports VPNProto. The exact versions are still pinned in project.yml, and Package.swift only sets minimums. Each target also has a Swift file containing only a comment, since SwiftPM won't load a target without one and the generated code doesn't count.

v2's bidirectional streams are scoped to a closure, so the prompting stream is now withPrompter { promptID in ... } rather than a stream we cancel in a defer. v2 also fails RPCs straight away whilst the channel is backing off after a failed connect, which broke the startup probe (the socket doesn't exist yet), so that call now sets waitForReady. FileSyncDaemonTests caught this, as they run against the real Mutagen binary.

The appcast's minimumSystemVersion and the cask's depends_on are bumped to 15 too, so macOS 14 users don't get offered an update that won't launch.

I also bumped the rest of the app dependencies whilst I was here: Sparkle 2.10.1 (its updater APIs are now @MainActor, so UpdaterService is too), Subprocess 4.0.1, URLRouting 0.7.0, SDWebImageSwiftUI 3.1.4, SDWebImageSVGCoder 1.8.0, and the SwiftLintPlugins floor to 0.65.1 to match the flake's swiftlint. URLRouting 0.7.0 deprecates the .case(CoderRoute.open(...)) form we use; the replacement needs @CasePathable, which needs a direct swift-case-paths dependency, so I've left that warning for now.

This is on top of the stack (#276, #277, #275). I've tested it locally with Xcode 27.

@ethanndickson
ethanndickson added this pull request to stack #278 October 29, 2026 06:53
@ethanndickson
ethanndickson force-pushed the chore/bump-swift-deps branch 2 times, most recently from 30cf862 to 7e83f2e Compare October 29, 2026 08:25
@ethanndickson
ethanndickson removed this pull request from stack #278 October 30, 2026 01:33
Base automatically changed from fix/trusted-app-links to fix/xcode-27 October 30, 2026 01:33
@ethanndickson
ethanndickson added this pull request to stack #281 October 30, 2026 01:45
@ethanndickson
ethanndickson removed this pull request from stack #281 October 30, 2026 01:47
@ethanndickson
ethanndickson added this pull request to stack #282 October 30, 2026 01:47
grpc-swift v2 needs macOS 15. With it, the Swift code for the .proto
files is generated at build time by grpc-swift-protobuf's build tool
plugin, which builds protoc and both protoc plugins from the resolved
packages. The generated files, `make proto`, and the protoc tooling in
the flake (including the stale grpc-swift flake and its separate nixpkgs
pin) are all gone.

Also bumps SwiftProtobuf, Sparkle, Subprocess, URLRouting,
SDWebImageSwiftUI, SDWebImageSVGCoder, and the SwiftLintPlugins and
ViewInspector floors, and raises the appcast and cask minimum macOS to
15.
The GRPCProtobufGenerator plugin only sees files in a build phase when it's
attached to an Xcode target, which needed the .proto and .json files in the
sources phase project-wide and no-op build rules to silence Xcode. In a Swift
package the plugin picks up the files in the target directory as-is.

VPNProto holds the tunnel messages and MutagenProto the Mutagen messages and
gRPC clients. VPNLib imports MutagenProto internally so the Mutagen types stay
out of its public API.
Depot runners enable Xcode compilation caching through an xcconfig that
prefix maps DerivedData to /^dd. swift-protobuf's protoc finds the
well-known type protos relative to __FILE__, which is remapped too, so the
generator plugin fails with "google/protobuf/timestamp.proto: File not
found". Passing COMPILATION_CACHE_ENABLE_CACHING=NO to xcodebuild wasn't
enough, so opt out with DEPOT_XCODE_CACHE_ENABLED=0 for the jobs that build.
See apple/swift-protobuf#2060
@matifali

Copy link
Copy Markdown
Member

I wonder if we can migarte to mise from nix here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants