Skip to content

Commit f118d44

Browse files
authored
feat: add run:ios command (#41)
* feat: add run:ios command * refactor output for more feedback with spinners * adjust error handling * slightly better handling of ios-deploy * remove --list-devices flag * move error to normalizer * drastically simplify createRun data flow * cleanup * add warnings and handle devices case * use spawn * create runOnMac helper * move single-use utils closer to callsites * handle prompt cancellation * move code under src/lib to match repo convention * add success message * add missing dot * remove copyright * support preferred device; ts was right * extract selectDevice * move warnings to helper * cache per platform, remove unused legacyPath * fix test * remove fallback sim logic; prompt for devices when none open or cached * allow for --simulator without specified name * remove unixifyPaths * remove preferred device logic * perf: use devicectl instead of xcdevice; refactor Device * base catalyst support with --catalyst flag * get rid of chdir * feat: recent devices sort * filter devices by platform
1 parent dcb5656 commit f118d44

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1764
-284
lines changed

packages/plugin-platform-android/src/lib/commands/runAndroid/__tests__/tryLaunchAppOnDevice.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const args: Flags = {
3636
port: '8081',
3737
appId: '',
3838
appIdSuffix: '',
39+
mode: 'debug',
3940
};
4041

4142
const androidProject: AndroidProjectConfig = {

packages/plugin-platform-apple/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@react-native-community/cli-config-apple": "^15.1.2",
2121
"fast-glob": "^3.3.2",
2222
"fast-xml-parser": "^4.5.0",
23+
"is-interactive": "^2.0.0",
2324
"nano-spawn": "^0.2.0",
2425
"picocolors": "^1.1.1",
2526
"tslib": "^2.3.0"

packages/plugin-platform-apple/src/commands/build/index.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

packages/plugin-platform-apple/src/lib/__tests__/dummy.test.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

packages/plugin-platform-apple/src/commands/build/buildOptions.ts renamed to packages/plugin-platform-apple/src/lib/commands/build/buildOptions.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export type BuildFlags = {
99
target?: string;
1010
extraParams?: string[];
1111
device?: string;
12+
catalyst?: boolean;
1213
buildFolder?: string;
1314
destination?: string;
1415
};
@@ -47,8 +48,11 @@ export const getBuildOptions = ({ platformName }: BuilderCommand) => {
4748
{
4849
name: '--device [string]',
4950
description:
50-
'Explicitly set the device to use by name or by unique device identifier. If the value is not provided,' +
51-
'the app will run on the first available physical device.',
51+
'Explicitly set the device to use by name or by unique device identifier. If the value is not provided, the app will run on the first available physical device.',
52+
},
53+
{
54+
name: '--catalyst',
55+
description: 'Run on Mac Catalyst.',
5256
},
5357
{
5458
name: '--buildFolder <string>',
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
import type { BuildFlags } from './buildOptions.js';
2-
import { supportedPlatforms } from '../../supportedPlatforms.js';
2+
import { supportedPlatforms } from '../../utils/supportedPlatforms.js';
33
import { ApplePlatform, XcodeProjectInfo } from '../../types/index.js';
44
import { logger } from '@callstack/rnef-tools';
5-
import { getConfiguration } from './getConfiguration.js';
65
import { simulatorDestinationMap } from './simulatorDestinationMap.js';
76
import { spinner } from '@clack/prompts';
8-
import spawn from 'nano-spawn';
9-
import { selectFromInteractiveMode } from '../../utils/selectFromInteractiveMode.js';
10-
import path from 'node:path';
7+
import spawn, { SubprocessError } from 'nano-spawn';
118

12-
const buildProject = async (
9+
export const buildProject = async (
1310
xcodeProject: XcodeProjectInfo,
11+
sourceDir: string,
1412
platformName: ApplePlatform,
1513
udid: string | undefined,
14+
scheme: string,
15+
mode: string,
1616
args: BuildFlags
1717
) => {
18-
normalizeArgs(args, xcodeProject);
1918
const simulatorDest = simulatorDestinationMap[platformName];
2019

2120
if (!simulatorDest) {
@@ -26,15 +25,6 @@ const buildProject = async (
2625
);
2726
}
2827

29-
const { scheme, mode } = args.interactive
30-
? await selectFromInteractiveMode(xcodeProject, args.scheme, args.mode)
31-
: await getConfiguration(
32-
xcodeProject,
33-
args.scheme,
34-
args.mode,
35-
platformName
36-
);
37-
3828
const xcodebuildArgs = [
3929
xcodeProject.isWorkspace ? '-workspace' : '-project',
4030
xcodeProject.name,
@@ -56,7 +46,9 @@ const buildProject = async (
5646
}
5747
}
5848

59-
return udid
49+
return args.catalyst
50+
? 'platform=macOS,variant=Mac Catalyst'
51+
: udid
6052
? `id=${udid}`
6153
: mode === 'Debug' || args.device
6254
? `generic/platform=${simulatorDest}`
@@ -74,33 +66,22 @@ const buildProject = async (
7466
`Builing the app with xcodebuild for ${scheme} scheme in ${mode} mode.`
7567
);
7668
logger.debug(`Running "xcodebuild ${xcodebuildArgs.join(' ')}.`);
77-
7869
try {
79-
await spawn('xcodebuild', xcodebuildArgs, {
80-
stdio: logger.isVerbose() ? 'inherit' : ['ignore', 'ignore', 'inherit'],
70+
const { output } = await spawn('xcodebuild', xcodebuildArgs, {
71+
cwd: sourceDir,
8172
});
8273
loader.stop(
8374
`Built the app with xcodebuild for ${scheme} scheme in ${mode} mode.`
8475
);
76+
return output;
8577
} catch (error) {
78+
logger.log('');
79+
logger.log((error as SubprocessError).stdout);
80+
logger.error((error as SubprocessError).stderr);
8681
loader.stop(
8782
'Running xcodebuild failed. Check the error message above for details.',
8883
1
8984
);
90-
throw error;
85+
throw new Error('Running xcodebuild failed');
9186
}
9287
};
93-
94-
function normalizeArgs(args: BuildFlags, xcodeProject: XcodeProjectInfo) {
95-
if (!args.mode) {
96-
args.mode = 'Debug';
97-
}
98-
if (!args.scheme) {
99-
args.scheme = path.basename(
100-
xcodeProject.name,
101-
path.extname(xcodeProject.name)
102-
);
103-
}
104-
}
105-
106-
export { buildProject };
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { BuildFlags } from './buildOptions.js';
2+
import { buildProject } from './buildProject.js';
3+
import {
4+
BuilderCommand,
5+
ProjectConfig,
6+
XcodeProjectInfo,
7+
} from '../../types/index.js';
8+
import { logger } from '@callstack/rnef-tools';
9+
import { outro, cancel } from '@clack/prompts';
10+
import path from 'path';
11+
import { selectFromInteractiveMode } from '../../utils/selectFromInteractiveMode.js';
12+
import { getConfiguration } from './getConfiguration.js';
13+
import isInteractive from 'is-interactive';
14+
15+
export const createBuild = async (
16+
platformName: BuilderCommand['platformName'],
17+
projectConfig: ProjectConfig,
18+
args: BuildFlags
19+
) => {
20+
// TODO: add logic for installing Cocoapods based on @expo/fingerprint & pod-install package.
21+
22+
const { xcodeProject, sourceDir } = projectConfig;
23+
24+
if (!xcodeProject) {
25+
logger.error(
26+
`Could not find Xcode project files in "${sourceDir}" folder. Please make sure that you have installed Cocoapods and "${sourceDir}" is a valid path`
27+
);
28+
process.exit(1);
29+
}
30+
31+
normalizeArgs(args, xcodeProject);
32+
33+
const { scheme, mode } = args.interactive
34+
? await selectFromInteractiveMode(
35+
xcodeProject,
36+
sourceDir,
37+
args.scheme,
38+
args.mode
39+
)
40+
: await getConfiguration(
41+
xcodeProject,
42+
sourceDir,
43+
args.scheme,
44+
args.mode,
45+
platformName
46+
);
47+
48+
try {
49+
await buildProject(
50+
xcodeProject,
51+
sourceDir,
52+
platformName,
53+
undefined,
54+
scheme,
55+
mode,
56+
args
57+
);
58+
outro('Success 🎉.');
59+
} catch {
60+
cancel('Command failed.');
61+
}
62+
};
63+
64+
function normalizeArgs(args: BuildFlags, xcodeProject: XcodeProjectInfo) {
65+
if (!args.mode) {
66+
args.mode = 'Debug';
67+
}
68+
if (!args.scheme) {
69+
args.scheme = path.basename(
70+
xcodeProject.name,
71+
path.extname(xcodeProject.name)
72+
);
73+
}
74+
if (args.interactive && !isInteractive()) {
75+
logger.warn(
76+
'Interactive mode is not supported in non-interactive environments.'
77+
);
78+
args.interactive = false;
79+
}
80+
}

packages/plugin-platform-apple/src/commands/build/getConfiguration.ts renamed to packages/plugin-platform-apple/src/lib/commands/build/getConfiguration.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@ import color from 'picocolors';
77

88
export async function getConfiguration(
99
xcodeProject: XcodeProjectInfo,
10+
sourceDir: string,
1011
inputScheme: string,
1112
inputMode: string,
1213
platformName: ApplePlatform
1314
) {
14-
const sourceDir = process.cwd();
1515
const info = await getInfo(xcodeProject, sourceDir);
16-
1716
checkIfConfigurationExists(info?.configurations ?? [], inputMode);
18-
1917
let scheme = inputScheme;
2018

2119
if (!info?.schemes?.includes(scheme)) {

packages/plugin-platform-apple/src/commands/build/simulatorDestinationMap.ts renamed to packages/plugin-platform-apple/src/lib/commands/build/simulatorDestinationMap.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ApplePlatform } from '../../types/index.js';
22

33
export const simulatorDestinationMap: Record<ApplePlatform, string> = {
44
ios: 'iOS Simulator',
5-
// macos: 'macOS',
6-
// visionos: 'visionOS Simulator',
7-
// tvos: 'tvOS Simulator',
5+
macos: 'macOS',
6+
visionos: 'visionOS Simulator',
7+
tvos: 'tvOS Simulator',
88
};

0 commit comments

Comments
 (0)