eas-cli 2.7.1 → 2.8.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.
Files changed (52) hide show
  1. package/README.md +49 -99
  2. package/build/branch/queries.d.ts +1 -0
  3. package/build/branch/queries.js +2 -2
  4. package/build/build/build.js +2 -2
  5. package/build/build/createContext.js +1 -0
  6. package/build/build/graphql.js +6 -0
  7. package/build/build/local.js +1 -1
  8. package/build/build/queries.d.ts +4 -2
  9. package/build/build/queries.js +32 -7
  10. package/build/commands/build/run.js +24 -11
  11. package/build/commands/submit.js +1 -1
  12. package/build/commands/update/index.js +8 -6
  13. package/build/devices/utils/formatDevice.js +1 -2
  14. package/build/graphql/generated.d.ts +12 -0
  15. package/build/graphql/generated.js +9 -2
  16. package/build/graphql/mutations/SubmissionMutation.js +14 -2
  17. package/build/graphql/mutations/UploadSessionMutation.d.ts +4 -3
  18. package/build/run/android/aapt.d.ts +5 -0
  19. package/build/run/android/aapt.js +51 -0
  20. package/build/run/android/adb.d.ts +23 -0
  21. package/build/run/android/adb.js +120 -0
  22. package/build/run/android/emulator.d.ts +7 -0
  23. package/build/run/android/emulator.js +109 -0
  24. package/build/run/android/run.d.ts +1 -1
  25. package/build/run/android/run.js +10 -3
  26. package/build/run/android/sdk.d.ts +3 -0
  27. package/build/run/android/sdk.js +29 -0
  28. package/build/run/android/systemRequirements.d.ts +1 -0
  29. package/build/run/android/systemRequirements.js +24 -0
  30. package/build/submit/ArchiveSource.d.ts +20 -10
  31. package/build/submit/ArchiveSource.js +59 -60
  32. package/build/submit/BaseSubmitter.d.ts +4 -1
  33. package/build/submit/BaseSubmitter.js +20 -0
  34. package/build/submit/android/AndroidSubmitCommand.js +1 -2
  35. package/build/submit/android/AndroidSubmitter.d.ts +3 -3
  36. package/build/submit/android/AndroidSubmitter.js +12 -7
  37. package/build/submit/commons.d.ts +1 -1
  38. package/build/submit/commons.js +1 -16
  39. package/build/submit/ios/IosSubmitCommand.js +1 -2
  40. package/build/submit/ios/IosSubmitter.d.ts +3 -3
  41. package/build/submit/ios/IosSubmitter.js +11 -6
  42. package/build/submit/utils/files.js +2 -2
  43. package/build/submit/utils/summary.d.ts +2 -2
  44. package/build/submit/utils/summary.js +7 -8
  45. package/build/uploads.d.ts +4 -10
  46. package/build/uploads.js +16 -36
  47. package/build/utils/download.d.ts +3 -2
  48. package/build/utils/download.js +37 -30
  49. package/build/utils/progress.d.ts +1 -1
  50. package/build/utils/progress.js +6 -4
  51. package/oclif.manifest.json +1 -1
  52. package/package.json +3 -3
@@ -6,7 +6,6 @@ const core_1 = require("@oclif/core");
6
6
  const fs_extra_1 = require("fs-extra");
7
7
  const node_assert_1 = tslib_1.__importDefault(require("node:assert"));
8
8
  const queries_1 = require("../../build/queries");
9
- const types_1 = require("../../build/types");
10
9
  const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
11
10
  const pagination_1 = require("../../commandUtils/pagination");
12
11
  const generated_1 = require("../../graphql/generated");
@@ -14,7 +13,6 @@ const BuildQuery_1 = require("../../graphql/queries/BuildQuery");
14
13
  const projectUtils_1 = require("../../project/projectUtils");
15
14
  const prompts_1 = require("../../prompts");
16
15
  const run_1 = require("../../run/run");
17
- const buildDistribution_1 = require("../../utils/buildDistribution");
18
16
  const download_1 = require("../../utils/download");
19
17
  class Run extends EasCommand_1.default {
20
18
  async runAsync() {
@@ -30,11 +28,16 @@ class Run extends EasCommand_1.default {
30
28
  async sanitizeFlagsAsync(flags) {
31
29
  const { platform, limit, offset, ...runArchiveFlags } = flags;
32
30
  const selectedPlatform = await resolvePlatformAsync(platform);
31
+ if (platform === 'ios' && process.platform !== 'darwin') {
32
+ core_1.Errors.error('You can only use an iOS simulator to run apps on macOS devices', {
33
+ exit: 1,
34
+ });
35
+ }
33
36
  if (runArchiveFlags.path &&
34
37
  !((runArchiveFlags.path.endsWith('.tar.gz') ||
35
38
  runArchiveFlags.path.endsWith('.app') ||
36
39
  runArchiveFlags.path.endsWith('.apk')) &&
37
- (0, fs_extra_1.existsSync)(runArchiveFlags.path))) {
40
+ (await (0, fs_extra_1.pathExists)(runArchiveFlags.path)))) {
38
41
  core_1.Errors.error('The path must point to a .tar.gz archive, .apk file, or .app directory', {
39
42
  exit: 1,
40
43
  });
@@ -61,7 +64,7 @@ Run.flags = {
61
64
  exclusive: ['latest', 'id', 'path'],
62
65
  }),
63
66
  path: core_1.Flags.string({
64
- description: 'Path to the simulator/emulator build archive or simulator build app',
67
+ description: 'Path to the simulator/emulator build archive or app',
65
68
  exclusive: ['latest', 'id', 'url'],
66
69
  }),
67
70
  id: core_1.Flags.string({
@@ -80,6 +83,9 @@ Run.contextDefinition = {
80
83
  ..._a.ContextOptions.ProjectDir,
81
84
  };
82
85
  async function resolvePlatformAsync(platform) {
86
+ if (process.platform !== 'darwin') {
87
+ return generated_1.AppPlatform.Android;
88
+ }
83
89
  if (platform && Object.values(generated_1.AppPlatform).includes(platform.toUpperCase())) {
84
90
  return platform.toUpperCase();
85
91
  }
@@ -95,6 +101,7 @@ async function resolvePlatformAsync(platform) {
95
101
  return selectedPlatform;
96
102
  }
97
103
  async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQueryOptions) {
104
+ const distributionType = flags.selectedPlatform === generated_1.AppPlatform.Ios ? generated_1.DistributionType.Simulator : undefined;
98
105
  if (flags.runArchiveFlags.id) {
99
106
  return BuildQuery_1.BuildQuery.byIdAsync(graphqlClient, flags.runArchiveFlags.id);
100
107
  }
@@ -102,15 +109,22 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
102
109
  !flags.runArchiveFlags.path &&
103
110
  !flags.runArchiveFlags.url &&
104
111
  !flags.runArchiveFlags.latest) {
105
- return await (0, queries_1.listAndSelectBuildsOnAppAsync)(graphqlClient, {
112
+ return await (0, queries_1.listAndSelectBuildsOnAppAsync)(graphqlClient, flags.selectedPlatform, {
106
113
  projectId,
107
114
  projectDisplayName: await (0, projectUtils_1.getDisplayNameForProjectIdAsync)(graphqlClient, projectId),
108
115
  filter: {
109
116
  platform: flags.selectedPlatform,
110
- distribution: (0, buildDistribution_1.buildDistributionTypeToGraphQLDistributionType)(types_1.BuildDistributionType.SIMULATOR),
117
+ distribution: distributionType,
111
118
  status: generated_1.BuildStatus.Finished,
112
119
  },
113
120
  queryOptions: paginatedQueryOptions,
121
+ selectPromptDisabledFunction: build => {
122
+ var _b, _c, _d;
123
+ return build.platform === generated_1.AppPlatform.Ios
124
+ ? false
125
+ : (_d = !((_c = (_b = build.artifacts) === null || _b === void 0 ? void 0 : _b.applicationArchiveUrl) === null || _c === void 0 ? void 0 : _c.endsWith('.apk'))) !== null && _d !== void 0 ? _d : false;
126
+ },
127
+ warningMessage: 'This is not a simulator/emulator build',
114
128
  });
115
129
  }
116
130
  else if (flags.runArchiveFlags.latest) {
@@ -118,7 +132,7 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
118
132
  projectId,
119
133
  filter: {
120
134
  platform: flags.selectedPlatform,
121
- distribution: (0, buildDistribution_1.buildDistributionTypeToGraphQLDistributionType)(types_1.BuildDistributionType.SIMULATOR),
135
+ distribution: distributionType,
122
136
  status: generated_1.BuildStatus.Finished,
123
137
  },
124
138
  });
@@ -130,18 +144,17 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
130
144
  async function getPathToSimulatorBuildAppAsync(graphqlClient, projectId, flags, queryOptions) {
131
145
  var _b, _c;
132
146
  const maybeBuild = await maybeGetBuildAsync(graphqlClient, flags, projectId, queryOptions);
133
- const appExtension = flags.selectedPlatform === generated_1.AppPlatform.Ios ? 'app' : 'apk';
134
147
  if (maybeBuild) {
135
148
  if (!((_b = maybeBuild.artifacts) === null || _b === void 0 ? void 0 : _b.applicationArchiveUrl)) {
136
149
  throw new Error('Build does not have an application archive url');
137
150
  }
138
- return await (0, download_1.downloadAndExtractAppAsync)(maybeBuild.artifacts.applicationArchiveUrl, appExtension);
151
+ return await (0, download_1.downloadAndMaybeExtractAppAsync)(maybeBuild.artifacts.applicationArchiveUrl, flags.selectedPlatform);
139
152
  }
140
153
  if (flags.runArchiveFlags.url) {
141
- return await (0, download_1.downloadAndExtractAppAsync)(flags.runArchiveFlags.url, appExtension);
154
+ return await (0, download_1.downloadAndMaybeExtractAppAsync)(flags.runArchiveFlags.url, flags.selectedPlatform);
142
155
  }
143
156
  if ((_c = flags.runArchiveFlags.path) === null || _c === void 0 ? void 0 : _c.endsWith('.tar.gz')) {
144
- return await (0, download_1.extractAppFromLocalArchiveAsync)(flags.runArchiveFlags.path, appExtension);
157
+ return await (0, download_1.extractAppFromLocalArchiveAsync)(flags.runArchiveFlags.path, flags.selectedPlatform);
145
158
  }
146
159
  // this should never fail, due to the validation in sanitizeFlagsAsync
147
160
  (0, node_assert_1.default)(flags.runArchiveFlags.path);
@@ -124,7 +124,7 @@ Submit.flags = {
124
124
  exclusive: ['latest', 'id', 'path'],
125
125
  }),
126
126
  verbose: core_1.Flags.boolean({
127
- description: 'Always print logs from Submission Service',
127
+ description: 'Always print logs from EAS Submit',
128
128
  default: false,
129
129
  }),
130
130
  wait: core_1.Flags.boolean({
@@ -248,15 +248,17 @@ class UpdatePublish extends EasCommand_1.default {
248
248
  runtimeToPlatformMapping.push({ runtimeVersion: runtime.runtimeVersion, platforms });
249
249
  }
250
250
  }
251
- const { branchId } = await (0, queries_1.ensureBranchExistsAsync)(graphqlClient, {
251
+ const { branchId, createdBranch } = await (0, queries_1.ensureBranchExistsAsync)(graphqlClient, {
252
252
  appId: projectId,
253
253
  branchName,
254
254
  });
255
- await (0, queries_2.ensureChannelExistsAsync)(graphqlClient, {
256
- appId: projectId,
257
- branchId,
258
- channelName: branchName,
259
- });
255
+ if (createdBranch) {
256
+ await (0, queries_2.ensureChannelExistsAsync)(graphqlClient, {
257
+ appId: projectId,
258
+ branchId,
259
+ channelName: branchName,
260
+ });
261
+ }
260
262
  log_1.default.withTick(`Channel: ${chalk_1.default.bold(branchName)} pointed at branch: ${chalk_1.default.bold(branchName)}`);
261
263
  const gitCommitHash = await (0, vcs_1.getVcsClient)().getCommitHashAsync();
262
264
  // Sort the updates into different groups based on their platform specific runtime versions
@@ -19,13 +19,12 @@ function formatDeviceClass(device) {
19
19
  function formatDevice(device, team) {
20
20
  var _a, _b;
21
21
  const fields = [
22
- { label: 'ID', value: device.id },
22
+ { label: 'UDID', value: device.identifier },
23
23
  { label: 'Name', value: (_a = device.name) !== null && _a !== void 0 ? _a : 'Unknown' },
24
24
  {
25
25
  label: 'Class',
26
26
  value: formatDeviceClass(device),
27
27
  },
28
- { label: 'UDID', value: device.identifier },
29
28
  ];
30
29
  if (team) {
31
30
  fields.push({ label: 'Apple Team ID', value: team.appleTeamIdentifier }, { label: 'Apple Team Name', value: (_b = team.appleTeamName) !== null && _b !== void 0 ? _b : 'Unknown' });
@@ -2114,6 +2114,11 @@ export declare type GetSignedAssetUploadSpecificationsResult = {
2114
2114
  __typename?: 'GetSignedAssetUploadSpecificationsResult';
2115
2115
  specifications: Array<Scalars['String']>;
2116
2116
  };
2117
+ export declare enum GitHubAppEnvironment {
2118
+ Development = "DEVELOPMENT",
2119
+ Production = "PRODUCTION",
2120
+ Staging = "STAGING"
2121
+ }
2117
2122
  export declare type GitHubAppInstallation = {
2118
2123
  __typename?: 'GitHubAppInstallation';
2119
2124
  accessibleRepositories: GitHubRepositoryPaginationResult;
@@ -2166,7 +2171,9 @@ export declare type GitHubAppQuery = {
2166
2171
  __typename?: 'GitHubAppQuery';
2167
2172
  appIdentifier: Scalars['String'];
2168
2173
  clientIdentifier: Scalars['String'];
2174
+ environment: GitHubAppEnvironment;
2169
2175
  installation: GitHubAppInstallation;
2176
+ name: Scalars['String'];
2170
2177
  searchRepositories: GitHubRepositoryPaginationResult;
2171
2178
  };
2172
2179
  export declare type GitHubAppQueryInstallationArgs = {
@@ -2187,12 +2194,14 @@ export declare type GitHubRepository = {
2187
2194
  };
2188
2195
  export declare type GitHubRepositoryMetadata = {
2189
2196
  __typename?: 'GitHubRepositoryMetadata';
2197
+ defaultBranch?: Maybe<Scalars['String']>;
2190
2198
  githubRepoDescription?: Maybe<Scalars['String']>;
2191
2199
  githubRepoName: Scalars['String'];
2192
2200
  githubRepoOwnerName: Scalars['String'];
2193
2201
  githubRepoUrl: Scalars['String'];
2194
2202
  lastPushed: Scalars['DateTime'];
2195
2203
  lastUpdated: Scalars['DateTime'];
2204
+ openGraphImageUrl?: Maybe<Scalars['String']>;
2196
2205
  private: Scalars['Boolean'];
2197
2206
  };
2198
2207
  export declare type GitHubRepositoryMutation = {
@@ -2735,6 +2744,7 @@ export declare type ProjectArchiveSourceInput = {
2735
2744
  url?: InputMaybe<Scalars['String']>;
2736
2745
  };
2737
2746
  export declare enum ProjectArchiveSourceType {
2747
+ Gcs = "GCS",
2738
2748
  S3 = "S3",
2739
2749
  Url = "URL"
2740
2750
  }
@@ -6939,6 +6949,7 @@ export declare type CreateAndroidSubmissionMutationVariables = Exact<{
6939
6949
  appId: Scalars['ID'];
6940
6950
  config: AndroidSubmissionConfigInput;
6941
6951
  submittedBuildId?: InputMaybe<Scalars['ID']>;
6952
+ archiveSource?: InputMaybe<SubmissionArchiveSourceInput>;
6942
6953
  }>;
6943
6954
  export declare type CreateAndroidSubmissionMutation = {
6944
6955
  __typename?: 'RootMutation';
@@ -6987,6 +6998,7 @@ export declare type CreateIosSubmissionMutationVariables = Exact<{
6987
6998
  appId: Scalars['ID'];
6988
6999
  config: IosSubmissionConfigInput;
6989
7000
  submittedBuildId?: InputMaybe<Scalars['ID']>;
7001
+ archiveSource?: InputMaybe<SubmissionArchiveSourceInput>;
6990
7002
  }>;
6991
7003
  export declare type CreateIosSubmissionMutation = {
6992
7004
  __typename?: 'RootMutation';
@@ -6,8 +6,8 @@
6
6
  * For more info and docs, visit https://graphql-code-generator.com/
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.SubmissionStatus = exports.SubmissionArchiveSourceType = exports.SubmissionAndroidTrack = exports.SubmissionAndroidReleaseStatus = exports.SubmissionAndroidArchiveType = exports.StatuspageServiceStatus = exports.StatuspageServiceName = exports.StatuspageIncidentStatus = exports.StatuspageIncidentImpact = exports.StandardOffer = exports.SecondFactorMethod = exports.Role = exports.ProjectArchiveSourceType = exports.Permission = exports.Order = exports.OfferType = exports.MailchimpTag = exports.MailchimpAudience = exports.IosSchemeBuildConfiguration = exports.IosManagedBuildType = exports.IosDistributionType = exports.IosBuildType = exports.InvoiceDiscountType = exports.GitHubAppInstallationStatus = exports.Feature = exports.EnvironmentSecretType = exports.EasServiceMetric = exports.EasBuildDeprecationInfoType = exports.DistributionType = exports.CacheControlScope = exports.BuildWorkflow = exports.BuildStatus = exports.BuildResourceClass = exports.BuildPriority = exports.BuildJobStatus = exports.BuildJobLogsFormat = exports.BuildIosEnterpriseProvisioning = exports.BuildCredentialsSource = exports.AuthProtocolType = exports.AssetMetadataStatus = exports.AppsFilter = exports.AppleDeviceClass = exports.AppStoreConnectUserRole = exports.AppSort = exports.AppPrivacy = exports.AppPlatform = exports.AndroidKeystoreType = exports.AndroidFcmVersion = exports.AndroidBuildType = exports.ActivityTimelineProjectActivityType = void 0;
10
- exports.WebhookType = exports.UsageMetricsGranularity = exports.UsageMetricType = exports.UploadSessionType = void 0;
9
+ exports.SubmissionArchiveSourceType = exports.SubmissionAndroidTrack = exports.SubmissionAndroidReleaseStatus = exports.SubmissionAndroidArchiveType = exports.StatuspageServiceStatus = exports.StatuspageServiceName = exports.StatuspageIncidentStatus = exports.StatuspageIncidentImpact = exports.StandardOffer = exports.SecondFactorMethod = exports.Role = exports.ProjectArchiveSourceType = exports.Permission = exports.Order = exports.OfferType = exports.MailchimpTag = exports.MailchimpAudience = exports.IosSchemeBuildConfiguration = exports.IosManagedBuildType = exports.IosDistributionType = exports.IosBuildType = exports.InvoiceDiscountType = exports.GitHubAppInstallationStatus = exports.GitHubAppEnvironment = exports.Feature = exports.EnvironmentSecretType = exports.EasServiceMetric = exports.EasBuildDeprecationInfoType = exports.DistributionType = exports.CacheControlScope = exports.BuildWorkflow = exports.BuildStatus = exports.BuildResourceClass = exports.BuildPriority = exports.BuildJobStatus = exports.BuildJobLogsFormat = exports.BuildIosEnterpriseProvisioning = exports.BuildCredentialsSource = exports.AuthProtocolType = exports.AssetMetadataStatus = exports.AppsFilter = exports.AppleDeviceClass = exports.AppStoreConnectUserRole = exports.AppSort = exports.AppPrivacy = exports.AppPlatform = exports.AndroidKeystoreType = exports.AndroidFcmVersion = exports.AndroidBuildType = exports.ActivityTimelineProjectActivityType = void 0;
10
+ exports.WebhookType = exports.UsageMetricsGranularity = exports.UsageMetricType = exports.UploadSessionType = exports.SubmissionStatus = void 0;
11
11
  var ActivityTimelineProjectActivityType;
12
12
  (function (ActivityTimelineProjectActivityType) {
13
13
  ActivityTimelineProjectActivityType["Build"] = "BUILD";
@@ -186,6 +186,12 @@ var Feature;
186
186
  /** Share access to projects */
187
187
  Feature["Teams"] = "TEAMS";
188
188
  })(Feature = exports.Feature || (exports.Feature = {}));
189
+ var GitHubAppEnvironment;
190
+ (function (GitHubAppEnvironment) {
191
+ GitHubAppEnvironment["Development"] = "DEVELOPMENT";
192
+ GitHubAppEnvironment["Production"] = "PRODUCTION";
193
+ GitHubAppEnvironment["Staging"] = "STAGING";
194
+ })(GitHubAppEnvironment = exports.GitHubAppEnvironment || (exports.GitHubAppEnvironment = {}));
189
195
  var GitHubAppInstallationStatus;
190
196
  (function (GitHubAppInstallationStatus) {
191
197
  GitHubAppInstallationStatus["Active"] = "ACTIVE";
@@ -253,6 +259,7 @@ var Permission;
253
259
  })(Permission = exports.Permission || (exports.Permission = {}));
254
260
  var ProjectArchiveSourceType;
255
261
  (function (ProjectArchiveSourceType) {
262
+ ProjectArchiveSourceType["Gcs"] = "GCS";
256
263
  ProjectArchiveSourceType["S3"] = "S3";
257
264
  ProjectArchiveSourceType["Url"] = "URL";
258
265
  })(ProjectArchiveSourceType = exports.ProjectArchiveSourceType || (exports.ProjectArchiveSourceType = {}));
@@ -15,10 +15,16 @@ exports.SubmissionMutation = {
15
15
  $appId: ID!
16
16
  $config: AndroidSubmissionConfigInput!
17
17
  $submittedBuildId: ID
18
+ $archiveSource: SubmissionArchiveSourceInput
18
19
  ) {
19
20
  submission {
20
21
  createAndroidSubmission(
21
- input: { appId: $appId, config: $config, submittedBuildId: $submittedBuildId }
22
+ input: {
23
+ appId: $appId
24
+ config: $config
25
+ submittedBuildId: $submittedBuildId
26
+ archiveSource: $archiveSource
27
+ }
22
28
  ) {
23
29
  submission {
24
30
  id
@@ -39,10 +45,16 @@ exports.SubmissionMutation = {
39
45
  $appId: ID!
40
46
  $config: IosSubmissionConfigInput!
41
47
  $submittedBuildId: ID
48
+ $archiveSource: SubmissionArchiveSourceInput
42
49
  ) {
43
50
  submission {
44
51
  createIosSubmission(
45
- input: { appId: $appId, config: $config, submittedBuildId: $submittedBuildId }
52
+ input: {
53
+ appId: $appId
54
+ config: $config
55
+ submittedBuildId: $submittedBuildId
56
+ archiveSource: $archiveSource
57
+ }
46
58
  ) {
47
59
  submission {
48
60
  id
@@ -1,9 +1,10 @@
1
1
  import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
2
2
  import { UploadSessionType } from '../generated';
3
- export interface PresignedPost {
3
+ export interface SignedUrl {
4
4
  url: string;
5
- fields: Record<string, string>;
5
+ headers: Record<string, string>;
6
+ bucketKey: string;
6
7
  }
7
8
  export declare const UploadSessionMutation: {
8
- createUploadSessionAsync(graphqlClient: ExpoGraphqlClient, type: UploadSessionType): Promise<PresignedPost>;
9
+ createUploadSessionAsync(graphqlClient: ExpoGraphqlClient, type: UploadSessionType): Promise<SignedUrl>;
9
10
  };
@@ -0,0 +1,5 @@
1
+ export declare function getAaptExecutableAsync(): Promise<string>;
2
+ export declare function getAptParametersAsync(appPath: string): Promise<{
3
+ packageName: string;
4
+ activityName: string;
5
+ }>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAptParametersAsync = exports.getAaptExecutableAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const log_1 = tslib_1.__importDefault(require("../../log"));
9
+ const sdk_1 = require("./sdk");
10
+ async function aaptAsync(...options) {
11
+ try {
12
+ return await (0, spawn_async_1.default)(await getAaptExecutableAsync(), options);
13
+ }
14
+ catch (error) {
15
+ if (error.stderr) {
16
+ log_1.default.error(error.stderr);
17
+ }
18
+ throw error;
19
+ }
20
+ }
21
+ async function getAaptExecutableAsync() {
22
+ const sdkRoot = await (0, sdk_1.getAndroidSdkRootAsync)();
23
+ if (!sdkRoot) {
24
+ log_1.default.debug('Failed to resolve the Android SDK path, falling back to global aapt executable');
25
+ return 'aapt';
26
+ }
27
+ const aaptPaths = await (0, fast_glob_1.default)(path_1.default.posix.join('build-tools/**', process.platform === 'win32' ? 'aapt.exe' : 'aapt'), { cwd: sdkRoot, absolute: true });
28
+ if (aaptPaths.length === 0) {
29
+ throw new Error('Failed to resolve the Android aapt path');
30
+ }
31
+ const sorted = aaptPaths.sort();
32
+ return sorted[sorted.length - 1];
33
+ }
34
+ exports.getAaptExecutableAsync = getAaptExecutableAsync;
35
+ async function getAptParametersAsync(appPath) {
36
+ const { stdout } = await aaptAsync('dump', 'badging', appPath);
37
+ const packageNameMatch = stdout.match(/package: name='([^']+)'/);
38
+ if (!packageNameMatch) {
39
+ throw new Error(`Could not read package name from ${appPath}`);
40
+ }
41
+ // get activity name
42
+ const activityNameMatch = stdout.match(/launchable-activity: name='([^']+)'/);
43
+ if (!activityNameMatch) {
44
+ throw new Error(`Could not read activity name from ${appPath}`);
45
+ }
46
+ return {
47
+ packageName: packageNameMatch[1],
48
+ activityName: activityNameMatch[1],
49
+ };
50
+ }
51
+ exports.getAptParametersAsync = getAptParametersAsync;
@@ -0,0 +1,23 @@
1
+ import { SpawnResult } from '@expo/spawn-async';
2
+ export interface AndroidEmulator {
3
+ pid?: string;
4
+ name: string;
5
+ }
6
+ export declare function adbAsync(...args: string[]): Promise<SpawnResult>;
7
+ export declare function getAdbExecutableAsync(): Promise<string>;
8
+ export declare function sanitizeAdbDeviceName(deviceName: string): string | undefined;
9
+ /**
10
+ * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.
11
+ *
12
+ * @param devicePid a value like `emulator-5554` from `abd devices`
13
+ */
14
+ export declare function getAdbNameForDeviceIdAsync(emulatorPid: string): Promise<string | null>;
15
+ export declare function getRunningEmulatorsAsync(): Promise<AndroidEmulator[]>;
16
+ export declare function getFirstRunningEmulatorAsync(): Promise<AndroidEmulator | null>;
17
+ /**
18
+ * Returns true if emulator is booted
19
+ *
20
+ * @param emulatorPid
21
+ */
22
+ export declare function isEmulatorBootedAsync(emulatorPid: string): Promise<boolean>;
23
+ export declare function waitForEmulatorToBeBootedAsync(maxWaitTimeMs: number, intervalMs: number): Promise<AndroidEmulator>;
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.waitForEmulatorToBeBootedAsync = exports.isEmulatorBootedAsync = exports.getFirstRunningEmulatorAsync = exports.getRunningEmulatorsAsync = exports.getAdbNameForDeviceIdAsync = exports.sanitizeAdbDeviceName = exports.getAdbExecutableAsync = exports.adbAsync = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const os_1 = tslib_1.__importDefault(require("os"));
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const log_1 = tslib_1.__importDefault(require("../../log"));
9
+ const filter_1 = require("../../utils/expodash/filter");
10
+ const promise_1 = require("../../utils/promise");
11
+ const sdk_1 = require("./sdk");
12
+ const BEGINNING_OF_ADB_ERROR_MESSAGE = 'error: ';
13
+ async function adbAsync(...args) {
14
+ const adbExecutable = await getAdbExecutableAsync();
15
+ try {
16
+ return await (0, spawn_async_1.default)(adbExecutable, args);
17
+ }
18
+ catch (error) {
19
+ let errorMessage = (error.stderr || error.stdout || error.message).trim();
20
+ if (errorMessage.startsWith(BEGINNING_OF_ADB_ERROR_MESSAGE)) {
21
+ errorMessage = errorMessage.substring(BEGINNING_OF_ADB_ERROR_MESSAGE.length);
22
+ }
23
+ error.message = errorMessage;
24
+ throw error;
25
+ }
26
+ }
27
+ exports.adbAsync = adbAsync;
28
+ async function getAdbExecutableAsync() {
29
+ const sdkRoot = await (0, sdk_1.getAndroidSdkRootAsync)();
30
+ if (!sdkRoot) {
31
+ log_1.default.debug('Failed to resolve the Android SDK path, falling back to global adb executable');
32
+ return 'adb';
33
+ }
34
+ return path_1.default.join(sdkRoot, 'platform-tools/adb');
35
+ }
36
+ exports.getAdbExecutableAsync = getAdbExecutableAsync;
37
+ function sanitizeAdbDeviceName(deviceName) {
38
+ return deviceName.trim().split(/[\r\n]+/)[0];
39
+ }
40
+ exports.sanitizeAdbDeviceName = sanitizeAdbDeviceName;
41
+ /**
42
+ * Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.
43
+ *
44
+ * @param devicePid a value like `emulator-5554` from `abd devices`
45
+ */
46
+ async function getAdbNameForDeviceIdAsync(emulatorPid) {
47
+ var _a;
48
+ const { stdout } = await adbAsync('-s', emulatorPid, 'emu', 'avd', 'name');
49
+ if (stdout.match(/could not connect to TCP port .*: Connection refused/)) {
50
+ // Can also occur when the emulator does not exist.
51
+ throw new Error(`Emulator not found: ${stdout}`);
52
+ }
53
+ return (_a = sanitizeAdbDeviceName(stdout)) !== null && _a !== void 0 ? _a : null;
54
+ }
55
+ exports.getAdbNameForDeviceIdAsync = getAdbNameForDeviceIdAsync;
56
+ // TODO: This is very expensive for some operations.
57
+ async function getRunningEmulatorsAsync() {
58
+ const { stdout } = await adbAsync('devices', '-l');
59
+ const splitItems = stdout.trim().split(os_1.default.EOL);
60
+ const attachedDevices = splitItems
61
+ // First line is `"List of devices attached"`, remove it
62
+ .slice(1, splitItems.length)
63
+ .map(line => {
64
+ // unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']
65
+ // authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']
66
+ // emulator: ['emulator-5554', 'offline', 'transport_id:1']
67
+ const [pid] = line.split(' ').filter(filter_1.truthy);
68
+ const type = line.includes('emulator') ? 'emulator' : 'device';
69
+ return { pid, type };
70
+ })
71
+ .filter(({ pid, type }) => !!pid && type === 'emulator');
72
+ const devicePromises = attachedDevices.map(async ({ pid }) => {
73
+ var _a;
74
+ const name = (_a = (await getAdbNameForDeviceIdAsync(pid))) !== null && _a !== void 0 ? _a : '';
75
+ return {
76
+ pid,
77
+ name,
78
+ };
79
+ });
80
+ return Promise.all(devicePromises);
81
+ }
82
+ exports.getRunningEmulatorsAsync = getRunningEmulatorsAsync;
83
+ async function getFirstRunningEmulatorAsync() {
84
+ var _a;
85
+ const emulators = await getRunningEmulatorsAsync();
86
+ return (_a = emulators[0]) !== null && _a !== void 0 ? _a : null;
87
+ }
88
+ exports.getFirstRunningEmulatorAsync = getFirstRunningEmulatorAsync;
89
+ /**
90
+ * Returns true if emulator is booted
91
+ *
92
+ * @param emulatorPid
93
+ */
94
+ async function isEmulatorBootedAsync(emulatorPid) {
95
+ try {
96
+ const { stdout } = await adbAsync('-s', emulatorPid, 'shell', 'getprop', 'sys.boot_completed');
97
+ if (stdout.trim() === '1') {
98
+ return true;
99
+ }
100
+ return false;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ exports.isEmulatorBootedAsync = isEmulatorBootedAsync;
107
+ async function waitForEmulatorToBeBootedAsync(maxWaitTimeMs, intervalMs) {
108
+ log_1.default.newLine();
109
+ log_1.default.log('Waiting for the Android emulator to start...');
110
+ const startTime = Date.now();
111
+ while (Date.now() - startTime < maxWaitTimeMs) {
112
+ const emulator = await getFirstRunningEmulatorAsync();
113
+ if ((emulator === null || emulator === void 0 ? void 0 : emulator.pid) && (await isEmulatorBootedAsync(emulator.pid))) {
114
+ return emulator;
115
+ }
116
+ await (0, promise_1.sleepAsync)(intervalMs);
117
+ }
118
+ throw new Error('Timed out waiting for the Android emulator to start.');
119
+ }
120
+ exports.waitForEmulatorToBeBootedAsync = waitForEmulatorToBeBootedAsync;
@@ -0,0 +1,7 @@
1
+ import { AndroidEmulator } from './adb';
2
+ export declare const EMULATOR_MAX_WAIT_TIMEOUT_MS: number;
3
+ export declare function getEmulatorExecutableAsync(): Promise<string>;
4
+ export declare function selectEmulatorAsync(): Promise<AndroidEmulator>;
5
+ export declare function ensureEmulatorBootedAsync(emulator: AndroidEmulator): Promise<AndroidEmulator>;
6
+ export declare function installAppAsync(emulator: AndroidEmulator, apkFilePath: string): Promise<void>;
7
+ export declare function startAppAsync(emulator: AndroidEmulator, packageName: string, activityName: string): Promise<void>;
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startAppAsync = exports.installAppAsync = exports.ensureEmulatorBootedAsync = exports.selectEmulatorAsync = exports.getEmulatorExecutableAsync = exports.EMULATOR_MAX_WAIT_TIMEOUT_MS = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const node_assert_1 = tslib_1.__importDefault(require("node:assert"));
8
+ const os_1 = tslib_1.__importDefault(require("os"));
9
+ const path_1 = tslib_1.__importDefault(require("path"));
10
+ const log_1 = tslib_1.__importDefault(require("../../log"));
11
+ const prompts_1 = require("../../prompts");
12
+ const filter_1 = require("../../utils/expodash/filter");
13
+ const adb_1 = require("./adb");
14
+ const sdk_1 = require("./sdk");
15
+ exports.EMULATOR_MAX_WAIT_TIMEOUT_MS = 60 * 1000 * 3;
16
+ async function getEmulatorExecutableAsync() {
17
+ const sdkRoot = await (0, sdk_1.getAndroidSdkRootAsync)();
18
+ if (sdkRoot) {
19
+ return path_1.default.join(sdkRoot, 'emulator', 'emulator');
20
+ }
21
+ return 'emulator';
22
+ }
23
+ exports.getEmulatorExecutableAsync = getEmulatorExecutableAsync;
24
+ async function emulatorAsync(...options) {
25
+ const emulatorExecutable = await getEmulatorExecutableAsync();
26
+ try {
27
+ return await (0, spawn_async_1.default)(emulatorExecutable, options);
28
+ }
29
+ catch (error) {
30
+ if (error.stderr) {
31
+ log_1.default.error(error.stderr);
32
+ }
33
+ throw error;
34
+ }
35
+ }
36
+ async function getAvaliableAndroidEmulatorsAsync() {
37
+ try {
38
+ const { stdout } = await emulatorAsync('-list-avds');
39
+ return stdout
40
+ .split(os_1.default.EOL)
41
+ .filter(filter_1.truthy)
42
+ .map(name => ({
43
+ name,
44
+ }));
45
+ }
46
+ catch {
47
+ return [];
48
+ }
49
+ }
50
+ /** Start an Android device and wait until it is booted. */
51
+ async function bootEmulatorAsync(emulator, { timeout = exports.EMULATOR_MAX_WAIT_TIMEOUT_MS, interval = 1000, } = {}) {
52
+ log_1.default.newLine();
53
+ log_1.default.log(`Opening emulator ${chalk_1.default.bold(emulator.name)}`);
54
+ const emulatorExecutable = await getEmulatorExecutableAsync();
55
+ // Start a process to open an emulator
56
+ const emulatorProcess = (0, spawn_async_1.default)(emulatorExecutable, [`@${emulator.name}`], {
57
+ stdio: 'ignore',
58
+ detached: true,
59
+ });
60
+ // we don't want to wait for the emulator process to exit before we can finish `eas build:run` command
61
+ // https://github.com/expo/eas-cli/pull/1485#discussion_r1007935871
62
+ emulatorProcess.child.unref();
63
+ return await (0, adb_1.waitForEmulatorToBeBootedAsync)(timeout, interval);
64
+ }
65
+ async function selectEmulatorAsync() {
66
+ const runningEmulator = await (0, adb_1.getFirstRunningEmulatorAsync)();
67
+ if (runningEmulator) {
68
+ log_1.default.newLine();
69
+ log_1.default.log(`Using open emulator: ${chalk_1.default.bold(runningEmulator.name)}`);
70
+ return runningEmulator;
71
+ }
72
+ const emulators = await getAvaliableAndroidEmulatorsAsync();
73
+ log_1.default.newLine();
74
+ const { selectedEmulator } = await (0, prompts_1.promptAsync)({
75
+ type: 'select',
76
+ message: `Select an emulator to run your app on`,
77
+ name: 'selectedEmulator',
78
+ choices: emulators.map(emulator => ({
79
+ title: emulator.name,
80
+ value: emulator,
81
+ })),
82
+ });
83
+ return selectedEmulator;
84
+ }
85
+ exports.selectEmulatorAsync = selectEmulatorAsync;
86
+ async function ensureEmulatorBootedAsync(emulator) {
87
+ if (!emulator.pid || !(await (0, adb_1.isEmulatorBootedAsync)(emulator.pid))) {
88
+ return await bootEmulatorAsync(emulator);
89
+ }
90
+ return emulator;
91
+ }
92
+ exports.ensureEmulatorBootedAsync = ensureEmulatorBootedAsync;
93
+ async function installAppAsync(emulator, apkFilePath) {
94
+ log_1.default.newLine();
95
+ log_1.default.log('Installing your app...');
96
+ (0, node_assert_1.default)(emulator.pid);
97
+ await (0, adb_1.adbAsync)('-s', emulator.pid, 'install', '-r', '-d', apkFilePath);
98
+ log_1.default.succeed('Successfully installed your app!');
99
+ }
100
+ exports.installAppAsync = installAppAsync;
101
+ async function startAppAsync(emulator, packageName, activityName) {
102
+ log_1.default.newLine();
103
+ log_1.default.log('Starting your app...');
104
+ (0, node_assert_1.default)(emulator.pid);
105
+ await (0, adb_1.adbAsync)('-s', emulator.pid, 'shell', 'am', 'start', '-a', 'android.intent.action.RUN', '-f', '0x20000000', // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.
106
+ '-n', `${packageName}/${activityName}`);
107
+ log_1.default.succeed('Successfully started your app!');
108
+ }
109
+ exports.startAppAsync = startAppAsync;
@@ -1 +1 @@
1
- export declare function runAppOnAndroidEmulatorAsync(_appPath: string): Promise<void>;
1
+ export declare function runAppOnAndroidEmulatorAsync(appPath: string): Promise<void>;