@threadedstack/wmd-web 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/RELEASE.json +41 -56
- package/guest/arm64/Image +2 -2
- package/guest/arm64/Image-4k +1 -1
- package/guest/arm64/initramfs.cpio.gz +0 -0
- package/guest/arm64/vm.wasm +0 -0
- package/package.json +4 -4
- package/relay/hosted.ts +10 -8
- package/relay/main.ts +2 -2
- package/relay/relay.ts +1 -0
- package/relay/token.ts +34 -5
- package/relay/wisp.ts +37 -5
- package/src/boot.js +53 -9
- package/src/build/builder.js +791 -0
- package/src/build/context.js +349 -0
- package/src/build/dockerfile.js +1055 -0
- package/src/build/dockerignore.js +270 -0
- package/src/build/fast.js +1187 -0
- package/src/build/inspect.js +78 -0
- package/src/build/pin.js +6 -0
- package/src/build/tar.js +304 -0
- package/src/host/ckpt-point.js +55 -10
- package/src/host/ckpt.js +35 -2
- package/src/host/ctl.js +17 -0
- package/src/host/disk-map.js +330 -0
- package/src/host/disk-worker.js +125 -0
- package/src/host/disk.js +219 -0
- package/src/host/wmd-imports.js +3 -3
- package/src/image-files.js +2 -1
- package/src/registry/hub.js +113 -44
- package/src/registry/load-tar.js +473 -0
- package/src/registry/pull.js +5 -3
- package/src/worker.js +5 -1
- package/wmdpack.wasm +0 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// .dockerignore: a port of github.com/moby/patternmatcher (patternmatcher.go and ignorefile/ignorefile.go).
|
|
2
|
+
// BuildKit v0.33 pins patternmatcher v0.6.1 (third_party/buildkit/go.mod); this port was written against the
|
|
3
|
+
// source at github.com/moby/patternmatcher main (5a6d8429a19bb6948a372ff19e86fe83599a04b7), whose matching
|
|
4
|
+
// code is the same as v0.6.1's for the functions ported here (except the escape set, see compile()): New, MatchesOrParentMatches, Pattern.compile and
|
|
5
|
+
// Pattern.match, plus ReadAll. Only Unix separators exist here (the page has no Windows paths).
|
|
6
|
+
//
|
|
7
|
+
// Differences that cannot be matched exactly:
|
|
8
|
+
// - Go's regexp is RE2; patterns compile to JavaScript RegExp. RE2-only syntax is not translated: POSIX classes
|
|
9
|
+
// such as `[[:alpha:]]` and `\Q...\E` literal runs behave as JavaScript reads them, not as Go does.
|
|
10
|
+
// Pattern classes use the same '[a-z]' / '[^a-z]' / '\\x' forms in both, so the shared syntax behaves the same.
|
|
11
|
+
// - Go's `regexp` treats `\a`, `\f`, `\v` etc. as control characters; JavaScript's non-unicode mode treats an
|
|
12
|
+
// unknown escape as the literal character. Only reachable through a backslash before a letter.
|
|
13
|
+
|
|
14
|
+
/** filepath.Clean on '/' paths (Go's lexical Clean). */
|
|
15
|
+
export function cleanPath(p) {
|
|
16
|
+
if (p === '') return '.'
|
|
17
|
+
const rooted = p[0] === '/'
|
|
18
|
+
const out = []
|
|
19
|
+
for (const seg of p.split('/')) {
|
|
20
|
+
if (seg === '' || seg === '.') continue
|
|
21
|
+
if (seg === '..') {
|
|
22
|
+
if (out.length && out[out.length - 1] !== '..') out.pop()
|
|
23
|
+
else if (!rooted) out.push('..')
|
|
24
|
+
continue
|
|
25
|
+
}
|
|
26
|
+
out.push(seg)
|
|
27
|
+
}
|
|
28
|
+
const s = out.join('/')
|
|
29
|
+
if (rooted) return `/${s}`
|
|
30
|
+
return s === '' ? '.' : s
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** filepath.Dir on '/' paths. */
|
|
34
|
+
function dirOf(p) {
|
|
35
|
+
const i = p.lastIndexOf('/')
|
|
36
|
+
if (i < 0) return '.'
|
|
37
|
+
return cleanPath(p.slice(0, i + 1))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** ignorefile.ReadAll: the pattern list of a .dockerignore text. */
|
|
41
|
+
export function parseDockerignore(text) {
|
|
42
|
+
const out = []
|
|
43
|
+
const lines = String(text).split('\n')
|
|
44
|
+
if (lines.length && lines[lines.length - 1] === '') lines.pop() // bufio.ScanLines: no phantom last line
|
|
45
|
+
lines.forEach((raw, idx) => {
|
|
46
|
+
let line = raw.endsWith('\r') ? raw.slice(0, -1) : raw
|
|
47
|
+
if (idx === 0 && line.charCodeAt(0) === 0xfeff) line = line.slice(1)
|
|
48
|
+
if (line.startsWith('#')) return
|
|
49
|
+
let pattern = goTrim(line)
|
|
50
|
+
if (pattern === '') return
|
|
51
|
+
const invert = pattern[0] === '!'
|
|
52
|
+
if (invert) pattern = goTrim(pattern.slice(1))
|
|
53
|
+
if (pattern.length > 0) {
|
|
54
|
+
pattern = cleanPath(pattern)
|
|
55
|
+
if (pattern.length > 1 && pattern[0] === '/') pattern = pattern.slice(1)
|
|
56
|
+
}
|
|
57
|
+
out.push(invert ? `!${pattern}` : pattern)
|
|
58
|
+
})
|
|
59
|
+
return out
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// strings.TrimSpace: Unicode White_Space (JS trim() also strips U+FEFF, which Go does not).
|
|
63
|
+
function goTrim(s) {
|
|
64
|
+
const ws = (c) => {
|
|
65
|
+
const n = c.charCodeAt(0)
|
|
66
|
+
return (n >= 9 && n <= 13) || n === 32 || n === 0x85 || n === 0xa0 || n === 0x1680 || (n >= 0x2000 && n <= 0x200a) ||
|
|
67
|
+
n === 0x2028 || n === 0x2029 || n === 0x202f || n === 0x205f || n === 0x3000
|
|
68
|
+
}
|
|
69
|
+
let a = 0
|
|
70
|
+
let b = s.length
|
|
71
|
+
while (a < b && ws(s[a])) a++
|
|
72
|
+
while (b > a && ws(s[b - 1])) b--
|
|
73
|
+
return s.slice(a, b)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const BAD = 'syntax error in pattern'
|
|
77
|
+
|
|
78
|
+
/** The syntax check New does through filepath.Match(p, "."): throws on a malformed pattern. */
|
|
79
|
+
export function checkPatternSyntax(p) {
|
|
80
|
+
const cs = Array.from(p)
|
|
81
|
+
let i = 0
|
|
82
|
+
const getEsc = () => {
|
|
83
|
+
if (i >= cs.length || cs[i] === '-' || cs[i] === ']') throw new Error(BAD)
|
|
84
|
+
if (cs[i] === '\\') {
|
|
85
|
+
i++
|
|
86
|
+
if (i >= cs.length) throw new Error(BAD)
|
|
87
|
+
}
|
|
88
|
+
i++
|
|
89
|
+
}
|
|
90
|
+
while (i < cs.length) {
|
|
91
|
+
const c = cs[i]
|
|
92
|
+
if (c === '[') {
|
|
93
|
+
i++
|
|
94
|
+
if (cs[i] === '^') i++
|
|
95
|
+
let nrange = 0
|
|
96
|
+
for (;;) {
|
|
97
|
+
if (cs[i] === ']' && nrange > 0) {
|
|
98
|
+
i++
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
getEsc()
|
|
102
|
+
if (cs[i] === '-') {
|
|
103
|
+
i++
|
|
104
|
+
getEsc()
|
|
105
|
+
}
|
|
106
|
+
nrange++
|
|
107
|
+
if (i >= cs.length) throw new Error(BAD)
|
|
108
|
+
}
|
|
109
|
+
} else if (c === '\\') {
|
|
110
|
+
i++
|
|
111
|
+
if (i >= cs.length) throw new Error(BAD)
|
|
112
|
+
i++
|
|
113
|
+
} else i++
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const EXACT = 1
|
|
118
|
+
const PREFIX = 2
|
|
119
|
+
const SUFFIX = 3
|
|
120
|
+
const REGEXP = 4
|
|
121
|
+
const SL = '/'
|
|
122
|
+
|
|
123
|
+
class Pattern {
|
|
124
|
+
constructor(cleaned, exclusion) {
|
|
125
|
+
this.cleanedPattern = cleaned
|
|
126
|
+
this.exclusion = exclusion
|
|
127
|
+
this.dirs = cleaned.split(SL)
|
|
128
|
+
this.matchType = 0
|
|
129
|
+
this.regexp = null
|
|
130
|
+
}
|
|
131
|
+
toString() {
|
|
132
|
+
return this.cleanedPattern
|
|
133
|
+
}
|
|
134
|
+
match(path) {
|
|
135
|
+
if (this.matchType === 0) this.compile()
|
|
136
|
+
switch (this.matchType) {
|
|
137
|
+
case EXACT:
|
|
138
|
+
return path === this.cleanedPattern
|
|
139
|
+
case PREFIX:
|
|
140
|
+
return path.startsWith(this.cleanedPattern.slice(0, -2))
|
|
141
|
+
case SUFFIX: {
|
|
142
|
+
const suffix = this.cleanedPattern.slice(2)
|
|
143
|
+
if (path.endsWith(suffix)) return true
|
|
144
|
+
return suffix[0] === SL && path === suffix.slice(1) // **/foo matches "foo"
|
|
145
|
+
}
|
|
146
|
+
case REGEXP:
|
|
147
|
+
if (!this.regexp) throw new Error(BAD)
|
|
148
|
+
return this.regexp.test(path)
|
|
149
|
+
default:
|
|
150
|
+
throw new Error(BAD)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
compile() {
|
|
154
|
+
let reg = '^'
|
|
155
|
+
let type = EXACT
|
|
156
|
+
const cs = Array.from(this.cleanedPattern)
|
|
157
|
+
let p = 0
|
|
158
|
+
for (let i = 0; p < cs.length; i++) {
|
|
159
|
+
const ch = cs[p++]
|
|
160
|
+
if (ch === '*') {
|
|
161
|
+
if (cs[p] === '*') {
|
|
162
|
+
p++
|
|
163
|
+
if (cs[p] === SL) p++ // treat **/ as **
|
|
164
|
+
if (p >= cs.length) {
|
|
165
|
+
// "**EOF": accept all, as .gitignore
|
|
166
|
+
if (type === EXACT) type = PREFIX
|
|
167
|
+
else {
|
|
168
|
+
reg += '.*'
|
|
169
|
+
type = REGEXP
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
reg += `(.*${SL})?`
|
|
173
|
+
type = REGEXP
|
|
174
|
+
}
|
|
175
|
+
if (i === 0) type = SUFFIX
|
|
176
|
+
} else {
|
|
177
|
+
reg += `[^${SL}]*`
|
|
178
|
+
type = REGEXP
|
|
179
|
+
}
|
|
180
|
+
} else if (ch === '?') {
|
|
181
|
+
reg += `[^${SL}]`
|
|
182
|
+
type = REGEXP
|
|
183
|
+
} else if ('.+()$'.includes(ch)) {
|
|
184
|
+
// v0.6.1 escapes only these: its escapeBytes bitset is [8]byte indexed b%8 with bit 1<<(b/8), and for
|
|
185
|
+
// '|' (124), '{' (123) and '}' (125) b/8 is 15, which overflows the byte, so they are never escaped.
|
|
186
|
+
// Mirrored on purpose: `{1,2}` is a repeat and `|` an alternation, as in Go.
|
|
187
|
+
reg += `\\${ch}`
|
|
188
|
+
} else if (ch === '\\') {
|
|
189
|
+
if (p < cs.length) {
|
|
190
|
+
reg += `\\${cs[p++]}`
|
|
191
|
+
type = REGEXP
|
|
192
|
+
} else reg += '\\'
|
|
193
|
+
} else if (ch === '[' || ch === ']') {
|
|
194
|
+
reg += ch
|
|
195
|
+
type = REGEXP
|
|
196
|
+
} else reg += ch
|
|
197
|
+
}
|
|
198
|
+
if (type === REGEXP) {
|
|
199
|
+
reg += '$'
|
|
200
|
+
let re = null
|
|
201
|
+
try {
|
|
202
|
+
re = new RegExp(reg, 'u')
|
|
203
|
+
} catch {
|
|
204
|
+
try {
|
|
205
|
+
re = new RegExp(reg)
|
|
206
|
+
} catch {
|
|
207
|
+
throw new Error(BAD)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
this.regexp = re
|
|
211
|
+
}
|
|
212
|
+
this.matchType = type
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* patternmatcher.New: build a matcher from the patterns ParseDockerignore returns (or any list; blank ones are
|
|
218
|
+
* skipped). Throws on '!' alone or a malformed pattern.
|
|
219
|
+
* `ignored(path, isDir)`: moby's MatchesOrParentMatches (a path is ignored when a pattern matches it or any
|
|
220
|
+
* parent directory, and no later '!' pattern re-includes it). isDir is accepted for callers' symmetry; moby does
|
|
221
|
+
* not use it. `hasExceptions` is moby's Exclusions(): when false, an ignored directory can be skipped whole.
|
|
222
|
+
*/
|
|
223
|
+
export function matcher(patterns) {
|
|
224
|
+
const list = []
|
|
225
|
+
let hasExceptions = false
|
|
226
|
+
for (let raw of patterns) {
|
|
227
|
+
let p = goTrim(raw)
|
|
228
|
+
if (p === '') continue
|
|
229
|
+
p = cleanPath(p)
|
|
230
|
+
let exclusion = false
|
|
231
|
+
if (p[0] === '!') {
|
|
232
|
+
if (p.length === 1) throw new Error('illegal exclusion pattern: "!"')
|
|
233
|
+
exclusion = true
|
|
234
|
+
p = p.slice(1)
|
|
235
|
+
hasExceptions = true
|
|
236
|
+
}
|
|
237
|
+
checkPatternSyntax(p)
|
|
238
|
+
list.push(new Pattern(p, exclusion))
|
|
239
|
+
}
|
|
240
|
+
function matchesOrParentMatches(file) {
|
|
241
|
+
let matched = false
|
|
242
|
+
const parentPath = dirOf(file)
|
|
243
|
+
const parentDirs = parentPath.split(SL)
|
|
244
|
+
for (const pattern of list) {
|
|
245
|
+
if (pattern.exclusion !== matched) continue
|
|
246
|
+
let match = pattern.match(file)
|
|
247
|
+
if (!match && parentPath !== '.') {
|
|
248
|
+
for (let i = 0; i < parentDirs.length; i++) {
|
|
249
|
+
try {
|
|
250
|
+
match = pattern.match(parentDirs.slice(0, i + 1).join(SL))
|
|
251
|
+
} catch {
|
|
252
|
+
match = false
|
|
253
|
+
}
|
|
254
|
+
if (match) break
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (match) matched = !pattern.exclusion
|
|
258
|
+
}
|
|
259
|
+
return matched
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
patterns: list,
|
|
263
|
+
hasExceptions,
|
|
264
|
+
ignored(path, _isDir) {
|
|
265
|
+
const f = cleanPath(path)
|
|
266
|
+
if (f === '.') return false // never exclude everything
|
|
267
|
+
return matchesOrParentMatches(f)
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
}
|