Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
path-reservations.js170 linesDownload Raw Back to commonjs
1"use strict";
2// A path exclusive reservation system
3// reserve([list, of, paths], fn)
4// When the fn is first in line for all its paths, it
5// is called with a cb that clears the reservation.
6//
7// Used by async unpack to avoid clobbering paths in use,
8// while still allowing maximal safe parallelization.
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.PathReservations = void 0;
11const node_path_1 = require("node:path");
12const normalize_unicode_js_1 = require("./normalize-unicode.js");
13const strip_trailing_slashes_js_1 = require("./strip-trailing-slashes.js");
14const platform = process.env.TESTING_TAR_FAKE_PLATFORM || process.platform;
15const isWindows = platform === 'win32';
16// return a set of parent dirs for a given path
17// '/a/b/c/d' -> ['/', '/a', '/a/b', '/a/b/c', '/a/b/c/d']
18const getDirs = (path) => {
19    const dirs = path
20        .split('/')
21        .slice(0, -1)
22        .reduce((set, path) => {
23        const s = set.at(-1);
24        if (s !== undefined) {
25            path = (0, node_path_1.join)(s, path);
26        }
27        set.push(path || '/');
28        return set;
29    }, []);
30    return dirs;
31};
32class PathReservations {
33    // path => [function or Set]
34    // A Set object means a directory reservation
35    // A fn is a direct reservation on that path
36    #queues = new Map();
37    // fn => {paths:[path,...], dirs:[path, ...]}
38    #reservations = new Map();
39    // functions currently running
40    #running = new Set();
41    reserve(paths, fn) {
42        paths =
43            isWindows ?
44                ['win32 parallelization disabled']
45                : paths.map(p => {
46                    // don't need normPath, because we skip this entirely for windows
47                    return (0, strip_trailing_slashes_js_1.stripTrailingSlashes)((0, node_path_1.join)((0, normalize_unicode_js_1.normalizeUnicode)(p)));
48                });
49        const dirs = new Set(paths.map(path => getDirs(path)).reduce((a, b) => a.concat(b)));
50        this.#reservations.set(fn, { dirs, paths });
51        for (const p of paths) {
52            const q = this.#queues.get(p);
53            if (!q) {
54                this.#queues.set(p, [fn]);
55            }
56            else {
57                q.push(fn);
58            }
59        }
60        for (const dir of dirs) {
61            const q = this.#queues.get(dir);
62            if (!q) {
63                this.#queues.set(dir, [new Set([fn])]);
64            }
65            else {
66                const l = q.at(-1);
67                if (l instanceof Set) {
68                    l.add(fn);
69                }
70                else {
71                    q.push(new Set([fn]));
72                }
73            }
74        }
75        return this.#run(fn);
76    }
77    // return the queues for each path the function cares about
78    // fn => {paths, dirs}
79    #getQueues(fn) {
80        const res = this.#reservations.get(fn);
81        /* c8 ignore start */
82        if (!res) {
83            throw new Error('function does not have any path reservations');
84        }
85        /* c8 ignore stop */
86        return {
87            paths: res.paths.map((path) => this.#queues.get(path)),
88            dirs: [...res.dirs].map(path => this.#queues.get(path)),
89        };
90    }
91    // check if fn is first in line for all its paths, and is
92    // included in the first set for all its dir queues
93    check(fn) {
94        const { paths, dirs } = this.#getQueues(fn);
95        return (paths.every(q => q && q[0] === fn) &&
96            dirs.every(q => q && q[0] instanceof Set && q[0].has(fn)));
97    }
98    // run the function if it's first in line and not already running
99    #run(fn) {
100        if (this.#running.has(fn) || !this.check(fn)) {
101            return false;
102        }
103        this.#running.add(fn);
104        fn(() => this.#clear(fn));
105        return true;
106    }
107    #clear(fn) {
108        if (!this.#running.has(fn)) {
109            return false;
110        }
111        const res = this.#reservations.get(fn);
112        /* c8 ignore start */
113        if (!res) {
114            throw new Error('invalid reservation');
115        }
116        /* c8 ignore stop */
117        const { paths, dirs } = res;
118        const next = new Set();
119        for (const path of paths) {
120            const q = this.#queues.get(path);
121            /* c8 ignore start */
122            if (!q || q?.[0] !== fn) {
123                continue;
124            }
125            /* c8 ignore stop */
126            const q0 = q[1];
127            if (!q0) {
128                this.#queues.delete(path);
129                continue;
130            }
131            q.shift();
132            if (typeof q0 === 'function') {
133                next.add(q0);
134            }
135            else {
136                for (const f of q0) {
137                    next.add(f);
138                }
139            }
140        }
141        for (const dir of dirs) {
142            const q = this.#queues.get(dir);
143            const q0 = q?.[0];
144            /* c8 ignore next - type safety only */
145            if (!q || !(q0 instanceof Set))
146                continue;
147            if (q0.size === 1 && q.length === 1) {
148                this.#queues.delete(dir);
149                continue;
150            }
151            else if (q0.size === 1) {
152                q.shift();
153                // next one must be a function,
154                // or else the Set would've been reused
155                const n = q[0];
156                if (typeof n === 'function') {
157                    next.add(n);
158                }
159            }
160            else {
161                q0.delete(fn);
162            }
163        }
164        this.#running.delete(fn);
165        next.forEach(fn => this.#run(fn));
166        return true;
167    }
168}
169exports.PathReservations = PathReservations;
170//# sourceMappingURL=path-reservations.js.map
codekingpro/portable-devtools · Team Ai