1*8d3f3824SCedric van Puttenimport spawnAsync, { SpawnOptions, SpawnPromise } from '@expo/spawn-async'; 2*8d3f3824SCedric van Puttenimport sudo from 'sudo-prompt'; 3*8d3f3824SCedric van Putten 4*8d3f3824SCedric van Putten/** 5*8d3f3824SCedric van Putten * The pending spawn promise is similar to the spawn promise from `@expo/spawn-async`. 6*8d3f3824SCedric van Putten * Instead of the `child` process being available immediately, the `child` is behind another promise. 7*8d3f3824SCedric van Putten * We need this to perform async tasks before running the actual spawn promise. 8*8d3f3824SCedric van Putten * Use it like: `await manager.installAsync().child` 9*8d3f3824SCedric van Putten */ 10*8d3f3824SCedric van Puttenexport interface PendingSpawnPromise<T> extends Promise<T> { 11*8d3f3824SCedric van Putten /** 12*8d3f3824SCedric van Putten * The child process from the delayed spawn. 13*8d3f3824SCedric van Putten * This is `null` whenever the promise before the spawn promise is rejected. 14*8d3f3824SCedric van Putten */ 15*8d3f3824SCedric van Putten child: Promise<SpawnPromise<T>['child'] | null>; 16*8d3f3824SCedric van Putten} 17*8d3f3824SCedric van Putten 18*8d3f3824SCedric van Puttenexport function createPendingSpawnAsync<V, T>( 19*8d3f3824SCedric van Putten actionAsync: () => Promise<V>, 20*8d3f3824SCedric van Putten spawnAsync: (result: V) => SpawnPromise<T> 21*8d3f3824SCedric van Putten): PendingSpawnPromise<T> { 22*8d3f3824SCedric van Putten // Manually rsolve the child promise whenever the prepending async action is resolved. 23*8d3f3824SCedric van Putten // Avoid `childReject` to prevent "unhandled promise rejection" for one of the two promises. 24*8d3f3824SCedric van Putten let childResolve: (child: SpawnPromise<T>['child'] | null) => void; 25*8d3f3824SCedric van Putten const child: Promise<SpawnPromise<T>['child'] | null> = new Promise((resolve, reject) => { 26*8d3f3824SCedric van Putten childResolve = resolve; 27*8d3f3824SCedric van Putten }); 28*8d3f3824SCedric van Putten 29*8d3f3824SCedric van Putten const pendingPromise = new Promise<T>((spawnResolve, spawnReject) => { 30*8d3f3824SCedric van Putten actionAsync() 31*8d3f3824SCedric van Putten .then((result) => { 32*8d3f3824SCedric van Putten const spawnPromise = spawnAsync(result); 33*8d3f3824SCedric van Putten childResolve(spawnPromise.child); 34*8d3f3824SCedric van Putten spawnPromise.then(spawnResolve).catch(spawnReject); 35*8d3f3824SCedric van Putten }) 36*8d3f3824SCedric van Putten .catch((error) => { 37*8d3f3824SCedric van Putten childResolve(null); 38*8d3f3824SCedric van Putten spawnReject(error); 39*8d3f3824SCedric van Putten }); 40*8d3f3824SCedric van Putten }); 41*8d3f3824SCedric van Putten 42*8d3f3824SCedric van Putten (pendingPromise as PendingSpawnPromise<T>).child = child; 43*8d3f3824SCedric van Putten return pendingPromise as PendingSpawnPromise<T>; 44*8d3f3824SCedric van Putten} 45*8d3f3824SCedric van Putten 46*8d3f3824SCedric van Putten/** 47*8d3f3824SCedric van Putten * Spawn a command with sudo privileges. 48*8d3f3824SCedric van Putten * On windows, this uses the `sudo-prompt` package. 49*8d3f3824SCedric van Putten * on other systems, this uses the `sudo` binary. 50*8d3f3824SCedric van Putten */ 51*8d3f3824SCedric van Puttenexport async function spawnSudoAsync(command: string[], spawnOptions: SpawnOptions): Promise<void> { 52*8d3f3824SCedric van Putten // sudo prompt only seems to work on win32 machines. 53*8d3f3824SCedric van Putten if (process.platform === 'win32') { 54*8d3f3824SCedric van Putten return new Promise((resolve, reject) => { 55*8d3f3824SCedric van Putten sudo.exec(command.join(' '), { name: 'pod install' }, (error) => { 56*8d3f3824SCedric van Putten if (error) { 57*8d3f3824SCedric van Putten reject(error); 58*8d3f3824SCedric van Putten } 59*8d3f3824SCedric van Putten resolve(); 60*8d3f3824SCedric van Putten }); 61*8d3f3824SCedric van Putten }); 62*8d3f3824SCedric van Putten } else { 63*8d3f3824SCedric van Putten // Attempt to use sudo to run the command on Mac and Linux. 64*8d3f3824SCedric van Putten // TODO(Bacon): Make a v of sudo-prompt that's win32 only for better bundle size. 65*8d3f3824SCedric van Putten console.log( 66*8d3f3824SCedric van Putten 'Your password might be needed to install CocoaPods CLI: https://guides.cocoapods.org/using/getting-started.html#installation' 67*8d3f3824SCedric van Putten ); 68*8d3f3824SCedric van Putten await spawnAsync('sudo', command, spawnOptions); 69*8d3f3824SCedric van Putten } 70*8d3f3824SCedric van Putten} 71