1import JsonFile from '@expo/json-file'; 2import spawnAsync from '@expo/spawn-async'; 3import { ExponentTools, Project, UrlUtils } from '@expo/xdl'; 4import chalk from 'chalk'; 5import ip from 'ip'; 6import os from 'os'; 7import path from 'path'; 8import request from 'request-promise-native'; 9import { v4 as uuidv4 } from 'uuid'; 10 11import { getExpoRepositoryRootDir } from '../Directories'; 12import { getHomeSDKVersionAsync } from '../ProjectVersions'; 13 14interface Manifest { 15 id: string; 16 name: string; 17} 18 19// some files are absent on turtle builders and we don't want log errors there 20const isTurtle = !!process.env.TURTLE_WORKING_DIR_PATH; 21 22const EXPO_DIR = getExpoRepositoryRootDir(); 23 24async function getManifestAsync( 25 url: string, 26 platform: string, 27 sdkVersion: string | null 28): Promise<Manifest> { 29 const headers = { 30 'Exponent-Platform': platform, 31 Accept: 'application/expo+json,application/json', 32 }; 33 if (sdkVersion) { 34 headers['Exponent-SDK-Version'] = sdkVersion; 35 } 36 return await ExponentTools.getManifestAsync(url, headers, { 37 logger: { 38 log: () => {}, 39 error: () => {}, 40 info: () => {}, 41 }, 42 }); 43} 44 45async function getSavedDevHomeUrlAsync(): Promise<string> { 46 const devHomeConfig = await new JsonFile(path.join(EXPO_DIR, 'dev-home-config.json')).readAsync(); 47 return devHomeConfig.url as string; 48} 49 50function kernelManifestObjectToJson(manifest) { 51 if (!manifest.id) { 52 // hack for now because unsigned manifest won't have an id 53 manifest.id = '@exponent/home'; 54 } 55 manifest.sdkVersion = 'UNVERSIONED'; 56 return JSON.stringify(manifest); 57} 58 59export default { 60 async TEST_APP_URI() { 61 if (process.env.TEST_SUITE_URI) { 62 return process.env.TEST_SUITE_URI; 63 } else { 64 try { 65 let testSuitePath = path.join(__dirname, '..', 'apps', 'test-suite'); 66 let status = await Project.currentStatus(testSuitePath); 67 if (status === 'running') { 68 return await UrlUtils.constructManifestUrlAsync(testSuitePath); 69 } else { 70 return ''; 71 } 72 } catch (e) { 73 return ''; 74 } 75 } 76 }, 77 78 async TEST_CONFIG() { 79 if (process.env.TEST_CONFIG) { 80 return process.env.TEST_CONFIG; 81 } else { 82 return ''; 83 } 84 }, 85 86 async TEST_SERVER_URL() { 87 let url = 'TODO'; 88 89 try { 90 let lanAddress = ip.address(); 91 let localServerUrl = `http://${lanAddress}:3013`; 92 let result = await request.get({ 93 url: `${localServerUrl}/expo-test-server-status`, 94 timeout: 500, // ms 95 resolveWithFullResponse: true, 96 }); 97 if (result.body === 'running!') { 98 url = localServerUrl; 99 } 100 } catch (e) {} 101 102 return url; 103 }, 104 105 async TEST_RUN_ID() { 106 return process.env.UNIVERSE_BUILD_ID || uuidv4(); 107 }, 108 109 async BUILD_MACHINE_LOCAL_HOSTNAME() { 110 if (process.env.SHELL_APP_BUILDER) { 111 return ''; 112 } 113 114 try { 115 let result = await spawnAsync('scutil', ['--get', 'LocalHostName']); 116 return `${result.stdout.trim()}.local`; 117 } catch (e) { 118 if (e.code !== 'ENOENT') { 119 console.error(e.stack); 120 } 121 return os.hostname(); 122 } 123 }, 124 125 async DEV_PUBLISHED_KERNEL_MANIFEST(platform) { 126 let manifest, savedDevHomeUrl; 127 try { 128 savedDevHomeUrl = await getSavedDevHomeUrlAsync(); 129 const sdkVersion = await this.TEMPORARY_SDK_VERSION(); 130 131 manifest = await getManifestAsync(savedDevHomeUrl, platform, sdkVersion); 132 } catch (e) { 133 const msg = `Unable to download manifest from ${savedDevHomeUrl}: ${e.message}`; 134 console[isTurtle ? 'debug' : 'error'](msg); 135 return ''; 136 } 137 138 return kernelManifestObjectToJson(manifest); 139 }, 140 141 async BUILD_MACHINE_KERNEL_MANIFEST(platform) { 142 if (process.env.SHELL_APP_BUILDER) { 143 return ''; 144 } 145 146 const pathToHome = 'home'; 147 const url = await UrlUtils.constructManifestUrlAsync(path.join(EXPO_DIR, pathToHome)); 148 149 try { 150 const manifest = await getManifestAsync(url, platform, null); 151 152 if (manifest.name !== 'expo-home') { 153 console.log( 154 `Manifest at ${url} is not expo-home; using published kernel manifest instead...` 155 ); 156 return ''; 157 } 158 return kernelManifestObjectToJson(manifest); 159 } catch (e) { 160 console.error( 161 chalk.red( 162 `Unable to generate manifest from ${chalk.cyan( 163 pathToHome 164 )}: Failed to fetch manifest from ${chalk.cyan(url)}` 165 ) 166 ); 167 return ''; 168 } 169 }, 170 171 async TEMPORARY_SDK_VERSION(): Promise<string> { 172 return await getHomeSDKVersionAsync(); 173 }, 174 175 INITIAL_URL() { 176 return null; 177 }, 178}; 179