import * as fse from 'fs-extra' ; import { glob as globGitignore } from 'glob-gitignore' ; import * as globby from 'globby' ; import * as path from 'path' ; import * as prettybytes from 'pretty-bytes' ; import { Readable } from 'stream' ; import * as vscode from 'vscode' ; import { IActionContext } from 'vscode-azureextensionui' ; import * as yazl from 'yazl' ; import { ext } from '../extensionVariables' ; import { localize } from '../localize' ; import { ParsedSite } from '../SiteClient' ; import { getFileExtension } from '../utils/pathUtils' ; export async function runWithZipStream ( context , options ) { function onFileSize ( size ) { context . telemetry . measurements . zipFileSize = size ; ext . outputChannel . appendLog ( localize ( 'zipSize' , 'Zip package size: {0}' , prettybytes ( size ) ) , { resourceName : site . fullName } ) ; } let zipStream ; const { site , pathFileMap , callback } = options ; let { fsPath } = options ; if ( getFileExtension ( fsPath ) === 'zip' ) { context . telemetry . properties . alreadyZipped = 'true' ; zipStream = fse . createReadStream ( fsPath ) ; void fse . lstat ( fsPath ) . then ( stats => { onFileSize ( stats . size ) ; } ) ; } else { ext . outputChannel . appendLog ( localize ( 'zipCreate' , 'Creating zip package...' ) , { resourceName : site . fullName } ) ; const zipFile = new yazl . ZipFile ( ) ; let filesToZip = [ ] ; let sizeOfZipFile = 0 ; zipFile . outputStream . on ( 'data' , ( chunk ) => { if ( typeof chunk === 'string' || Buffer . isBuffer ( chunk ) ) { sizeOfZipFile += chunk . length ; } } ) ; zipFile . outputStream . on ( 'finish' , ( ) => onFileSize ( sizeOfZipFile ) ) ; if ( ( await fse . lstat ( fsPath ) ) . isDirectory ( ) ) { if ( ! fsPath . endsWith ( path . sep ) ) { fsPath += path . sep ; } if ( site . isFunctionApp ) { filesToZip = await getFilesFromGitignore ( fsPath , '.funcignore' ) ; } else { filesToZip = await getFilesFromGlob ( fsPath , site ) ; } for ( const file of filesToZip ) { zipFile . addFile ( path . join ( fsPath , file ) , getPathFromMap ( file , pathFileMap ) ) ; } } else { zipFile . addFile ( fsPath , getPathFromMap ( path . basename ( fsPath ) , pathFileMap ) ) ; } zipFile . end ( ) ; zipStream = new Readable ( ) . wrap ( zipFile . outputStream ) ; } await callback ( zipStream ) ; } function getPathFromMap ( realPath , pathfileMap ? ) { return pathfileMap ?. get ( realPath ) || realPath ; } const commonGlobSettings = { dot : true , nodir : true , follow : true } ; /**
 * Adds files using glob filtering
 */ async function getFilesFromGlob ( folderPath , site ) { const zipDeployConfig = vscode . workspace . getConfiguration ( ext . prefix , vscode . Uri . file ( folderPath ) ) ; const globOptions = { cwd : folderPath , followSymbolicLinks : true , dot : true } ; const globPattern = zipDeployConfig . get < string > ( 'zipGlobPattern' ) || '**/*' ; const filesToInclude = await globby ( globPattern , globOptions ) ; const zipIgnorePatternStr = 'zipIgnorePattern' ; let ignorePatternList = zipDeployConfig . get < string | string [ ] > ( zipIgnorePatternStr ) || '' ; const filesToIgnore = await globby ( ignorePatternList , globOptions ) ; if ( ignorePatternList ) { if ( typeof ignorePatternList === 'string' ) { ignorePatternList = [ ignorePatternList ] ; } if ( ignorePatternList . length > 0 ) { ext . outputChannel . appendLog ( localize ( 'zipIgnoreFileMsg' , `Ignoring files from \"{0}.{1}\"` , ext . prefix , zipIgnorePatternStr ) , { resourceName : site . fullName } ) ; for ( const pattern of ignorePatternList ) { ext . outputChannel . appendLine ( `\"${ pattern }\"` ) ; } } } return filesToInclude . filter ( file => { return ! filesToIgnore . includes ( file ) ; } ) ; } /**
 * Adds files using gitignore filtering
 */ async function getFilesFromGitignore ( folderPath , gitignoreName ) { let ignore = [ ] ; const gitignorePath = path . join ( folderPath , gitignoreName ) ; if ( await fse . pathExists ( gitignorePath ) ) { const funcIgnoreContents = ( await fse . readFile ( gitignorePath ) ) . toString ( ) ; ignore = funcIgnoreContents . split ( '\n' ) . map ( l => l . trim ( ) ) ; } const paths = await globGitignore ( '**/*' , { cwd : folderPath , ignore , ... commonGlobSettings } ) ; return paths ; }