diff --git a/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx b/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx index 0d29e4c88..07fd68bca 100644 --- a/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx +++ b/desktop/flipper-server-core/src/devices/ios/__tests__/iOSDevice.node.tsx @@ -7,7 +7,7 @@ * @format */ -import {parseXcodeFromCoreSimPath} from '../iOSDeviceManager'; +import {checkXcodeVersionMismatch} from '../iOSDeviceManager'; import {getLogger} from 'flipper-common'; import {IOSBridge} from '../IOSBridge'; import {FlipperServerImpl} from '../../../FlipperServerImpl'; @@ -36,46 +36,28 @@ afterEach(() => { setFlipperServerConfig(undefined); }); -const standardCoresimulatorLog = - 'username 1264 0.0 0.1 5989740 41648 ?? Ss 2:23PM 0:12.92 /Applications/Xcode_12.4.0_fb.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd'; - -const nonStandardCoresimulatorLog = - 'username 1264 0.0 0.1 5989740 41648 ?? Ss 2:23PM 0:12.92 /Some/Random/Path/Xcode_12.4.0_fb.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd'; - -const nonStandardSpecialCharacterAphanumericCoresimulatorLog = - 'username 1264 0.0 0.1 5989740 41648 ?? Ss 2:23PM 0:12.92 /Some_R@d0m/Path-3455355/path(2)+connection/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/libexec/mobileassetd'; - -test('test parseXcodeFromCoreSimPath from non standard locations', () => { - const match = parseXcodeFromCoreSimPath(nonStandardCoresimulatorLog); - expect(match && match.length > 0).toBeTruthy(); - expect( - // @ts-ignore the null and non zero lenght check for match is already done above - match[0], - ).toEqual('/Some/Random/Path/Xcode_12.4.0_fb.app/Contents/Developer'); +test('test checkXcodeVersionMismatch with correct Simulator.app', () => { + const invalidVersion = checkXcodeVersionMismatch( + [ + '/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator', + ], + '/Applications/Xcode.app/Contents/Developer', + ); + expect(invalidVersion).toEqual(undefined); }); -test('test parseXcodeFromCoreSimPath from non standard alphanumeric special character locations', () => { - const match = parseXcodeFromCoreSimPath( - nonStandardSpecialCharacterAphanumericCoresimulatorLog, +test('test checkXcodeVersionMismatch with an incorrect Simulator.app', () => { + const invalidVersion = checkXcodeVersionMismatch( + [ + '/Applications/Xcode_Incorrect.app/Contents/Developer/Applications/Simulator.app/Contents/MacOS/Simulator', + ], + '/Applications/Xcode.app/Contents/Developer', ); - expect(match && match.length > 0).toBeTruthy(); - expect( - // @ts-ignore the null and non zero lenght check for match is already done above - match[0], - ).toEqual( - '/Some_R@d0m/Path-3455355/path(2)+connection/Xcode.app/Contents/Developer', + expect(invalidVersion).toEqual( + '/Applications/Xcode_Incorrect.app/Contents/Developer', ); }); -test('test parseXcodeFromCoreSimPath from standard locations', () => { - const match = parseXcodeFromCoreSimPath(standardCoresimulatorLog); - expect(match && match.length > 0).toBeTruthy(); - expect( - // @ts-ignore the null and non zero lenght check for match is already done above - match[0], - ).toEqual('/Applications/Xcode_12.4.0_fb.app/Contents/Developer'); -}); - test('test getAllPromisesForQueryingDevices when xcode detected', () => { const flipperServer = new FlipperServerImpl( getFlipperServerConfig(), diff --git a/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx b/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx index 354bd60b1..c918feda5 100644 --- a/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx +++ b/desktop/flipper-server-core/src/devices/ios/iOSDeviceManager.tsx @@ -231,21 +231,27 @@ export class IOSDeviceManager { try { let {stdout: xcodeCLIVersion} = await exec('xcode-select -p'); xcodeCLIVersion = xcodeCLIVersion!.toString().trim(); - const {stdout} = await exec('ps aux | grep CoreSimulator'); - for (const line of stdout!.toString().split('\n')) { - const match = parseXcodeFromCoreSimPath(line); - const runningVersion = - match && match.length > 0 ? match[0].trim() : null; - if (runningVersion && runningVersion !== xcodeCLIVersion) { - const errorMessage = `Xcode version mismatch: Simulator is running from "${runningVersion}" while Xcode CLI is "${xcodeCLIVersion}". Running "xcode-select --switch ${runningVersion}" can fix this. For example: "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"`; - this.flipperServer.emit('notification', { - type: 'error', - title: 'Xcode version mismatch', - description: '' + errorMessage, - }); - this.xcodeVersionMismatchFound = true; - break; + const {stdout} = await exec( + "pgrep Simulator | xargs ps | grep Simulator.app | awk '{print $NF}'", + ); + for (const runningSimulatorApp of stdout!.toString().split('\n')) { + if (!runningSimulatorApp) { + continue; } + if (runningSimulatorApp.startsWith(xcodeCLIVersion)) { + continue; + } + const runningVersion = + runningSimulatorApp.split('/Contents/Developer')[0] + + '/Contents/Developer'; + const errorMessage = `Xcode version mismatch: Simulator is running from "${runningVersion}" while Xcode CLI is "${xcodeCLIVersion}". Running "xcode-select --switch ${runningVersion}" can fix this. For example: "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer"`; + this.flipperServer.emit('notification', { + type: 'error', + title: 'Xcode version mismatch', + description: '' + errorMessage, + }); + this.xcodeVersionMismatchFound = true; + break; } } catch (e) { console.error('Failed to determine Xcode version:', e); @@ -253,15 +259,28 @@ export class IOSDeviceManager { } } +export function checkXcodeVersionMismatch( + runningSimulatorApps: Array, + xcodeCLIVersion: string, +): string | undefined { + for (const runningSimulatorApp of runningSimulatorApps) { + if (!runningSimulatorApp) { + continue; + } + if (runningSimulatorApp.startsWith(xcodeCLIVersion)) { + continue; + } + return ( + runningSimulatorApp.split('/Contents/Developer')[0] + + '/Contents/Developer' + ); + } + return undefined; +} + function getActiveDevices( idbPath: string, isPhysicalDeviceEnabled: boolean, ): Promise> { return new IDBBridge(idbPath, isPhysicalDeviceEnabled).getActiveDevices(true); } - -export function parseXcodeFromCoreSimPath( - line: string, -): RegExpMatchArray | null { - return line.match(/\/[\/\w@)(\-\+]*\/Xcode[^/]*\.app\/Contents\/Developer/); -}