pinokiod 7.3.15 → 7.4.0
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/kernel/api/index.js +111 -15
- package/kernel/api/script/index.js +10 -0
- package/kernel/autolaunch.js +111 -0
- package/kernel/environment.js +89 -1
- package/kernel/git.js +9 -19
- package/kernel/index.js +142 -43
- package/kernel/launch_requirements.js +1115 -0
- package/kernel/ready.js +231 -0
- package/kernel/script.js +16 -0
- package/kernel/shells.js +9 -1
- package/kernel/workspace_status.js +111 -45
- package/package.json +1 -1
- package/server/autolaunch.js +725 -0
- package/server/index.js +244 -411
- package/server/views/app.ejs +256 -152
- package/server/views/autolaunch.ejs +363 -75
- package/server/views/index.ejs +550 -26
- package/server/views/partials/app_autolaunch_dependency_events.ejs +99 -0
- package/server/views/partials/app_autolaunch_dependency_save.ejs +10 -0
- package/server/views/partials/app_autolaunch_dependency_styles.ejs +357 -0
- package/server/views/partials/app_autolaunch_modal_helpers.ejs +347 -0
- package/server/views/partials/autolaunch_dependency_helpers.ejs +204 -0
- package/server/views/partials/autolaunch_dependency_save.ejs +13 -0
- package/server/views/partials/autolaunch_dependency_styles.ejs +347 -0
- package/server/views/partials/home_action_modal.ejs +4 -1
- package/server/views/partials/launch_requirements_status_client.ejs +271 -0
- package/server/views/partials/launch_requirements_status_styles.ejs +171 -0
- package/server/views/partials/launch_settings_dependency_save_factory.ejs +45 -0
- package/server/views/partials/launch_settings_dependency_script_loader_factory.ejs +25 -0
- package/server/views/terminal.ejs +196 -2
- package/test/home-autolaunch-live-ui.test.js +455 -0
- package/test/launch-requirements-browser.test.js +579 -0
- package/test/launch-requirements-contract-coverage.test.js +627 -0
- package/test/launch-requirements-real-browser.js +625 -0
- package/test/launch-requirements-status-client.test.js +132 -0
- package/test/launch-requirements.test.js +1806 -0
- package/test/launch-settings-ui.test.js +370 -0
- package/test/ready-state.test.js +49 -0
- package/test/server-autolaunch.test.js +1052 -0
- package/test/startup-git-index-benchmark.js +409 -0
- package/test/startup-git-index-browser.js +320 -0
- package/test/startup-git-index-performance.test.js +380 -0
- package/test/startup-git-index-refactor.test.js +450 -0
- package/test/startup-git-index-route.test.js +588 -0
- package/test/universal-launcher.smoke.spec.js +10 -9
- package/test/workspace-gitignore-benchmark.js +815 -0
- package/test/workspace-gitignore-path-scoped.test.js +256 -0
- package/spec/INSTRUCTION_SYNC.md +0 -432
package/kernel/ready.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
3
|
+
class ReadyState {
|
|
4
|
+
constructor(kernel) {
|
|
5
|
+
this.kernel = kernel
|
|
6
|
+
this.status = {
|
|
7
|
+
apps: {}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
normalizeAppId(value) {
|
|
11
|
+
if (typeof value !== "string") {
|
|
12
|
+
return ""
|
|
13
|
+
}
|
|
14
|
+
const id = value.trim()
|
|
15
|
+
if (!id || id === "." || id === ".." || id.includes("\0") || /[\\/]/.test(id)) {
|
|
16
|
+
return ""
|
|
17
|
+
}
|
|
18
|
+
return id
|
|
19
|
+
}
|
|
20
|
+
getAppIdForLaunchPath(launchPath) {
|
|
21
|
+
if (!launchPath || typeof launchPath !== "string" || !path.isAbsolute(launchPath)) {
|
|
22
|
+
return ""
|
|
23
|
+
}
|
|
24
|
+
const apiRoot = this.kernel.path("api")
|
|
25
|
+
const relative = path.relative(apiRoot, launchPath)
|
|
26
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
27
|
+
return ""
|
|
28
|
+
}
|
|
29
|
+
return this.normalizeAppId(relative.split(path.sep)[0])
|
|
30
|
+
}
|
|
31
|
+
getAppRelativeLaunchScript(appId, launchPath) {
|
|
32
|
+
const id = this.normalizeAppId(appId)
|
|
33
|
+
if (!id || !launchPath || typeof launchPath !== "string" || !path.isAbsolute(launchPath)) {
|
|
34
|
+
return ""
|
|
35
|
+
}
|
|
36
|
+
const appRoot = path.resolve(this.kernel.path("api"), id)
|
|
37
|
+
const relative = path.relative(appRoot, launchPath)
|
|
38
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
39
|
+
return ""
|
|
40
|
+
}
|
|
41
|
+
return relative.split(path.sep).join("/")
|
|
42
|
+
}
|
|
43
|
+
resolveScriptPath(uri, cwd) {
|
|
44
|
+
if (typeof uri !== "string" || !uri.trim() || !this.kernel.api) {
|
|
45
|
+
return ""
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return this.kernel.api.filePath(uri.trim(), cwd)
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return ""
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
isScriptReady(scriptPath) {
|
|
54
|
+
if (!scriptPath || typeof scriptPath !== "string") {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
const resolved = path.resolve(scriptPath)
|
|
58
|
+
const appId = this.getAppIdForLaunchPath(resolved)
|
|
59
|
+
if (!appId) {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
const status = this.status && this.status.apps
|
|
63
|
+
? this.status.apps[appId]
|
|
64
|
+
: null
|
|
65
|
+
if (!status) {
|
|
66
|
+
return false
|
|
67
|
+
}
|
|
68
|
+
const script = this.getAppRelativeLaunchScript(appId, resolved)
|
|
69
|
+
const scriptStatus = status.scripts ? status.scripts[script] : null
|
|
70
|
+
if (scriptStatus) {
|
|
71
|
+
return scriptStatus.state === "ready"
|
|
72
|
+
}
|
|
73
|
+
return status.state === "ready" && (!status.script || status.script === script)
|
|
74
|
+
}
|
|
75
|
+
ready(requestOrUri) {
|
|
76
|
+
if (typeof requestOrUri === "string") {
|
|
77
|
+
return this.isScriptReady(this.resolveScriptPath(requestOrUri))
|
|
78
|
+
}
|
|
79
|
+
const params = requestOrUri && requestOrUri.params
|
|
80
|
+
const parent = requestOrUri && requestOrUri.parent && typeof requestOrUri.parent === "object"
|
|
81
|
+
? requestOrUri.parent
|
|
82
|
+
: null
|
|
83
|
+
let uri = ""
|
|
84
|
+
if (typeof params === "string") {
|
|
85
|
+
uri = params
|
|
86
|
+
} else if (params && typeof params === "object") {
|
|
87
|
+
uri = params.uri || params.path || params.script || ""
|
|
88
|
+
} else if (parent && parent.path) {
|
|
89
|
+
uri = parent.path
|
|
90
|
+
}
|
|
91
|
+
return this.isScriptReady(this.resolveScriptPath(uri, requestOrUri && requestOrUri.cwd))
|
|
92
|
+
}
|
|
93
|
+
getScriptProgress(scriptPath) {
|
|
94
|
+
if (!scriptPath || typeof scriptPath !== "string") {
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
const resolved = path.resolve(scriptPath)
|
|
98
|
+
const rpc = this.kernel.memory && this.kernel.memory.rpc
|
|
99
|
+
? this.kernel.memory.rpc[resolved]
|
|
100
|
+
: null
|
|
101
|
+
if (!rpc || typeof rpc !== "object") {
|
|
102
|
+
return null
|
|
103
|
+
}
|
|
104
|
+
const current = Number(rpc.current)
|
|
105
|
+
const total = Number(rpc.total)
|
|
106
|
+
if (!Number.isInteger(current) || !Number.isInteger(total) || total <= 0) {
|
|
107
|
+
return null
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
step_current: Math.max(1, current + 1),
|
|
111
|
+
step_total: total
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
stripProgress(record = {}) {
|
|
115
|
+
const next = { ...record }
|
|
116
|
+
delete next.step_current
|
|
117
|
+
delete next.step_total
|
|
118
|
+
return next
|
|
119
|
+
}
|
|
120
|
+
clearScriptProgress(launchPath) {
|
|
121
|
+
if (!launchPath || typeof launchPath !== "string") {
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
const resolved = path.resolve(launchPath)
|
|
125
|
+
const rpc = this.kernel.memory && this.kernel.memory.rpc
|
|
126
|
+
? this.kernel.memory.rpc[resolved]
|
|
127
|
+
: null
|
|
128
|
+
if (rpc && typeof rpc === "object") {
|
|
129
|
+
delete rpc.current
|
|
130
|
+
delete rpc.total
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
writeScriptProgress(launchPath, current, total) {
|
|
134
|
+
if (!launchPath || typeof launchPath !== "string") {
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
if (!this.kernel.memory) {
|
|
138
|
+
this.kernel.memory = {}
|
|
139
|
+
}
|
|
140
|
+
if (!this.kernel.memory.rpc) {
|
|
141
|
+
this.kernel.memory.rpc = {}
|
|
142
|
+
}
|
|
143
|
+
const resolved = path.resolve(launchPath)
|
|
144
|
+
this.kernel.memory.rpc[resolved] = {
|
|
145
|
+
...(this.kernel.memory.rpc[resolved] || {}),
|
|
146
|
+
current,
|
|
147
|
+
total
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
updateLaunchStatus(launchPath, state, details) {
|
|
151
|
+
const appId = this.getAppIdForLaunchPath(launchPath)
|
|
152
|
+
if (!appId) {
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
const script = this.getAppRelativeLaunchScript(appId, launchPath)
|
|
156
|
+
const current = this.status.apps[appId] || { id: appId, scripts: {} }
|
|
157
|
+
const scripts = { ...(current.scripts || {}) }
|
|
158
|
+
const hasProgress = Object.prototype.hasOwnProperty.call(details || {}, "step_current")
|
|
159
|
+
|| Object.prototype.hasOwnProperty.call(details || {}, "step_total")
|
|
160
|
+
if (script) {
|
|
161
|
+
scripts[script] = {
|
|
162
|
+
...(hasProgress ? (scripts[script] || { script }) : this.stripProgress(scripts[script] || { script })),
|
|
163
|
+
script,
|
|
164
|
+
state,
|
|
165
|
+
...details
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.status.apps[appId] = {
|
|
169
|
+
...(hasProgress ? current : this.stripProgress(current)),
|
|
170
|
+
id: appId,
|
|
171
|
+
state,
|
|
172
|
+
script: script || current.script,
|
|
173
|
+
...details,
|
|
174
|
+
scripts
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
markStarted(launchPath) {
|
|
178
|
+
this.clearScriptProgress(launchPath)
|
|
179
|
+
this.updateLaunchStatus(launchPath, "starting", {
|
|
180
|
+
started_at: Date.now()
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
markProgress(launchPath, current, total) {
|
|
184
|
+
const stepCurrent = Number(current)
|
|
185
|
+
const stepTotal = Number(total)
|
|
186
|
+
if (!Number.isInteger(stepCurrent) || !Number.isInteger(stepTotal) || stepTotal <= 0) {
|
|
187
|
+
return null
|
|
188
|
+
}
|
|
189
|
+
const progress = {
|
|
190
|
+
step_current: Math.max(1, stepCurrent + 1),
|
|
191
|
+
step_total: stepTotal
|
|
192
|
+
}
|
|
193
|
+
this.writeScriptProgress(launchPath, stepCurrent, stepTotal)
|
|
194
|
+
this.updateLaunchStatus(launchPath, "starting", progress)
|
|
195
|
+
return progress
|
|
196
|
+
}
|
|
197
|
+
markReady(launchPath) {
|
|
198
|
+
this.clearScriptProgress(launchPath)
|
|
199
|
+
this.updateLaunchStatus(launchPath, "ready", {
|
|
200
|
+
ready_at: Date.now()
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
markFailed(launchPath, error) {
|
|
204
|
+
this.clearScriptProgress(launchPath)
|
|
205
|
+
this.updateLaunchStatus(launchPath, "failed", {
|
|
206
|
+
error: error && error.message ? error.message : String(error || "Launch failed"),
|
|
207
|
+
failed_at: Date.now()
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
markStopped(launchPath) {
|
|
211
|
+
this.clearScriptProgress(launchPath)
|
|
212
|
+
this.updateLaunchStatus(launchPath, "stopped", {
|
|
213
|
+
stopped_at: Date.now()
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
isAppReady(appId) {
|
|
217
|
+
const dependencyId = this.normalizeAppId(appId)
|
|
218
|
+
const status = this.status && this.status.apps
|
|
219
|
+
? this.status.apps[dependencyId]
|
|
220
|
+
: null
|
|
221
|
+
if (!status) {
|
|
222
|
+
return false
|
|
223
|
+
}
|
|
224
|
+
if (status.scripts && Object.values(status.scripts).some((script) => script && script.state === "ready")) {
|
|
225
|
+
return true
|
|
226
|
+
}
|
|
227
|
+
return status.state === "ready"
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
module.exports = ReadyState
|
package/kernel/script.js
CHANGED
|
@@ -39,6 +39,22 @@ class Script {
|
|
|
39
39
|
return false
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
// script.ready('https://github.com/cocktailpeanutlabs/comfyui.git/start.json')
|
|
43
|
+
// script.ready('~/api/comfyui.git/start.json')
|
|
44
|
+
// script.ready(cwd, 'start.json')
|
|
45
|
+
ready(...chunks) {
|
|
46
|
+
let id
|
|
47
|
+
try {
|
|
48
|
+
id = this.resolve(...chunks)
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
if (id) {
|
|
53
|
+
return this.kernel.isScriptReady(id)
|
|
54
|
+
} else {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
42
58
|
// script.local('https://github.com/cocktailpeanutlabs/comfyui.git/start.json')
|
|
43
59
|
// script.local('~/api/comfyui.git/start.json')
|
|
44
60
|
// script.local(cwd, 'start.json')
|
package/kernel/shells.js
CHANGED
|
@@ -235,7 +235,15 @@ class Shells {
|
|
|
235
235
|
if (segments.length > 0) {
|
|
236
236
|
workspaceName = segments[0]
|
|
237
237
|
workspaceRoot = this.kernel.path("api", workspaceName)
|
|
238
|
-
beforeDirs = new Set(
|
|
238
|
+
beforeDirs = new Set()
|
|
239
|
+
try {
|
|
240
|
+
const beforeRepos = await this.kernel.git.repos(workspaceRoot)
|
|
241
|
+
for (const repo of beforeRepos) {
|
|
242
|
+
if (repo && repo.gitParentPath) {
|
|
243
|
+
beforeDirs.add(repo.gitParentPath)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch (_) {}
|
|
239
247
|
}
|
|
240
248
|
}
|
|
241
249
|
}
|
|
@@ -11,6 +11,7 @@ class WorkspaceStatusManager {
|
|
|
11
11
|
this.watchers = new Map()
|
|
12
12
|
this.onEvent = typeof options.onEvent === 'function' ? options.onEvent : null
|
|
13
13
|
this.gitIgnoreEngines = new Map()
|
|
14
|
+
this.gitIgnoreScanSkipDirs = new Set(['.git', 'node_modules', 'venv', '.venv'])
|
|
14
15
|
this.defaultIgnores = options.ignores && Array.isArray(options.ignores) ? options.ignores : [
|
|
15
16
|
'**/.git/**',
|
|
16
17
|
'**/node_modules/**',
|
|
@@ -50,7 +51,7 @@ class WorkspaceStatusManager {
|
|
|
50
51
|
}
|
|
51
52
|
for (const entry of entries) {
|
|
52
53
|
if (entry.isDirectory()) {
|
|
53
|
-
if (
|
|
54
|
+
if (this.gitIgnoreScanSkipDirs.has(entry.name)) {
|
|
54
55
|
continue
|
|
55
56
|
}
|
|
56
57
|
await walk(path.join(dir, entry.name))
|
|
@@ -73,34 +74,119 @@ class WorkspaceStatusManager {
|
|
|
73
74
|
} catch (_) {
|
|
74
75
|
continue
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
-
const prefix = relDir && relDir !== '.' ? relDir.split(path.sep).join('/') + '/' : ''
|
|
78
|
-
const lines = content.split(/\r?\n/)
|
|
79
|
-
for (let line of lines) {
|
|
80
|
-
if (!line) continue
|
|
81
|
-
line = line.trim()
|
|
82
|
-
if (!line || line.startsWith('#')) continue
|
|
83
|
-
let negated = false
|
|
84
|
-
if (line.startsWith('!')) {
|
|
85
|
-
negated = true
|
|
86
|
-
line = line.slice(1)
|
|
87
|
-
}
|
|
88
|
-
if (!line) continue
|
|
89
|
-
line = line.replace(/^\/+/, '')
|
|
90
|
-
if (!line) continue
|
|
91
|
-
const pattern = prefix + line
|
|
92
|
-
if (!pattern) continue
|
|
93
|
-
if (negated) {
|
|
94
|
-
ig.add('!' + pattern)
|
|
95
|
-
} else {
|
|
96
|
-
ig.add(pattern)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
77
|
+
this.addGitIgnoreContent(ig, workspaceRoot, gitignorePath, content)
|
|
99
78
|
}
|
|
100
79
|
|
|
101
80
|
this.gitIgnoreEngines.set(workspaceName, ig)
|
|
102
81
|
}
|
|
103
82
|
|
|
83
|
+
normalizeGitIgnorePath(value) {
|
|
84
|
+
return String(value || '').replace(/\\/g, '/').replace(/\/+/g, '/')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
addGitIgnoreContent(engine, workspaceRoot, gitignorePath, content) {
|
|
88
|
+
const relDir = path.relative(workspaceRoot, path.dirname(gitignorePath))
|
|
89
|
+
const prefix = relDir && relDir !== '.' ? this.normalizeGitIgnorePath(relDir) + '/' : ''
|
|
90
|
+
const lines = String(content || '').split(/\r?\n/)
|
|
91
|
+
for (let line of lines) {
|
|
92
|
+
if (!line) continue
|
|
93
|
+
line = line.trim()
|
|
94
|
+
if (!line || line.startsWith('#')) continue
|
|
95
|
+
let negated = false
|
|
96
|
+
if (line.startsWith('!')) {
|
|
97
|
+
negated = true
|
|
98
|
+
line = line.slice(1)
|
|
99
|
+
}
|
|
100
|
+
if (!line) continue
|
|
101
|
+
line = line.replace(/^\/+/, '')
|
|
102
|
+
if (!line) continue
|
|
103
|
+
const pattern = prefix + line
|
|
104
|
+
if (!pattern) continue
|
|
105
|
+
engine.add((negated ? '!' : '') + pattern)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
createPathScopedGitIgnoreContext(workspaceRoot) {
|
|
110
|
+
return {
|
|
111
|
+
workspaceRoot,
|
|
112
|
+
contentCache: new Map(),
|
|
113
|
+
engineCache: new Map(),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async readPathScopedGitIgnore(context, gitignorePath) {
|
|
118
|
+
if (context.contentCache.has(gitignorePath)) {
|
|
119
|
+
return context.contentCache.get(gitignorePath)
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const content = await fs.promises.readFile(gitignorePath, 'utf8')
|
|
123
|
+
context.contentCache.set(gitignorePath, content)
|
|
124
|
+
return content
|
|
125
|
+
} catch (_) {
|
|
126
|
+
context.contentCache.set(gitignorePath, null)
|
|
127
|
+
return null
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pathScopedGitIgnoreDirs(workspaceRelativePath) {
|
|
132
|
+
const normalized = this.normalizeGitIgnorePath(workspaceRelativePath)
|
|
133
|
+
const parts = normalized.split('/').filter(Boolean)
|
|
134
|
+
const dirs = []
|
|
135
|
+
for (let depth = 0; depth < parts.length; depth++) {
|
|
136
|
+
dirs.push(depth === 0 ? '' : parts.slice(0, depth).join('/'))
|
|
137
|
+
if (this.gitIgnoreScanSkipDirs.has(parts[depth])) {
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return dirs
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async pathScopedGitIgnoreEngine(context, workspaceRelativePath) {
|
|
145
|
+
if (!context || !context.workspaceRoot) {
|
|
146
|
+
return null
|
|
147
|
+
}
|
|
148
|
+
const dirs = this.pathScopedGitIgnoreDirs(workspaceRelativePath)
|
|
149
|
+
const cacheKey = dirs.join('\0')
|
|
150
|
+
if (context.engineCache.has(cacheKey)) {
|
|
151
|
+
return context.engineCache.get(cacheKey)
|
|
152
|
+
}
|
|
153
|
+
const engine = ignore()
|
|
154
|
+
for (const relDir of dirs) {
|
|
155
|
+
const gitignorePath = path.join(context.workspaceRoot, relDir, '.gitignore')
|
|
156
|
+
const content = await this.readPathScopedGitIgnore(context, gitignorePath)
|
|
157
|
+
if (content) {
|
|
158
|
+
this.addGitIgnoreContent(engine, context.workspaceRoot, gitignorePath, content)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
context.engineCache.set(cacheKey, engine)
|
|
162
|
+
return engine
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async isPathScopedGitIgnored(context, workspaceRelativePath) {
|
|
166
|
+
const normalized = this.normalizeGitIgnorePath(workspaceRelativePath)
|
|
167
|
+
if (!normalized) {
|
|
168
|
+
return false
|
|
169
|
+
}
|
|
170
|
+
const engine = await this.pathScopedGitIgnoreEngine(context, normalized)
|
|
171
|
+
return !!(engine && engine.ignores(normalized))
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async filterPathScopedGitIgnored(contextOrWorkspaceRoot, records) {
|
|
175
|
+
const context = typeof contextOrWorkspaceRoot === 'string'
|
|
176
|
+
? this.createPathScopedGitIgnoreContext(contextOrWorkspaceRoot)
|
|
177
|
+
: contextOrWorkspaceRoot
|
|
178
|
+
const ignored = new Set()
|
|
179
|
+
for (const record of records || []) {
|
|
180
|
+
if (!record || !record.key || !record.workspaceRelative) {
|
|
181
|
+
continue
|
|
182
|
+
}
|
|
183
|
+
if (await this.isPathScopedGitIgnored(context, record.workspaceRelative)) {
|
|
184
|
+
ignored.add(record.key)
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return ignored
|
|
188
|
+
}
|
|
189
|
+
|
|
104
190
|
markDirty(workspaceName) {
|
|
105
191
|
let entry = this.cache.get(workspaceName)
|
|
106
192
|
if (!entry) {
|
|
@@ -119,7 +205,6 @@ class WorkspaceStatusManager {
|
|
|
119
205
|
return
|
|
120
206
|
}
|
|
121
207
|
try {
|
|
122
|
-
await this.ensureGitIgnoreEngine(workspaceName, workspaceRoot)
|
|
123
208
|
const subscription = await ParcelWatcher.subscribe(
|
|
124
209
|
workspaceRoot,
|
|
125
210
|
(error, events) => {
|
|
@@ -130,29 +215,10 @@ class WorkspaceStatusManager {
|
|
|
130
215
|
if (!events || events.length === 0) {
|
|
131
216
|
return
|
|
132
217
|
}
|
|
133
|
-
let relevantEvents = events
|
|
134
|
-
const engine = this.gitIgnoreEngines.get(workspaceName)
|
|
135
|
-
if (engine && workspaceRoot) {
|
|
136
|
-
const root = workspaceRoot
|
|
137
|
-
relevantEvents = events.filter((evt) => {
|
|
138
|
-
if (!evt || !evt.path) {
|
|
139
|
-
return true
|
|
140
|
-
}
|
|
141
|
-
let rel = path.relative(root, evt.path)
|
|
142
|
-
if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
143
|
-
return true
|
|
144
|
-
}
|
|
145
|
-
const normalized = rel.split(path.sep).join('/')
|
|
146
|
-
return !engine.ignores(normalized)
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
if (relevantEvents.length === 0) {
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
218
|
this.markDirty(workspaceName)
|
|
153
219
|
if (this.onEvent) {
|
|
154
220
|
try {
|
|
155
|
-
this.onEvent(workspaceName,
|
|
221
|
+
this.onEvent(workspaceName, events)
|
|
156
222
|
} catch (err) {
|
|
157
223
|
console.warn('workspace watcher callback error', workspaceName, err && err.message ? err.message : err)
|
|
158
224
|
}
|