"use strict";const fs=require("fs"),path=require("path"),stream=require("stream"),tar=require("tar-stream"),utils=require("../utils"),BaseStream=require("../base_stream");class TarStream extends BaseStream{constructor(r){super(r),this._waitingEntries=[],this._processing=!1,this._init(r)}_init(){const r=this._pack=tar.pack();r.on("end",()=>this.push(null)),r.on("data",r=>this.push(r)),r.on("error",r=>this.emit("error",r))}addEntry(r,t){if(this._processing)return this._waitingEntries.push([r,t]);t=t||{},this._processing=!0;const e=utils.entryType(r);e&&("fileOrDir"===e?this._addFileOrDirEntry(r,t):"buffer"===e?this._addBufferEntry(r,t):this._addStreamEntry(r,t))}_addFileOrDirEntry(r,t){fs.stat(r,(e,i)=>{if(e)return this.emit("error",e);if(i.isDirectory())return this._addDirEntry(r,t);if(i.isFile())return this._addFileEntry(r,t);const s=new Error("Type is not supported, must be a file path, directory path, file buffer, or a readable stream");s.name="IlligalEntryError",this.emit("error",s)})}_addFileEntry(r,t){fs.stat(r,(e,i)=>{if(e)return this.emit("error",e);const s=this._pack.entry({name:t.relativePath||path.basename(r),size:i.size,mode:511&i.mode},this._onEntryFinish.bind(this)),a=fs.createReadStream(r,t.fs);a.on("error",r=>this.emit("error",r)),a.pipe(s)})}_addDirEntry(r,t){fs.readdir(r,(e,i)=>{if(e)return this.emit("error",e);const s=t.relativePath||"";i.forEach(e=>{const i=utils.clone(t);t.ignoreBase?i.relativePath=path.join(s,e):i.relativePath=path.join(s,path.basename(r),e),i.ignoreBase=!0,this.addEntry(path.join(r,e),i)}),this._onEntryFinish()})}_addBufferEntry(r,t){if(!t.relativePath)return this.emit("error","opts.relativePath is required if entry is a buffer");this._pack.entry({name:t.relativePath},r,this._onEntryFinish.bind(this))}_addStreamEntry(r,t){if(r.on("error",r=>this.emit("error",r)),!t.relativePath)return this.emit("error",new Error("opts.relativePath is required"));if(t.size){const e=this._pack.entry({name:t.relativePath,size:t.size},this._onEntryFinish.bind(this));r.pipe(e)}else{t.suppressSizeWarning||console.warn("You should specify the size of streamming data by opts.size to prevent all streaming data from loading into memory. If you are sure about memory cost, pass opts.supressSizeWarning: true to suppress this warning");const e=[],i=new stream.Writable({write(r,t,i){e.push(r),i()}});i.on("error",r=>this.emit("error",r)),i.on("finish",()=>{this._pack.entry({name:t.relativePath},Buffer.concat(e),this._onEntryFinish.bind(this))}),r.pipe(i)}}_read(){}_onEntryFinish(r){if(r)return this.emit("error",r);this._processing=!1;const t=this._waitingEntries.shift();t?this.addEntry.apply(this,t):this._finalize()}_finalize(){this._pack.finalize()}}module.exports=TarStream;