import { bestzip } from 'bestzip' ; import * as archiver from 'archiver' ; import * as childProcess from 'child_process' ; import * as fs from 'fs-extra' ; import * as path from 'path' ; import * as os from 'os' ; import { join } from 'ramda' ; import { IFiles } from './types' ; export class SpawnError extends Error { constructor ( message , public stdout , public stderr ) { super ( message ) ; } toString ( ) { return `${ this . message }\n${ this . stderr }` ; } } param { string } command param { string [ ] } args param { Object } options export function spawnProcess ( command , args , options ) { return new Promise < { stdout : string ; stderr : string ; } > ( ( resolve , reject ) => { const child = childProcess . spawn ( command , args , options ) ; let stdout = '' ; let stderr = '' ; child . stdout . setEncoding ( 'utf8' ) ; child . stderr . setEncoding ( 'utf8' ) ; child . stdout . on ( 'data' , ( data ) => { stdout += data ; } ) ; child . stderr . on ( 'data' , ( data ) => { stderr += data ; } ) ; child . on ( 'error' , ( err ) => { reject ( err ) ; } ) ; child . on ( 'close' , ( exitCode ) => { if ( exitCode !== 0 ) { reject ( new SpawnError ( `${ command } ${ join ( ' ' , args ) } failed with code ${ exitCode }` , stdout , stderr ) ) ; } else { resolve ( { stdout , stderr } ) ; } } ) ; } ) ; } /**
 * Find a file by walking up parent directories
 */ export function findUp ( names , directory = process . cwd ( ) ) { const absoluteDirectory = path . resolve ( directory ) ; if ( typeof names === 'string' ) { names = [ names ] ; } for ( const name of names ) { if ( fs . existsSync ( path . join ( directory , name ) ) ) { return directory ; } } const { root } = path . parse ( absoluteDirectory ) ; if ( absoluteDirectory === root ) { return undefined ; } return findUp ( names , path . dirname ( absoluteDirectory ) ) ; } /**
 * Forwards `rootDir` or finds project root folder.
 */ export function findProjectRoot ( rootDir ? ) { return rootDir ?? findUp ( [ 'yarn.lock' , 'package-lock.json' ] ) ; } export const humanSize = ( size ) => { const i = Math . floor ( Math . log ( size ) / Math . log ( 1024 ) ) ; const sanitized = ( size / Math . pow ( 1024 , i ) ) . toFixed ( 2 ) ; return `${ sanitized } ${ [ 'B' , 'KB' , 'MB' , 'GB' , 'TB' ] [ i ] }` ; } ; export const zip = async ( zipPath , filesPathList , useNativeZip = false ) : Promise < void > => { const tempDirName = `${ path . basename ( zipPath ) . slice ( 0 , - 4 ) }-${ Date . now ( ) . toString ( ) }` ; const tempDirPath = path . join ( os . tmpdir ( ) , tempDirName ) ; fs . mkdirpSync ( tempDirPath ) ; await Promise . all ( filesPathList . map ( ( file ) => fs . copy ( file . rootPath , path . join ( tempDirPath , file . localPath ) ) ) ) ; fs . mkdirpSync ( path . dirname ( zipPath ) ) ; if ( useNativeZip ) { await bestzip ( { source : '*' , destination : zipPath , cwd : tempDirPath , } ) ; fs . rmdirSync ( tempDirPath , { recursive : true } ) ; } else { const zip = archiver . create ( 'zip' ) ; const output = fs . createWriteStream ( zipPath ) ; output . on ( 'open' , ( ) => { zip . pipe ( output ) ; filesPathList . forEach ( ( file ) => { const stats = fs . statSync ( file . rootPath ) ; if ( stats . isDirectory ( ) ) return ; zip . append ( fs . readFileSync ( file . rootPath ) , { name : file . localPath , mode : stats . mode , date : new Date ( 0 ) , } ) ; } ) ; zip . finalize ( ) ; } ) ; return new Promise ( ( resolve , reject ) => { output . on ( 'close' , ( ) => { fs . rmdirSync ( tempDirPath , { recursive : true } ) ; resolve ( ) ; } ) ; zip . on ( 'error' , ( err ) => reject ( err ) ) ; } ) ; } } ; export function trimExtension ( entry ) { return entry . slice ( 0 , - path . extname ( entry ) . length ) ; }