diff --git a/lib/parse.js b/lib/parse.js index 16023f08..4b85915c 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -28,6 +28,7 @@ const maxMetaEntrySize = 1024 * 1024 const Entry = require('./read-entry.js') const Pax = require('./pax.js') const zlib = require('minizlib') +const { nextTick } = require('process') const gzipHeader = Buffer.from([0x1f, 0x8b]) const STATE = Symbol('state') @@ -59,6 +60,7 @@ const DONE = Symbol('onDone') const SAW_VALID_ENTRY = Symbol('sawValidEntry') const SAW_NULL_BLOCK = Symbol('sawNullBlock') const SAW_EOF = Symbol('sawEOF') +const CLOSESTREAM = Symbol('closeStream') const noop = _ => true @@ -89,7 +91,6 @@ module.exports = warner(class Parser extends EE { this.emit('prefinish') this.emit('finish') this.emit('end') - this.emit('close') }) } @@ -114,6 +115,9 @@ module.exports = warner(class Parser extends EE { this[ABORTED] = false this[SAW_NULL_BLOCK] = false this[SAW_EOF] = false + + this.on('end', () => this[CLOSESTREAM]()) + if (typeof opt.onwarn === 'function') { this.on('warn', opt.onwarn) } @@ -217,6 +221,10 @@ module.exports = warner(class Parser extends EE { } } + [CLOSESTREAM] () { + nextTick(() => this.emit('close')) + } + [PROCESSENTRY] (entry) { let go = true diff --git a/lib/unpack.js b/lib/unpack.js index 458f593d..bfe0dddb 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -234,7 +234,6 @@ class Unpack extends Parser { this.emit('prefinish') this.emit('finish') this.emit('end') - this.emit('close') } } diff --git a/package.json b/package.json index bae4b5e2..5db9f816 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,7 @@ "events-to-array": "^1.1.2", "mutate-fs": "^2.1.1", "rimraf": "^3.0.2", - "tap": "^16.0.1", - "tar-fs": "^2.1.1", - "tar-stream": "^2.2.0" + "tap": "^16.0.1" }, "license": "ISC", "engines": { diff --git a/test/extract.js b/test/extract.js index ae13739c..5bbffeec 100644 --- a/test/extract.js +++ b/test/extract.js @@ -10,6 +10,8 @@ const mkdirp = require('mkdirp') const { promisify } = require('util') const rimraf = promisify(require('rimraf')) const mutateFS = require('mutate-fs') +const pipeline = promisify(require('stream').pipeline) +const https = require('https') t.teardown(_ => rimraf(extractdir)) @@ -54,6 +56,32 @@ t.test('basic extracting', t => { t.end() }) +t.test('ensure an open stream is not prematuraly closed', t => { + const dir = path.resolve(extractdir, 'basic-with-stream') + + t.beforeEach(async () => { + await rimraf(dir) + await mkdirp(dir) + }) + + const check = async t => { + fs.lstatSync(dir + '/node-tar-main/LICENSE') + await rimraf(dir) + t.end() + } + + t.test('async promisey', t => { + https.get('https://codeload.github.com/npm/node-tar/tar.gz/main', (stream) => { + return pipeline( + stream, + x({ cwd: dir }, ['node-tar-main/LICENSE']) + ).then(_ => check(t)) + }) + }) + + t.end() +}) + t.test('file list and filter', t => { const file = path.resolve(tars, 'utf8.tar') const dir = path.resolve(extractdir, 'filter')