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.
- package/README.md +49 -99
- package/build/branch/queries.d.ts +1 -0
- package/build/branch/queries.js +2 -2
- package/build/build/build.js +2 -2
- package/build/build/createContext.js +1 -0
- package/build/build/graphql.js +6 -0
- package/build/build/local.js +1 -1
- package/build/build/queries.d.ts +4 -2
- package/build/build/queries.js +32 -7
- package/build/commands/build/run.js +24 -11
- package/build/commands/submit.js +1 -1
- package/build/commands/update/index.js +8 -6
- package/build/devices/utils/formatDevice.js +1 -2
- package/build/graphql/generated.d.ts +12 -0
- package/build/graphql/generated.js +9 -2
- package/build/graphql/mutations/SubmissionMutation.js +14 -2
- package/build/graphql/mutations/UploadSessionMutation.d.ts +4 -3
- package/build/run/android/aapt.d.ts +5 -0
- package/build/run/android/aapt.js +51 -0
- package/build/run/android/adb.d.ts +23 -0
- package/build/run/android/adb.js +120 -0
- package/build/run/android/emulator.d.ts +7 -0
- package/build/run/android/emulator.js +109 -0
- package/build/run/android/run.d.ts +1 -1
- package/build/run/android/run.js +10 -3
- package/build/run/android/sdk.d.ts +3 -0
- package/build/run/android/sdk.js +29 -0
- package/build/run/android/systemRequirements.d.ts +1 -0
- package/build/run/android/systemRequirements.js +24 -0
- package/build/submit/ArchiveSource.d.ts +20 -10
- package/build/submit/ArchiveSource.js +59 -60
- package/build/submit/BaseSubmitter.d.ts +4 -1
- package/build/submit/BaseSubmitter.js +20 -0
- package/build/submit/android/AndroidSubmitCommand.js +1 -2
- package/build/submit/android/AndroidSubmitter.d.ts +3 -3
- package/build/submit/android/AndroidSubmitter.js +12 -7
- package/build/submit/commons.d.ts +1 -1
- package/build/submit/commons.js +1 -16
- package/build/submit/ios/IosSubmitCommand.js +1 -2
- package/build/submit/ios/IosSubmitter.d.ts +3 -3
- package/build/submit/ios/IosSubmitter.js +11 -6
- package/build/submit/utils/files.js +2 -2
- package/build/submit/utils/summary.d.ts +2 -2
- package/build/submit/utils/summary.js +7 -8
- package/build/uploads.d.ts +4 -10
- package/build/uploads.js +16 -36
- package/build/utils/download.d.ts +3 -2
- package/build/utils/download.js +37 -30
- package/build/utils/progress.d.ts +1 -1
- package/build/utils/progress.js +6 -4
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Platform } from '@expo/eas-build-job';
|
|
2
2
|
import { IosSubmissionConfigInput, SubmissionFragment } from '../../graphql/generated';
|
|
3
|
-
import {
|
|
3
|
+
import { ArchiveSource, ResolvedArchiveSource } from '../ArchiveSource';
|
|
4
4
|
import BaseSubmitter, { SubmissionInput } from '../BaseSubmitter';
|
|
5
5
|
import { SubmissionContext } from '../context';
|
|
6
6
|
import { AppSpecificPasswordCredentials, AppSpecificPasswordSource } from './AppSpecificPasswordSource';
|
|
@@ -14,7 +14,7 @@ export interface IosSubmissionOptions extends Pick<IosSubmissionConfigInput, 'ap
|
|
|
14
14
|
credentialsServiceSource?: CredentialsServiceSource;
|
|
15
15
|
}
|
|
16
16
|
interface ResolvedSourceOptions {
|
|
17
|
-
archive:
|
|
17
|
+
archive: ResolvedArchiveSource;
|
|
18
18
|
credentials: {
|
|
19
19
|
appSpecificPassword?: AppSpecificPasswordCredentials;
|
|
20
20
|
ascApiKeyResult?: AscApiKeyResult;
|
|
@@ -23,7 +23,7 @@ interface ResolvedSourceOptions {
|
|
|
23
23
|
export default class IosSubmitter extends BaseSubmitter<Platform.IOS, ResolvedSourceOptions, IosSubmissionOptions> {
|
|
24
24
|
constructor(ctx: SubmissionContext<Platform.IOS>, options: IosSubmissionOptions);
|
|
25
25
|
createSubmissionInputAsync(resolvedSourceOptions: ResolvedSourceOptions): Promise<SubmissionInput<Platform.IOS>>;
|
|
26
|
-
protected createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }: SubmissionInput<Platform.IOS>): Promise<SubmissionFragment>;
|
|
26
|
+
protected createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, archiveSource, }: SubmissionInput<Platform.IOS>): Promise<SubmissionFragment>;
|
|
27
27
|
private formatSubmissionConfig;
|
|
28
28
|
private formatAppSpecificPassword;
|
|
29
29
|
private formatAscApiKeyResult;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
4
5
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
5
6
|
const AnalyticsManager_1 = require("../../analytics/AnalyticsManager");
|
|
6
7
|
const SubmissionMutation_1 = require("../../graphql/mutations/SubmissionMutation");
|
|
@@ -15,7 +16,12 @@ class IosSubmitter extends BaseSubmitter_1.default {
|
|
|
15
16
|
constructor(ctx, options) {
|
|
16
17
|
const sourceOptionsResolver = {
|
|
17
18
|
// eslint-disable-next-line async-protect/async-suffix
|
|
18
|
-
archive: async () => await (0, ArchiveSource_1.getArchiveAsync)(
|
|
19
|
+
archive: async () => await (0, ArchiveSource_1.getArchiveAsync)({
|
|
20
|
+
graphqlClient: ctx.graphqlClient,
|
|
21
|
+
platform: eas_build_job_1.Platform.IOS,
|
|
22
|
+
projectId: ctx.projectId,
|
|
23
|
+
nonInteractive: ctx.nonInteractive,
|
|
24
|
+
}, this.options.archiveSource),
|
|
19
25
|
// eslint-disable-next-line async-protect/async-suffix
|
|
20
26
|
credentials: async () => {
|
|
21
27
|
const maybeAppSpecificPassword = this.options.appSpecificPasswordSource
|
|
@@ -49,29 +55,28 @@ class IosSubmitter extends BaseSubmitter_1.default {
|
|
|
49
55
|
super(ctx, options, sourceOptionsResolver, sourceOptionsAnalytics);
|
|
50
56
|
}
|
|
51
57
|
async createSubmissionInputAsync(resolvedSourceOptions) {
|
|
52
|
-
var _a;
|
|
53
58
|
const submissionConfig = this.formatSubmissionConfig(this.options, resolvedSourceOptions);
|
|
54
59
|
(0, summary_1.printSummary)(this.prepareSummaryData(this.options, resolvedSourceOptions), SummaryHumanReadableKeys);
|
|
55
60
|
return {
|
|
56
61
|
projectId: this.options.projectId,
|
|
57
62
|
submissionConfig,
|
|
58
|
-
|
|
63
|
+
...this.formatArchive(resolvedSourceOptions.archive),
|
|
59
64
|
};
|
|
60
65
|
}
|
|
61
|
-
async createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }) {
|
|
66
|
+
async createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, archiveSource, }) {
|
|
62
67
|
return await SubmissionMutation_1.SubmissionMutation.createIosSubmissionAsync(this.ctx.graphqlClient, {
|
|
63
68
|
appId: projectId,
|
|
64
69
|
config: submissionConfig,
|
|
65
70
|
submittedBuildId: buildId,
|
|
71
|
+
archiveSource,
|
|
66
72
|
});
|
|
67
73
|
}
|
|
68
|
-
formatSubmissionConfig(options, {
|
|
74
|
+
formatSubmissionConfig(options, { credentials }) {
|
|
69
75
|
const { appSpecificPassword, ascApiKeyResult } = credentials;
|
|
70
76
|
const { appleIdUsername, ascAppIdentifier } = options;
|
|
71
77
|
return {
|
|
72
78
|
ascAppIdentifier,
|
|
73
79
|
appleIdUsername,
|
|
74
|
-
archiveUrl: archive.url,
|
|
75
80
|
...(appSpecificPassword ? this.formatAppSpecificPassword(appSpecificPassword) : null),
|
|
76
81
|
...((ascApiKeyResult === null || ascApiKeyResult === void 0 ? void 0 : ascApiKeyResult.result) ? this.formatAscApiKeyResult(ascApiKeyResult.result) : null),
|
|
77
82
|
};
|
|
@@ -18,11 +18,11 @@ async function isExistingFileAsync(filePath) {
|
|
|
18
18
|
exports.isExistingFileAsync = isExistingFileAsync;
|
|
19
19
|
async function uploadAppArchiveAsync(graphqlClient, path) {
|
|
20
20
|
const fileSize = (await fs_extra_1.default.stat(path)).size;
|
|
21
|
-
const
|
|
21
|
+
const bucketKey = await (0, uploads_1.uploadFileAtPathToGCSAsync)(graphqlClient, generated_1.UploadSessionType.EasSubmitGcsAppArchive, path, (0, progress_1.createProgressTracker)({
|
|
22
22
|
total: fileSize,
|
|
23
23
|
message: 'Uploading to EAS Submit',
|
|
24
24
|
completedMessage: 'Uploaded to EAS Submit',
|
|
25
25
|
}));
|
|
26
|
-
return
|
|
26
|
+
return bucketKey;
|
|
27
27
|
}
|
|
28
28
|
exports.uploadAppArchiveAsync = uploadAppArchiveAsync;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ResolvedArchiveSource } from '../ArchiveSource';
|
|
2
2
|
export interface ArchiveSourceSummaryFields {
|
|
3
3
|
archiveUrl?: string;
|
|
4
4
|
archivePath?: string;
|
|
5
5
|
formattedBuild?: string;
|
|
6
6
|
}
|
|
7
|
-
export declare function formatArchiveSourceSummary(
|
|
7
|
+
export declare function formatArchiveSourceSummary(archive: ResolvedArchiveSource): ArchiveSourceSummaryFields;
|
|
8
8
|
export declare function printSummary<T extends object>(summary: T, keyMap: Record<keyof T, string>): void;
|
|
@@ -32,18 +32,17 @@ function formatSubmissionBuildSummary(build) {
|
|
|
32
32
|
labelFormat: label => ` ${chalk_1.default.dim(label)}:`,
|
|
33
33
|
}));
|
|
34
34
|
}
|
|
35
|
-
function formatArchiveSourceSummary(
|
|
35
|
+
function formatArchiveSourceSummary(archive) {
|
|
36
36
|
const summarySlice = {};
|
|
37
|
-
switch (
|
|
38
|
-
case ArchiveSource_1.ArchiveSourceType.
|
|
39
|
-
summarySlice.archivePath =
|
|
37
|
+
switch (archive.sourceType) {
|
|
38
|
+
case ArchiveSource_1.ArchiveSourceType.gcs:
|
|
39
|
+
summarySlice.archivePath = archive.localSource.path;
|
|
40
40
|
break;
|
|
41
41
|
case ArchiveSource_1.ArchiveSourceType.url:
|
|
42
|
-
summarySlice.archiveUrl =
|
|
42
|
+
summarySlice.archiveUrl = archive.url;
|
|
43
43
|
break;
|
|
44
|
-
case ArchiveSource_1.ArchiveSourceType.
|
|
45
|
-
|
|
46
|
-
summarySlice.formattedBuild = formatSubmissionBuildSummary(build);
|
|
44
|
+
case ArchiveSource_1.ArchiveSourceType.build:
|
|
45
|
+
summarySlice.formattedBuild = formatSubmissionBuildSummary(archive.build);
|
|
47
46
|
break;
|
|
48
47
|
}
|
|
49
48
|
return summarySlice;
|
package/build/uploads.d.ts
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { Response } from 'node-fetch';
|
|
2
2
|
import { ExpoGraphqlClient } from './commandUtils/context/contextUtils/createGraphqlClient';
|
|
3
3
|
import { UploadSessionType } from './graphql/generated';
|
|
4
|
-
import { PresignedPost } from './graphql/mutations/UploadSessionMutation';
|
|
5
4
|
import { ProgressHandler } from './utils/progress';
|
|
6
|
-
export
|
|
5
|
+
export interface PresignedPost {
|
|
7
6
|
url: string;
|
|
8
|
-
|
|
9
|
-
}
|
|
7
|
+
fields: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
export declare function uploadFileAtPathToGCSAsync(graphqlClient: ExpoGraphqlClient, type: UploadSessionType, path: string, handleProgressEvent: ProgressHandler): Promise<string>;
|
|
10
10
|
export declare function uploadWithPresignedPostWithRetryAsync(file: string, presignedPost: PresignedPost): Promise<Response>;
|
|
11
|
-
/**
|
|
12
|
-
* S3 returns broken URLs, sth like:
|
|
13
|
-
* https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
|
|
14
|
-
* This function replaces %2F with /.
|
|
15
|
-
*/
|
|
16
|
-
export declare function fixS3Url(archiveUrl: string): string;
|
package/build/uploads.js
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.uploadWithPresignedPostWithRetryAsync = exports.uploadFileAtPathToGCSAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
5
|
const form_data_1 = tslib_1.__importDefault(require("form-data"));
|
|
7
6
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
8
|
-
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
9
7
|
const promise_retry_1 = tslib_1.__importDefault(require("promise-retry"));
|
|
10
|
-
const url_1 = require("url");
|
|
11
8
|
const fetch_1 = tslib_1.__importDefault(require("./fetch"));
|
|
12
9
|
const UploadSessionMutation_1 = require("./graphql/mutations/UploadSessionMutation");
|
|
13
|
-
async function
|
|
14
|
-
const
|
|
15
|
-
(
|
|
16
|
-
|
|
17
|
-
const location = (0, nullthrows_1.default)(response.headers.get('location'), `location does not exist in response headers (make sure you're uploading to AWS S3)`);
|
|
18
|
-
const url = fixS3Url(location);
|
|
19
|
-
return { url, bucketKey: presignedPost.fields.key };
|
|
10
|
+
async function uploadFileAtPathToGCSAsync(graphqlClient, type, path, handleProgressEvent) {
|
|
11
|
+
const signedUrl = await UploadSessionMutation_1.UploadSessionMutation.createUploadSessionAsync(graphqlClient, type);
|
|
12
|
+
await uploadWithSignedUrlWithProgressAsync(path, signedUrl, handleProgressEvent);
|
|
13
|
+
return signedUrl.bucketKey;
|
|
20
14
|
}
|
|
21
|
-
exports.
|
|
15
|
+
exports.uploadFileAtPathToGCSAsync = uploadFileAtPathToGCSAsync;
|
|
22
16
|
async function uploadWithPresignedPostWithRetryAsync(file, presignedPost) {
|
|
23
17
|
return await (0, promise_retry_1.default)(async (retry) => {
|
|
24
18
|
// retry fetch errors (usually connection or DNS errors)
|
|
@@ -48,7 +42,7 @@ async function uploadWithPresignedPostWithRetryAsync(file, presignedPost) {
|
|
|
48
42
|
});
|
|
49
43
|
}
|
|
50
44
|
exports.uploadWithPresignedPostWithRetryAsync = uploadWithPresignedPostWithRetryAsync;
|
|
51
|
-
async function
|
|
45
|
+
async function uploadWithPresignedPostAsync(file, presignedPost) {
|
|
52
46
|
const fileStat = await fs_extra_1.default.stat(file);
|
|
53
47
|
const fileSize = fileStat.size;
|
|
54
48
|
const form = new form_data_1.default();
|
|
@@ -56,10 +50,6 @@ async function createPresignedPostFormDataAsync(file, presignedPost) {
|
|
|
56
50
|
form.append(fieldKey, fieldValue);
|
|
57
51
|
}
|
|
58
52
|
form.append('file', fs_extra_1.default.createReadStream(file), { knownLength: fileSize });
|
|
59
|
-
return { form, fileSize };
|
|
60
|
-
}
|
|
61
|
-
async function uploadWithPresignedPostAsync(file, presignedPost) {
|
|
62
|
-
const { form } = await createPresignedPostFormDataAsync(file, presignedPost);
|
|
63
53
|
const formHeaders = form.getHeaders();
|
|
64
54
|
return await (0, fetch_1.default)(presignedPost.url, {
|
|
65
55
|
method: 'POST',
|
|
@@ -69,18 +59,19 @@ async function uploadWithPresignedPostAsync(file, presignedPost) {
|
|
|
69
59
|
},
|
|
70
60
|
});
|
|
71
61
|
}
|
|
72
|
-
async function
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
async function uploadWithSignedUrlWithProgressAsync(file, signedUrl, handleProgressEvent) {
|
|
63
|
+
const fileStat = await fs_extra_1.default.stat(file);
|
|
64
|
+
const fileSize = fileStat.size;
|
|
65
|
+
const readStream = fs_extra_1.default.createReadStream(file);
|
|
66
|
+
const uploadPromise = (0, fetch_1.default)(signedUrl.url, {
|
|
67
|
+
method: 'PUT',
|
|
68
|
+
body: readStream,
|
|
78
69
|
headers: {
|
|
79
|
-
...
|
|
70
|
+
...signedUrl.headers,
|
|
80
71
|
},
|
|
81
72
|
});
|
|
82
73
|
let currentSize = 0;
|
|
83
|
-
|
|
74
|
+
readStream.addListener('data', (chunk) => {
|
|
84
75
|
currentSize += Buffer.byteLength(chunk);
|
|
85
76
|
handleProgressEvent({
|
|
86
77
|
progress: {
|
|
@@ -100,14 +91,3 @@ async function uploadWithPresignedPostWithProgressAsync(file, presignedPost, han
|
|
|
100
91
|
throw error;
|
|
101
92
|
}
|
|
102
93
|
}
|
|
103
|
-
/**
|
|
104
|
-
* S3 returns broken URLs, sth like:
|
|
105
|
-
* https://submission-service-archives.s3.amazonaws.com/production%2Fdc98ca84-1473-4cb3-ae81-8c7b291cb27e%2F4424aa95-b985-4e2f-8755-9507b1037c1c
|
|
106
|
-
* This function replaces %2F with /.
|
|
107
|
-
*/
|
|
108
|
-
function fixS3Url(archiveUrl) {
|
|
109
|
-
const parsed = new url_1.URL(archiveUrl);
|
|
110
|
-
parsed.pathname = decodeURIComponent(parsed.pathname);
|
|
111
|
-
return parsed.toString();
|
|
112
|
-
}
|
|
113
|
-
exports.fixS3Url = fixS3Url;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
1
|
+
import { AppPlatform } from '../graphql/generated';
|
|
2
|
+
export declare function downloadAndMaybeExtractAppAsync(url: string, platform: AppPlatform): Promise<string>;
|
|
3
|
+
export declare function extractAppFromLocalArchiveAsync(appArchivePath: string, platform: AppPlatform): Promise<string>;
|
package/build/utils/download.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractAppFromLocalArchiveAsync = exports.
|
|
3
|
+
exports.extractAppFromLocalArchiveAsync = exports.downloadAndMaybeExtractAppAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
|
|
6
|
-
const cli_progress_1 = tslib_1.__importDefault(require("cli-progress"));
|
|
7
6
|
const fast_glob_1 = tslib_1.__importDefault(require("fast-glob"));
|
|
8
7
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
8
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
@@ -12,11 +11,15 @@ const tar_1 = require("tar");
|
|
|
12
11
|
const util_1 = require("util");
|
|
13
12
|
const uuid_1 = require("uuid");
|
|
14
13
|
const fetch_1 = tslib_1.__importDefault(require("../fetch"));
|
|
14
|
+
const generated_1 = require("../graphql/generated");
|
|
15
15
|
const log_1 = tslib_1.__importDefault(require("../log"));
|
|
16
|
+
const files_1 = require("./files");
|
|
16
17
|
const paths_1 = require("./paths");
|
|
18
|
+
const progress_1 = require("./progress");
|
|
17
19
|
const pipeline = (0, util_1.promisify)(stream_1.Stream.pipeline);
|
|
20
|
+
let didProgressBarFinish = false;
|
|
18
21
|
function wrapFetchWithProgress() {
|
|
19
|
-
return async (url, init,
|
|
22
|
+
return async (url, init, progressHandler) => {
|
|
20
23
|
const response = await (0, fetch_1.default)(url, init);
|
|
21
24
|
if (response.ok) {
|
|
22
25
|
const totalDownloadSize = response.headers.get('Content-Length');
|
|
@@ -31,7 +34,15 @@ function wrapFetchWithProgress() {
|
|
|
31
34
|
length += chunkLength;
|
|
32
35
|
}
|
|
33
36
|
const progress = length / total;
|
|
34
|
-
|
|
37
|
+
if (!didProgressBarFinish) {
|
|
38
|
+
progressHandler({
|
|
39
|
+
progress: { total, percent: progress, transferred: length },
|
|
40
|
+
isComplete: total === length,
|
|
41
|
+
});
|
|
42
|
+
if (total === length) {
|
|
43
|
+
didProgressBarFinish = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
35
46
|
};
|
|
36
47
|
response.body.on('data', chunk => {
|
|
37
48
|
onProgress(chunk.length);
|
|
@@ -43,46 +54,42 @@ function wrapFetchWithProgress() {
|
|
|
43
54
|
return response;
|
|
44
55
|
};
|
|
45
56
|
}
|
|
46
|
-
async function
|
|
57
|
+
async function downloadFileWithProgressTrackerAsync(url, outputPath, progressTrackerMessage, progressTrackerCompletedMessage) {
|
|
47
58
|
log_1.default.newLine();
|
|
48
|
-
log_1.default.log(infoMessage ? infoMessage : `Downloading file from ${url}...`);
|
|
49
|
-
const downloadProgressBar = new cli_progress_1.default.SingleBar({ format: '|{bar}|' }, cli_progress_1.default.Presets.rect);
|
|
50
|
-
let downloadProgressBarStarted = false;
|
|
51
59
|
const response = await wrapFetchWithProgress()(url, {
|
|
52
60
|
timeout: 1000 * 60 * 5, // 5 minutes
|
|
53
|
-
}, (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
else if (loaded < total) {
|
|
59
|
-
downloadProgressBar.update(loaded);
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
downloadProgressBar.stop();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
61
|
+
}, (0, progress_1.createProgressTracker)({
|
|
62
|
+
message: progressTrackerMessage,
|
|
63
|
+
completedMessage: progressTrackerCompletedMessage,
|
|
64
|
+
}));
|
|
65
65
|
if (!response.ok) {
|
|
66
66
|
throw new Error(`Failed to download file from ${url}`);
|
|
67
67
|
}
|
|
68
68
|
await pipeline(response.body, fs_1.default.createWriteStream(outputPath));
|
|
69
69
|
}
|
|
70
|
-
async function
|
|
70
|
+
async function downloadAndMaybeExtractAppAsync(url, platform) {
|
|
71
71
|
const outputDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
|
|
72
72
|
await fs_1.default.promises.mkdir(outputDir, { recursive: true });
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
if (url.endsWith('apk')) {
|
|
74
|
+
const apkFilePath = path_1.default.join(outputDir, `${(0, uuid_1.v4)()}.apk`);
|
|
75
|
+
await downloadFileWithProgressTrackerAsync(url, apkFilePath, (ratio, total) => `Downloading app (${(0, files_1.formatBytes)(total * ratio)} / ${(0, files_1.formatBytes)(total)})`, 'Successfully downloaded app');
|
|
76
|
+
return apkFilePath;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const tmpArchivePathDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
|
|
80
|
+
await fs_1.default.promises.mkdir(tmpArchivePathDir, { recursive: true });
|
|
81
|
+
const tmpArchivePath = path_1.default.join(tmpArchivePathDir, `${(0, uuid_1.v4)()}.tar.gz`);
|
|
82
|
+
await downloadFileWithProgressTrackerAsync(url, tmpArchivePath, (ratio, total) => `Downloading app archive (${(0, files_1.formatBytes)(total * ratio)} / ${(0, files_1.formatBytes)(total)})`, 'Successfully downloaded app archive');
|
|
83
|
+
await tarExtractAsync(tmpArchivePath, outputDir);
|
|
84
|
+
return await getAppPathAsync(outputDir, platform === generated_1.AppPlatform.Ios ? 'app' : 'apk');
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
|
-
exports.
|
|
81
|
-
async function extractAppFromLocalArchiveAsync(appArchivePath,
|
|
87
|
+
exports.downloadAndMaybeExtractAppAsync = downloadAndMaybeExtractAppAsync;
|
|
88
|
+
async function extractAppFromLocalArchiveAsync(appArchivePath, platform) {
|
|
82
89
|
const outputDir = path_1.default.join((0, paths_1.getTmpDirectory)(), (0, uuid_1.v4)());
|
|
83
90
|
await fs_1.default.promises.mkdir(outputDir, { recursive: true });
|
|
84
91
|
await tarExtractAsync(appArchivePath, outputDir);
|
|
85
|
-
return await getAppPathAsync(outputDir,
|
|
92
|
+
return await getAppPathAsync(outputDir, platform === generated_1.AppPlatform.Android ? 'apk' : 'app');
|
|
86
93
|
}
|
|
87
94
|
exports.extractAppFromLocalArchiveAsync = extractAppFromLocalArchiveAsync;
|
|
88
95
|
async function getAppPathAsync(outputDir, applicationExtension) {
|
|
@@ -10,6 +10,6 @@ export declare type ProgressHandler = (props: {
|
|
|
10
10
|
}) => void;
|
|
11
11
|
export declare function createProgressTracker({ total, message, completedMessage, }: {
|
|
12
12
|
total?: number;
|
|
13
|
-
message: string | ((ratio: number) => string);
|
|
13
|
+
message: string | ((ratio: number, total: number) => string);
|
|
14
14
|
completedMessage: string | ((duration: string) => string);
|
|
15
15
|
}): ProgressHandler;
|
package/build/utils/progress.js
CHANGED
|
@@ -11,16 +11,18 @@ function createProgressTracker({ total, message, completedMessage, }) {
|
|
|
11
11
|
let transferredSoFar = 0;
|
|
12
12
|
let current = 0;
|
|
13
13
|
const timerLabel = String(Date.now());
|
|
14
|
-
const getMessage = (v) => {
|
|
14
|
+
const getMessage = (v, total) => {
|
|
15
15
|
const ratio = Math.min(Math.max(v, 0), 1);
|
|
16
16
|
const percent = Math.floor(ratio * 100);
|
|
17
|
-
return typeof message === 'string'
|
|
17
|
+
return typeof message === 'string'
|
|
18
|
+
? `${message} ${percent.toFixed(0)}%`
|
|
19
|
+
: message(ratio, total);
|
|
18
20
|
};
|
|
19
21
|
return ({ progress, isComplete, error }) => {
|
|
20
22
|
if (progress) {
|
|
21
23
|
if (!bar && (progress.total !== undefined || total !== undefined)) {
|
|
22
24
|
calcTotal = (total !== null && total !== void 0 ? total : progress.total);
|
|
23
|
-
bar = (0, ora_1.ora)(getMessage(0)).start();
|
|
25
|
+
bar = (0, ora_1.ora)(getMessage(0, calcTotal)).start();
|
|
24
26
|
(0, timer_1.startTimer)(timerLabel);
|
|
25
27
|
}
|
|
26
28
|
if (progress.total) {
|
|
@@ -35,7 +37,7 @@ function createProgressTracker({ total, message, completedMessage, }) {
|
|
|
35
37
|
current += progress.transferred - transferredSoFar;
|
|
36
38
|
percentage = current / calcTotal;
|
|
37
39
|
}
|
|
38
|
-
bar.text = getMessage(percentage);
|
|
40
|
+
bar.text = getMessage(percentage, calcTotal);
|
|
39
41
|
}
|
|
40
42
|
transferredSoFar = progress.transferred;
|
|
41
43
|
}
|