const Promise = require('bluebird')

const promisify = Promise.promisify

const {createHash} = require('crypto')
const {createWriteStream} = require('fs')
const {join, basename} = require('path')

const log = require('npmlog')
const mkdirp = promisify(require('mkdirp'))
const openZip = promisify(require('yauzl').open)

function unpack (sourceArchive, groups, directory) {
  log.silly('unpack', 'unpacking', sourceArchive)
  const path = join(directory, createHash('sha1').update(sourceArchive).digest('hex'))
  const group = groups.get(sourceArchive)
  return mkdirp(path).then(() => new Promise((resolve, reject) => {
    log.verbose('unpack', 'made', path)
    openZip(sourceArchive, {autoClose: false}).then(zf => {
      log.verbose('unpack', 'unpacking up to', zf.entryCount, 'entries')
      const entries = []

      const tracker = group.newItem(
        'scanning: ' + basename(sourceArchive),
        zf.entryCount,
        1
      )

      zf.on('error', reject)
      zf.on('entry', entry => {
        tracker.completeWork(1)

        if (/\/$/.test(entry.fileName)) {
          log.silly('unpack', 'skipping directory', entry.fileName)
          return
        }

        groups.set(entry.fileName, group.newGroup('extract: ' + entry.fileName))
        entries.push(entry)
      })
      zf.on('end', () => {
        Promise.map(entries, zipData => new Promise((resolve, reject) => {
          log.silly('unpack', 'zipData', zipData)

          const fullPath = join(path, zipData.fileName)
          const writeTracker = groups.get(zipData.fileName).newStream(
            'writing: ' + zipData.fileName,
            zipData.uncompressedSize,
            3
          )

          zf.openReadStream(zipData, function (err, zipstream) {
            if (err) {
              log.error('unpack', 'reading stream', err.stack)
              return reject(err)
            }

            log.verbose('unpack', 'writing', fullPath, zipData.uncompressedSize)
            zipstream
              .pipe(writeTracker)
              .pipe(createWriteStream(fullPath))
              .on('error', reject)
              .on('finish', () => {
                log.verbose('unpack', 'finished writing', fullPath)
                resolve({ sourceArchive, zipData, path: fullPath })
              })
          })
        }), {concurrency: 1}).then(paths => {
          log.silly('unpack', 'unpacked', sourceArchive, 'to', paths)
          resolve(paths)
        })
      })
    }).catch(reject)
  }))
}

module.exports = { unpack }

@@ -169,16 +169,25 @@
 basename
+, dirname
 %7D = requ
@@ -198,16 +198,16 @@
 'path')%0A
-
 %0Aconst l
@@ -1200,16 +1200,36 @@
 ups.set(
+%0A          basename(
 entry.fi
@@ -1234,17 +1234,28 @@
 fileName
-,
+),%0A         
  group.n
@@ -1291,16 +1291,25 @@
 ileName)
+%0A        
 )%0A      
@@ -1590,16 +1590,25 @@
 ups.get(
+basename(
 zipData.
@@ -1616,16 +1616,17 @@
 ileName)
+)
 .newStre
@@ -1929,32 +1929,160 @@
 %0A            %7D%0A%0A
+            log.verbose('unpack', 'creating directory', dirname(fullPath))%0A            mkdirp(dirname(fullPath)).then(() =%3E %7B%0A  
             log.
@@ -2146,16 +2146,18 @@
 edSize)%0A
+  
         
@@ -2180,24 +2180,26 @@
             
+  
 .pipe(writeT
@@ -2206,16 +2206,18 @@
 racker)%0A
+  
         
@@ -2267,24 +2267,26 @@
             
+ 
+ 
 .on('error',
@@ -2290,24 +2290,26 @@
 r', reject)%0A
+  
             
@@ -2324,32 +2324,34 @@
 inish', () =%3E %7B%0A
+  
                 
@@ -2410,32 +2410,34 @@
                 
+  
 resolve(%7B source
@@ -2470,24 +2470,41 @@
 llPath %7D)%0A  
+              %7D)%0A
             

deal with zip files containing directories