function parseOpts()

in lib/build.js [32:146]


function parseOpts (options, resolvedTarget, projectRoot) {
    options = options || {};
    options.argv = nopt({
        prepenv: Boolean,
        versionCode: String,
        minSdkVersion: String,
        maxSdkVersion: String,
        targetSdkVersion: String,

        // This needs to be an array since nopts will parse its entries as further options for this process
        // It will be an array of 1 string: [ "string args" ]
        gradleArg: [String, Array],

        keystore: path,
        alias: String,
        storePassword: String,
        password: String,
        keystoreType: String,
        packageType: String
    }, {}, options.argv, 0);

    // Android Studio Build method is the default
    const ret = {
        buildType: options.release ? 'release' : 'debug',
        prepEnv: options.argv.prepenv,
        arch: resolvedTarget && resolvedTarget.arch,
        extraArgs: []
    };

    if (options.argv.versionCode) { ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode); }
    if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
    if (options.argv.maxSdkVersion) { ret.extraArgs.push('-PcdvMaxSdkVersion=' + options.argv.maxSdkVersion); }
    if (options.argv.targetSdkVersion) { ret.extraArgs.push('-PcdvTargetSdkVersion=' + options.argv.targetSdkVersion); }
    if (options.argv.gradleArg) {
        const gradleArgs = parseArgsStringToArgv(options.argv.gradleArg[0]);
        ret.extraArgs = ret.extraArgs.concat(gradleArgs);
    }

    const packageArgs = {};

    if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }

    ['alias', 'storePassword', 'password', 'keystoreType', 'packageType'].forEach(function (flagName) {
        if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
    });

    const buildConfig = options.buildConfig;

    // If some values are not specified as command line arguments - use build config to supplement them.
    // Command line arguments have precedence over build config.
    if (buildConfig) {
        if (!fs.existsSync(buildConfig)) {
            throw new Error('Specified build config file does not exist: ' + buildConfig);
        }
        events.emit('log', 'Reading build config file: ' + path.resolve(buildConfig));
        const buildjson = fs.readFileSync(buildConfig, 'utf8');
        const config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
        if (config.android && config.android[ret.buildType]) {
            const androidInfo = config.android[ret.buildType];
            if (androidInfo.keystore && !packageArgs.keystore) {
                androidInfo.keystore = untildify(androidInfo.keystore);
                packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
                events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);
            }

            ['alias', 'storePassword', 'password', 'keystoreType', 'packageType'].forEach(function (key) {
                packageArgs[key] = packageArgs[key] || androidInfo[key];
            });
        }
    }

    if (packageArgs.keystore && packageArgs.alias) {
        ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
            packageArgs.password, packageArgs.keystoreType);
    }

    if (!ret.packageInfo) {
        // The following loop is to decide whether to print a warning about generating a signed archive
        // We only want to produce a warning if they are using a config property that is related to signing, but
        // missing the required properties for signing. We don't want to produce a warning if they are simply
        // using a build property that isn't related to signing, such as --packageType
        let shouldWarn = false;
        const signingKeys = ['keystore', 'alias', 'storePassword', 'password', 'keystoreType'];

        for (const key in packageArgs) {
            if (!shouldWarn && signingKeys.indexOf(key) > -1) {
                // If we enter this condition, we have a key used for signing a build,
                // but we are missing some required signing properties
                shouldWarn = true;
            }
        }

        if (shouldWarn) {
            events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
        }
    }

    if (packageArgs.packageType) {
        const VALID_PACKAGE_TYPES = [PackageType.APK, PackageType.BUNDLE];
        if (VALID_PACKAGE_TYPES.indexOf(packageArgs.packageType) === -1) {
            events.emit('warn', '"' + packageArgs.packageType + '" is an invalid packageType. Valid values are: ' + VALID_PACKAGE_TYPES.join(', ') + '\nDefaulting packageType to ' + PackageType.APK);
            ret.packageType = PackageType.APK;
        } else {
            ret.packageType = packageArgs.packageType;
        }
    } else {
        if (ret.buildType === 'release') {
            ret.packageType = PackageType.BUNDLE;
        } else {
            ret.packageType = PackageType.APK;
        }
    }

    return ret;
}