@expo/build-tools 22.0.0 → 22.2.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.
@@ -11,9 +11,11 @@ const assert_1 = __importDefault(require("assert"));
11
11
  const fast_glob_1 = __importDefault(require("fast-glob"));
12
12
  const node_crypto_1 = require("node:crypto");
13
13
  const node_fs_1 = __importDefault(require("node:fs"));
14
+ const node_net_1 = require("node:net");
14
15
  const node_os_1 = __importDefault(require("node:os"));
15
16
  const node_path_1 = __importDefault(require("node:path"));
16
17
  const promises_1 = require("node:timers/promises");
18
+ const sentry_1 = require("../sentry");
17
19
  const retry_1 = require("./retry");
18
20
  var AndroidEmulatorUtils;
19
21
  (function (AndroidEmulatorUtils) {
@@ -216,17 +218,21 @@ var AndroidEmulatorUtils;
216
218
  AndroidEmulatorUtils.cloneAsync = cloneAsync;
217
219
  async function startAsync({ deviceName, env, logcatDirectory, }) {
218
220
  let logcatOutputPath;
221
+ let emulatorOutputPath;
219
222
  try {
220
223
  await node_fs_1.default.promises.mkdir(logcatDirectory, { recursive: true });
221
224
  const safeDeviceName = deviceName.replace(/[^a-zA-Z0-9_.-]/g, '_');
222
225
  const timestamp = Math.floor(Date.now() / 1000)
223
226
  .toString(16)
224
227
  .padStart(8, '0');
225
- logcatOutputPath = node_path_1.default.join(logcatDirectory, `${safeDeviceName}-${timestamp}-${(0, node_crypto_1.randomBytes)(2).toString('hex')}.log`);
228
+ const outputName = `${safeDeviceName}-${timestamp}-${(0, node_crypto_1.randomBytes)(2).toString('hex')}`;
229
+ logcatOutputPath = node_path_1.default.join(logcatDirectory, `${outputName}-logcat.log`);
230
+ emulatorOutputPath = node_path_1.default.join(logcatDirectory, `${outputName}-emulator.log`);
226
231
  await node_fs_1.default.promises.writeFile(logcatOutputPath, '');
232
+ await node_fs_1.default.promises.writeFile(emulatorOutputPath, '');
227
233
  }
228
234
  catch (err) {
229
- throw new eas_build_job_1.SystemError(`Failed to prepare Android emulator logcat output for ${deviceName}.`, {
235
+ throw new eas_build_job_1.SystemError(`Failed to prepare Android emulator output for ${deviceName}.`, {
230
236
  cause: err,
231
237
  });
232
238
  }
@@ -249,13 +255,49 @@ var AndroidEmulatorUtils;
249
255
  : []),
250
256
  ], {
251
257
  detached: true,
252
- stdio: 'inherit',
258
+ stdio: ['ignore', 'pipe', 'pipe'],
259
+ ignoreStdio: true,
253
260
  env: {
254
261
  ...env,
255
262
  // We don't need to wait for emulator to exit gracefully.
256
263
  ANDROID_EMULATOR_WAIT_TIME_BEFORE_KILL: '1',
257
264
  },
258
265
  });
266
+ const emulatorOutputStream = node_fs_1.default.createWriteStream(emulatorOutputPath, { flags: 'a' });
267
+ let reportedEmulatorOutputError = false;
268
+ emulatorOutputStream.on('error', err => {
269
+ process.stderr.write(`Failed to write Android emulator output to ${emulatorOutputPath}: ${err}\n`);
270
+ if (!reportedEmulatorOutputError) {
271
+ reportedEmulatorOutputError = true;
272
+ sentry_1.Sentry.capture('Failed to write Android emulator process output', err, {
273
+ level: 'warning',
274
+ tags: {
275
+ errorCode: err.code ?? 'unknown',
276
+ },
277
+ extras: {
278
+ deviceName,
279
+ emulatorOutputPath,
280
+ },
281
+ });
282
+ }
283
+ });
284
+ // Only into the log file -- this process' stdout/stderr is not watched or uploaded.
285
+ emulatorPromise.child.stdout?.pipe(emulatorOutputStream, { end: false });
286
+ emulatorPromise.child.stderr?.pipe(emulatorOutputStream, { end: false });
287
+ emulatorPromise.child.once('close', () => {
288
+ emulatorOutputStream.end();
289
+ });
290
+ // Piped stdio creates socket handles in this process which, unlike inherited
291
+ // file descriptors, keep the event loop alive for as long as the emulator runs.
292
+ // We never stop the emulator explicitly, so without unref-ing these the process
293
+ // would never exit on its own -- defeating the `detached` + `unref()` below.
294
+ // Output is still captured for as long as this process lives.
295
+ if (emulatorPromise.child.stdout instanceof node_net_1.Socket) {
296
+ emulatorPromise.child.stdout.unref();
297
+ }
298
+ if (emulatorPromise.child.stderr instanceof node_net_1.Socket) {
299
+ emulatorPromise.child.stderr.unref();
300
+ }
259
301
  // If emulator fails to start, throw its error.
260
302
  if (!emulatorPromise.child.pid) {
261
303
  await emulatorPromise;
@@ -276,7 +318,7 @@ var AndroidEmulatorUtils;
276
318
  });
277
319
  // We don't want to await the SpawnPromise here.
278
320
  // eslint-disable-next-line @typescript-eslint/return-await
279
- return { emulatorPromise, serialId, logcatOutputPath };
321
+ return { emulatorPromise, serialId, logcatOutputPath, emulatorOutputPath };
280
322
  }
281
323
  AndroidEmulatorUtils.startAsync = startAsync;
282
324
  async function waitForReadyAsync({ serialId, env, timeoutMs = 3 * 60 * 1_000, logger, }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expo/build-tools",
3
- "version": "22.0.0",
3
+ "version": "22.2.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.0.0",
49
+ "@expo/steps": "22.1.0",
50
50
  "@expo/template-file": "22.0.0",
51
51
  "@expo/turtle-spawn": "22.0.0",
52
52
  "@expo/xcpretty": "^4.3.1",
@@ -100,5 +100,5 @@
100
100
  "typescript": "^5.5.4",
101
101
  "uuid": "^9.0.1"
102
102
  },
103
- "gitHead": "b92a9cc5a718f133966e27b9fedcedb569f9cd17"
103
+ "gitHead": "5484dd607468c7711d915a2521df10531f8b9908"
104
104
  }