From 01f9ea942cd6b301b56406ac281e1847d9354280 Mon Sep 17 00:00:00 2001 From: PJ Date: Sun, 16 Aug 2026 01:05:59 +0530 Subject: [PATCH] fix(ios): one address picker for every bring-up bringUpRunner reads the picker from a field, and NewDevice only ever set the device one, so a device driver that reached bringUpRunner would call nil. The two fields held the same function; keeping one leaves no path that can be wired without it. --- internal/driver/ioscompanion/device.go | 6 +++--- internal/driver/ioscompanion/driver.go | 25 ++++++++++++++----------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/internal/driver/ioscompanion/device.go b/internal/driver/ioscompanion/device.go index 5d05982..b8dbdff 100644 --- a/internal/driver/ioscompanion/device.go +++ b/internal/driver/ioscompanion/device.go @@ -103,9 +103,9 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) { } } if options.pickAddress != nil { - d.pickDeviceAddress = options.pickAddress + d.pickRunnerAddress = options.pickAddress } else { - d.pickDeviceAddress = pickLoopbackAddress + d.pickRunnerAddress = pickLoopbackAddress } // Device seams: clear-state reinstalls via devicectl; the container reset and @@ -159,7 +159,7 @@ func NewDevice(ctx context.Context, options DeviceOptions) (*Driver, error) { // health. The build runs inside spawnRunner under the process context, so the // startup timeout only bounds the post-spawn wait, not the build. func (d *Driver) bringUpDevice(ctx context.Context) error { - address, err := d.pickDeviceAddress() + address, err := d.pickRunnerAddress() if err != nil { return err } diff --git a/internal/driver/ioscompanion/driver.go b/internal/driver/ioscompanion/driver.go index f629675..aa12589 100644 --- a/internal/driver/ioscompanion/driver.go +++ b/internal/driver/ioscompanion/driver.go @@ -157,23 +157,26 @@ type Driver struct { // lifecycle, screenshot) with an in-simulator runner that serves // collapse-free accessibility snapshots and native unicode typing. // runnerClient is nil on the legacy-only path. - runnerClient transport.Companion - runnerChild *exec.Cmd - runnerAddress string - spawnRunner func(ctx context.Context, address string) (*exec.Cmd, error) - dialRunner func(address string) (transport.Companion, error) + runnerClient transport.Companion + runnerChild *exec.Cmd + runnerAddress string + spawnRunner func(ctx context.Context, address string) (*exec.Cmd, error) + dialRunner func(address string) (transport.Companion, error) + hybrid bool + + // pickRunnerAddress hands every bring-up a free loopback port, on the + // simulator and the device alike. One field, so no path can be wired + // without it. pickRunnerAddress func() (string, error) - hybrid bool // Device-mode fields. On the physical-device path d.companion is the runner // dialed over a usbmux tunnel, hybrid is false, and runnerClient is nil. // coreDeviceID feeds devicectl; tunnel is the in-process usbmux forwarder // bridging the host loopback port to the runner's device-side port. - deviceMode bool - coreDeviceID string - tunnel io.Closer - startTunnel func(ctx context.Context, hardwareUDID, localAddress, devicePort string) (io.Closer, error) - pickDeviceAddress func() (string, error) + deviceMode bool + coreDeviceID string + tunnel io.Closer + startTunnel func(ctx context.Context, hardwareUDID, localAddress, devicePort string) (io.Closer, error) // processContext owns the companion child's lifetime: it is derived from // New's context (so a canceled run still reaps the child) and canceled by