@@ -4,14 +4,17 @@ import path from 'path';
44import fs from 'fs' ;
55import md5File from 'md5-file' ;
66import https from 'https' ;
7- import decompress from 'decompress' ; // 💩💩💩 this package does not work with Node@11+Jest+Babel
7+ import { createUnzip } from 'zlib' ;
8+ import tar from 'tar-stream' ;
9+ import yauzl from 'yauzl' ;
810import MongoBinaryDownloadUrl from './MongoBinaryDownloadUrl' ;
911import { DownloadProgressT } from '../types' ;
1012import { LATEST_VERSION } from './MongoBinary' ;
1113import { HttpsProxyAgent } from 'https-proxy-agent' ;
1214import { promisify } from 'util' ;
1315import resolveConfig , { envToBool } from './resolve-config' ;
1416import debug from 'debug' ;
17+ import dedent from 'dedent' ;
1518
1619const log = debug ( 'MongoMS:MongoBinaryDownload' ) ;
1720
@@ -186,24 +189,25 @@ export default class MongoBinaryDownload {
186189 fs . mkdirSync ( extractDir ) ;
187190 }
188191
189- let filter ;
192+ let filter : ( file : string ) => boolean ;
190193 if ( this . platform === 'win32' ) {
191- filter = ( file : any ) => {
192- return / b i n \/ m o n g o d .e x e $ / . test ( file . path ) || / .d l l $ / . test ( file . path ) ;
194+ filter = ( file : string ) => {
195+ return / b i n \/ m o n g o d .e x e $ / . test ( file ) || / .d l l $ / . test ( file ) ;
193196 } ;
194197 } else {
195- filter = ( file : any ) => / b i n \/ m o n g o d $ / . test ( file . path ) ;
198+ filter = ( file : string ) => / b i n \/ m o n g o d $ / . test ( file ) ;
196199 }
197200
198- await decompress ( mongoDBArchive , extractDir , {
199- // extract only `bin/mongod` file
200- filter,
201- // extract to root folder
202- map : ( file ) => {
203- file . path = path . basename ( file . path ) ;
204- return file ;
205- } ,
206- } ) ;
201+ if ( / ( .t a r .g z | .t g z ) $ / . test ( path . extname ( mongoDBArchive ) ) ) {
202+ await this . extractTarGz ( mongoDBArchive , extractDir , filter ) ;
203+ } else if ( / .z i p $ / . test ( path . extname ( mongoDBArchive ) ) ) {
204+ await this . extractZip ( mongoDBArchive , extractDir , filter ) ;
205+ } else {
206+ throw new Error (
207+ `MongoBinaryDownload: unsupported archive ${ mongoDBArchive } (downloaded from ${ this
208+ . _downloadingUrl ?? 'unkown' } ). Broken archive from MongoDB Provider?`
209+ ) ;
210+ }
207211
208212 if ( ! ( await this . locationExists ( path . resolve ( this . downloadDir , this . version , binaryName ) ) ) ) {
209213 throw new Error (
@@ -214,6 +218,83 @@ export default class MongoBinaryDownload {
214218 return extractDir ;
215219 }
216220
221+ /**
222+ * Extract a .tar.gz archive
223+ * @param mongoDBArchive Archive location
224+ * @param extractDir Directory to extract to
225+ * @param filter Method to determine which files to extract
226+ */
227+ async extractTarGz (
228+ mongoDBArchive : string ,
229+ extractDir : string ,
230+ filter : ( file : string ) => boolean
231+ ) : Promise < void > {
232+ const extract = tar . extract ( ) ;
233+ extract . on ( 'entry' , ( header , stream , next ) => {
234+ if ( filter ( header . name ) ) {
235+ stream . pipe (
236+ fs . createWriteStream ( path . resolve ( extractDir , path . basename ( header . name ) ) , {
237+ mode : 0o775 ,
238+ } )
239+ ) ;
240+ }
241+ stream . on ( 'end' , ( ) => next ( ) ) ;
242+ stream . resume ( ) ;
243+ } ) ;
244+
245+ return new Promise ( ( resolve , reject ) => {
246+ fs . createReadStream ( mongoDBArchive )
247+ . on ( 'error' , ( err ) => {
248+ reject ( 'Unable to open tarball ' + mongoDBArchive + ': ' + err ) ;
249+ } )
250+ . pipe ( createUnzip ( ) )
251+ . on ( 'error' , ( err ) => {
252+ reject ( 'Error during unzip for ' + mongoDBArchive + ': ' + err ) ;
253+ } )
254+ . pipe ( extract )
255+ . on ( 'error' , ( err ) => {
256+ reject ( 'Error during untar for ' + mongoDBArchive + ': ' + err ) ;
257+ } )
258+ . on ( 'finish' , ( result ) => {
259+ resolve ( result ) ;
260+ } ) ;
261+ } ) ;
262+ }
263+
264+ /**
265+ * Extract a .zip archive
266+ * @param mongoDBArchive Archive location
267+ * @param extractDir Directory to extract to
268+ * @param filter Method to determine which files to extract
269+ */
270+ async extractZip (
271+ mongoDBArchive : string ,
272+ extractDir : string ,
273+ filter : ( file : string ) => boolean
274+ ) : Promise < void > {
275+ return new Promise ( ( resolve , reject ) => {
276+ yauzl . open ( mongoDBArchive , { lazyEntries : true } , ( e , zipfile ) => {
277+ if ( e || ! zipfile ) return reject ( e ) ;
278+ zipfile . readEntry ( ) ;
279+
280+ zipfile . on ( 'end' , ( ) => resolve ( ) ) ;
281+
282+ zipfile . on ( 'entry' , ( entry ) => {
283+ if ( ! filter ( entry . fileName ) ) return zipfile . readEntry ( ) ;
284+ zipfile . openReadStream ( entry , ( e , r ) => {
285+ if ( e || ! r ) return reject ( e ) ;
286+ r . on ( 'end' , ( ) => zipfile . readEntry ( ) ) ;
287+ r . pipe (
288+ fs . createWriteStream ( path . resolve ( extractDir , path . basename ( entry . fileName ) ) , {
289+ mode : 0o775 ,
290+ } )
291+ ) ;
292+ } ) ;
293+ } ) ;
294+ } ) ;
295+ } ) ;
296+ }
297+
217298 /**
218299 * Downlaod given httpOptions to tempDownloadLocation, then move it to downloadLocation
219300 * @param httpOptions The httpOptions directly passed to https.get
@@ -233,10 +314,10 @@ export default class MongoBinaryDownload {
233314 if ( response . statusCode != 200 ) {
234315 if ( response . statusCode === 403 ) {
235316 reject (
236- new Error (
237- " Status Code is 403 (MongoDB's 404)\n" +
238- ' This means that the requested version-platform combination dosnt exist'
239- )
317+ new Error ( dedent `
318+ Status Code is 403 (MongoDB's 404)\n
319+ This means that the requested version-platform combination dosnt exist
320+ ` )
240321 ) ;
241322 return ;
242323 }
@@ -304,8 +385,7 @@ export default class MongoBinaryDownload {
304385
305386 const crReturn = this . platform === 'win32' ? '\x1b[0G' : '\r' ;
306387 process . stdout . write (
307- `Downloading MongoDB ${ this . version } : ${ percentComplete } % (${ mbComplete } mb ` +
308- `/ ${ this . dlProgress . totalMb } mb)${ crReturn } `
388+ `Downloading MongoDB ${ this . version } : ${ percentComplete } % (${ mbComplete } mb / ${ this . dlProgress . totalMb } mb)${ crReturn } `
309389 ) ;
310390 }
311391
0 commit comments