@naanlang/naan 1.4.0 → 1.4.2
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/LICENSE.md +1 -1
- package/README.md +10 -10
- package/bin/index.js +25 -15
- package/dist/env_web.js +68 -73
- package/dist/naan.min.js +5 -5
- package/frameworks/browser/sworker.js +23 -23
- package/frameworks/browser/terminals.nlg +52 -3
- package/frameworks/client/psm_client.nlg +2 -0
- package/frameworks/client/relaycon.nlg +1 -1
- package/frameworks/common/common.nlg +10 -54
- package/frameworks/node/filesystem.nlg +5 -4
- package/frameworks/node/psm_server.nlg +1 -1
- package/frameworks/node/shell.nlg +134 -0
- package/frameworks/node/worker.nlg +1 -1
- package/frameworks/project/build.nlg +19 -5
- package/frameworks/project/projects.nlg +12 -1
- package/frameworks/running/debugnub.nlg +102 -12
- package/frameworks/running/debugutil.nlg +30 -13
- package/frameworks/running/executors.nlg +7 -3
- package/frameworks/running/running.nlg +26 -6
- package/frameworks/running/sourcecode.nlg +3 -1
- package/frameworks/running/taskexec.nlg +1 -1
- package/frameworks/storage/dbt_pouch.nlg +37 -19
- package/frameworks/storage/file_manager.nlg +1 -1
- package/frameworks/storage/psm_dbtables.nlg +23 -24
- package/frameworks/storage/resources.nlg +12 -4
- package/frameworks/storage/storage.nlg +2 -2
- package/lib/browser/env_web.js +73 -78
- package/lib/core/naanlib.js +5 -5
- package/package.json +1 -1
- package/plugins/gitClient/gitClient.nlg +3 -3
- package/plugins/openSearch/openSearch.nlg +2 -2
- package/plugins/serviceAws/aws_s3.nlg +17 -1
- package/plugins/serviceAws/psm_aws.nlg +4 -2
- package/plugins/serviceAws/serviceAws.nlg +1 -1
- package/plugins/serviceGC/gc_api.nlg +4 -4
- package/plugins/serviceGitHub/serviceGitHub.nlg +1 -1
- package/plugins/serviceGitLab/psm_gitlab.nlg +1 -1
- package/plugins/serviceGitLab/serviceGitLab.nlg +1 -1
- package/test/harness.nlg +9 -9
- package/test/test_01_core.nlg +24 -2
- package/test/test_02_context.nlg +1 -1
|
@@ -33,6 +33,9 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
33
33
|
nub.codemgr = CodeManager()
|
|
34
34
|
nub.exenable = true
|
|
35
35
|
nub.watches = []
|
|
36
|
+
nub.contIDs = new(weakmap)
|
|
37
|
+
nub.stacks = { }
|
|
38
|
+
nub.usage = { }
|
|
36
39
|
|
|
37
40
|
// debugDepth
|
|
38
41
|
// Return the recursive debugging depth as an integer.
|
|
@@ -80,7 +83,7 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
80
83
|
for frame in nub.frames
|
|
81
84
|
if procedure(frame)
|
|
82
85
|
break
|
|
83
|
-
`(procdef, task) =
|
|
86
|
+
`(procdef, task) = debug.frameProcTask(frame)
|
|
84
87
|
}
|
|
85
88
|
if !procdef
|
|
86
89
|
return (false)
|
|
@@ -396,14 +399,75 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
396
399
|
output.push(breakInfo(bpid))
|
|
397
400
|
output
|
|
398
401
|
}
|
|
402
|
+
|
|
403
|
+
// procLoc
|
|
404
|
+
//
|
|
405
|
+
// Get the location of a procdef.
|
|
406
|
+
|
|
407
|
+
nub.procLoc = function procLoc(procdef, task, local comp, position) {
|
|
408
|
+
if !task
|
|
409
|
+
task = rrrest(procdef)
|
|
410
|
+
comp = nub.codemgr.procComponent(procdef)
|
|
411
|
+
position = comp.textpos(procdef, task)
|
|
412
|
+
{
|
|
413
|
+
modname: comp.modname
|
|
414
|
+
compname: comp.compname
|
|
415
|
+
first: position.first
|
|
416
|
+
last: position.last
|
|
417
|
+
line: position.line
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// getContID
|
|
422
|
+
//
|
|
423
|
+
// Get the contID for a continuation.
|
|
424
|
+
|
|
425
|
+
nub.getContID = function getContID(cont, local contID, frames) {
|
|
426
|
+
contID = nub.contIDs[cont]
|
|
427
|
+
if !contID
|
|
428
|
+
nub.contIDs[cont] = contID = UUID()
|
|
429
|
+
frames = cont.stacktrace().toarray
|
|
430
|
+
if frames.slice(-1).0 == `interrupt
|
|
431
|
+
frames.pop()
|
|
432
|
+
nub.stacks[contID] = frames
|
|
433
|
+
contID
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// contGC
|
|
437
|
+
//
|
|
438
|
+
// Remove any continuations that are not in the specified array.
|
|
439
|
+
|
|
440
|
+
nub.contGC = function contGC(contIDs, local contID) {
|
|
441
|
+
contIDs = contIDs.concat(nub.usage.*.toarray) // keep preserved ids
|
|
442
|
+
for contID in nub.stacks
|
|
443
|
+
if contIDs.indexOf(contID) < 0
|
|
444
|
+
nub.stacks[contID] = undefined
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// usingContID
|
|
448
|
+
//
|
|
449
|
+
// Mark that the contID is being used.
|
|
450
|
+
//
|
|
451
|
+
nub.usingContID = function usingContID(contID, usage) {
|
|
452
|
+
if nub.usage[contID]
|
|
453
|
+
nub.usage[contID] += usage
|
|
454
|
+
else if usage > 0
|
|
455
|
+
nub.usage[contID] = usage
|
|
456
|
+
if nub.usage[contID] == 0
|
|
457
|
+
nub.usage[contID] = undefined
|
|
458
|
+
}
|
|
399
459
|
|
|
400
460
|
// callStack
|
|
401
461
|
//
|
|
402
|
-
// List our callers as of the last entry.
|
|
462
|
+
// List our callers as of the last entry in the optional frames or current debugger stack.
|
|
403
463
|
|
|
404
|
-
nub.callStack = function callStack(local output, frame, type, record) {
|
|
464
|
+
nub.callStack = function callStack(contID, local frames, output, frame, type, record) {
|
|
405
465
|
output = []
|
|
406
|
-
|
|
466
|
+
if contID
|
|
467
|
+
frames = nub.stacks[contID]
|
|
468
|
+
else
|
|
469
|
+
frames = nub.frames
|
|
470
|
+
for frame in frames {
|
|
407
471
|
record = {
|
|
408
472
|
type: frame.0.tostring // e.g. "function"
|
|
409
473
|
}
|
|
@@ -425,8 +489,12 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
425
489
|
//
|
|
426
490
|
// Return the nth stack frame in the list returned by callStack above.
|
|
427
491
|
|
|
428
|
-
nub.nthFrame = function nthFrame(nth, local frame) {
|
|
429
|
-
|
|
492
|
+
nub.nthFrame = function nthFrame(nth, contID, local frames, frame) {
|
|
493
|
+
if contID
|
|
494
|
+
frames = nub.stacks[contID]
|
|
495
|
+
else
|
|
496
|
+
frames = nub.frames
|
|
497
|
+
for frame in frames
|
|
430
498
|
if procedure(frame) || frame.0.tostring == "interrupt" {
|
|
431
499
|
if nth-- == 0
|
|
432
500
|
return (frame)
|
|
@@ -469,14 +537,15 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
469
537
|
|
|
470
538
|
// evalWatchesInFrame
|
|
471
539
|
//
|
|
472
|
-
// Parse and evaluate our watchpoints, optionally in the context of the nth frame
|
|
473
|
-
//
|
|
540
|
+
// Parse and evaluate our watchpoints, optionally in the context of the nth frame of the
|
|
541
|
+
// specified continuation or the current debugger stack. Each entry in the returned array is for
|
|
542
|
+
// a watchpoint, comprising a tuple: `(error, expression, evaluated).
|
|
474
543
|
|
|
475
|
-
nub.evalWatchesInFrame = function evalWatchesInFrame(nth,
|
|
544
|
+
nub.evalWatchesInFrame = function evalWatchesInFrame(nth, contID,
|
|
476
545
|
local frame, locals, ns, mod, gohome, texts, watch, exprs, error, expr)
|
|
477
546
|
{
|
|
478
547
|
if integer(nth) {
|
|
479
|
-
frame = nthFrame(nth)
|
|
548
|
+
frame = nthFrame(nth, contID)
|
|
480
549
|
locals = localist(frame)
|
|
481
550
|
ns = frame.3.1.namespace
|
|
482
551
|
if ns !== nsactive().0 {
|
|
@@ -506,8 +575,29 @@ closure DebugNub(local nub, debug, paused) {
|
|
|
506
575
|
//
|
|
507
576
|
// Return procedure and task from a frame, as a `(procdef, task) tuple.
|
|
508
577
|
|
|
509
|
-
nub.procTask = function procTask(frame) {
|
|
510
|
-
|
|
578
|
+
nub.procTask = function procTask(frame, contID, local frames, ftrav, procdef, bodydef) {
|
|
579
|
+
if contID
|
|
580
|
+
frames = new(nub.stacks[contID])
|
|
581
|
+
else
|
|
582
|
+
frames = new(debug.frames)
|
|
583
|
+
loop {
|
|
584
|
+
if frames.length == 0
|
|
585
|
+
break
|
|
586
|
+
ftrav = frames.shift()
|
|
587
|
+
if ftrav eq frame
|
|
588
|
+
frame = false // can now stop on our desired procedure
|
|
589
|
+
if procedure(ftrav) {
|
|
590
|
+
if !frame {
|
|
591
|
+
procdef = ftrav.3 // first procedure definition starting with desired frame
|
|
592
|
+
if !bodydef
|
|
593
|
+
bodydef = procdef // use procdef as body if no body frame found
|
|
594
|
+
break }
|
|
595
|
+
bodydef = false } // any previously-found body applies to wrong procedure
|
|
596
|
+
else if ftrav.0 == `body || ftrav.0 == `loop {
|
|
597
|
+
if !bodydef
|
|
598
|
+
bodydef = ftrav.2 } } // use first body found before desired procedure
|
|
599
|
+
if procdef
|
|
600
|
+
list(procdef, bodydef) // found valid location
|
|
511
601
|
}
|
|
512
602
|
|
|
513
603
|
// lastStepValue
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2021 by Richard C. Zulch
|
|
9
|
+
* Copyright (c) 2021-2024 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -260,24 +260,33 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
260
260
|
here.breakInfo = function breakInfo(bpid) {
|
|
261
261
|
libBreakInfo(bpid)
|
|
262
262
|
}
|
|
263
|
+
|
|
264
|
+
// usingContID
|
|
265
|
+
//
|
|
266
|
+
// Mark that the contID is being used.
|
|
267
|
+
//
|
|
268
|
+
here.usingContID = function usingContID(contID, usage) {
|
|
269
|
+
debugNub = car(compress("debugNub"))
|
|
270
|
+
debugNub.usingContID(contID, usage)
|
|
271
|
+
}
|
|
263
272
|
|
|
264
273
|
// callstack
|
|
265
274
|
//
|
|
266
|
-
// Report current
|
|
275
|
+
// Report the specified fiber callstack or current debugger stack.
|
|
267
276
|
//
|
|
268
|
-
here.callStack = function callStack(local debugNub) {
|
|
277
|
+
here.callStack = function callStack(contID, local debugNub) {
|
|
269
278
|
debugNub = car(compress("debugNub"))
|
|
270
|
-
debugNub.callStack()
|
|
279
|
+
debugNub.callStack(contID)
|
|
271
280
|
}
|
|
272
281
|
|
|
273
282
|
// frameinfo
|
|
274
283
|
//
|
|
275
|
-
// Report information about the nth frame in the
|
|
284
|
+
// Report information about the nth frame in a fiber callstack or the current debugger stack.
|
|
276
285
|
//
|
|
277
|
-
here.frameinfo = function frameinfo(nth, local debugNub, frame, proctask, comp, position) {
|
|
286
|
+
here.frameinfo = function frameinfo(nth, contID, local debugNub, frame, proctask, comp, position) {
|
|
278
287
|
debugNub = car(compress("debugNub"))
|
|
279
|
-
frame = debugNub.nthFrame(nth)
|
|
280
|
-
proctask = debugNub.procTask(frame)
|
|
288
|
+
frame = debugNub.nthFrame(nth, contID)
|
|
289
|
+
proctask = debugNub.procTask(frame, contID)
|
|
281
290
|
comp = debugNub.codemgr.procComponent(proctask.0)
|
|
282
291
|
position = comp.textpos(proctask.0, proctask.1)
|
|
283
292
|
{
|
|
@@ -302,11 +311,11 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
302
311
|
// The optional visible array is a preceding result of this function, where "visible=true"
|
|
303
312
|
// can be applied to nested values to add recursive depth.
|
|
304
313
|
//
|
|
305
|
-
here.scopeinfo = function scopeinfo(nth, visible,
|
|
314
|
+
here.scopeinfo = function scopeinfo(nth, visible, contID
|
|
306
315
|
local debugNub, frame, procsym, parent, proc, lex1, ex1, params, content, scope, level, level1)
|
|
307
316
|
{
|
|
308
317
|
debugNub = car(compress("debugNub"))
|
|
309
|
-
frame = debugNub.nthFrame(nth)
|
|
318
|
+
frame = debugNub.nthFrame(nth, contID)
|
|
310
319
|
procsym = frame.3.1
|
|
311
320
|
parent = procsym@\.parent
|
|
312
321
|
while parent {
|
|
@@ -370,11 +379,11 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
370
379
|
// can be applied to nested values to add recursive depth. A stack frame index can be specified
|
|
371
380
|
// to evaluate an expression in that context.
|
|
372
381
|
|
|
373
|
-
here.watchInfo = function watchInfo(visible, nth,
|
|
382
|
+
here.watchInfo = function watchInfo(visible, nth, contID,
|
|
374
383
|
local debugNub, values, content, watch, child1, error, value, level, expr)
|
|
375
384
|
{
|
|
376
385
|
debugNub = car(compress("debugNub"))
|
|
377
|
-
values = debugNub.evalWatchesInFrame(nth)
|
|
386
|
+
values = debugNub.evalWatchesInFrame(nth, contID)
|
|
378
387
|
visible = new(visible) // don't modify original
|
|
379
388
|
content = []
|
|
380
389
|
for watch in debugNub.watches {
|
|
@@ -417,8 +426,9 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
417
426
|
//
|
|
418
427
|
// List the current futures.
|
|
419
428
|
|
|
420
|
-
here.futureslist =
|
|
429
|
+
here.futureslist = closure futureslist(local debugNub, contIDs, output, future, record, procsym) {
|
|
421
430
|
debugNub = car(compress("debugNub"))
|
|
431
|
+
contIDs = []
|
|
422
432
|
output = []
|
|
423
433
|
for future in futures() {
|
|
424
434
|
if member(debugNub.pauser, future.waiting)
|
|
@@ -431,6 +441,7 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
431
441
|
if procedure(future.execute) {
|
|
432
442
|
procsym = future.execute.1
|
|
433
443
|
record.execute = strcat(future.execute.0, space, procsym.namespace.tostring, "::", debugNub.procname(procsym))
|
|
444
|
+
record.execloc = debugNub.procLoc(future.execute)
|
|
434
445
|
}
|
|
435
446
|
else if future.execute
|
|
436
447
|
record.execute = tostring(future.execute)
|
|
@@ -439,9 +450,15 @@ closure DebugRemote(commander, local remoter, here, there, library) {
|
|
|
439
450
|
procsym = item.1
|
|
440
451
|
strcat(item.0, space, procsym.namespace.tostring, "::", debugNub.procname(procsym))
|
|
441
452
|
})
|
|
453
|
+
record.continuations = future.continuations.toarray.map(function(cont, local contID) {
|
|
454
|
+
contID = debugNub.getContID(cont)
|
|
455
|
+
contIDs.push(contID)
|
|
456
|
+
contID
|
|
457
|
+
})
|
|
442
458
|
}
|
|
443
459
|
output.push(record)
|
|
444
460
|
}
|
|
461
|
+
debugNub.contGC(contIDs)
|
|
445
462
|
output
|
|
446
463
|
}
|
|
447
464
|
|
|
@@ -71,10 +71,14 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
71
71
|
|
|
72
72
|
// execSetStatus
|
|
73
73
|
//
|
|
74
|
-
// Received a status update from the instance.
|
|
74
|
+
// Received a status update from the instance. This makes a copy of the specified dictionary for
|
|
75
|
+
// garbage collection, because if we store the status from a separate vsite window then it can
|
|
76
|
+
// cause the main window to retain a vsite window after it's closed. The last status update sets
|
|
77
|
+
// an object in the context of the detached window, and then it never gets updated until the
|
|
78
|
+
// executor goes away. That doesn't always happen as soon as you think.
|
|
75
79
|
//
|
|
76
80
|
exec.execSetStatus = function execSetStatus(status) {
|
|
77
|
-
exec.xstatus = status
|
|
81
|
+
exec.xstatus = new(status) // for GC (!)
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
// execFailed
|
|
@@ -218,7 +222,7 @@ closure ExecutorContext(exec, state, local context, coder, util) {
|
|
|
218
222
|
else if result.1.result
|
|
219
223
|
list(false, caar(util.pkgLoad(result.1.result, {
|
|
220
224
|
localroots: false
|
|
221
|
-
intern:
|
|
225
|
+
intern: "symbols"
|
|
222
226
|
execute: false
|
|
223
227
|
objectDecoder: coder.decodeObject
|
|
224
228
|
})))
|
|
@@ -207,12 +207,26 @@ closure packageCoder(evalf, local coder) {
|
|
|
207
207
|
quote(x@\.tostring = function() { "{proxy ${nn}}" }),
|
|
208
208
|
quote(x@\.undefined = closure undef args {
|
|
209
209
|
let (result) {
|
|
210
|
-
result = evalf(list(`\.
|
|
210
|
+
result = evalf(list(`\.invoke\-method, objectID, args))
|
|
211
211
|
if result.0
|
|
212
212
|
throw("remoting failure: ${ErrorString(result.0)}")
|
|
213
213
|
else
|
|
214
214
|
result.1
|
|
215
215
|
} ()
|
|
216
|
+
}),
|
|
217
|
+
quote(x@\.\.undefined = function (key, local result) {
|
|
218
|
+
result = evalf(list(`\.invoke\-method, objectID, list(`\.\.undefined, key)))
|
|
219
|
+
if result.0
|
|
220
|
+
throw("remoting failure: ${ErrorString(result.0)}")
|
|
221
|
+
else
|
|
222
|
+
result.1
|
|
223
|
+
}),
|
|
224
|
+
quote(x@\.\=undefined = function (key, value, local result) {
|
|
225
|
+
result = evalf(list(`\.invoke\-method, objectID, list(`\.\=undefined, key, value)))
|
|
226
|
+
if result.0
|
|
227
|
+
throw("remoting failure: ${ErrorString(result.0)}")
|
|
228
|
+
else
|
|
229
|
+
result.1
|
|
216
230
|
}), `x)))
|
|
217
231
|
} (ident.name, ident.objectID)
|
|
218
232
|
coder.wmapEncoding[obj] = ident
|
|
@@ -225,12 +239,18 @@ closure packageCoder(evalf, local coder) {
|
|
|
225
239
|
//
|
|
226
240
|
// Invoke a local object method from the remote proxy, returning a result tuple.
|
|
227
241
|
//
|
|
228
|
-
coder.invokeMethod = closure invokeMethod(objectID, args, local obj) {
|
|
242
|
+
coder.invokeMethod = closure invokeMethod(objectID, args, local obj, method) {
|
|
229
243
|
obj = coder.mapDecoding[objectID]
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
244
|
+
method = pop(args)
|
|
245
|
+
if obj {
|
|
246
|
+
if method == `\.\.undefined
|
|
247
|
+
obj[args.0]
|
|
248
|
+
else if method == `\.\=undefined
|
|
249
|
+
obj[args.0] = args.1
|
|
250
|
+
else
|
|
251
|
+
eval(list(deref, obj, method, args))
|
|
252
|
+
} else
|
|
253
|
+
throw("remoting error: object ${objectID} not found")
|
|
234
254
|
}
|
|
235
255
|
|
|
236
256
|
// finis
|
|
@@ -87,12 +87,14 @@ closure CodeManager(options, local coman, cache)
|
|
|
87
87
|
output.push(false)
|
|
88
88
|
continue
|
|
89
89
|
}
|
|
90
|
+
if text.startsWith("!")
|
|
91
|
+
text = "(${text})" // no shell escapes here
|
|
90
92
|
try {
|
|
91
93
|
source = new(textstream, text.concat(" ;")) // avoid EOF
|
|
92
94
|
if locals
|
|
93
95
|
source.setsymbols(locals)
|
|
94
96
|
registry = modlist().Lib.exports.Registry // dialect registry
|
|
95
|
-
dialect = registry.findName(registry.dialects().0) // ### default
|
|
97
|
+
dialect = registry.findName(registry.dialects().0) // ### default dialect
|
|
96
98
|
output.push(dialect.parse(source))
|
|
97
99
|
} catch {
|
|
98
100
|
if true {
|
|
@@ -88,7 +88,7 @@ closure TaskDispatcher(replier, local contexts, gohome, coder, util) {
|
|
|
88
88
|
objectDecoder: coder.decodeObject
|
|
89
89
|
})
|
|
90
90
|
expr = caar(expr)
|
|
91
|
-
if expr.0 == `\.
|
|
91
|
+
if expr.0 == `\.invoke\-method
|
|
92
92
|
expr = coder.invokeMethod(expr.1, expr.2) // object method, args
|
|
93
93
|
else
|
|
94
94
|
expr = evalactive(expr) // evaluate expression
|
|
@@ -34,13 +34,17 @@
|
|
|
34
34
|
*
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
closure dapoTable(database,
|
|
37
|
+
closure dapoTable(database, rootpath, local table, prefix) {
|
|
38
38
|
global()
|
|
39
|
+
if !database || !string(rootpath)
|
|
40
|
+
return (list(Error("invalid arguments")))
|
|
39
41
|
table = new(object, this)
|
|
40
42
|
table.type = database.type
|
|
41
43
|
table.db = database
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
if rootpath != "" && rootpath.slice(-1) != "/"
|
|
45
|
+
rootpath = rootpath.concat("/") // "" or "<path>/"
|
|
46
|
+
table.rootpath = rootpath
|
|
47
|
+
table.prefix = makePrefix(rootpath)
|
|
44
48
|
|
|
45
49
|
// makePrefix
|
|
46
50
|
//
|
|
@@ -80,7 +84,7 @@ closure dapoTable(database, path, local table, prefix) {
|
|
|
80
84
|
return (syncAdapter(add, key, content, metadata))
|
|
81
85
|
id = makeID(key)
|
|
82
86
|
if !string(id)
|
|
83
|
-
return (asyncResult(callback, id))
|
|
87
|
+
return (asyncResult(callback, id)) // error from makeID
|
|
84
88
|
if metadata && !dictionary(metadata)
|
|
85
89
|
return (asyncResult(callback, Error("invalid arguments")))
|
|
86
90
|
if !database.pouch
|
|
@@ -291,7 +295,7 @@ closure dapoTable(database, path, local table, prefix) {
|
|
|
291
295
|
// only immediate children are listed, with directories at the end--and no metadata for them.
|
|
292
296
|
//
|
|
293
297
|
|
|
294
|
-
table.records = closure records(options, callback, local prefix, pouchOpts, output) {
|
|
298
|
+
table.records = closure records(options, callback, local prefix, prelen, pouchOpts, output) {
|
|
295
299
|
if !callback
|
|
296
300
|
return (syncAdapter(records, options))
|
|
297
301
|
output = {
|
|
@@ -300,9 +304,11 @@ closure dapoTable(database, path, local table, prefix) {
|
|
|
300
304
|
if !string(options.prefix)
|
|
301
305
|
return (asyncResult(callback, Error("prefix option must be string")))
|
|
302
306
|
output.prefix = options.prefix
|
|
303
|
-
prefix = table.prefix.concat(makePrefix(options.prefix))
|
|
304
|
-
|
|
307
|
+
prefix = table.prefix.concat(makePrefix(options.prefix))
|
|
308
|
+
prelen = options.prefix.length }
|
|
309
|
+
else {
|
|
305
310
|
prefix = table.prefix
|
|
311
|
+
prelen = 0 }
|
|
306
312
|
if !database.pouch
|
|
307
313
|
return (asyncResult(callback, Error("database closed")))
|
|
308
314
|
pouchOpts = {
|
|
@@ -321,19 +327,24 @@ closure dapoTable(database, path, local table, prefix) {
|
|
|
321
327
|
key = obj.id.substring(table.prefix.length)
|
|
322
328
|
else
|
|
323
329
|
key = "*key error*" // should not happen
|
|
324
|
-
if !options.deep {
|
|
325
|
-
offset = key.indexOf("/", prefix.length)
|
|
326
|
-
if offset >= 0 {
|
|
327
|
-
key = key.substring(0, offset+1) // child directory name
|
|
328
|
-
if !firstkids[key]
|
|
329
|
-
firstkids[key] = key // first time we've seen this child directory
|
|
330
|
-
else
|
|
331
|
-
continue } } // ignore deeper child
|
|
332
330
|
item = {
|
|
333
331
|
key: key
|
|
334
332
|
_id: obj.id
|
|
335
333
|
_rev: obj.value.rev
|
|
336
334
|
}
|
|
335
|
+
if !options.deep {
|
|
336
|
+
offset = key.indexOf("/", prelen) // start looking past options.prefix
|
|
337
|
+
if offset >= 0 { // directory child
|
|
338
|
+
if length(key) > offset+1 { // transitive child (not directory itself)
|
|
339
|
+
obj.doc = undefined // just record directory name
|
|
340
|
+
item._id = undefined
|
|
341
|
+
item._rev = undefined }
|
|
342
|
+
key = key.substring(0, offset+1) // child directory name
|
|
343
|
+
if !firstkids[key]
|
|
344
|
+
firstkids[key] = key // first time we've seen this child directory
|
|
345
|
+
else
|
|
346
|
+
continue // ignore deeper child
|
|
347
|
+
item.key = key } }
|
|
337
348
|
if obj.doc { // docs were requested
|
|
338
349
|
if obj.doc.content {
|
|
339
350
|
item._md5 = HashMD5(obj.doc.content)
|
|
@@ -518,7 +529,7 @@ closure DbConnector(psm, local connClassID, connector, watch) {
|
|
|
518
529
|
|
|
519
530
|
// localDBcred
|
|
520
531
|
//
|
|
521
|
-
// True iff the specified credential dictionary is for a local
|
|
532
|
+
// True iff the specified credential dictionary is for a local DB.
|
|
522
533
|
function localDBcred(creds) {
|
|
523
534
|
!creds.authName && creds.urlName.indexOf("://") < 0
|
|
524
535
|
}
|
|
@@ -711,8 +722,13 @@ closure DbConnector(psm, local connClassID, connector, watch) {
|
|
|
711
722
|
if creds {
|
|
712
723
|
if creds.label
|
|
713
724
|
info.name = creds.label
|
|
714
|
-
if localDBcred(creds)
|
|
715
|
-
|
|
725
|
+
if localDBcred(creds) {
|
|
726
|
+
if js.w
|
|
727
|
+
info.type = "PouchDB-browser"
|
|
728
|
+
else
|
|
729
|
+
info.type = "PouchDB-filesystem"
|
|
730
|
+
} else
|
|
731
|
+
info.type = "PouchDB-network"
|
|
716
732
|
if creds.locked
|
|
717
733
|
info.locked = true
|
|
718
734
|
if creds.hidden
|
|
@@ -741,6 +757,8 @@ closure DbConnector(psm, local connClassID, connector, watch) {
|
|
|
741
757
|
//
|
|
742
758
|
// Connect to a database, returning a PSM view.
|
|
743
759
|
connector.connect = function connect(resID, service, args, local error, creds, db, rootpath, table) {
|
|
760
|
+
if !resID || args && !tuple(args)
|
|
761
|
+
return (list(Error("invalid arguments")))
|
|
744
762
|
`(error, creds) = connector.access(resID)
|
|
745
763
|
if !error
|
|
746
764
|
`(error, db) = PouchDB(creds)
|
|
@@ -751,7 +769,7 @@ closure DbConnector(psm, local connClassID, connector, watch) {
|
|
|
751
769
|
else if service == "NideFS" {
|
|
752
770
|
rootpath = args.0 // connect to a NideFS filesystem
|
|
753
771
|
if !rootpath
|
|
754
|
-
return (Error("mandatory rootpath missing"))
|
|
772
|
+
return (list(Error("mandatory rootpath missing")))
|
|
755
773
|
`(error, table) = db.table(rootpath)
|
|
756
774
|
if error
|
|
757
775
|
list(error)
|
|
@@ -766,7 +766,7 @@ function fimaInit(local manifest) {
|
|
|
766
766
|
|
|
767
767
|
manifest = `(FileManager, fimaStore, fimaInit)
|
|
768
768
|
|
|
769
|
-
Naan.module.build(module.id, "
|
|
769
|
+
Naan.module.build(module.id, "file_manager", function(modobj, compobj) {
|
|
770
770
|
require("./storage.nlg")
|
|
771
771
|
commonWatching = require("../common/watching.nlg")
|
|
772
772
|
compobj.manifest = manifest
|
|
@@ -38,10 +38,12 @@
|
|
|
38
38
|
|
|
39
39
|
closure FSview(table, rootpath, local view) {
|
|
40
40
|
global(JSpath)
|
|
41
|
-
if !table
|
|
41
|
+
if !table || !string(rootpath)
|
|
42
42
|
return (list(Error("invalid arguments")))
|
|
43
43
|
view = new(object, this)
|
|
44
44
|
view.table = table
|
|
45
|
+
if rootpath != "" && rootpath.slice(-1) != "/"
|
|
46
|
+
rootpath = rootpath.concat("/") // "" or "<path>/"
|
|
45
47
|
view.rootpath = rootpath
|
|
46
48
|
view.path = JSpath.posix // for view.path.join(), etc.
|
|
47
49
|
|
|
@@ -118,23 +120,21 @@ closure FSview(table, rootpath, local view) {
|
|
|
118
120
|
// checkPathName
|
|
119
121
|
//
|
|
120
122
|
// Return a `(path, name) tuple for a directory, or false if callback executed due to error. The
|
|
121
|
-
// name is the empty string if the path is empty. Path "/" has name "
|
|
122
|
-
//
|
|
123
|
+
// name is the empty string if the path is empty. Path "/" has name "". Otherwise the name is the
|
|
124
|
+
// last segment of the path, omitting any trailing slash. A key invariant is that the information
|
|
125
|
+
// should be the same whether the pathname was part of the rootpath or specified in the source
|
|
126
|
+
// path to an operation. That is why this "steals" the rootpath name if needed.
|
|
123
127
|
//
|
|
124
|
-
function checkPathName(path, callback, local name
|
|
125
|
-
if path
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
name = path
|
|
135
|
-
else
|
|
136
|
-
name = path.slice(slashdex+1, -1) // omit trailing "/"
|
|
137
|
-
}
|
|
128
|
+
function checkPathName(path, callback, local name) {
|
|
129
|
+
if checkPath(path, callback)
|
|
130
|
+
return (false) // non-string
|
|
131
|
+
if path != "" && path.slice(-1) != "/"
|
|
132
|
+
path = path.concat("/") // force to be directory
|
|
133
|
+
if path == "/" && rootpath != ""
|
|
134
|
+
name = rootpath // avoid making "//"
|
|
135
|
+
else
|
|
136
|
+
name = rootpath.concat(path)
|
|
137
|
+
name = name.split("/").slice(0,-1).pop() || "" // <|| ""> not needed
|
|
138
138
|
list(path, name)
|
|
139
139
|
}
|
|
140
140
|
|
|
@@ -683,7 +683,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
683
683
|
return // already executed callback with error
|
|
684
684
|
dirdict = {
|
|
685
685
|
name: name
|
|
686
|
-
path: path
|
|
686
|
+
path: rootpath.concat(path)
|
|
687
687
|
data: {
|
|
688
688
|
platform: table.type
|
|
689
689
|
semantics: "dbfs"
|
|
@@ -715,8 +715,8 @@ closure FSview(table, rootpath, local view) {
|
|
|
715
715
|
finfo.type = "directory"
|
|
716
716
|
} else if !finfo.type
|
|
717
717
|
finfo.type = "file" // everything is a file in UNIX
|
|
718
|
-
finfo.md5 = item.doc._md5 || undefined
|
|
719
|
-
finfo.length = item.doc._length || item.doc.length || undefined
|
|
718
|
+
finfo.md5 = item._md5 || item.doc._md5 || undefined
|
|
719
|
+
finfo.length = item._length || item.doc._length || item.doc.length || undefined
|
|
720
720
|
if item.key.length > offset // not the directory itself
|
|
721
721
|
dirdict.children.push({
|
|
722
722
|
name: name
|
|
@@ -743,14 +743,13 @@ closure FSview(table, rootpath, local view) {
|
|
|
743
743
|
`(path, name) = checkPathName(path, callback)
|
|
744
744
|
if !path
|
|
745
745
|
return // already executed callback with error
|
|
746
|
-
options = {
|
|
746
|
+
options = merge({
|
|
747
747
|
prefix: path
|
|
748
748
|
deep: true
|
|
749
|
-
}
|
|
750
|
-
if name == "" && rootpath != ""
|
|
751
|
-
name = rootpath.split("/").slice(0,-1).pop() || ""
|
|
749
|
+
}, options)
|
|
752
750
|
treedict = {
|
|
753
751
|
name: name
|
|
752
|
+
path: rootpath.concat(path)
|
|
754
753
|
data: {
|
|
755
754
|
platform: table.type
|
|
756
755
|
semantics: "dbfs"
|
|
@@ -142,9 +142,14 @@ closure ResourceManager(dbname, prefix, local reman, watch, result) {
|
|
|
142
142
|
reman.unWatch = watch.unWatch
|
|
143
143
|
reman.dbname = dbname
|
|
144
144
|
reman.conns = {}
|
|
145
|
-
|
|
145
|
+
try {
|
|
146
|
+
require("./dbt_pouch.nlg")
|
|
147
|
+
result = PouchDB(dbname)
|
|
148
|
+
} catch {
|
|
149
|
+
result = list(Error("PouchDB not available", exception))
|
|
150
|
+
}
|
|
146
151
|
if result.0
|
|
147
|
-
return (result)
|
|
152
|
+
return (list(result)) // can't access our vault database
|
|
148
153
|
reman.db = result.1
|
|
149
154
|
|
|
150
155
|
// vault
|
|
@@ -423,19 +428,22 @@ closure ResourceTracker(reman, local retor, watch) {
|
|
|
423
428
|
// Start tracking resources.
|
|
424
429
|
retor.open = function open() {
|
|
425
430
|
if retor.classIdList
|
|
426
|
-
return
|
|
431
|
+
return (list(false, { open: true })) // already open
|
|
427
432
|
watch.reset()
|
|
428
433
|
retor.resids = { } // start empty
|
|
429
434
|
retor.classIdList = []
|
|
430
435
|
for classID in reman.connectors()
|
|
431
436
|
addConnResources(classID)
|
|
432
437
|
reman.watch(remanUpdateOnChange)
|
|
438
|
+
list(false, { ok: true })
|
|
433
439
|
}
|
|
434
440
|
|
|
435
441
|
// close
|
|
436
442
|
//
|
|
437
443
|
// stop tracking resources.
|
|
438
444
|
retor.close = function close(local classID, connector) {
|
|
445
|
+
if !retor.classIdList
|
|
446
|
+
return (list(false, { open: false }))
|
|
439
447
|
watch.reset()
|
|
440
448
|
if retor.classIdList {
|
|
441
449
|
for classID in retor.classIdList {
|
|
@@ -446,6 +454,7 @@ closure ResourceTracker(reman, local retor, watch) {
|
|
|
446
454
|
}
|
|
447
455
|
reman.unWatch(remanUpdateOnChange)
|
|
448
456
|
retor.resids = false
|
|
457
|
+
list(false, { ok: true })
|
|
449
458
|
}
|
|
450
459
|
|
|
451
460
|
// finis
|
|
@@ -466,7 +475,6 @@ function rsrcInit(local manifest) {
|
|
|
466
475
|
|
|
467
476
|
Naan.module.build(module.id, "resources", function(modobj, compobj) {
|
|
468
477
|
require("./storage.nlg")
|
|
469
|
-
require("./dbt_pouch.nlg")
|
|
470
478
|
commonWatching = require("../common/watching.nlg")
|
|
471
479
|
compobj.manifest = manifest
|
|
472
480
|
module.exports.ResourceManager = ResourceManager
|