1eeffdb10STomasz Sapetaimport spawnAsync from '@expo/spawn-async'; 2eeffdb10STomasz Sapetaimport chalk from 'chalk'; 3eeffdb10STomasz Sapetaimport fs from 'fs-extra'; 4eeffdb10STomasz Sapetaimport inquirer from 'inquirer'; 5eeffdb10STomasz Sapetaimport path from 'path'; 6eeffdb10STomasz Sapetaimport readline from 'readline'; 7eeffdb10STomasz Sapeta 8eeffdb10STomasz Sapetaimport * as Directories from '../Directories'; 9eeffdb10STomasz Sapetaimport * as Packages from '../Packages'; 10eeffdb10STomasz Sapetaimport * as ProjectVersions from '../ProjectVersions'; 11eeffdb10STomasz Sapeta 12eeffdb10STomasz Sapetatype ActionOptions = { 13eeffdb10STomasz Sapeta sdkVersion: string; 14eeffdb10STomasz Sapeta packages?: string; 15eeffdb10STomasz Sapeta}; 16eeffdb10STomasz Sapeta 17eeffdb10STomasz Sapetatype Package = { 18eeffdb10STomasz Sapeta name: string; 19eeffdb10STomasz Sapeta sourceDir: string; 20eeffdb10STomasz Sapeta buildDirRelative: string; 21eeffdb10STomasz Sapeta}; 22eeffdb10STomasz Sapeta 23eeffdb10STomasz Sapeta// There are a few packages that we want to exclude from shell app builds; they don't follow any 24eeffdb10STomasz Sapeta// easy pattern so we just keep track of them manually here. 25eeffdb10STomasz Sapetaexport const EXCLUDED_PACKAGE_SLUGS = [ 2607f89462SEric Samelson 'expo-dev-client', 2707f89462SEric Samelson 'expo-dev-launcher', 28eeffdb10STomasz Sapeta 'expo-dev-menu', 29eeffdb10STomasz Sapeta 'expo-dev-menu-interface', 30eeffdb10STomasz Sapeta 'expo-module-template', 31e229380eSŁukasz Kosmaty 'expo-modules-test-core', 320b794d50SŁukasz Kosmaty 'unimodules-core', 330b794d50SŁukasz Kosmaty 'unimodules-react-native-adapter', 34eeffdb10STomasz Sapeta]; 35eeffdb10STomasz Sapeta 36eeffdb10STomasz Sapetaconst EXPO_ROOT_DIR = Directories.getExpoRepositoryRootDir(); 37eeffdb10STomasz Sapetaconst ANDROID_DIR = Directories.getAndroidDir(); 38eeffdb10STomasz Sapeta 39eeffdb10STomasz Sapetaconst REACT_ANDROID_PKG = { 40eeffdb10STomasz Sapeta name: 'ReactAndroid', 41eeffdb10STomasz Sapeta sourceDir: path.join(ANDROID_DIR, 'ReactAndroid'), 42eeffdb10STomasz Sapeta buildDirRelative: path.join('com', 'facebook', 'react'), 43eeffdb10STomasz Sapeta}; 44eeffdb10STomasz Sapetaconst EXPOVIEW_PKG = { 45eeffdb10STomasz Sapeta name: 'expoview', 46eeffdb10STomasz Sapeta sourceDir: path.join(ANDROID_DIR, 'expoview'), 47eeffdb10STomasz Sapeta buildDirRelative: path.join('host', 'exp', 'exponent', 'expoview'), 48eeffdb10STomasz Sapeta}; 49eeffdb10STomasz Sapeta 50eeffdb10STomasz Sapetaasync function _findUnimodules(pkgDir: string): Promise<Package[]> { 51eeffdb10STomasz Sapeta const unimodules: Package[] = []; 52eeffdb10STomasz Sapeta 53eeffdb10STomasz Sapeta const packages = await Packages.getListOfPackagesAsync(); 54eeffdb10STomasz Sapeta for (const pkg of packages) { 55eeffdb10STomasz Sapeta if (!pkg.isSupportedOnPlatform('android') || !pkg.androidPackageName) continue; 56eeffdb10STomasz Sapeta unimodules.push({ 57eeffdb10STomasz Sapeta name: pkg.packageSlug, 58eeffdb10STomasz Sapeta sourceDir: path.join(pkg.path, pkg.androidSubdirectory), 59eeffdb10STomasz Sapeta buildDirRelative: `${pkg.androidPackageName.replace(/\./g, '/')}/${pkg.packageSlug}`, 60eeffdb10STomasz Sapeta }); 61eeffdb10STomasz Sapeta } 62eeffdb10STomasz Sapeta 63eeffdb10STomasz Sapeta return unimodules; 64eeffdb10STomasz Sapeta} 65eeffdb10STomasz Sapeta 66eeffdb10STomasz Sapetaasync function _isPackageUpToDate(sourceDir: string, buildDir: string): Promise<boolean> { 67eeffdb10STomasz Sapeta try { 68eeffdb10STomasz Sapeta const sourceCommits = await _gitLogAsync(sourceDir); 69eeffdb10STomasz Sapeta const buildCommits = await _gitLogAsync(buildDir); 70eeffdb10STomasz Sapeta 71eeffdb10STomasz Sapeta const latestSourceCommitSha = sourceCommits.lines[0].split(' ')[0]; 72eeffdb10STomasz Sapeta const latestBuildCommitSha = buildCommits.lines[0].split(' ')[0]; 73eeffdb10STomasz Sapeta 74eeffdb10STomasz Sapeta // throws if source commit is not an ancestor of build commit 75eeffdb10STomasz Sapeta await spawnAsync( 76eeffdb10STomasz Sapeta 'git', 77eeffdb10STomasz Sapeta ['merge-base', '--is-ancestor', latestSourceCommitSha, latestBuildCommitSha], 78eeffdb10STomasz Sapeta { 79eeffdb10STomasz Sapeta cwd: EXPO_ROOT_DIR, 80eeffdb10STomasz Sapeta } 81eeffdb10STomasz Sapeta ); 82eeffdb10STomasz Sapeta return true; 83*a272999eSBartosz Kaszubowski } catch { 84eeffdb10STomasz Sapeta return false; 85eeffdb10STomasz Sapeta } 86eeffdb10STomasz Sapeta} 87eeffdb10STomasz Sapeta 88eeffdb10STomasz Sapetaasync function _gitLogAsync(path: string): Promise<{ lines: string[] }> { 89eeffdb10STomasz Sapeta const child = await spawnAsync('git', ['log', `--pretty=oneline`, '--', path], { 90eeffdb10STomasz Sapeta stdio: 'pipe', 91eeffdb10STomasz Sapeta cwd: EXPO_ROOT_DIR, 92eeffdb10STomasz Sapeta }); 93eeffdb10STomasz Sapeta 94eeffdb10STomasz Sapeta return { 95eeffdb10STomasz Sapeta lines: child.stdout 96eeffdb10STomasz Sapeta .trim() 97eeffdb10STomasz Sapeta .split(/\r?\n/g) 98eeffdb10STomasz Sapeta .filter((a) => a), 99eeffdb10STomasz Sapeta }; 100eeffdb10STomasz Sapeta} 101eeffdb10STomasz Sapeta 102eeffdb10STomasz Sapetaasync function _getSuggestedPackagesToBuild(packages: Package[]): Promise<string[]> { 103*a272999eSBartosz Kaszubowski const packagesToBuild: string[] = []; 104eeffdb10STomasz Sapeta for (const pkg of packages) { 105eeffdb10STomasz Sapeta const isUpToDate = await _isPackageUpToDate( 106eeffdb10STomasz Sapeta pkg.sourceDir, 107eeffdb10STomasz Sapeta path.join(EXPO_ROOT_DIR, 'android', 'maven', pkg.buildDirRelative) 108eeffdb10STomasz Sapeta ); 109eeffdb10STomasz Sapeta if (!isUpToDate) { 110eeffdb10STomasz Sapeta packagesToBuild.push(pkg.name); 111eeffdb10STomasz Sapeta } 112eeffdb10STomasz Sapeta } 113eeffdb10STomasz Sapeta return packagesToBuild; 114eeffdb10STomasz Sapeta} 115eeffdb10STomasz Sapeta 116eeffdb10STomasz Sapetaasync function _regexFileAsync( 117eeffdb10STomasz Sapeta filename: string, 118eeffdb10STomasz Sapeta regex: RegExp | string, 119eeffdb10STomasz Sapeta replace: string 120eeffdb10STomasz Sapeta): Promise<void> { 121*a272999eSBartosz Kaszubowski const file = await fs.readFile(filename); 122*a272999eSBartosz Kaszubowski const fileString = file.toString(); 123eeffdb10STomasz Sapeta await fs.writeFile(filename, fileString.replace(regex, replace)); 124eeffdb10STomasz Sapeta} 125eeffdb10STomasz Sapeta 126*a272999eSBartosz Kaszubowskiconst savedFiles = {}; 127eeffdb10STomasz Sapetaasync function _stashFilesAsync(filenames: string[]): Promise<void> { 128eeffdb10STomasz Sapeta for (const filename of filenames) { 129*a272999eSBartosz Kaszubowski const file = await fs.readFile(filename); 130eeffdb10STomasz Sapeta savedFiles[filename] = file.toString(); 131eeffdb10STomasz Sapeta } 132eeffdb10STomasz Sapeta} 133eeffdb10STomasz Sapeta 134eeffdb10STomasz Sapetaasync function _restoreFilesAsync(): Promise<void> { 135eeffdb10STomasz Sapeta for (const filename in savedFiles) { 136eeffdb10STomasz Sapeta await fs.writeFile(filename, savedFiles[filename]); 137eeffdb10STomasz Sapeta delete savedFiles[filename]; 138eeffdb10STomasz Sapeta } 139eeffdb10STomasz Sapeta} 140eeffdb10STomasz Sapeta 141eeffdb10STomasz Sapetaasync function _commentWhenDistributing(filenames: string[]): Promise<void> { 142eeffdb10STomasz Sapeta for (const filename of filenames) { 143eeffdb10STomasz Sapeta await _regexFileAsync( 144eeffdb10STomasz Sapeta filename, 145eeffdb10STomasz Sapeta /\/\/ WHEN_DISTRIBUTING_REMOVE_FROM_HERE/g, 146eeffdb10STomasz Sapeta '/* WHEN_DISTRIBUTING_REMOVE_FROM_HERE' 147eeffdb10STomasz Sapeta ); 148eeffdb10STomasz Sapeta await _regexFileAsync( 149eeffdb10STomasz Sapeta filename, 150eeffdb10STomasz Sapeta /\/\ WHEN_DISTRIBUTING_REMOVE_TO_HERE/g, 151eeffdb10STomasz Sapeta 'WHEN_DISTRIBUTING_REMOVE_TO_HERE */' 152eeffdb10STomasz Sapeta ); 153eeffdb10STomasz Sapeta } 154eeffdb10STomasz Sapeta} 155eeffdb10STomasz Sapeta 156eeffdb10STomasz Sapetaasync function _uncommentWhenDistributing(filenames: string[]): Promise<void> { 157eeffdb10STomasz Sapeta for (const filename of filenames) { 158eeffdb10STomasz Sapeta await _regexFileAsync(filename, '/* UNCOMMENT WHEN DISTRIBUTING', ''); 159eeffdb10STomasz Sapeta await _regexFileAsync(filename, 'END UNCOMMENT WHEN DISTRIBUTING */', ''); 160eeffdb10STomasz Sapeta } 161eeffdb10STomasz Sapeta} 162eeffdb10STomasz Sapeta 163eeffdb10STomasz Sapetaasync function _updateExpoViewAsync(packages: Package[], sdkVersion: string): Promise<number> { 164*a272999eSBartosz Kaszubowski const appBuildGradle = path.join(ANDROID_DIR, 'app', 'build.gradle'); 165*a272999eSBartosz Kaszubowski const rootBuildGradle = path.join(ANDROID_DIR, 'build.gradle'); 166*a272999eSBartosz Kaszubowski const expoViewBuildGradle = path.join(ANDROID_DIR, 'expoview', 'build.gradle'); 167eeffdb10STomasz Sapeta const settingsGradle = path.join(ANDROID_DIR, 'settings.gradle'); 168eeffdb10STomasz Sapeta const constantsJava = path.join( 169eeffdb10STomasz Sapeta ANDROID_DIR, 170eeffdb10STomasz Sapeta 'expoview/src/main/java/host/exp/exponent/Constants.java' 171eeffdb10STomasz Sapeta ); 172eeffdb10STomasz Sapeta const multipleVersionReactNativeActivity = path.join( 173eeffdb10STomasz Sapeta ANDROID_DIR, 174a2ffa225SBartłomiej Klocek 'expoview/src/versioned/java/host/exp/exponent/experience/MultipleVersionReactNativeActivity.java' 175eeffdb10STomasz Sapeta ); 176eeffdb10STomasz Sapeta 177eeffdb10STomasz Sapeta // Modify permanently 178eeffdb10STomasz Sapeta await _regexFileAsync(expoViewBuildGradle, /version = '[\d.]+'/, `version = '${sdkVersion}'`); 179eeffdb10STomasz Sapeta await _regexFileAsync( 180eeffdb10STomasz Sapeta expoViewBuildGradle, 181eeffdb10STomasz Sapeta /api 'com.facebook.react:react-native:[\d.]+'/, 182eeffdb10STomasz Sapeta `api 'com.facebook.react:react-native:${sdkVersion}'` 183eeffdb10STomasz Sapeta ); 184eeffdb10STomasz Sapeta await _regexFileAsync( 1852ed31047SKudo Chien path.join(ANDROID_DIR, 'ReactAndroid', 'build.gradle'), 186eeffdb10STomasz Sapeta /version = '[\d.]+'/, 187eeffdb10STomasz Sapeta `version = '${sdkVersion}'` 188eeffdb10STomasz Sapeta ); 189eeffdb10STomasz Sapeta await _regexFileAsync( 190eeffdb10STomasz Sapeta path.join(ANDROID_DIR, 'app', 'build.gradle'), 191eeffdb10STomasz Sapeta /host.exp.exponent:expoview:[\d.]+/, 192eeffdb10STomasz Sapeta `host.exp.exponent:expoview:${sdkVersion}` 193eeffdb10STomasz Sapeta ); 194eeffdb10STomasz Sapeta 195eeffdb10STomasz Sapeta await _stashFilesAsync([ 196eeffdb10STomasz Sapeta appBuildGradle, 197eeffdb10STomasz Sapeta rootBuildGradle, 198eeffdb10STomasz Sapeta expoViewBuildGradle, 199eeffdb10STomasz Sapeta multipleVersionReactNativeActivity, 200eeffdb10STomasz Sapeta constantsJava, 201eeffdb10STomasz Sapeta settingsGradle, 202eeffdb10STomasz Sapeta ]); 203eeffdb10STomasz Sapeta 204eeffdb10STomasz Sapeta // Modify temporarily 205eeffdb10STomasz Sapeta await _regexFileAsync( 206eeffdb10STomasz Sapeta constantsJava, 207eeffdb10STomasz Sapeta /TEMPORARY_ABI_VERSION\s*=\s*null/, 208eeffdb10STomasz Sapeta `TEMPORARY_ABI_VERSION = "${sdkVersion}"` 209eeffdb10STomasz Sapeta ); 210eeffdb10STomasz Sapeta await _uncommentWhenDistributing([appBuildGradle, expoViewBuildGradle]); 211eeffdb10STomasz Sapeta await _commentWhenDistributing([ 212eeffdb10STomasz Sapeta constantsJava, 213eeffdb10STomasz Sapeta rootBuildGradle, 214eeffdb10STomasz Sapeta expoViewBuildGradle, 215eeffdb10STomasz Sapeta multipleVersionReactNativeActivity, 216eeffdb10STomasz Sapeta ]); 217eeffdb10STomasz Sapeta 218eeffdb10STomasz Sapeta // Clear maven local so that we don't end up with multiple versions 219eeffdb10STomasz Sapeta console.log(' ❌ Clearing old package versions...'); 220eeffdb10STomasz Sapeta 221eeffdb10STomasz Sapeta for (const pkg of packages) { 222eeffdb10STomasz Sapeta await fs.remove(path.join(process.env.HOME!, '.m2', 'repository', pkg.buildDirRelative)); 223eeffdb10STomasz Sapeta await fs.remove(path.join(ANDROID_DIR, 'maven', pkg.buildDirRelative)); 224eeffdb10STomasz Sapeta await fs.remove(path.join(pkg.sourceDir, 'build')); 225eeffdb10STomasz Sapeta } 226eeffdb10STomasz Sapeta 227eeffdb10STomasz Sapeta // hacky workaround for weird issue where some packages need to be built twice after cleaning 228eeffdb10STomasz Sapeta // in order to have .so libs included in the aar 229b06291d9Sjkh const reactAndroidIndex = packages.findIndex((pkg) => pkg.name === REACT_ANDROID_PKG.name); 230eeffdb10STomasz Sapeta if (reactAndroidIndex > -1) { 231eeffdb10STomasz Sapeta packages.splice(reactAndroidIndex, 0, REACT_ANDROID_PKG); 232eeffdb10STomasz Sapeta } 233b06291d9Sjkh const expoviewIndex = packages.findIndex((pkg) => pkg.name === EXPOVIEW_PKG.name); 234eeffdb10STomasz Sapeta if (expoviewIndex > -1) { 235eeffdb10STomasz Sapeta packages.splice(expoviewIndex, 0, EXPOVIEW_PKG); 236eeffdb10STomasz Sapeta } 237eeffdb10STomasz Sapeta 238*a272999eSBartosz Kaszubowski const failedPackages: string[] = []; 239eeffdb10STomasz Sapeta for (const pkg of packages) { 240eeffdb10STomasz Sapeta process.stdout.write(` Building ${pkg.name}...`); 241eeffdb10STomasz Sapeta try { 2422ed31047SKudo Chien await spawnAsync('./gradlew', [`:${pkg.name}:publish`], { 243eeffdb10STomasz Sapeta cwd: ANDROID_DIR, 244eeffdb10STomasz Sapeta }); 245eeffdb10STomasz Sapeta readline.clearLine(process.stdout, 0); 246eeffdb10STomasz Sapeta readline.cursorTo(process.stdout, 0); 247eeffdb10STomasz Sapeta process.stdout.write(` ✅ Finished building ${pkg.name}\n`); 248eeffdb10STomasz Sapeta } catch (e) { 249eeffdb10STomasz Sapeta if ( 250eeffdb10STomasz Sapeta e.status === 130 || 251eeffdb10STomasz Sapeta e.signal === 'SIGINT' || 252eeffdb10STomasz Sapeta e.status === 137 || 253eeffdb10STomasz Sapeta e.signal === 'SIGKILL' || 254eeffdb10STomasz Sapeta e.status === 143 || 255eeffdb10STomasz Sapeta e.signal === 'SIGTERM' 256eeffdb10STomasz Sapeta ) { 257eeffdb10STomasz Sapeta throw e; 258eeffdb10STomasz Sapeta } else { 259eeffdb10STomasz Sapeta failedPackages.push(pkg.name); 260eeffdb10STomasz Sapeta readline.clearLine(process.stdout, 0); 261eeffdb10STomasz Sapeta readline.cursorTo(process.stdout, 0); 262eeffdb10STomasz Sapeta process.stdout.write(` ❌ Failed to build ${pkg.name}:\n`); 263eeffdb10STomasz Sapeta console.error(chalk.red(e.message)); 264eeffdb10STomasz Sapeta console.error(chalk.red(e.stderr)); 265eeffdb10STomasz Sapeta } 266eeffdb10STomasz Sapeta } 267eeffdb10STomasz Sapeta } 268eeffdb10STomasz Sapeta 269eeffdb10STomasz Sapeta await _restoreFilesAsync(); 270eeffdb10STomasz Sapeta 271eeffdb10STomasz Sapeta console.log(' Copying newly built packages...'); 272eeffdb10STomasz Sapeta 273eeffdb10STomasz Sapeta await fs.mkdirs(path.join(ANDROID_DIR, 'maven/com/facebook')); 274eeffdb10STomasz Sapeta await fs.mkdirs(path.join(ANDROID_DIR, 'maven/host/exp/exponent')); 275eeffdb10STomasz Sapeta await fs.mkdirs(path.join(ANDROID_DIR, 'maven/org/unimodules')); 276eeffdb10STomasz Sapeta 277eeffdb10STomasz Sapeta for (const pkg of packages) { 278eeffdb10STomasz Sapeta if (failedPackages.includes(pkg.name)) { 279eeffdb10STomasz Sapeta continue; 280eeffdb10STomasz Sapeta } 281eeffdb10STomasz Sapeta await fs.copy( 282eeffdb10STomasz Sapeta path.join(process.env.HOME!, '.m2', 'repository', pkg.buildDirRelative), 283eeffdb10STomasz Sapeta path.join(ANDROID_DIR, 'maven', pkg.buildDirRelative) 284eeffdb10STomasz Sapeta ); 285eeffdb10STomasz Sapeta } 286eeffdb10STomasz Sapeta 287eeffdb10STomasz Sapeta if (failedPackages.length) { 288eeffdb10STomasz Sapeta console.log(' ❌ The following packages failed to build:'); 289eeffdb10STomasz Sapeta console.log(failedPackages); 290eeffdb10STomasz Sapeta console.log( 291eeffdb10STomasz Sapeta `You will need to fix the compilation errors show in the logs above and then run \`et abp -s ${sdkVersion} -p ${failedPackages.join( 292eeffdb10STomasz Sapeta ',' 293eeffdb10STomasz Sapeta )}\`` 294eeffdb10STomasz Sapeta ); 295eeffdb10STomasz Sapeta } 296eeffdb10STomasz Sapeta 297eeffdb10STomasz Sapeta return failedPackages.length; 298eeffdb10STomasz Sapeta} 299eeffdb10STomasz Sapeta 300eeffdb10STomasz Sapetaasync function action(options: ActionOptions) { 301eeffdb10STomasz Sapeta process.on('SIGINT', _exitHandler); 302eeffdb10STomasz Sapeta process.on('SIGTERM', _exitHandler); 303eeffdb10STomasz Sapeta 304eeffdb10STomasz Sapeta const detachableUniversalModules = ( 305eeffdb10STomasz Sapeta await _findUnimodules(path.join(EXPO_ROOT_DIR, 'packages')) 306eeffdb10STomasz Sapeta ).filter((unimodule) => !EXCLUDED_PACKAGE_SLUGS.includes(unimodule.name)); 307eeffdb10STomasz Sapeta 308eeffdb10STomasz Sapeta // packages must stay in this order -- 309eeffdb10STomasz Sapeta // ReactAndroid MUST be first and expoview MUST be last 310eeffdb10STomasz Sapeta const packages: Package[] = [REACT_ANDROID_PKG, ...detachableUniversalModules, EXPOVIEW_PKG]; 311eeffdb10STomasz Sapeta let packagesToBuild: string[] = []; 312eeffdb10STomasz Sapeta 313eeffdb10STomasz Sapeta const expoviewBuildGradle = await fs.readFile(path.join(ANDROID_DIR, 'expoview', 'build.gradle')); 314eeffdb10STomasz Sapeta const match = expoviewBuildGradle 315eeffdb10STomasz Sapeta .toString() 316eeffdb10STomasz Sapeta .match(/api 'com.facebook.react:react-native:([\d.]+)'/); 317eeffdb10STomasz Sapeta if (!match || !match[1]) { 318eeffdb10STomasz Sapeta throw new Error( 319eeffdb10STomasz Sapeta 'Could not find SDK version in android/expoview/build.gradle: unexpected format' 320eeffdb10STomasz Sapeta ); 321eeffdb10STomasz Sapeta } 322eeffdb10STomasz Sapeta 323eeffdb10STomasz Sapeta if (match[1] !== options.sdkVersion) { 324eeffdb10STomasz Sapeta console.log( 325eeffdb10STomasz Sapeta " It looks like you're adding a new SDK version. Ignoring the `--packages` option and rebuilding all packages..." 326eeffdb10STomasz Sapeta ); 327eeffdb10STomasz Sapeta packagesToBuild = packages.map((pkg) => pkg.name); 328eeffdb10STomasz Sapeta } else if (options.packages) { 329eeffdb10STomasz Sapeta if (options.packages === 'all') { 330eeffdb10STomasz Sapeta packagesToBuild = packages.map((pkg) => pkg.name); 331eeffdb10STomasz Sapeta } else if (options.packages === 'suggested') { 332eeffdb10STomasz Sapeta console.log(' Gathering data about packages...'); 333eeffdb10STomasz Sapeta packagesToBuild = await _getSuggestedPackagesToBuild(packages); 334eeffdb10STomasz Sapeta } else { 335eeffdb10STomasz Sapeta const packageNames = options.packages.split(','); 336eeffdb10STomasz Sapeta packagesToBuild = packages 337eeffdb10STomasz Sapeta .map((pkg) => pkg.name) 338eeffdb10STomasz Sapeta .filter((pkgName) => packageNames.includes(pkgName)); 339eeffdb10STomasz Sapeta } 340eeffdb10STomasz Sapeta console.log(' Rebuilding the following packages:'); 341eeffdb10STomasz Sapeta console.log(packagesToBuild); 342eeffdb10STomasz Sapeta } else { 343eeffdb10STomasz Sapeta // gather suggested package data and then show prompts 344eeffdb10STomasz Sapeta console.log(' Gathering data...'); 345eeffdb10STomasz Sapeta 346eeffdb10STomasz Sapeta packagesToBuild = await _getSuggestedPackagesToBuild(packages); 347eeffdb10STomasz Sapeta 348eeffdb10STomasz Sapeta console.log(' ️ It appears that the following packages need to be rebuilt:'); 349eeffdb10STomasz Sapeta console.log(packagesToBuild); 350eeffdb10STomasz Sapeta 351eeffdb10STomasz Sapeta const { option } = await inquirer.prompt<{ option: string }>([ 352eeffdb10STomasz Sapeta { 353eeffdb10STomasz Sapeta type: 'list', 354eeffdb10STomasz Sapeta name: 'option', 355eeffdb10STomasz Sapeta message: 'What would you like to do?', 356eeffdb10STomasz Sapeta choices: [ 357eeffdb10STomasz Sapeta { value: 'suggested', name: 'Build the suggested packages only' }, 358eeffdb10STomasz Sapeta { value: 'all', name: 'Build all packages' }, 359eeffdb10STomasz Sapeta { value: 'choose', name: 'Choose packages manually' }, 360eeffdb10STomasz Sapeta ], 361eeffdb10STomasz Sapeta }, 362eeffdb10STomasz Sapeta ]); 363eeffdb10STomasz Sapeta 364eeffdb10STomasz Sapeta if (option === 'all') { 365eeffdb10STomasz Sapeta packagesToBuild = packages.map((pkg) => pkg.name); 366eeffdb10STomasz Sapeta } else if (option === 'choose') { 367eeffdb10STomasz Sapeta const result = await inquirer.prompt<{ packagesToBuild: string[] }>([ 368eeffdb10STomasz Sapeta { 369eeffdb10STomasz Sapeta type: 'checkbox', 370eeffdb10STomasz Sapeta name: 'packagesToBuild', 371b06291d9Sjkh message: 'Choose which packages to build\n ● selected ○ unselected\n', 372eeffdb10STomasz Sapeta choices: packages.map((pkg) => pkg.name), 373eeffdb10STomasz Sapeta default: packagesToBuild, 374eeffdb10STomasz Sapeta pageSize: Math.min(packages.length, (process.stdout.rows || 100) - 2), 375eeffdb10STomasz Sapeta }, 376eeffdb10STomasz Sapeta ]); 377eeffdb10STomasz Sapeta packagesToBuild = result.packagesToBuild; 378eeffdb10STomasz Sapeta } 379eeffdb10STomasz Sapeta } 380eeffdb10STomasz Sapeta 381eeffdb10STomasz Sapeta try { 382eeffdb10STomasz Sapeta const failedPackagesCount = await _updateExpoViewAsync( 383eeffdb10STomasz Sapeta packages.filter((pkg) => packagesToBuild.includes(pkg.name)), 384eeffdb10STomasz Sapeta options.sdkVersion 385eeffdb10STomasz Sapeta ); 386eeffdb10STomasz Sapeta if (failedPackagesCount > 0) { 387eeffdb10STomasz Sapeta process.exitCode = 1; 388eeffdb10STomasz Sapeta } 389eeffdb10STomasz Sapeta } catch (e) { 390eeffdb10STomasz Sapeta await _exitHandler(); 391eeffdb10STomasz Sapeta throw e; 392eeffdb10STomasz Sapeta } 393eeffdb10STomasz Sapeta} 394eeffdb10STomasz Sapeta 395eeffdb10STomasz Sapetaasync function _exitHandler(): Promise<void> { 396eeffdb10STomasz Sapeta if (Object.keys(savedFiles).length) { 397eeffdb10STomasz Sapeta console.log('Exited early, cleaning up...'); 398eeffdb10STomasz Sapeta await _restoreFilesAsync(); 399eeffdb10STomasz Sapeta } 400eeffdb10STomasz Sapeta} 401eeffdb10STomasz Sapeta 402eeffdb10STomasz Sapetaexport default (program: any) => { 403eeffdb10STomasz Sapeta program 404eeffdb10STomasz Sapeta .command('android-build-packages') 405eeffdb10STomasz Sapeta .alias('abp') 406eeffdb10STomasz Sapeta .description('Builds all Android AAR packages for Turtle') 407eeffdb10STomasz Sapeta .option('-s, --sdkVersion [string]', '[optional] SDK version') 408eeffdb10STomasz Sapeta .option( 409eeffdb10STomasz Sapeta '-p, --packages [string]', 410eeffdb10STomasz Sapeta '[optional] packages to build. May be `all`, `suggested`, or a comma-separate list of package names.' 411eeffdb10STomasz Sapeta ) 412eeffdb10STomasz Sapeta .asyncAction(async (options: Partial<ActionOptions>) => { 413eeffdb10STomasz Sapeta const sdkVersion = 414eeffdb10STomasz Sapeta options.sdkVersion ?? (await ProjectVersions.getNewestSDKVersionAsync('android')); 415eeffdb10STomasz Sapeta 416eeffdb10STomasz Sapeta if (!sdkVersion) { 417eeffdb10STomasz Sapeta throw new Error('Could not infer SDK version, please run with `--sdkVersion SDK_VERSION`'); 418eeffdb10STomasz Sapeta } 419eeffdb10STomasz Sapeta 420eeffdb10STomasz Sapeta await action({ ...options, sdkVersion }); 421eeffdb10STomasz Sapeta }); 422eeffdb10STomasz Sapeta}; 423