"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _xdl() {
const data = require("@expo/xdl");
_xdl = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _delayAsync() {
const data = _interopRequireDefault(require("delay-async"));
_delayAsync = function () {
return data;
};
return data;
}
function _fp() {
const data = _interopRequireDefault(require("lodash/fp"));
_fp = function () {
return data;
};
return data;
}
function _get() {
const data = _interopRequireDefault(require("lodash/get"));
_get = function () {
return data;
};
return data;
}
function _ora() {
const data = _interopRequireDefault(require("ora"));
_ora = function () {
return data;
};
return data;
}
function _semver() {
const data = _interopRequireDefault(require("semver"));
_semver = function () {
return data;
};
return data;
}
function UrlUtils() {
const data = _interopRequireWildcard(require("../utils/url"));
UrlUtils = function () {
return data;
};
return data;
}
function _log() {
const data = _interopRequireDefault(require("../../log"));
_log = function () {
return data;
};
return data;
}
function _publish() {
const data = require("../publish");
_publish = function () {
return data;
};
return data;
}
function _BuildError() {
const data = _interopRequireDefault(require("./BuildError"));
_BuildError = function () {
return data;
};
return data;
}
function _prompt() {
const data = _interopRequireDefault(require("../../prompt"));
_prompt = function () {
return data;
};
return data;
}
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const secondsToMilliseconds = seconds => seconds * 1000;
class BaseBuilder {
constructor(projectDir, options = {}) {
_defineProperty(this, "projectDir", '');
_defineProperty(this, "options", {
wait: true,
clearCredentials: false,
releaseChannel: 'default',
publish: false
});
_defineProperty(this, "manifest", {});
this.projectDir = projectDir;
this.options = options;
}
async command() {
try {
await this.prepareProjectInfo();
await this.run();
} catch (e) {
if (!(e instanceof _BuildError().default)) {
throw e;
} else {
_log().default.error(e.message);
process.exit(1);
}
}
}
async commandCheckStatus() {
try {
await this.prepareProjectInfo();
await this.checkStatus();
} catch (e) {
if (!(e instanceof _BuildError().default)) {
throw e;
} else {
_log().default.error(e.message);
process.exit(1);
}
}
}
async prepareProjectInfo() {
// always use local json to unify behaviour between regular apps and self hosted ones
const {
exp
} = await _xdl().ProjectUtils.readConfigJsonAsync(this.projectDir);
this.manifest = exp;
this.user = await _xdl().UserManager.ensureLoggedInAsync();
await this.checkProjectConfig();
}
async checkProjectConfig() {
if (this.manifest.isDetached) {
_log().default.error(`'expo build:${this.platform()}' is not supported for detached projects.`);
process.exit(1);
} // Warn user if building a project using the next deprecated SDK version
let oldestSupportedMajorVersion = await _xdl().Versions.oldestSupportedMajorVersionAsync();
if (_semver().default.major(this.manifest.sdkVersion) === oldestSupportedMajorVersion) {
let {
version
} = await _xdl().Versions.newestSdkVersionAsync();
_log().default.warn(`\nSDK${oldestSupportedMajorVersion} will be ${_chalk().default.bold('deprecated')} next! We recommend upgrading versions, ideally to the latest (SDK${_semver().default.major(version)}), so you can continue to build new binaries of your app and develop in the Expo Client.\n`);
}
}
async checkForBuildInProgress() {
(0, _log().default)('Checking if there is a build in progress...\n');
const buildStatus = await _xdl().Project.buildAsync(this.projectDir, {
mode: 'status',
platform: this.platform(),
current: true,
releaseChannel: this.options.releaseChannel,
publicUrl: this.options.publicUrl,
sdkVersion: this.manifest.sdkVersion
});
if (buildStatus.jobs && buildStatus.jobs.length) {
throw new (_BuildError().default)('Cannot start a new build, as there is already an in-progress build.');
}
}
async checkStatus(platform = 'all') {
(0, _log().default)('Fetching build history...\n');
const buildStatus = await _xdl().Project.buildAsync(this.projectDir, {
mode: 'status',
platform,
current: false,
releaseChannel: this.options.releaseChannel
});
if (buildStatus.err) {
throw new Error('Error getting current build status for this project.');
}
if (!(buildStatus.jobs && buildStatus.jobs.length)) {
(0, _log().default)('No currently active or previous builds for this project.');
return;
}
this.logBuildStatuses(buildStatus);
}
async checkStatusBeforeBuild() {
(0, _log().default)('Checking if this build already exists...\n');
const reuseStatus = await _xdl().Project.findReusableBuildAsync(this.options.releaseChannel, this.platform(), this.manifest.sdkVersion, this.manifest.slug);
if (reuseStatus.canReuse) {
_log().default.warn(`Did you know that Expo provides over-the-air updates?
Please see the docs (${_chalk().default.underline('https://docs.expo.io/versions/latest/guides/configuring-ota-updates/')}) and check if you can use them instead of building your app binaries again.`);
_log().default.warn(`There were no new changes from the last build, you can download that build from here: ${_chalk().default.underline(reuseStatus.downloadUrl)}`);
let questions = [{
type: 'confirm',
name: 'confirm',
message: 'Do you want to build app anyway?'
}];
const answers = await (0, _prompt().default)(questions);
if (!answers.confirm) {
(0, _log().default)('Stopping the build process');
process.exit(0);
}
}
}
logBuildStatuses(buildStatus) {
_log().default.raw();
(0, _log().default)('=================');
(0, _log().default)(' Builds Statuses ');
(0, _log().default)('=================\n');
buildStatus.jobs.forEach((job, i) => {
let platform, packageExtension;
if (job.platform === 'ios') {
platform = 'iOS';
packageExtension = 'IPA';
} else {
platform = 'Android';
packageExtension = 'APK';
}
(0, _log().default)(`### ${i} | ${platform} | ${UrlUtils().constructBuildLogsUrl(job.id)} ###`);
const hasPriorityBuilds = buildStatus.numberOfRemainingPriorityBuilds > 0 || buildStatus.hasUnlimitedPriorityBuilds;
const shouldShowUpgradeInfo = !hasPriorityBuilds && i === 0 && job.priority === 'normal' && buildStatus.canPurchasePriorityBuilds;
let status;
switch (job.status) {
case 'pending':
case 'sent-to-queue':
status = `Build waiting in queue...\nQueue length: ${_chalk().default.underline(UrlUtils().constructTurtleStatusUrl())}`;
if (shouldShowUpgradeInfo) {
status += `\nWant to wait less? Get priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`;
}
break;
case 'started':
status = 'Build started...';
break;
case 'in-progress':
status = 'Build in progress...';
if (shouldShowUpgradeInfo) {
status += `\nWant to wait less? Get priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`;
}
break;
case 'finished':
status = 'Build finished.';
if (shouldShowUpgradeInfo) {
status += `\nLooks like this build could have been faster.\nRead more about priority builds at ${_chalk().default.underline('https://expo.io/settings/billing')}.`;
}
break;
case 'errored':
status = 'There was an error with this build.';
if (job.id) {
status += `
When requesting support, please provide this build ID:
${job.id}
`;
}
break;
default:
status = '';
break;
}
(0, _log().default)(status);
if (job.status === 'finished') {
if (job.artifacts) {
(0, _log().default)(`${packageExtension}: ${job.artifacts.url}`);
} else {
(0, _log().default)(`Problem getting ${packageExtension} URL. Please try to build again.`);
}
}
(0, _log().default)();
});
}
async ensureReleaseExists() {
if (this.options.publish) {
const {
ids,
url,
err
} = await (0, _publish().action)(this.projectDir, { ...this.options,
platform: this.platform(),
duringBuild: true
});
if (err) {
throw new (_BuildError().default)(`No url was returned from publish. Please try again.\n${err}`);
} else if (!url || url === '') {
throw new (_BuildError().default)('No url was returned from publish. Please try again.');
}
return ids;
} else {
(0, _log().default)('Looking for releases...');
const release = await _xdl().Project.getLatestReleaseAsync(this.projectDir, {
releaseChannel: this.options.releaseChannel,
platform: this.platform()
});
if (!release) {
throw new (_BuildError().default)('No releases found. Please create one using `expo publish` first.');
}
(0, _log().default)(`Using existing release on channel "${release.channel}":\n` + `publicationId: ${release.publicationId}\n publishedTime: ${release.publishedTime}`);
return [release.publicationId];
}
}
async wait(buildId, {
timeout = 1200,
interval = 30,
publicUrl
} = {}) {
(0, _log().default)(`Waiting for build to complete. You can press Ctrl+C to exit.`);
let spinner = (0, _ora().default)().start();
let time = new Date().getTime();
const endTime = time + secondsToMilliseconds(timeout);
while (time <= endTime) {
const res = await _xdl().Project.buildAsync(this.projectDir, {
current: false,
mode: 'status',
...(publicUrl ? {
publicUrl
} : {})
});
const job = _fp().default.compose(_fp().default.head, _fp().default.filter(job => buildId && job.id === buildId), _fp().default.getOr([], 'jobs'))(res);
switch (job.status) {
case 'finished':
spinner.succeed('Build finished.');
return job;
case 'pending':
case 'sent-to-queue':
spinner.text = 'Build queued...';
break;
case 'started':
case 'in-progress':
spinner.text = 'Build in progress...';
break;
case 'errored':
spinner.fail('Build failed.');
throw new (_BuildError().default)(`Standalone build failed!`);
default:
spinner.warn('Unknown status.');
throw new (_BuildError().default)(`Unknown status: ${job.status} - aborting!`);
}
time = new Date().getTime();
await (0, _delayAsync().default)(secondsToMilliseconds(interval));
}
spinner.warn('Timed out.');
throw new (_BuildError().default)('Timeout reached! Project is taking longer than expected to finish building, aborting wait...');
}
async build(expIds) {
const {
publicUrl
} = this.options;
const platform = this.platform();
const bundleIdentifier = (0, _get().default)(this.manifest, 'ios.bundleIdentifier');
let opts = {
mode: 'create',
expIds,
platform,
releaseChannel: this.options.releaseChannel,
...(publicUrl ? {
publicUrl
} : {})
};
if (platform === 'ios') {
opts = { ...opts,
type: this.options.type,
bundleIdentifier
};
} else if (platform === 'android') {
opts = { ...opts,
type: this.options.type
};
} // call out to build api here with url
const {
id: buildId,
priority,
canPurchasePriorityBuilds
} = await _xdl().Project.buildAsync(this.projectDir, opts);
(0, _log().default)('Build started, it may take a few minutes to complete.');
(0, _log().default)(`You can check the queue length at ${_chalk().default.underline(UrlUtils().constructTurtleStatusUrl())}\n`);
if (priority === 'normal' && canPurchasePriorityBuilds) {
(0, _log().default)('You can make this faster. 🐢\nGet priority builds at: https://expo.io/settings/billing\n');
}
if (buildId) {
(0, _log().default)(`You can monitor the build at\n\n ${_chalk().default.underline(UrlUtils().constructBuildLogsUrl(buildId))}\n`);
}
if (this.options.wait) {
const waitOpts = publicUrl ? {
publicUrl
} : {};
const completedJob = await this.wait(buildId, waitOpts);
const artifactUrl = completedJob.artifactId ? UrlUtils().constructArtifactUrl(completedJob.artifactId) : completedJob.artifacts.url;
(0, _log().default)(`${_chalk().default.green('Successfully built standalone app:')} ${_chalk().default.underline(artifactUrl)}`);
} else {
(0, _log().default)('Alternatively, run `expo build:status` to monitor it from the command line.');
}
}
platform() {
return 'all';
}
}
exports.default = BaseBuilder;
//# sourceMappingURL=../../__sourcemaps__/commands/build/BaseBuilder.js.map