"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.buildAndCopyArtifactAsync = buildAndCopyArtifactAsync;
exports.configureAndCopyArchiveAsync = configureAndCopyArchiveAsync;
exports.createTurtleWorkspaceAsync = createTurtleWorkspaceAsync;
exports.EXPONENT_APP = exports.EXPOKIT_APP = 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 _rimraf() {
  const data = _interopRequireDefault(require("rimraf"));

  _rimraf = function () {
    return data;
  };

  return data;
}

function _get() {
  const data = _interopRequireDefault(require("lodash/get"));

  _get = function () {
    return data;
  };

  return data;
}

function _has() {
  const data = _interopRequireDefault(require("lodash/has"));

  _has = function () {
    return data;
  };

  return data;
}

function _pascalCase() {
  const data = _interopRequireDefault(require("pascal-case"));

  _pascalCase = function () {
    return data;
  };

  return data;
}

function _ExponentTools() {
  const data = require("./ExponentTools");

  _ExponentTools = function () {
    return data;
  };

  return data;
}

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

  IosNSBundle = function () {
    return data;
  };

  return data;
}

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

  IosWorkspace = function () {
    return data;
  };

  return data;
}

function _StandaloneBuildFlags() {
  const data = _interopRequireDefault(require("./StandaloneBuildFlags"));

  _StandaloneBuildFlags = function () {
    return data;
  };

  return data;
}

function _StandaloneContext() {
  const data = _interopRequireDefault(require("./StandaloneContext"));

  _StandaloneContext = function () {
    return data;
  };

  return data;
}

function _Logger() {
  const data = _interopRequireDefault(require("./Logger"));

  _Logger = 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 EXPOKIT_APP = 'ExpoKitApp';
exports.EXPOKIT_APP = EXPOKIT_APP;
const EXPONENT_APP = 'Exponent';
exports.EXPONENT_APP = EXPONENT_APP;

function _validateCLIArgs(args) {
  args.type = args.type || 'archive';
  args.configuration = args.configuration || 'Release';
  args.verbose = args.verbose || false;
  args.testEnvironment = args.testEnvironment || 'none';

  switch (args.type) {
    case 'simulator':
      {
        if (args.configuration !== 'Debug' && args.configuration !== 'Release') {
          throw new Error(`Unsupported build configuration ${args.configuration}`);
        }

        break;
      }

    case 'archive':
      {
        if (args.configuration !== 'Release') {
          throw new Error('Release is the only supported configuration when archiving');
        }

        break;
      }

    case 'client':
      break;

    default:
      {
        throw new Error(`Unsupported build type ${args.type}`);
      }
  }

  switch (args.action) {
    case 'configure':
      {
        if (args.type === 'client') {
          break;
        }

        if (!args.url) {
          throw new Error('Must run with `--url MANIFEST_URL`');
        }

        if (!args.sdkVersion) {
          throw new Error('Must run with `--sdkVersion SDK_VERSION`');
        }

        if (!args.archivePath) {
          throw new Error('Need to provide --archivePath <path to existing archive for configuration>');
        }

        if (args.testEnvironment !== 'local' && args.testEnvironment !== 'ci' && args.testEnvironment !== 'none') {
          throw new Error(`Unsupported test environment ${args.testEnvironment}`);
        }

        break;
      }

    case 'build':
      {
        break;
      }

    case 'create-workspace':
      {
        break;
      }

    default:
      {
        throw new Error(`Unsupported build action ${args.action}`);
      }
  }

  return args;
}
/**
 *  Build the iOS workspace at the given path.
 *  @return the path to the resulting build artifact
 */


async function _buildAsync(projectName, workspacePath, configuration, type, relativeBuildDestination, verbose, useModernBuildSystem = false) {
  const modernBuildSystemFragment = `-UseModernBuildSystem=${useModernBuildSystem ? 'YES' : 'NO'}`;
  const buildDest = `${relativeBuildDestination}-${type}`;
  let buildCmd = `set -o pipefail && xcodebuild -workspace ${projectName}.xcworkspace -scheme ${projectName} -configuration ${configuration} -derivedDataPath ${buildDest} ${modernBuildSystemFragment}`,
      pathToArtifact;

  if (type === 'simulator') {
    buildCmd += ` -sdk iphonesimulator CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO | xcpretty`;
    pathToArtifact = _path().default.join(buildDest, 'Build', 'Products', `${configuration}-iphonesimulator`, `${projectName}.app`);
  } else if (type === 'archive') {
    buildCmd += ` -sdk iphoneos -destination generic/platform=iOS archive -archivePath ${buildDest}/${projectName}.xcarchive CODE_SIGNING_ALLOWED=NO | xcpretty`;
    pathToArtifact = _path().default.join(buildDest, `${projectName}.xcarchive`);
  } else {
    throw new Error(`Unsupported build type: ${type}`);
  }

  _Logger().default.info(`Building iOS workspace at ${workspacePath} to ${buildDest}:\n`);

  _Logger().default.info(buildCmd);

  if (!verbose) {
    _Logger().default.info('\nxcodebuild is running. Logging errors only. To see full output, use --verbose 1...');
  }

  await (0, _ExponentTools().spawnAsyncThrowError)(buildCmd, null, {
    // only stderr
    stdio: verbose ? 'inherit' : ['ignore', 'ignore', 'inherit'],
    cwd: workspacePath,
    shell: true
  });
  return _path().default.resolve(workspacePath, pathToArtifact);
}

async function _podInstallAsync(workspacePath, isRepoUpdateEnabled) {
  // ensure pods are clean
  const pathsToClean = [_path().default.join(workspacePath, 'Pods'), _path().default.join(workspacePath, 'Podfile.lock')];
  pathsToClean.forEach(path => {
    if (_fsExtra().default.existsSync(path)) {
      _rimraf().default.sync(path);
    }
  }); // Disable cocoapod stats to speed up the install

  const COCOAPODS_DISABLE_STATS = process.env.COCOAPODS_DISABLE_STATS;
  process.env.COCOAPODS_DISABLE_STATS = true; // install

  let cocoapodsArgs = ['install'];

  if (isRepoUpdateEnabled) {
    cocoapodsArgs.push('--repo-update');
  }

  _Logger().default.info('Installing iOS workspace dependencies...');

  _Logger().default.info(`pod ${cocoapodsArgs.join(' ')}`);

  try {
    await (0, _ExponentTools().spawnAsyncThrowError)('pod', cocoapodsArgs, {
      stdio: 'inherit',
      cwd: workspacePath
    });
  } finally {
    // Revert the stats to the user preference
    process.env.COCOAPODS_DISABLE_STATS = COCOAPODS_DISABLE_STATS;
  }
}
/**
 * @param workspacePath optionally provide a path for the unbuilt xcode workspace to create/use.
 * @param expoSourcePath path to expo client app sourcecode (/ios dir from expo/expo repo)
 * @param shellAppSdkVersion sdk version for shell app
 */


async function _createStandaloneContextAsync(args) {
  // right now we only ever build a single detached workspace for service contexts.
  // TODO: support multiple different pod configurations, assemble a cache of those builds.
  const expoSourcePath = args.expoSourcePath || '../ios';
  let workspaceSourcePath;

  if (args.workspacePath) {
    workspaceSourcePath = args.workspacePath;
  } else {
    workspaceSourcePath = _path().default.join(expoSourcePath, '..', 'shellAppWorkspaces', 'default', 'ios');
  }

  let {
    privateConfigFile,
    privateConfigData
  } = args;
  let privateConfig;

  if (privateConfigData) {
    privateConfig = privateConfigData;
  } else if (privateConfigFile) {
    let privateConfigContents = await _fsExtra().default.readFile(privateConfigFile, 'utf8');
    privateConfig = JSON.parse(privateConfigContents);
  }

  let manifest;

  if (args.manifest) {
    manifest = args.manifest;

    _Logger().default.withFields({
      buildPhase: 'reading manifest'
    }).info('Using manifest:', JSON.stringify(manifest));
  } else if (args.url && args.sdkVersion) {
    const {
      url,
      sdkVersion,
      releaseChannel
    } = args;
    manifest = await (0, _ExponentTools().getManifestAsync)(url, {
      'Exponent-SDK-Version': sdkVersion,
      'Exponent-Platform': 'ios',
      'Expo-Release-Channel': releaseChannel ? releaseChannel : 'default',
      Accept: 'application/expo+json,application/json'
    });
  }

  let bundleExecutable = args.type === 'client' ? EXPONENT_APP : EXPOKIT_APP;

  if ((0, _has().default)(manifest, 'ios.infoPlist.CFBundleExecutable')) {
    bundleExecutable = (0, _get().default)(manifest, 'ios.infoPlist.CFBundleExecutable');
  } else if (privateConfig && privateConfig.bundleIdentifier) {
    bundleExecutable = (0, _pascalCase().default)(privateConfig.bundleIdentifier);
  }

  const buildFlags = _StandaloneBuildFlags().default.createIos(args.configuration, {
    workspaceSourcePath,
    appleTeamId: args.appleTeamId,
    buildType: args.type,
    bundleExecutable
  });

  const context = _StandaloneContext().default.createServiceContext(expoSourcePath, args.archivePath, manifest, privateConfig, args.testEnvironment, buildFlags, args.url, args.releaseChannel, args.shellAppSdkVersion);

  return context;
}
/**
 * possible args:
 *  @param url manifest url for shell experience
 *  @param sdkVersion sdk to use when requesting the manifest
 *  @param releaseChannel channel to pull manifests from, default is 'default'
 *  @param archivePath path to existing NSBundle to configure
 *  @param privateConfigFile path to a private config file containing, e.g., private api keys
 *  @param appleTeamId Apple Developer's account Team ID
 *  @param output specify the output path of the configured archive (ie) /tmp/my-app-archive-build.xcarchive or /tmp/my-app-ios-build.tar.gz
 *  @param type type of artifact to configure (simulator or archive)
 *  @param expoSourcePath path to expo client app sourcecode (/ios dir from expo/expo repo)
 */


async function configureAndCopyArchiveAsync(args) {
  args = _validateCLIArgs(args);
  const {
    output,
    type
  } = args;
  const context = await _createStandaloneContextAsync(args);
  await IosNSBundle().configureAsync(context);

  if (output) {
    const workspaceName = type === 'client' ? EXPONENT_APP : EXPOKIT_APP;

    if (context.build.ios.bundleExecutable !== workspaceName) {
      await (0, _ExponentTools().spawnAsync)('/bin/mv', [workspaceName, context.build.ios.bundleExecutable], {
        pipeToLogger: true,
        cwd: context.data.archivePath,
        loggerFields: {
          buildPhase: 'renaming bundle executable'
        }
      });
    }

    if (type === 'simulator') {
      const archiveName = context.config.slug.replace(/[^0-9a-z_-]/gi, '_');

      const appReleasePath = _path().default.resolve(context.data.archivePath, '..');

      await (0, _ExponentTools().spawnAsync)(`mv ${workspaceName}.app ${archiveName}.app && tar -czvf ${output} ${archiveName}.app`, null, {
        stdoutOnly: true,
        pipeToLogger: true,
        loggerFields: {
          buildPhase: 'creating an archive for simulator'
        },
        cwd: appReleasePath,
        shell: true
      });
    } else if (type === 'archive' || type === 'client') {
      await (0, _ExponentTools().spawnAsync)('/bin/mv', [`${workspaceName}.xcarchive`, output], {
        pipeToLogger: true,
        cwd: _path().default.join(context.data.archivePath, '../../../..'),
        loggerFields: {
          buildPhase: 'renaming archive'
        }
      });
    }
  }

  return context.data.manifest;
}
/**
 * possible args:
 *  @param skipRepoUpdate if true, omit `--repo-update` cocoapods flag.
 */


async function _createTurtleWorkspaceAsync(context, args) {
  const {
    skipRepoUpdate
  } = args;

  if (_fsExtra().default.existsSync(context.build.ios.workspaceSourcePath)) {
    _Logger().default.info(`Removing existing workspace at ${context.build.ios.workspaceSourcePath}...`);

    try {
      _rimraf().default.sync(context.build.ios.workspaceSourcePath);
    } catch (_) {}
  }

  await IosWorkspace().createDetachedAsync(context);
  await _podInstallAsync(context.build.ios.workspaceSourcePath, !skipRepoUpdate);
}
/**
 * External-facing version can be used to create a turtle workspace without building it.
 * Probably only useful for local testing.
 *
 * @param workspacePath (optional) provide some other path to create the workspace besides the default
 * @param url (optional, with sdkVersion) url to an expo manifest, if you want the workspace to be configured automatically
 * @param sdkVersion (optional, with url) sdkVersion to an expo manifest, if you want the workspace to be configured automatically
 */


async function createTurtleWorkspaceAsync(args) {
  args = _validateCLIArgs(args);

  if (!args.workspacePath) {
    _Logger().default.info('No workspace path was provided with --workspacePath, so the default will be used.');
  }

  const context = await _createStandaloneContextAsync(args);
  await _createTurtleWorkspaceAsync(context, args);

  _Logger().default.info(`Created turtle workspace at ${context.build.ios.workspaceSourcePath}. You can open and run this in Xcode.`);

  if (context.config) {
    await IosNSBundle().configureAsync(context);

    _Logger().default.info(`The turtle workspace was configured for the url ${args.url}. To run this app with a Debug scheme, make sure to add a development url to 'EXBuildConstants.plist'.`);
  } else {
    _Logger().default.info(`You can specify --url <manifestUrl> --sdkVersion <version> to configure this workspace as a particular Expo app.\n\nBecause those arguments were omitted, the workspace has not been configured. It will compile but not run. The minimum configuration to get something running is to specify a manifest url in 'EXShell.plist' (for Release builds) or 'EXBuildConstants.plist' (for Debug builds).`);
  }
}
/**
 * possible args:
 *  @param configuration StandaloneBuildConfiguration (Debug or Release)
 *  @param verbose show all xcodebuild output (default false)
 *  @param reuseWorkspace if true, when building, assume a detached workspace already exists rather than creating a new one.
 *  @param type type of artifact to build (simulator or archive)
 *  @param shellAppSdkVersion sdk version for shell app
 */


async function buildAndCopyArtifactAsync(args) {
  args = _validateCLIArgs(args);
  const context = await _createStandaloneContextAsync(args);
  const {
    verbose,
    type,
    reuseWorkspace
  } = args;
  const {
    projectName
  } = IosWorkspace().getPaths(context);

  if (!reuseWorkspace) {
    await _createTurtleWorkspaceAsync(context, args);
  }

  const pathToArtifact = await _buildAsync(projectName, context.build.ios.workspaceSourcePath, context.build.configuration, type, _path().default.relative(context.build.ios.workspaceSourcePath, '../shellAppBase'), verbose, (0, _ExponentTools().parseSdkMajorVersion)(args.shellAppSdkVersion) > 33);

  const artifactDestPath = _path().default.join('../shellAppBase-builds', type, context.build.configuration);

  _Logger().default.info(`\nFinished building, copying artifact to ${_path().default.resolve(artifactDestPath)}...`);

  if (_fsExtra().default.existsSync(artifactDestPath)) {
    await (0, _ExponentTools().spawnAsyncThrowError)('/bin/rm', ['-rf', artifactDestPath]);
  }

  _Logger().default.info(`mkdir -p ${artifactDestPath}`);

  await (0, _ExponentTools().spawnAsyncThrowError)('/bin/mkdir', ['-p', artifactDestPath]);

  _Logger().default.info(`cp -R ${pathToArtifact} ${artifactDestPath}`);

  await (0, _ExponentTools().spawnAsyncThrowError)('/bin/cp', ['-R', pathToArtifact, artifactDestPath]);
}
//# sourceMappingURL=../__sourcemaps__/detach/IosShellApp.js.map