Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
pack.js511 linesDownload Raw Back to commonjs
1"use strict";
2// A readable tar stream creator
3// Technically, this is a transform stream that you write paths into,
4// and tar format comes out of.
5// The `add()` method is like `write()` but returns this,
6// and end() return `this` as well, so you can
7// do `new Pack(opt).add('files').add('dir').end().pipe(output)
8// You could also do something like:
9// streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar'))
10var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11    if (k2 === undefined) k2 = k;
12    var desc = Object.getOwnPropertyDescriptor(m, k);
13    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14      desc = { enumerable: true, get: function() { return m[k]; } };
15    }
16    Object.defineProperty(o, k2, desc);
17}) : (function(o, m, k, k2) {
18    if (k2 === undefined) k2 = k;
19    o[k2] = m[k];
20}));
21var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22    Object.defineProperty(o, "default", { enumerable: true, value: v });
23}) : function(o, v) {
24    o["default"] = v;
25});
26var __importStar = (this && this.__importStar) || (function () {
27    var ownKeys = function(o) {
28        ownKeys = Object.getOwnPropertyNames || function (o) {
29            var ar = [];
30            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31            return ar;
32        };
33        return ownKeys(o);
34    };
35    return function (mod) {
36        if (mod && mod.__esModule) return mod;
37        var result = {};
38        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39        __setModuleDefault(result, mod);
40        return result;
41    };
42})();
43var __importDefault = (this && this.__importDefault) || function (mod) {
44    return (mod && mod.__esModule) ? mod : { "default": mod };
45};
46Object.defineProperty(exports, "__esModule", { value: true });
47exports.PackSync = exports.Pack = exports.PackJob = void 0;
48const fs_1 = __importDefault(require("fs"));
49const write_entry_js_1 = require("./write-entry.js");
50class PackJob {
51    path;
52    absolute;
53    entry;
54    stat;
55    readdir;
56    pending = false;
57    ignore = false;
58    piped = false;
59    constructor(path, absolute) {
60        this.path = path || './';
61        this.absolute = absolute;
62    }
63}
64exports.PackJob = PackJob;
65const minipass_1 = require("minipass");
66const zlib = __importStar(require("minizlib"));
67const yallist_1 = require("yallist");
68const read_entry_js_1 = require("./read-entry.js");
69const warn_method_js_1 = require("./warn-method.js");
70const EOF = Buffer.alloc(1024);
71const ONSTAT = Symbol('onStat');
72const ENDED = Symbol('ended');
73const QUEUE = Symbol('queue');
74const CURRENT = Symbol('current');
75const PROCESS = Symbol('process');
76const PROCESSING = Symbol('processing');
77const PROCESSJOB = Symbol('processJob');
78const JOBS = Symbol('jobs');
79const JOBDONE = Symbol('jobDone');
80const ADDFSENTRY = Symbol('addFSEntry');
81const ADDTARENTRY = Symbol('addTarEntry');
82const STAT = Symbol('stat');
83const READDIR = Symbol('readdir');
84const ONREADDIR = Symbol('onreaddir');
85const PIPE = Symbol('pipe');
86const ENTRY = Symbol('entry');
87const ENTRYOPT = Symbol('entryOpt');
88const WRITEENTRYCLASS = Symbol('writeEntryClass');
89const WRITE = Symbol('write');
90const ONDRAIN = Symbol('ondrain');
91const path_1 = __importDefault(require("path"));
92const normalize_windows_path_js_1 = require("./normalize-windows-path.js");
93class Pack extends minipass_1.Minipass {
94    sync = false;
95    opt;
96    cwd;
97    maxReadSize;
98    preservePaths;
99    strict;
100    noPax;
101    prefix;
102    linkCache;
103    statCache;
104    file;
105    portable;
106    zip;
107    readdirCache;
108    noDirRecurse;
109    follow;
110    noMtime;
111    mtime;
112    filter;
113    jobs;
114    [WRITEENTRYCLASS];
115    onWriteEntry;
116    // Note: we actually DO need a linked list here, because we
117    // shift() to update the head of the list where we start, but still
118    // while that happens, need to know what the next item in the queue
119    // will be. Since we do multiple jobs in parallel, it's not as simple
120    // as just an Array.shift(), since that would lose the information about
121    // the next job in the list. We could add a .next field on the PackJob
122    // class, but then we'd have to be tracking the tail of the queue the
123    // whole time, and Yallist just does that for us anyway.
124    [QUEUE];
125    [JOBS] = 0;
126    [PROCESSING] = false;
127    [ENDED] = false;
128    constructor(opt = {}) {
129        super();
130        this.opt = opt;
131        this.file = opt.file || '';
132        this.cwd = opt.cwd || process.cwd();
133        this.maxReadSize = opt.maxReadSize;
134        this.preservePaths = !!opt.preservePaths;
135        this.strict = !!opt.strict;
136        this.noPax = !!opt.noPax;
137        this.prefix = (0, normalize_windows_path_js_1.normalizeWindowsPath)(opt.prefix || '');
138        this.linkCache = opt.linkCache || new Map();
139        this.statCache = opt.statCache || new Map();
140        this.readdirCache = opt.readdirCache || new Map();
141        this.onWriteEntry = opt.onWriteEntry;
142        this[WRITEENTRYCLASS] = write_entry_js_1.WriteEntry;
143        if (typeof opt.onwarn === 'function') {
144            this.on('warn', opt.onwarn);
145        }
146        this.portable = !!opt.portable;
147        if (opt.gzip || opt.brotli || opt.zstd) {
148            if ((opt.gzip ? 1 : 0) + (opt.brotli ? 1 : 0) + (opt.zstd ? 1 : 0) >
149                1) {
150                throw new TypeError('gzip, brotli, zstd are mutually exclusive');
151            }
152            if (opt.gzip) {
153                if (typeof opt.gzip !== 'object') {
154                    opt.gzip = {};
155                }
156                if (this.portable) {
157                    opt.gzip.portable = true;
158                }
159                this.zip = new zlib.Gzip(opt.gzip);
160            }
161            if (opt.brotli) {
162                if (typeof opt.brotli !== 'object') {
163                    opt.brotli = {};
164                }
165                this.zip = new zlib.BrotliCompress(opt.brotli);
166            }
167            if (opt.zstd) {
168                if (typeof opt.zstd !== 'object') {
169                    opt.zstd = {};
170                }
171                this.zip = new zlib.ZstdCompress(opt.zstd);
172            }
173            /* c8 ignore next */
174            if (!this.zip)
175                throw new Error('impossible');
176            const zip = this.zip;
177            zip.on('data', chunk => super.write(chunk));
178            zip.on('end', () => super.end());
179            zip.on('drain', () => this[ONDRAIN]());
180            this.on('resume', () => zip.resume());
181        }
182        else {
183            this.on('drain', this[ONDRAIN]);
184        }
185        this.noDirRecurse = !!opt.noDirRecurse;
186        this.follow = !!opt.follow;
187        this.noMtime = !!opt.noMtime;
188        if (opt.mtime)
189            this.mtime = opt.mtime;
190        this.filter =
191            typeof opt.filter === 'function' ? opt.filter : () => true;
192        this[QUEUE] = new yallist_1.Yallist();
193        this[JOBS] = 0;
194        this.jobs = Number(opt.jobs) || 4;
195        this[PROCESSING] = false;
196        this[ENDED] = false;
197    }
198    [WRITE](chunk) {
199        return super.write(chunk);
200    }
201    add(path) {
202        this.write(path);
203        return this;
204    }
205    end(path, encoding, cb) {
206        /* c8 ignore start */
207        if (typeof path === 'function') {
208            cb = path;
209            path = undefined;
210        }
211        if (typeof encoding === 'function') {
212            cb = encoding;
213            encoding = undefined;
214        }
215        /* c8 ignore stop */
216        if (path) {
217            this.add(path);
218        }
219        this[ENDED] = true;
220        this[PROCESS]();
221        /* c8 ignore next */
222        if (cb)
223            cb();
224        return this;
225    }
226    write(path) {
227        if (this[ENDED]) {
228            throw new Error('write after end');
229        }
230        if (path instanceof read_entry_js_1.ReadEntry) {
231            this[ADDTARENTRY](path);
232        }
233        else {
234            this[ADDFSENTRY](path);
235        }
236        return this.flowing;
237    }
238    [ADDTARENTRY](p) {
239        const absolute = (0, normalize_windows_path_js_1.normalizeWindowsPath)(path_1.default.resolve(this.cwd, p.path));
240        // in this case, we don't have to wait for the stat
241        if (!this.filter(p.path, p)) {
242            p.resume();
243        }
244        else {
245            const job = new PackJob(p.path, absolute);
246            job.entry = new write_entry_js_1.WriteEntryTar(p, this[ENTRYOPT](job));
247            job.entry.on('end', () => this[JOBDONE](job));
248            this[JOBS] += 1;
249            this[QUEUE].push(job);
250        }
251        this[PROCESS]();
252    }
253    [ADDFSENTRY](p) {
254        const absolute = (0, normalize_windows_path_js_1.normalizeWindowsPath)(path_1.default.resolve(this.cwd, p));
255        this[QUEUE].push(new PackJob(p, absolute));
256        this[PROCESS]();
257    }
258    [STAT](job) {
259        job.pending = true;
260        this[JOBS] += 1;
261        const stat = this.follow ? 'stat' : 'lstat';
262        fs_1.default[stat](job.absolute, (er, stat) => {
263            job.pending = false;
264            this[JOBS] -= 1;
265            if (er) {
266                this.emit('error', er);
267            }
268            else {
269                this[ONSTAT](job, stat);
270            }
271        });
272    }
273    [ONSTAT](job, stat) {
274        this.statCache.set(job.absolute, stat);
275        job.stat = stat;
276        // now we have the stat, we can filter it.
277        if (!this.filter(job.path, stat)) {
278            job.ignore = true;
279        }
280        else if (stat.isFile() &&
281            stat.nlink > 1 &&
282            job === this[CURRENT] &&
283            !this.linkCache.get(`${stat.dev}:${stat.ino}`) &&
284            !this.sync) {
285            // if it's not filtered, and it's a new File entry,
286            // jump the queue in case any pending Link entries are about
287            // to try to link to it. This prevents a hardlink from coming ahead
288            // of its target in the archive.
289            this[PROCESSJOB](job);
290        }
291        this[PROCESS]();
292    }
293    [READDIR](job) {
294        job.pending = true;
295        this[JOBS] += 1;
296        fs_1.default.readdir(job.absolute, (er, entries) => {
297            job.pending = false;
298            this[JOBS] -= 1;
299            if (er) {
300                return this.emit('error', er);
301            }
302            this[ONREADDIR](job, entries);
303        });
304    }
305    [ONREADDIR](job, entries) {
306        this.readdirCache.set(job.absolute, entries);
307        job.readdir = entries;
308        this[PROCESS]();
309    }
310    [PROCESS]() {
311        if (this[PROCESSING]) {
312            return;
313        }
314        this[PROCESSING] = true;
315        for (let w = this[QUEUE].head; !!w && this[JOBS] < this.jobs; w = w.next) {
316            this[PROCESSJOB](w.value);
317            if (w.value.ignore) {
318                const p = w.next;
319                this[QUEUE].removeNode(w);
320                w.next = p;
321            }
322        }
323        this[PROCESSING] = false;
324        if (this[ENDED] && this[QUEUE].length === 0 && this[JOBS] === 0) {
325            if (this.zip) {
326                this.zip.end(EOF);
327            }
328            else {
329                super.write(EOF);
330                super.end();
331            }
332        }
333    }
334    get [CURRENT]() {
335        return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value;
336    }
337    [JOBDONE](_job) {
338        this[QUEUE].shift();
339        this[JOBS] -= 1;
340        this[PROCESS]();
341    }
342    [PROCESSJOB](job) {
343        if (job.pending) {
344            return;
345        }
346        if (job.entry) {
347            if (job === this[CURRENT] && !job.piped) {
348                this[PIPE](job);
349            }
350            return;
351        }
352        if (!job.stat) {
353            const sc = this.statCache.get(job.absolute);
354            if (sc) {
355                this[ONSTAT](job, sc);
356            }
357            else {
358                this[STAT](job);
359            }
360        }
361        if (!job.stat) {
362            return;
363        }
364        // filtered out!
365        if (job.ignore) {
366            return;
367        }
368        if (!this.noDirRecurse && job.stat.isDirectory() && !job.readdir) {
369            const rc = this.readdirCache.get(job.absolute);
370            if (rc) {
371                this[ONREADDIR](job, rc);
372            }
373            else {
374                this[READDIR](job);
375            }
376            if (!job.readdir) {
377                return;
378            }
379        }
380        // we know it doesn't have an entry, because that got checked above
381        job.entry = this[ENTRY](job);
382        if (!job.entry) {
383            job.ignore = true;
384            return;
385        }
386        if (job === this[CURRENT] && !job.piped) {
387            this[PIPE](job);
388        }
389    }
390    [ENTRYOPT](job) {
391        return {
392            onwarn: (code, msg, data) => this.warn(code, msg, data),
393            noPax: this.noPax,
394            cwd: this.cwd,
395            absolute: job.absolute,
396            preservePaths: this.preservePaths,
397            maxReadSize: this.maxReadSize,
398            strict: this.strict,
399            portable: this.portable,
400            linkCache: this.linkCache,
401            statCache: this.statCache,
402            noMtime: this.noMtime,
403            mtime: this.mtime,
404            prefix: this.prefix,
405            onWriteEntry: this.onWriteEntry,
406        };
407    }
408    [ENTRY](job) {
409        this[JOBS] += 1;
410        try {
411            const e = new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job));
412            return e
413                .on('end', () => this[JOBDONE](job))
414                .on('error', er => this.emit('error', er));
415        }
416        catch (er) {
417            this.emit('error', er);
418        }
419    }
420    [ONDRAIN]() {
421        if (this[CURRENT] && this[CURRENT].entry) {
422            this[CURRENT].entry.resume();
423        }
424    }
425    // like .pipe() but using super, because our write() is special
426    [PIPE](job) {
427        job.piped = true;
428        if (job.readdir) {
429            job.readdir.forEach(entry => {
430                const p = job.path;
431                const base = p === './' ? '' : p.replace(/\/*$/, '/');
432                this[ADDFSENTRY](base + entry);
433            });
434        }
435        const source = job.entry;
436        const zip = this.zip;
437        /* c8 ignore start */
438        if (!source)
439            throw new Error('cannot pipe without source');
440        /* c8 ignore stop */
441        if (zip) {
442            source.on('data', chunk => {
443                if (!zip.write(chunk)) {
444                    source.pause();
445                }
446            });
447        }
448        else {
449            source.on('data', chunk => {
450                if (!super.write(chunk)) {
451                    source.pause();
452                }
453            });
454        }
455    }
456    pause() {
457        if (this.zip) {
458            this.zip.pause();
459        }
460        return super.pause();
461    }
462    warn(code, message, data = {}) {
463        (0, warn_method_js_1.warnMethod)(this, code, message, data);
464    }
465}
466exports.Pack = Pack;
467class PackSync extends Pack {
468    sync = true;
469    constructor(opt) {
470        super(opt);
471        this[WRITEENTRYCLASS] = write_entry_js_1.WriteEntrySync;
472    }
473    // pause/resume are no-ops in sync streams.
474    pause() { }
475    resume() { }
476    [STAT](job) {
477        const stat = this.follow ? 'statSync' : 'lstatSync';
478        this[ONSTAT](job, fs_1.default[stat](job.absolute));
479    }
480    [READDIR](job) {
481        this[ONREADDIR](job, fs_1.default.readdirSync(job.absolute));
482    }
483    // gotta get it all in this tick
484    [PIPE](job) {
485        const source = job.entry;
486        const zip = this.zip;
487        if (job.readdir) {
488            job.readdir.forEach(entry => {
489                const p = job.path;
490                const base = p === './' ? '' : p.replace(/\/*$/, '/');
491                this[ADDFSENTRY](base + entry);
492            });
493        }
494        /* c8 ignore start */
495        if (!source)
496            throw new Error('Cannot pipe without source');
497        /* c8 ignore stop */
498        if (zip) {
499            source.on('data', chunk => {
500                zip.write(chunk);
501            });
502        }
503        else {
504            source.on('data', chunk => {
505                super[WRITE](chunk);
506            });
507        }
508    }
509}
510exports.PackSync = PackSync;
511//# sourceMappingURL=pack.js.map
codekingpro/portable-devtools · Team Ai