UNPKG

tar-iterator

Version:

Extract contents from tar archive type using an iterator API using streams or paths. Use stream interface and pipe transforms to add decompression algorithms

69 lines (68 loc) 2.55 kB
import once from 'call-once-fn'; import BaseIterator, { Lock } from 'extract-base-iterator'; import fs from 'graceful-fs'; import nextEntry from './nextEntry.js'; import TarExtract from './tar/TarExtract.js'; let TarIterator = class TarIterator extends BaseIterator { end(err) { const lock = this.lock; if (lock) { this.lock = null; // Clear FIRST to prevent re-entrancy lock.err = err; lock.release(); // Lock.__destroy() handles BaseIterator.end() } this.extract = null; } constructor(source, options = {}){ super(options); this.lock = new Lock(); this.lock.onDestroy = (err)=>BaseIterator.prototype.end.call(this, err); let cancelled = false; const setup = ()=>{ cancelled = true; }; this.processing.push(setup); // Use our pure TarExtract instead of tar-stream-compat // Note: options passed here are ExtractOptions (strip, force, etc.) // TarExtract uses TarExtractOptions (filenameEncoding, etc.) which is different this.extract = new TarExtract(); const pipe = (cb)=>{ try { if (typeof source === 'string') source = fs.createReadStream(source); } catch (err) { cb(err); } // Register cleanup for source stream const stream = source; this.lock.registerCleanup(()=>{ const s = stream; if (typeof s.destroy === 'function') s.destroy(); }); const end = once(cb); const self = this; let firstData = true; source.on('data', function onData(chunk) { try { if (self.extract) self.extract.write(chunk); if (firstData) { firstData = false; end(); } } catch (err) { // Handle synchronous errors from TarExtract (e.g., invalid format) end(err); } }); source.on('error', end); source.on('end', function onEnd() { if (self.extract) self.extract.end(); }); }; pipe((err)=>{ this.processing.remove(setup); if (this.done || cancelled) return; // done err ? this.end(err) : this.push(nextEntry.bind(null, null)); }); } }; export { TarIterator as default };