Repository navigation
chore: require macOS 15, move to grpc-swift v2 and bump dependencies - #280
ethanndickson wants to merge 8 commits into
Conversation
30cf862 to
7e83f2e
Compare
7e83f2e to
00bdd92
Compare
00bdd92 to
487876c
Compare
487876c to
af1182e
Compare
af1182e to
9deb355
Compare
|
I wonder if we can migrate to |
9deb355 to
1a9cbc7
Compare
01485bc to
bdd6220
Compare
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
swift-parsing deprecated `.case(CoderRoute.open(workspace:agent:route:))` in favour of a `CasePathable` case key path. Make `CoderRoute` `@CasePathable` and route through `\CoderRoute.Cases.open`. The case key path's value is the labelled payload `(workspace:agent:route:)`, while the parsers output an unlabelled `(String, String, OpenRoute)`, so add a conversion that labels the tuple. URLRouting doesn't re-export CasePaths, so add swift-case-paths as a direct VPNLib dependency, pinned to the 1.10.0 that swift-parsing already resolves.
XcodeGen adds a local package as both a package reference and a folder reference. Xcode 27 opens the folder first, then refuses to load Proto as a package because it's "already open as a Folder", so the VPNProto and MutagenProto products go missing. xcodebuild doesn't mind, which is why CI passes without this. There's no XcodeGen option to skip the folder reference yet (yonaskolb/XcodeGen#1631), so remove it in a postGenCommand. It's a no-op if XcodeGen stops adding it.
bdd6220 to
611d726
Compare
|
@codex review |
Codex Review Summary: ✅ CompletedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
grpc-swift v2's graceful shutdown waits for in-flight RPCs to finish, whereas v1's `channel.close()` failed them straight away. `sync.list` has no deadline, so if the daemon hung, `stop()` and app quit would hang with it. Cancel the task running the connections instead, and drop the `grpcClient` property, which was only kept for the graceful shutdown.
The whole prompter stream ran at `.background`, including the first message that `createSession` waits on. Before the grpc-swift v2 move, only the reply loop did.
Nothing in VPNLib's public API uses them, the same as `MutagenProto`.
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
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
.protofiles at build time, buildingprotocand both plugins from the resolved packages. The generated code can't drift from the runtime anymore, and the committed.pb.swift/.grpc.swiftfiles,make proto, and all of the protoc tooling in the flake are gone. Clean builds do compileprotocfrom source once.The protos now live in a local Swift package,
Coder-Desktop/Proto, with aVPNPrototarget forvpn.protoand aMutagenPrototarget 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.protoand.jsonin 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 importsMutagenProtowithinternal import, so the Mutagen types stay out of its public API, and anything using theVpn_types now importsVPNProto. The exact versions are still pinned inproject.yml, andPackage.swiftonly 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 adefer. 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 setswaitForReady.FileSyncDaemonTestscaught this, as they run against the real Mutagen binary.The appcast's
minimumSystemVersionand the cask'sdepends_onare 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, soUpdaterServiceis 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'sswiftlint. 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.