1import { getExpoHomeDirectory } from '@expo/config/build/getUserState';
2import path from 'path';
3import ProgressBar from 'progress';
4
5import { getVersionsAsync } from '../api/getVersions';
6import * as Log from '../log';
7import { downloadAppAsync } from './downloadAppAsync';
8import { profile } from './profile';
9import { setProgressBar } from './progress';
10
11const platformSettings: Record<
12  string,
13  {
14    shouldExtractResults: boolean;
15    versionsKey: keyof Awaited<ReturnType<typeof getVersionsAsync>>;
16    getFilePath: (filename: string) => string;
17  }
18> = {
19  ios: {
20    versionsKey: 'iosUrl',
21    getFilePath: (filename) =>
22      path.join(getExpoHomeDirectory(), 'ios-simulator-app-cache', `${filename}.app`),
23    shouldExtractResults: true,
24  },
25  android: {
26    versionsKey: 'androidUrl',
27    getFilePath: (filename) =>
28      path.join(getExpoHomeDirectory(), 'android-apk-cache', `${filename}.apk`),
29    shouldExtractResults: false,
30  },
31};
32
33/** Download the Expo Go app from the Expo servers (if only it was this easy for every app). */
34export async function downloadExpoGoAsync(
35  platform: keyof typeof platformSettings,
36  {
37    url,
38  }: {
39    url?: string;
40  } = {}
41): Promise<string> {
42  const { getFilePath, versionsKey, shouldExtractResults } = platformSettings[platform];
43
44  const bar = new ProgressBar('Downloading the Expo Go app [:bar] :percent :etas', {
45    width: 64,
46    total: 100,
47    clear: true,
48    complete: '=',
49    incomplete: ' ',
50  });
51  // TODO: Auto track progress
52  setProgressBar(bar);
53
54  if (!url) {
55    const versions = await getVersionsAsync();
56    url = versions[versionsKey] as string;
57  }
58
59  const filename = path.parse(url).name;
60
61  try {
62    const outputPath = getFilePath(filename);
63    Log.debug(`Downloading Expo Go from "${url}" to "${outputPath}".`);
64    Log.debug(
65      `The requested copy of Expo Go might already be cached in: "${getExpoHomeDirectory()}". You can disable the cache with EXPO_NO_CACHE=1`
66    );
67    await profile(downloadAppAsync)({
68      url,
69      // Save all encrypted cache data to `~/.expo/expo-go`
70      cacheDirectory: 'expo-go',
71      outputPath,
72      extract: shouldExtractResults,
73      onProgress({ progress }) {
74        if (bar) {
75          bar.tick(1, progress);
76        }
77      },
78    });
79    return outputPath;
80  } finally {
81    bar.terminate();
82    setProgressBar(null);
83  }
84}
85