Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
pack.js516 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        //@ts-ignore
130        super();
131        this.opt = opt;
132        this.file = opt.file || '';
133        this.cwd = opt.cwd || process.cwd();
134        this.maxReadSize = opt.maxReadSize;
135        this.preservePaths = !!opt.preservePaths;
136        this.strict = !!opt.strict;
137        this.noPax = !!opt.noPax;
138        this.prefix = (0, normalize_windows_path_js_1.normalizeWindowsPath)(opt.prefix || '');
139        this.linkCache = opt.linkCache || new Map();
140        this.statCache = opt.statCache || new Map();
141        this.readdirCache = opt.readdirCache || new Map();
142        this.onWriteEntry = opt.onWriteEntry;
143        this[WRITEENTRYCLASS] = write_entry_js_1.WriteEntry;
144        if (typeof opt.onwarn === 'function') {
145            this.on('warn', opt.onwarn);
146        }
147        this.portable = !!opt.portable;
148        if (opt.gzip || opt.brotli || opt.zstd) {
149            if ((opt.gzip ? 1 : 0) +
150                (opt.brotli ? 1 : 0) +
151                (opt.zstd ? 1 : 0) >
152                1) {
153                throw new TypeError('gzip, brotli, zstd are mutually exclusive');
154            }
155            if (opt.gzip) {
156                if (typeof opt.gzip !== 'object') {
157                    opt.gzip = {};
158                }
159                if (this.portable) {
160                    opt.gzip.portable = true;
161                }
162                this.zip = new zlib.Gzip(opt.gzip);
163            }
164            if (opt.brotli) {
165                if (typeof opt.brotli !== 'object') {
166                    opt.brotli = {};
167                }
168                this.zip = new zlib.BrotliCompress(opt.brotli);
169            }
170            if (opt.zstd) {
171                if (typeof opt.zstd !== 'object') {
172                    opt.zstd = {};
173                }
174                this.zip = new zlib.ZstdCompress(opt.zstd);
175            }
176            /* c8 ignore next */
177            if (!this.zip)
178                throw new Error('impossible');
179            const zip = this.zip;
180            zip.on('data', chunk => super.write(chunk));
181            zip.on('end', () => super.end());
182            zip.on('drain', () => this[ONDRAIN]());
183            this.on('resume', () => zip.resume());
184        }
185        else {
186            this.on('drain', this[ONDRAIN]);
187        }
188        this.noDirRecurse = !!opt.noDirRecurse;
189        this.follow = !!opt.follow;
190        this.noMtime = !!opt.noMtime;
191        if (opt.mtime)
192            this.mtime = opt.mtime;
193        this.filter =
194            typeof opt.filter === 'function' ? opt.filter : () => true;
195        this[QUEUE] = new yallist_1.Yallist();
196        this[JOBS] = 0;
197        this.jobs = Number(opt.jobs) || 4;
198        this[PROCESSING] = false;
199        this[ENDED] = false;
200    }
201    [WRITE](chunk) {
202        return super.write(chunk);
203    }
204    add(path) {
205        this.write(path);
206        return this;
207    }
208    end(path, encoding, cb) {
209        /* c8 ignore start */
210        if (typeof path === 'function') {
211            cb = path;
212            path = undefined;
213        }
214        if (typeof encoding === 'function') {
215            cb = encoding;
216            encoding = undefined;
217        }
218        /* c8 ignore stop */
219        if (path) {
220            this.add(path);
221        }
222        this[ENDED] = true;
223        this[PROCESS]();
224        /* c8 ignore next */
225        if (cb)
226            cb();
227        return this;
228    }
229    write(path) {
230        if (this[ENDED]) {
231            throw new Error('write after end');
232        }
233        if (path instanceof read_entry_js_1.ReadEntry) {
234            this[ADDTARENTRY](path);
235        }
236        else {
237            this[ADDFSENTRY](path);
238        }
239        return this.flowing;
240    }
241    [ADDTARENTRY](p) {
242        const absolute = (0, normalize_windows_path_js_1.normalizeWindowsPath)(path_1.default.resolve(this.cwd, p.path));
243        // in this case, we don't have to wait for the stat
244        if (!this.filter(p.path, p)) {
245            p.resume();
246        }
247        else {
248            const job = new PackJob(p.path, absolute);
249            job.entry = new write_entry_js_1.WriteEntryTar(p, this[ENTRYOPT](job));
250            job.entry.on('end', () => this[JOBDONE](job));
251            this[JOBS] += 1;
252            this[QUEUE].push(job);
253        }
254        this[PROCESS]();
255    }
256    [ADDFSENTRY](p) {
257        const absolute = (0, normalize_windows_path_js_1.normalizeWindowsPath)(path_1.default.resolve(this.cwd, p));
258        this[QUEUE].push(new PackJob(p, absolute));
259        this[PROCESS]();
260    }
261    [STAT](job) {
262        job.pending = true;
263        this[JOBS] += 1;
264        const stat = this.follow ? 'stat' : 'lstat';
265        fs_1.default[stat](job.absolute, (er, stat) => {
266            job.pending = false;
267            this[JOBS] -= 1;
268            if (er) {
269                this.emit('error', er);
270            }
271            else {
272                this[ONSTAT](job, stat);
273            }
274        });
275    }
276    [ONSTAT](job, stat) {
277        this.statCache.set(job.absolute, stat);
278        job.stat = stat;
279        // now we have the stat, we can filter it.
280        if (!this.filter(job.path, stat)) {
281            job.ignore = true;
282        }
283        else if (stat.isFile() &&
284            stat.nlink > 1 &&
285            job === this[CURRENT] &&
286            !this.linkCache.get(`${stat.dev}:${stat.ino}`) &&
287            !this.sync) {
288            // if it's not filtered, and it's a new File entry,
289            // jump the queue in case any pending Link entries are about
290            // to try to link to it. This prevents a hardlink from coming ahead
291            // of its target in the archive.
292            this[PROCESSJOB](job);
293        }
294        this[PROCESS]();
295    }
296    [READDIR](job) {
297        job.pending = true;
298        this[JOBS] += 1;
299        fs_1.default.readdir(job.absolute, (er, entries) => {
300            job.pending = false;
301            this[JOBS] -= 1;
302            if (er) {
303                return this.emit('error', er);
304            }
305            this[ONREADDIR](job, entries);
306        });
307    }
308    [ONREADDIR](job, entries) {
309        this.readdirCache.set(job.absolute, entries);
310        job.readdir = entries;
311        this[PROCESS]();
312    }
313    [PROCESS]() {
314        if (this[PROCESSING]) {
315            return;
316        }
317        this[PROCESSING] = true;
318        for (let w = this[QUEUE].head; !!w && this[JOBS] < this.jobs; w = w.next) {
319            this[PROCESSJOB](w.value);
320            if (w.value.ignore) {
321                const p = w.next;
322                this[QUEUE].removeNode(w);
323                w.next = p;
324            }
325        }
326        this[PROCESSING] = false;
327        if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) {
328            if (this.zip) {
329                this.zip.end(EOF);
330            }
331            else {
332                super.write(EOF);
333                super.end();
334            }
335        }
336    }
337    get [CURRENT]() {
338        return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value;
339    }
340    [JOBDONE](_job) {
341        this[QUEUE].shift();
342        this[JOBS] -= 1;
343        this[PROCESS]();
344    }
345    [PROCESSJOB](job) {
346        if (job.pending) {
347            return;
348        }
349        if (job.entry) {
350            if (job === this[CURRENT] && !job.piped) {
351                this[PIPE](job);
352            }
353            return;
354        }
355        if (!job.stat) {
356            const sc = this.statCache.get(job.absolute);
357            if (sc) {
358                this[ONSTAT](job, sc);
359            }
360            else {
361                this[STAT](job);
362            }
363        }
364        if (!job.stat) {
365            return;
366        }
367        // filtered out!
368        if (job.ignore) {
369            return;
370        }
371        if (!this.noDirRecurse &&
372            job.stat.isDirectory() &&
373            !job.readdir) {
374            const rc = this.readdirCache.get(job.absolute);
375            if (rc) {
376                this[ONREADDIR](job, rc);
377            }
378            else {
379                this[READDIR](job);
380            }
381            if (!job.readdir) {
382                return;
383            }
384        }
385        // we know it doesn't have an entry, because that got checked above
386        job.entry = this[ENTRY](job);
387        if (!job.entry) {
388            job.ignore = true;
389            return;
390        }
391        if (job === this[CURRENT] && !job.piped) {
392            this[PIPE](job);
393        }
394    }
395    [ENTRYOPT](job) {
396        return {
397            onwarn: (code, msg, data) => this.warn(code, msg, data),
398            noPax: this.noPax,
399            cwd: this.cwd,
400            absolute: job.absolute,
401            preservePaths: this.preservePaths,
402            maxReadSize: this.maxReadSize,
403            strict: this.strict,
404            portable: this.portable,
405            linkCache: this.linkCache,
406            statCache: this.statCache,
407            noMtime: this.noMtime,
408            mtime: this.mtime,
409            prefix: this.prefix,
410            onWriteEntry: this.onWriteEntry,
411        };
412    }
413    [ENTRY](job) {
414        this[JOBS] += 1;
415        try {
416            const e = new this[WRITEENTRYCLASS](job.path, this[ENTRYOPT](job));
417            return e
418                .on('end', () => this[JOBDONE](job))
419                .on('error', er => this.emit('error', er));
420        }
421        catch (er) {
422            this.emit('error', er);
423        }
424    }
425    [ONDRAIN]() {
426        if (this[CURRENT] && this[CURRENT].entry) {
427            this[CURRENT].entry.resume();
428        }
429    }
430    // like .pipe() but using super, because our write() is special
431    [PIPE](job) {
432        job.piped = true;
433        if (job.readdir) {
434            job.readdir.forEach(entry => {
435                const p = job.path;
436                const base = p === './' ? '' : p.replace(/\/*$/, '/');
437                this[ADDFSENTRY](base + entry);
438            });
439        }
440        const source = job.entry;
441        const zip = this.zip;
442        /* c8 ignore start */
443        if (!source)
444            throw new Error('cannot pipe without source');
445        /* c8 ignore stop */
446        if (zip) {
447            source.on('data', chunk => {
448                if (!zip.write(chunk)) {
449                    source.pause();
450                }
451            });
452        }
453        else {
454            source.on('data', chunk => {
455                if (!super.write(chunk)) {
456                    source.pause();
457                }
458            });
459        }
460    }
461    pause() {
462        if (this.zip) {
463            this.zip.pause();
464        }
465        return super.pause();
466    }
467    warn(code, message, data = {}) {
468        (0, warn_method_js_1.warnMethod)(this, code, message, data);
469    }
470}
471exports.Pack = Pack;
472class PackSync extends Pack {
473    sync = true;
474    constructor(opt) {
475        super(opt);
476        this[WRITEENTRYCLASS] = write_entry_js_1.WriteEntrySync;
477    }
478    // pause/resume are no-ops in sync streams.
479    pause() { }
480    resume() { }
481    [STAT](job) {
482        const stat = this.follow ? 'statSync' : 'lstatSync';
483        this[ONSTAT](job, fs_1.default[stat](job.absolute));
484    }
485    [READDIR](job) {
486        this[ONREADDIR](job, fs_1.default.readdirSync(job.absolute));
487    }
488    // gotta get it all in this tick
489    [PIPE](job) {
490        const source = job.entry;
491        const zip = this.zip;
492        if (job.readdir) {
493            job.readdir.forEach(entry => {
494                const p = job.path;
495                const base = p === './' ? '' : p.replace(/\/*$/, '/');
496                this[ADDFSENTRY](base + entry);
497            });
498        }
499        /* c8 ignore start */
500        if (!source)
501            throw new Error('Cannot pipe without source');
502        /* c8 ignore stop */
503        if (zip) {
504            source.on('data', chunk => {
505                zip.write(chunk);
506            });
507        }
508        else {
509            source.on('data', chunk => {
510                super[WRITE](chunk);
511            });
512        }
513    }
514}
515exports.PackSync = PackSync;
516//# sourceMappingURL=pack.js.map
codekingpro/portable-devtools · Team Ai