1import { Command } from '@expo/commander';
2import chalk from 'chalk';
3import { hashElement } from 'folder-hash';
4import path from 'path';
5import process from 'process';
6
7import { podInstallAsync } from '../CocoaPods';
8import { EXPO_DIR } from '../Constants';
9import logger from '../Logger';
10
11type ActionOptions = {
12  force: boolean;
13  verbose: boolean;
14};
15
16async function action(options: ActionOptions) {
17  if (process.platform !== 'darwin') {
18    throw new Error('This command is not supported on this platform.');
19  }
20
21  for (const relativeProjectPath of ['ios', 'apps/bare-expo/ios']) {
22    const absoluteProjectPath = path.join(EXPO_DIR, relativeProjectPath);
23    const podfileLockHash = await md5(path.join(absoluteProjectPath, 'Podfile.lock'));
24    const manifestLockHash = await md5(path.join(absoluteProjectPath, 'Pods/Manifest.lock'));
25
26    if (!manifestLockHash || podfileLockHash !== manifestLockHash || options.force) {
27      logger.info(`�� Installing pods in ${chalk.yellow(relativeProjectPath)} directory`);
28
29      try {
30        await podInstallAsync(absoluteProjectPath, {
31          stdio: options.verbose ? 'inherit' : 'pipe',
32        });
33      } catch (e) {
34        if (!options.verbose) {
35          // In this case, the output has already been printed.
36          logger.error(`�� Installation failed with output: ${e.output}`);
37        }
38        return;
39      }
40    }
41  }
42  logger.success('�� All iOS projects have up-to-date local pods');
43}
44
45async function md5(path: string): Promise<string | null> {
46  try {
47    const { hash } = await hashElement(path, {
48      algo: 'md5',
49      encoding: 'hex',
50      files: {
51        ignoreBasename: true,
52        ignoreRootName: true,
53      },
54    });
55    return hash;
56  } catch {
57    return null;
58  }
59}
60
61export default (program: Command) => {
62  program
63    .command('pod-install')
64    .alias('pods')
65    .description('Installs pods in the directories where they are not in-sync')
66    .option('-f, --force', 'Whether to force installing pods in all projects.', false)
67    .option('-v, --verbose', 'Whether to inherit logs from `pod install` command.', false)
68    .asyncAction(action);
69};
70