import path from 'path' ; import debug from '../debug' ; import FileFsRef from '../file-fs-ref' ; import { File , Files , Meta } from '../types' ; import { remove , mkdirp , readlink , symlink } from 'fs-extra' ; export interface DownloadedFiles { [ filePath ] : FileFsRef ; } const S_IFMT = 61440 ; const S_IFLNK = 40960 ; export function isSymbolicLink ( mode ) { return ( mode & S_IFMT ) === S_IFLNK ; } async function downloadFile ( file , fsPath ) { const { mode } = file ; if ( mode && isSymbolicLink ( mode ) && file . type === 'FileFsRef' ) { const [ target ] = await Promise . all ( [ readlink ( ( file as FileFsRef ) . fsPath ) , mkdirp ( path . dirname ( fsPath ) ) , ] ) ; await symlink ( target , fsPath ) ; return FileFsRef . fromFsPath ( { mode , fsPath } ) ; } else { const stream = file . toStream ( ) ; return FileFsRef . fromStream ( { mode , stream , fsPath } ) ; } } async function removeFile ( basePath , fileMatched ) { const file = path . join ( basePath , fileMatched ) ; await remove ( file ) ; } export default async function download ( files , basePath , meta ? ) { const { isDev = false , skipDownload = false , filesChanged = null , filesRemoved = null , } = meta || { } ; if ( isDev || skipDownload ) { return files as DownloadedFiles ; } debug ( 'Downloading deployment source files...' ) ; const start = Date . now ( ) ; const files2 = { } ; const filenames = Object . keys ( files ) ; await Promise . all ( filenames . map ( async ( name ) => { if ( Array . isArray ( filesRemoved ) && filesRemoved . includes ( name ) ) { await removeFile ( basePath , name ) ; return ; } if ( Array . isArray ( filesChanged ) && ! filesChanged . includes ( name ) ) { return ; } const file = files [ name ] ; const fsPath = path . join ( basePath , name ) ; files2 [ name ] = await downloadFile ( file , fsPath ) ; } ) ) ; const duration = Date . now ( ) - start ; debug ( `Downloaded ${ filenames . length } source files: ${ duration }ms` ) ; return files2 ; }