@expo/build-tools 22.3.0 → 22.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ios/xcode.d.ts +3 -0
- package/dist/ios/xcode.js +22 -0
- package/dist/steps/functions/downloadBuild.js +25 -1
- package/dist/steps/functions/installMaestro.js +92 -11
- package/dist/steps/functions/launchApplication.d.ts +3 -1
- package/dist/steps/functions/launchApplication.js +59 -5
- package/dist/steps/utils/ios/xcactivitylog.js +2 -8
- package/dist/utils/IosSimulatorUtils.d.ts +8 -0
- package/dist/utils/IosSimulatorUtils.js +9 -0
- package/dist/utils/download.d.ts +4 -0
- package/dist/utils/download.js +10 -0
- package/package.json +3 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getXcodeVersionAsync = getXcodeVersionAsync;
|
|
7
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
8
|
+
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
9
|
+
async function getXcodeVersionAsync({ env }) {
|
|
10
|
+
let stdout;
|
|
11
|
+
try {
|
|
12
|
+
({ stdout } = await (0, turtle_spawn_1.default)('xcodebuild', ['-version'], { stdio: 'pipe', env }));
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
throw new eas_build_job_1.SystemError('Failed to get Xcode version', { cause: error });
|
|
16
|
+
}
|
|
17
|
+
const version = /^Xcode\s+(\d+(?:\.\d+)*)$/m.exec(stdout)?.[1];
|
|
18
|
+
if (!version) {
|
|
19
|
+
throw new eas_build_job_1.SystemError(`Failed to determine Xcode version from: ${stdout.trim()}`);
|
|
20
|
+
}
|
|
21
|
+
return version;
|
|
22
|
+
}
|
|
@@ -19,6 +19,8 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
19
19
|
const stream_1 = __importDefault(require("stream"));
|
|
20
20
|
const util_1 = require("util");
|
|
21
21
|
const zod_1 = require("zod");
|
|
22
|
+
const bplist_parser_1 = __importDefault(require("bplist-parser"));
|
|
23
|
+
const plist_1 = __importDefault(require("plist"));
|
|
22
24
|
const artifacts_1 = require("../../utils/artifacts");
|
|
23
25
|
const files_1 = require("../../utils/files");
|
|
24
26
|
const retryOnDNSFailure_1 = require("../../utils/retryOnDNSFailure");
|
|
@@ -163,12 +165,34 @@ async function downloadBuildAsync(params) {
|
|
|
163
165
|
onlyFiles: false,
|
|
164
166
|
onlyDirectories: false,
|
|
165
167
|
});
|
|
168
|
+
let matchingFilesRoot = extractionDirectory;
|
|
169
|
+
if (matchingFiles.length === 0 &&
|
|
170
|
+
extensions.includes('app') &&
|
|
171
|
+
(await isIosAppBundleAsync(extractionDirectory))) {
|
|
172
|
+
const appBundlePath = `${extractionDirectory}.app`;
|
|
173
|
+
await node_fs_1.default.promises.rename(extractionDirectory, appBundlePath);
|
|
174
|
+
matchingFiles.push(appBundlePath);
|
|
175
|
+
matchingFilesRoot = node_path_1.default.dirname(appBundlePath);
|
|
176
|
+
}
|
|
166
177
|
if (matchingFiles.length === 0) {
|
|
167
178
|
throw new eas_build_job_1.UserError('EAS_DOWNLOAD_BUILD_NO_MATCHING_FILES', `No ${extensions.map(ext => `.${ext}`).join(', ')} entries found in the archive.`);
|
|
168
179
|
}
|
|
169
|
-
logger.info(`Found ${matchingFiles.length} matching ${(0, strings_1.pluralize)(matchingFiles.length, 'entry')}:\n${matchingFiles.map(f => `- ${node_path_1.default.relative(
|
|
180
|
+
logger.info(`Found ${matchingFiles.length} matching ${(0, strings_1.pluralize)(matchingFiles.length, 'entry')}:\n${matchingFiles.map(f => `- ${node_path_1.default.relative(matchingFilesRoot, f)}`).join('\n')}`);
|
|
170
181
|
return { artifactPath: matchingFiles[0] };
|
|
171
182
|
}
|
|
183
|
+
async function isIosAppBundleAsync(directory) {
|
|
184
|
+
try {
|
|
185
|
+
const infoPlist = await node_fs_1.default.promises.readFile(node_path_1.default.join(directory, 'Info.plist'));
|
|
186
|
+
const isBinaryPlist = infoPlist.subarray(0, 8).toString('ascii') === 'bplist00';
|
|
187
|
+
const parsedInfoPlist = (isBinaryPlist
|
|
188
|
+
? bplist_parser_1.default.parseBuffer(infoPlist)[0]
|
|
189
|
+
: plist_1.default.parse(infoPlist.toString('utf8')));
|
|
190
|
+
return parsedInfoPlist?.CFBundlePackageType === 'APPL';
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
172
196
|
function parseHttpApplicationArchiveUrl(value) {
|
|
173
197
|
try {
|
|
174
198
|
const applicationArchiveUrl = zod_1.z.string().parse(value);
|
|
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createInstallMaestroBuildFunction = createInstallMaestroBuildFunction;
|
|
7
7
|
exports.installIdbFromBrew = installIdbFromBrew;
|
|
8
|
+
const downloader_1 = __importDefault(require("@expo/downloader"));
|
|
8
9
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
9
10
|
const results_1 = require("@expo/results");
|
|
10
11
|
const steps_1 = require("@expo/steps");
|
|
@@ -16,6 +17,10 @@ const path_1 = __importDefault(require("path"));
|
|
|
16
17
|
const semver_1 = __importDefault(require("semver"));
|
|
17
18
|
const maestroBackend_1 = require("./maestroBackend");
|
|
18
19
|
const datadog_1 = require("../../datadog");
|
|
20
|
+
const xcode_1 = require("../../ios/xcode");
|
|
21
|
+
const IosSimulatorUtils_1 = require("../../utils/IosSimulatorUtils");
|
|
22
|
+
const download_1 = require("../../utils/download");
|
|
23
|
+
const MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
19
24
|
function createInstallMaestroBuildFunction() {
|
|
20
25
|
return new steps_1.BuildFunction({
|
|
21
26
|
namespace: 'eas',
|
|
@@ -118,10 +123,12 @@ function createInstallMaestroBuildFunction() {
|
|
|
118
123
|
requestedVersion === 'latest' ||
|
|
119
124
|
(requestedVersion === undefined &&
|
|
120
125
|
(!currentMaestroRunnerVersion || semver_1.default.gt(currentMaestroRunnerVersion, '1.1.15'))))) {
|
|
121
|
-
|
|
126
|
+
// `getXcodeVersionAsync` returns the raw version (e.g. "16.4"), which
|
|
127
|
+
// `semver.coerce` normalizes (e.g. "16.4.0") for comparison and display.
|
|
128
|
+
const xcodeVersion = semver_1.default.coerce(await (0, xcode_1.getXcodeVersionAsync)({ env }));
|
|
122
129
|
// maestro-runner 1.1.16 added `arch` to its xcodebuild destination. Xcode versions
|
|
123
130
|
// below 26 reject that option, so use the last compatible maestro-runner version.
|
|
124
|
-
if (semver_1.default.lt(xcodeVersion, '26.0.0')) {
|
|
131
|
+
if (xcodeVersion && semver_1.default.lt(xcodeVersion, '26.0.0')) {
|
|
125
132
|
if (requestedMaestroRunnerVersion) {
|
|
126
133
|
throw new eas_build_job_1.UserError('ERR_MAESTRO_INVALID_INPUT', `maestro-runner ${requestedVersion} is not compatible with Xcode ${xcodeVersion}. Use maestro-runner 1.1.15 or an Xcode 26+ image.`);
|
|
127
134
|
}
|
|
@@ -147,6 +154,12 @@ function createInstallMaestroBuildFunction() {
|
|
|
147
154
|
logger.error(maestroVersionResult.reason, 'Failed to get Maestro version.');
|
|
148
155
|
throw new Error(`Failed to ensure ${backend} is installed.`);
|
|
149
156
|
}
|
|
157
|
+
if (backend === 'maestro-runner' && global.runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
158
|
+
await installMaestroRunnerWdaCache({
|
|
159
|
+
logger,
|
|
160
|
+
env,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
150
163
|
logger.info(`${backend} ${maestroVersionResult.value} is ready.`);
|
|
151
164
|
outputs.maestro_version.set(maestroVersionResult.value);
|
|
152
165
|
datadog_1.Datadog.distribution('eas.maestro.install', 1, {
|
|
@@ -156,19 +169,87 @@ function createInstallMaestroBuildFunction() {
|
|
|
156
169
|
},
|
|
157
170
|
});
|
|
158
171
|
}
|
|
159
|
-
async function
|
|
160
|
-
|
|
172
|
+
async function installMaestroRunnerWdaCache({ logger, env, }) {
|
|
173
|
+
if (!env.HOME) {
|
|
174
|
+
logger.warn('Skipping the prebuilt WebDriverAgent cache because the $HOME environment variable is empty.');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const maestroRunnerHome = path_1.default.join(env.HOME, '.maestro-runner');
|
|
161
178
|
try {
|
|
162
|
-
|
|
179
|
+
const wdaVersion = await getMaestroRunnerWdaVersion({ maestroRunnerHome });
|
|
180
|
+
if (!wdaVersion) {
|
|
181
|
+
logger.info('Skipping the prebuilt WebDriverAgent cache because the installed WDA version is unknown.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const xcodeVersion = await (0, xcode_1.getXcodeVersionAsync)({ env });
|
|
185
|
+
const iosRuntimes = await IosSimulatorUtils_1.IosSimulatorUtils.getAvailableRuntimesAsync({ env });
|
|
186
|
+
const iosRuntimeIdentifierPrefix = 'com.apple.CoreSimulator.SimRuntime.iOS-';
|
|
187
|
+
// maestro-runner derives its WDA cache key from the runtime identifier, not from the runtime
|
|
188
|
+
// version. These values can differ for patched runtimes, for example the iOS-26-3 identifier
|
|
189
|
+
// can report version 26.3.1.
|
|
190
|
+
const iosRuntimeVersions = [
|
|
191
|
+
...new Set(iosRuntimes.map(runtime => runtime.identifier.slice(iosRuntimeIdentifierPrefix.length).replaceAll('-', '.'))),
|
|
192
|
+
];
|
|
193
|
+
if (iosRuntimeVersions.length === 0) {
|
|
194
|
+
logger.info('Skipping the prebuilt WebDriverAgent cache because no iOS runtime is available.');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const tempDirectory = await fs_1.default.promises.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'install_maestro_runner_wda_cache'));
|
|
198
|
+
try {
|
|
199
|
+
const archivePath = path_1.default.join(tempDirectory, 'wda-cache.tar.gz');
|
|
200
|
+
const directArchiveUrl = `https://storage.googleapis.com/turtle-v2/maestro-runner-wda-cache/` +
|
|
201
|
+
`xcode-${encodeURIComponent(xcodeVersion)}-wda-${encodeURIComponent(wdaVersion)}.tar.gz`;
|
|
202
|
+
const proxiedArchiveUrl = (0, download_1.getProxiedDownloadUrl)({
|
|
203
|
+
directUrl: directArchiveUrl,
|
|
204
|
+
proxyBaseUrl: env.EAS_BUILD_COCOAPODS_CACHE_URL,
|
|
205
|
+
});
|
|
206
|
+
logger.info(`Downloading the prebuilt WebDriverAgent cache for Xcode ${xcodeVersion}`);
|
|
207
|
+
if (proxiedArchiveUrl) {
|
|
208
|
+
try {
|
|
209
|
+
await (0, downloader_1.default)(proxiedArchiveUrl, archivePath, {
|
|
210
|
+
retry: 3,
|
|
211
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
logger.debug({ err }, 'Failed to download the prebuilt WebDriverAgent cache via the proxy; falling back to the direct URL.');
|
|
216
|
+
await (0, downloader_1.default)(directArchiveUrl, archivePath, {
|
|
217
|
+
retry: 3,
|
|
218
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
await (0, downloader_1.default)(directArchiveUrl, archivePath, {
|
|
224
|
+
retry: 3,
|
|
225
|
+
timeout: MAESTRO_RUNNER_WDA_CACHE_DOWNLOAD_TIMEOUT_MS,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
await fs_1.default.promises.mkdir(maestroRunnerHome, { recursive: true });
|
|
229
|
+
await (0, turtle_spawn_1.default)('tar', ['-xzf', archivePath, '-C', maestroRunnerHome], { logger, env });
|
|
230
|
+
const genericProductsDirectory = path_1.default.join(maestroRunnerHome, 'cache', 'wda-builds', 'generic', 'DerivedData', 'Build', 'Products');
|
|
231
|
+
for (const runtimeVersion of iosRuntimeVersions) {
|
|
232
|
+
const productsDirectory = path_1.default.join(maestroRunnerHome, 'cache', 'wda-builds', `sim-ios${runtimeVersion}-iphone`, 'DerivedData', 'Build', 'Products');
|
|
233
|
+
await fs_1.default.promises.cp(genericProductsDirectory, productsDirectory, { recursive: true });
|
|
234
|
+
}
|
|
235
|
+
logger.info(`Installed the prebuilt WebDriverAgent cache for iOS ${iosRuntimeVersions.join(', ')}.`);
|
|
236
|
+
}
|
|
237
|
+
finally {
|
|
238
|
+
await fs_1.default.promises.rm(tempDirectory, { force: true, recursive: true });
|
|
239
|
+
}
|
|
163
240
|
}
|
|
164
|
-
catch (
|
|
165
|
-
|
|
241
|
+
catch (err) {
|
|
242
|
+
logger.warn({ err }, 'Failed to install the prebuilt WebDriverAgent cache. maestro-runner will build WebDriverAgent when it is needed.');
|
|
166
243
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
244
|
+
}
|
|
245
|
+
async function getMaestroRunnerWdaVersion({ maestroRunnerHome, }) {
|
|
246
|
+
try {
|
|
247
|
+
const packageJson = JSON.parse(await fs_1.default.promises.readFile(path_1.default.join(maestroRunnerHome, 'drivers', 'ios', 'WebDriverAgent', 'package.json'), 'utf8'));
|
|
248
|
+
return typeof packageJson.version === 'string' ? packageJson.version : null;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return null;
|
|
170
252
|
}
|
|
171
|
-
return xcodeVersion;
|
|
172
253
|
}
|
|
173
254
|
async function getMaestroVersion({ env, backend, }) {
|
|
174
255
|
switch (backend) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { bunyan } from '@expo/logger';
|
|
2
2
|
import { BuildFunction, BuildRuntimePlatform, BuildStepEnv } from '@expo/steps';
|
|
3
3
|
export declare function createLaunchApplicationFunction(): BuildFunction;
|
|
4
|
-
export declare function launchApplicationAsync({ applicationIdentifier, activityName, runtimePlatform, env, logger, }: {
|
|
4
|
+
export declare function launchApplicationAsync({ applicationIdentifier, activityName, launchArgs, openUrl, runtimePlatform, env, logger, }: {
|
|
5
5
|
applicationIdentifier: string;
|
|
6
6
|
activityName?: string;
|
|
7
|
+
launchArgs?: string[];
|
|
8
|
+
openUrl?: string;
|
|
7
9
|
runtimePlatform: BuildRuntimePlatform;
|
|
8
10
|
env: BuildStepEnv;
|
|
9
11
|
logger: bunyan;
|
|
@@ -25,15 +25,29 @@ function createLaunchApplicationFunction() {
|
|
|
25
25
|
required: false,
|
|
26
26
|
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
27
27
|
}),
|
|
28
|
+
steps_1.BuildStepInput.createProvider({
|
|
29
|
+
id: 'launch_args',
|
|
30
|
+
required: false,
|
|
31
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.JSON,
|
|
32
|
+
}),
|
|
33
|
+
steps_1.BuildStepInput.createProvider({
|
|
34
|
+
id: 'open_url',
|
|
35
|
+
required: false,
|
|
36
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
37
|
+
}),
|
|
28
38
|
],
|
|
29
39
|
fn: async ({ global, logger }, { inputs, env }) => {
|
|
30
40
|
const applicationIdentifier = parseNonEmptyStringInput(inputs.application_identifier.value, 'application_identifier');
|
|
31
41
|
const activityName = inputs.activity_name.value === undefined
|
|
32
42
|
? undefined
|
|
33
43
|
: parseNonEmptyStringInput(inputs.activity_name.value, 'activity_name');
|
|
44
|
+
const launchArgs = parseLaunchArgsInput(inputs.launch_args.value);
|
|
45
|
+
const openUrl = inputs.open_url.value === undefined ? undefined : parseOpenUrlInput(inputs.open_url.value);
|
|
34
46
|
await launchApplicationAsync({
|
|
35
47
|
applicationIdentifier,
|
|
36
48
|
activityName,
|
|
49
|
+
launchArgs,
|
|
50
|
+
openUrl,
|
|
37
51
|
runtimePlatform: global.runtimePlatform,
|
|
38
52
|
env,
|
|
39
53
|
logger,
|
|
@@ -41,23 +55,47 @@ function createLaunchApplicationFunction() {
|
|
|
41
55
|
},
|
|
42
56
|
});
|
|
43
57
|
}
|
|
44
|
-
async function launchApplicationAsync({ applicationIdentifier, activityName, runtimePlatform, env, logger, }) {
|
|
58
|
+
async function launchApplicationAsync({ applicationIdentifier, activityName, launchArgs = [], openUrl, runtimePlatform, env, logger, }) {
|
|
45
59
|
if (runtimePlatform === steps_1.BuildRuntimePlatform.DARWIN) {
|
|
46
|
-
logger
|
|
47
|
-
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'launch', 'booted', applicationIdentifier], {
|
|
60
|
+
logApplicationLaunch(logger, applicationIdentifier, launchArgs);
|
|
61
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'launch', 'booted', applicationIdentifier, ...launchArgs], {
|
|
48
62
|
env,
|
|
49
63
|
logger,
|
|
50
64
|
});
|
|
65
|
+
if (openUrl) {
|
|
66
|
+
logger.info(`Opening ${openUrl} in ${applicationIdentifier}.`);
|
|
67
|
+
await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'openurl', 'booted', openUrl], { env, logger });
|
|
68
|
+
}
|
|
51
69
|
return;
|
|
52
70
|
}
|
|
53
71
|
if (!activityName) {
|
|
54
72
|
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_MISSING_ACTIVITY', 'Launching an Android application requires activity_name.');
|
|
55
73
|
}
|
|
56
|
-
logger
|
|
57
|
-
|
|
74
|
+
logApplicationLaunch(logger, applicationIdentifier, launchArgs);
|
|
75
|
+
// Android does not support process arguments like iOS. Pass raw `am start` Intent
|
|
76
|
+
// arguments instead, such as `--es key value` or `--ez key true`.
|
|
77
|
+
await (0, turtle_spawn_1.default)('adb', ['shell', 'am', 'start', ...launchArgs, '-n', `${applicationIdentifier}/${activityName}`], {
|
|
58
78
|
env,
|
|
59
79
|
logger,
|
|
60
80
|
});
|
|
81
|
+
if (openUrl) {
|
|
82
|
+
logger.info(`Opening ${openUrl} in ${applicationIdentifier}.`);
|
|
83
|
+
await (0, turtle_spawn_1.default)('adb', [
|
|
84
|
+
'shell',
|
|
85
|
+
'am',
|
|
86
|
+
'start',
|
|
87
|
+
'-a',
|
|
88
|
+
'android.intent.action.VIEW',
|
|
89
|
+
'-d',
|
|
90
|
+
openUrl,
|
|
91
|
+
'-n',
|
|
92
|
+
`${applicationIdentifier}/${activityName}`,
|
|
93
|
+
], { env, logger });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function logApplicationLaunch(logger, applicationIdentifier, launchArgs) {
|
|
97
|
+
const argumentsDescription = launchArgs.length > 0 ? ` with arguments ${JSON.stringify(launchArgs)}` : '';
|
|
98
|
+
logger.info(`Launching ${applicationIdentifier}${argumentsDescription}.`);
|
|
61
99
|
}
|
|
62
100
|
function parseNonEmptyStringInput(value, inputName) {
|
|
63
101
|
if (typeof value !== 'string' || value.length === 0) {
|
|
@@ -65,3 +103,19 @@ function parseNonEmptyStringInput(value, inputName) {
|
|
|
65
103
|
}
|
|
66
104
|
return value;
|
|
67
105
|
}
|
|
106
|
+
function parseLaunchArgsInput(value) {
|
|
107
|
+
if (value === undefined) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
if (!Array.isArray(value) || !value.every(argument => typeof argument === 'string')) {
|
|
111
|
+
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_INVALID_INPUT', 'Input "launch_args" must be an array of strings.');
|
|
112
|
+
}
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
function parseOpenUrlInput(value) {
|
|
116
|
+
const openUrl = parseNonEmptyStringInput(value, 'open_url');
|
|
117
|
+
if (!URL.canParse(openUrl)) {
|
|
118
|
+
throw new eas_build_job_1.UserError('EAS_LAUNCH_APPLICATION_INVALID_INPUT', 'Input "open_url" must be a valid URL.');
|
|
119
|
+
}
|
|
120
|
+
return openUrl;
|
|
121
|
+
}
|
|
@@ -16,6 +16,7 @@ const os_1 = __importDefault(require("os"));
|
|
|
16
16
|
const path_1 = __importDefault(require("path"));
|
|
17
17
|
const zod_1 = require("zod");
|
|
18
18
|
const sentry_1 = require("../../../sentry");
|
|
19
|
+
const download_1 = require("../../../utils/download");
|
|
19
20
|
const DEFAULT_XCLOGPARSER_VERSION = 'v0.2.47';
|
|
20
21
|
const XCLOGPARSER_DOWNLOAD_URL = 'https://storage.googleapis.com/turtle-v2/xclogparser';
|
|
21
22
|
const XCLOGPARSER_DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
@@ -123,7 +124,7 @@ async function downloadXclogparser({ tempDir, version, logger, proxyBaseUrl, env
|
|
|
123
124
|
const zipName = getXclogparserZipName(version);
|
|
124
125
|
const zipPath = path_1.default.join(tempDir, zipName);
|
|
125
126
|
const directUrl = `${XCLOGPARSER_DOWNLOAD_URL}/${zipName}`;
|
|
126
|
-
const proxiedUrl = getProxiedDownloadUrl({ directUrl, proxyBaseUrl });
|
|
127
|
+
const proxiedUrl = (0, download_1.getProxiedDownloadUrl)({ directUrl, proxyBaseUrl });
|
|
127
128
|
if (proxiedUrl) {
|
|
128
129
|
const proxiedDownloadResult = await (0, results_1.asyncResult)(downloadAndUnpackXclogparser({ tempDir, zipPath, sourceUrl: proxiedUrl, env }));
|
|
129
130
|
if (!proxiedDownloadResult.ok) {
|
|
@@ -188,13 +189,6 @@ const COMPILE_SIGNATURE_PREFIXES = ['SwiftCompile ', 'SwiftGeneratePch '];
|
|
|
188
189
|
function getXclogparserZipName(version) {
|
|
189
190
|
return `XCLogParser-macOS-x86-64-arm64-${version}.zip`;
|
|
190
191
|
}
|
|
191
|
-
function getProxiedDownloadUrl({ directUrl, proxyBaseUrl, }) {
|
|
192
|
-
if (!proxyBaseUrl) {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
const parsedUrl = new URL(directUrl);
|
|
196
|
-
return directUrl.replace(`${parsedUrl.protocol}//${parsedUrl.host}`, `${proxyBaseUrl}/${parsedUrl.host}`);
|
|
197
|
-
}
|
|
198
192
|
function isCompileStep(step) {
|
|
199
193
|
const detailStepType = step.detailStepType ?? '';
|
|
200
194
|
const signature = step.signature ?? '';
|
|
@@ -27,6 +27,14 @@ export declare namespace IosSimulatorUtils {
|
|
|
27
27
|
runtimeDisplayName: string;
|
|
28
28
|
displayName: string;
|
|
29
29
|
};
|
|
30
|
+
export type IosSimulatorRuntime = {
|
|
31
|
+
identifier: string;
|
|
32
|
+
isAvailable?: boolean;
|
|
33
|
+
version?: string;
|
|
34
|
+
};
|
|
35
|
+
export function getAvailableRuntimesAsync({ env, }: {
|
|
36
|
+
env: NodeJS.ProcessEnv;
|
|
37
|
+
}): Promise<IosSimulatorRuntime[]>;
|
|
30
38
|
export function getAvailableDevicesAsync({ env, filter, }: {
|
|
31
39
|
env: NodeJS.ProcessEnv;
|
|
32
40
|
filter: 'available' | 'booted';
|
|
@@ -13,6 +13,15 @@ const promises_1 = require("node:timers/promises");
|
|
|
13
13
|
const retry_1 = require("./retry");
|
|
14
14
|
var IosSimulatorUtils;
|
|
15
15
|
(function (IosSimulatorUtils) {
|
|
16
|
+
async function getAvailableRuntimesAsync({ env, }) {
|
|
17
|
+
const { stdout } = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'runtimes', '--json'], { env });
|
|
18
|
+
const { runtimes } = JSON.parse(stdout);
|
|
19
|
+
return runtimes.flatMap(runtime => runtime.isAvailable !== false &&
|
|
20
|
+
runtime.identifier?.startsWith('com.apple.CoreSimulator.SimRuntime.iOS-')
|
|
21
|
+
? [{ ...runtime, identifier: runtime.identifier }]
|
|
22
|
+
: []);
|
|
23
|
+
}
|
|
24
|
+
IosSimulatorUtils.getAvailableRuntimesAsync = getAvailableRuntimesAsync;
|
|
16
25
|
async function getAvailableDevicesAsync({ env, filter, }) {
|
|
17
26
|
const result = await (0, turtle_spawn_1.default)('xcrun', ['simctl', 'list', 'devices', '--json', '--no-escape-slashes', filter], { env });
|
|
18
27
|
const xcrunData = JSON.parse(result.stdout);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getProxiedDownloadUrl = getProxiedDownloadUrl;
|
|
4
|
+
function getProxiedDownloadUrl({ directUrl, proxyBaseUrl, }) {
|
|
5
|
+
if (!proxyBaseUrl) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
const parsedUrl = new URL(directUrl);
|
|
9
|
+
return directUrl.replace(`${parsedUrl.protocol}//${parsedUrl.host}`, `${proxyBaseUrl.replace(/\/$/, '')}/${parsedUrl.host}`);
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expo/build-tools",
|
|
3
|
-
"version": "22.
|
|
3
|
+
"version": "22.4.0",
|
|
4
4
|
"bugs": "https://github.com/expo/eas-cli/issues",
|
|
5
5
|
"license": "BUSL-1.1",
|
|
6
6
|
"author": "Expo <support@expo.io>",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@expo/plist": "^0.3.5",
|
|
47
47
|
"@expo/results": "^1.0.0",
|
|
48
48
|
"@expo/spawn-async": "1.7.2",
|
|
49
|
-
"@expo/steps": "22.
|
|
49
|
+
"@expo/steps": "22.4.0",
|
|
50
50
|
"@expo/template-file": "22.0.0",
|
|
51
51
|
"@expo/turtle-spawn": "22.0.0",
|
|
52
52
|
"@expo/xcpretty": "^4.3.1",
|
|
@@ -102,5 +102,5 @@
|
|
|
102
102
|
"typescript": "^5.5.4",
|
|
103
103
|
"uuid": "^9.0.1"
|
|
104
104
|
},
|
|
105
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "39c39ad4bfdd1e7e74417bb6f7178b011ce61bbe"
|
|
106
106
|
}
|