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
JavaScript
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 };