1dc51e206SEvan Baconimport path from 'path'; 2dc51e206SEvan Bacon 3*edeec536SEvan Baconimport { BundleAssetWithFileHashes } from './fork-bundleAsync'; 4dc51e206SEvan Baconimport * as Log from '../log'; 5dc51e206SEvan Baconimport { chunk } from '../utils/array'; 6dc51e206SEvan Baconimport { copyAsync } from '../utils/dir'; 7dc51e206SEvan Bacon 8474a7a4bSEvan Baconconst debug = require('debug')('expo:export:saveAssets') as typeof console.log; 9474a7a4bSEvan Bacon 10dc51e206SEvan Baconexport type ManifestAsset = { fileHashes: string[]; files: string[]; hash: string }; 11dc51e206SEvan Bacon 12dc51e206SEvan Baconexport type Asset = ManifestAsset | BundleAssetWithFileHashes; 13dc51e206SEvan Bacon 14dc51e206SEvan Baconfunction logAssetTask(projectRoot: string, action: 'uploading' | 'saving', pathName: string) { 15474a7a4bSEvan Bacon debug(`${action} ${pathName}`); 16dc51e206SEvan Bacon 17dc51e206SEvan Bacon const relativePath = pathName.replace(projectRoot, ''); 18dc51e206SEvan Bacon Log.log(`${action} ${relativePath}`); 19dc51e206SEvan Bacon} 20dc51e206SEvan Bacon 21dc51e206SEvan Baconfunction collectAssetPaths(assets: Asset[]): Record<string, string> { 22dc51e206SEvan Bacon // Collect paths by key, also effectively handles duplicates in the array 23dc51e206SEvan Bacon const paths: { [fileHash: string]: string } = {}; 24dc51e206SEvan Bacon assets.forEach((asset) => { 25dc51e206SEvan Bacon asset.files.forEach((path: string, index: number) => { 26dc51e206SEvan Bacon paths[asset.fileHashes[index]] = path; 27dc51e206SEvan Bacon }); 28dc51e206SEvan Bacon }); 29dc51e206SEvan Bacon return paths; 30dc51e206SEvan Bacon} 31dc51e206SEvan Bacon 32dc51e206SEvan Baconexport async function saveAssetsAsync( 33dc51e206SEvan Bacon projectRoot: string, 34dc51e206SEvan Bacon { assets, outputDir }: { assets: Asset[]; outputDir: string } 35dc51e206SEvan Bacon) { 36dc51e206SEvan Bacon // Collect paths by key, also effectively handles duplicates in the array 37dc51e206SEvan Bacon const paths = collectAssetPaths(assets); 38dc51e206SEvan Bacon 39dc51e206SEvan Bacon // save files one chunk at a time 40dc51e206SEvan Bacon for (const keys of chunk(Object.entries(paths), 5)) { 41dc51e206SEvan Bacon await Promise.all( 42dc51e206SEvan Bacon keys.map(([key, pathName]) => { 43dc51e206SEvan Bacon logAssetTask(projectRoot, 'saving', pathName); 44dc51e206SEvan Bacon // copy file over to assetPath 45dc51e206SEvan Bacon return copyAsync(pathName, path.join(outputDir, 'assets', key)); 46dc51e206SEvan Bacon }) 47dc51e206SEvan Bacon ); 48dc51e206SEvan Bacon } 49dc51e206SEvan Bacon Log.log('Files successfully saved.'); 50dc51e206SEvan Bacon} 51