"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _fsExtra() {
  const data = _interopRequireDefault(require("fs-extra"));

  _fsExtra = function () {
    return data;
  };

  return data;
}

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

function _untildify() {
  const data = _interopRequireDefault(require("untildify"));

  _untildify = function () {
    return data;
  };

  return data;
}

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 _get() {
  const data = _interopRequireDefault(require("lodash/get"));

  _get = function () {
    return data;
  };

  return data;
}

function _log() {
  const data = _interopRequireDefault(require("../../log"));

  _log = function () {
    return data;
  };

  return data;
}

function _BuildError() {
  const data = _interopRequireDefault(require("./BuildError"));

  _BuildError = function () {
    return data;
  };

  return data;
}

function _BaseBuilder() {
  const data = _interopRequireDefault(require("./BaseBuilder"));

  _BaseBuilder = function () {
    return data;
  };

  return data;
}

function _prompt() {
  const data = _interopRequireDefault(require("../../prompt"));

  _prompt = function () {
    return data;
  };

  return data;
}

function utils() {
  const data = _interopRequireWildcard(require("./utils"));

  utils = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("./constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _credentials() {
  const data = require("../../credentials");

  _credentials = function () {
    return data;
  };

  return data;
}

function _AndroidCredentials() {
  const data = require("../../credentials/views/AndroidCredentials");

  _AndroidCredentials = 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 }; }

const {
  ANDROID
} = _constants().PLATFORMS;

class AndroidBuilder extends _BaseBuilder().default {
  async run() {
    // Validate project
    await this.validateProject(); // Check SplashScreen images sizes

    await _xdl().Android.checkSplashScreenImages(this.projectDir); // Check the status of any current builds

    await this.checkForBuildInProgress(); // Check for existing credentials, collect any missing credentials, and validate them

    await this.collectAndValidateCredentials(); // Publish the current experience, if necessary

    let publishedExpIds = this.options.publicUrl ? undefined : await this.ensureReleaseExists();

    if (!this.options.publicUrl) {
      await this.checkStatusBeforeBuild();
    } // Initiate a build


    await this.build(publishedExpIds);
  }

  async validateProject() {
    await utils().checkIfSdkIsSupported(this.manifest.sdkVersion, ANDROID);

    if (!(0, _get().default)(this.manifest, 'android.package')) {
      throw new (_BuildError().default)(`Your project must have an Android package set in app.json
See https://docs.expo.io/versions/latest/distribution/building-standalone-apps/#2-configure-appjson`);
    }

    const androidPackage = (0, _get().default)(this.manifest, 'android.package');

    if (!androidPackage) {
      throw new (_BuildError().default)('Your project must have an Android package set in app.json.');
    }

    if (!/^[a-zA-Z][a-zA-Z0-9_]*(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(androidPackage)) {
      throw new (_BuildError().default)("Invalid format of Android package name (only alphanumeric characters, '.' and '_' are allowed, and each '.' must be followed by a letter)");
    }
  }

  async _clearCredentials() {
    const credentialMetadata = await _xdl().Credentials.getCredentialMetadataAsync(this.projectDir, ANDROID);

    _log().default.warn(`Clearing your Android build credentials from our build servers is a ${_chalk().default.red('PERMANENT and IRREVERSIBLE action.')}`);

    _log().default.warn('Android keystores must be identical to the one previously used to submit your app to the Google Play Store.');

    _log().default.warn('Please read https://docs.expo.io/versions/latest/distribution/building-standalone-apps/#if-you-choose-to-build-for-android for more info before proceeding.');

    _log().default.warn("We'll store a backup of your Android keystore in this directory in case you decide to delete it from our servers.");

    let questions = [{
      type: 'confirm',
      name: 'confirm',
      message: 'Permanently delete the Android build credentials from our servers?'
    }];
    const answers = await (0, _prompt().default)(questions);

    if (answers.confirm) {
      (0, _log().default)('Backing up your Android keystore now...');
      const ctx = new (_credentials().Context)();
      await ctx.init(this.projectDir);

      const backupKeystoreOutputPath = _path().default.resolve(this.projectDir, `${ctx.manifest.slug}.jks`);

      const view = new (_AndroidCredentials().DownloadKeystore)(ctx.manifest.slug);
      await view.fetch(ctx);
      await view.save(ctx, backupKeystoreOutputPath, true);
      await _xdl().Credentials.removeCredentialsForPlatform(ANDROID, credentialMetadata);

      _log().default.warn('Removed existing credentials from Expo servers');
    }
  }

  async collectAndValidateCredentials() {
    const credentialMetadata = await _xdl().Credentials.getCredentialMetadataAsync(this.projectDir, ANDROID);
    const credentialsExist = await _xdl().Credentials.credentialsExistForPlatformAsync(credentialMetadata);

    if (this.checkEnv()) {
      await this.collectAndValidateCredentialsFromCI(credentialMetadata);
    } else if (this.options.clearCredentials || !credentialsExist) {
      console.log('');
      const questions = [{
        type: 'rawlist',
        name: 'uploadKeystore',
        message: `Would you like to upload a keystore or have us generate one for you?\nIf you don't know what this means, let us handle it! :)\n`,
        choices: [{
          name: 'Let Expo handle the process!',
          value: false
        }, {
          name: 'I want to upload my own keystore!',
          value: true
        }]
      }, {
        type: 'input',
        name: 'keystorePath',
        message: `Path to keystore:`,
        validate: async keystorePath => {
          try {
            const keystorePathStats = await _fsExtra().default.stat(keystorePath);
            return keystorePathStats.isFile();
          } catch (e) {
            // file does not exist
            console.log('\nFile does not exist.');
            return false;
          }
        },
        filter: keystorePath => {
          keystorePath = (0, _untildify().default)(keystorePath);

          if (!_path().default.isAbsolute(keystorePath)) {
            keystorePath = _path().default.resolve(keystorePath);
          }

          return keystorePath;
        },
        when: answers => answers.uploadKeystore
      }, {
        type: 'input',
        name: 'keystoreAlias',
        message: `Keystore Alias:`,
        validate: val => val !== '',
        when: answers => answers.uploadKeystore
      }, {
        type: 'password',
        name: 'keystorePassword',
        message: `Keystore Password:`,
        validate: val => val !== '',
        when: answers => answers.uploadKeystore
      }, {
        type: 'password',
        name: 'keyPassword',
        message: `Key Password:`,
        validate: (password, answers) => {
          if (password === '') {
            return false;
          } // Todo validate keystore passwords


          return true;
        },
        when: answers => answers.uploadKeystore
      }];
      const answers = await (0, _prompt().default)(questions);

      if (!answers.uploadKeystore) {
        if (this.options.clearCredentials && credentialsExist) {
          await this._clearCredentials();
        } // just continue

      } else {
        const {
          keystorePath,
          keystoreAlias,
          keystorePassword,
          keyPassword
        } = answers; // read the keystore

        const keystoreData = await _fsExtra().default.readFile(keystorePath);
        const credentials = {
          keystore: keystoreData.toString('base64'),
          keystoreAlias,
          keystorePassword,
          keyPassword
        };
        await _xdl().Credentials.updateCredentialsForPlatform(ANDROID, credentials, [], credentialMetadata);
      }
    }
  }

  checkEnv() {
    return this.options.keystorePath && this.options.keystoreAlias && process.env.EXPO_ANDROID_KEYSTORE_PASSWORD && process.env.EXPO_ANDROID_KEY_PASSWORD;
  }

  async collectAndValidateCredentialsFromCI(credentialMetadata) {
    const credentials = {
      keystore: (await _fsExtra().default.readFile(this.options.keystorePath)).toString('base64'),
      keystoreAlias: this.options.keystoreAlias,
      keystorePassword: process.env.EXPO_ANDROID_KEYSTORE_PASSWORD,
      keyPassword: process.env.EXPO_ANDROID_KEY_PASSWORD
    };
    await _xdl().Credentials.updateCredentialsForPlatform(ANDROID, credentials, [], credentialMetadata);
  }

  platform() {
    return ANDROID;
  }

}

exports.default = AndroidBuilder;
//# sourceMappingURL=../../__sourcemaps__/commands/build/AndroidBuilder.js.map