@naanlang/naan 1.1.0 → 1.2.1
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 +12 -10
- package/bin/index.js +2 -2
- package/dist/naan.min.js +13 -13
- package/frameworks/browser/https_request.nlg +4 -2
- package/frameworks/browser/sworker.js +23 -23
- package/frameworks/browser/terminals.nlg +77 -45
- package/frameworks/browser/ws_client.nlg +6 -2
- package/frameworks/client/apiclient.nlg +80 -115
- package/frameworks/client/psm_client.nlg +39 -18
- package/frameworks/client/relaycon.nlg +2 -0
- package/frameworks/common/common.nlg +10 -4
- package/frameworks/node/https_request.nlg +2 -1
- package/frameworks/node/psm_server.nlg +2 -2
- package/frameworks/node/ws_client.nlg +7 -2
- package/frameworks/project/build.nlg +12 -11
- package/frameworks/project/projects.nlg +7 -5
- package/frameworks/running/executors.nlg +131 -38
- package/frameworks/running/taskexec.nlg +3 -2
- package/frameworks/storage/psm.nlg +2 -1
- package/frameworks/storage/psm_dbtables.nlg +23 -13
- package/lib/browser/env_web.js +6 -6
- package/lib/core/naanlib.js +13 -13
- package/package.json +1 -1
- package/plugins/serviceAws/aws_dynamo.nlg +91 -32
- package/plugins/serviceAws/dbt_aws.nlg +4 -4
- package/test/harness.nlg +1 -1
- package/test/test_02_context.nlg +1 -1
- package/test/test_03_jsinterop.nlg +2 -2
- package/test/test_05_strings.nlg +7 -4
- package/test/test_07_lingo.nlg +3 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* column positioning: // // !
|
|
7
7
|
*
|
|
8
|
-
* Copyright (c) 2020-
|
|
8
|
+
* Copyright (c) 2020-2024 by Richard C. Zulch
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
closure ExecutorBase(track, type, name, local exec) {
|
|
21
|
+
global()
|
|
21
22
|
exec = new(object, this)
|
|
22
23
|
exec.type = type
|
|
23
24
|
exec.name = name
|
|
@@ -51,7 +52,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
// execReceived
|
|
54
|
-
//
|
|
55
|
+
// The specified message was received from the instance, so signal it.
|
|
55
56
|
|
|
56
57
|
exec.execReceived = closure execReceived(data, local pending) {
|
|
57
58
|
pending = exec.pending[data.xid]
|
|
@@ -64,6 +65,13 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
64
65
|
pending.signal(list(false, data))
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
// execSetStatus
|
|
69
|
+
// Received a status update from the instance.
|
|
70
|
+
|
|
71
|
+
exec.execSetStatus = function execSetStatus(status) {
|
|
72
|
+
exec.xstatus = status
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
// execFailed
|
|
68
76
|
// Communication has failed.
|
|
69
77
|
|
|
@@ -76,7 +84,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
76
84
|
// execClosed
|
|
77
85
|
// Note that the connection has closed, so signal all the waiters.
|
|
78
86
|
|
|
79
|
-
exec.execClosed = closure execClosed(error, local xid) {
|
|
87
|
+
exec.execClosed = closure execClosed(error, local xid, pending) {
|
|
80
88
|
for `(xid, pending) in exec.pending {
|
|
81
89
|
pending.signal(list(error))
|
|
82
90
|
pending[xid] = undefined
|
|
@@ -135,6 +143,7 @@ closure ExecutorBase(track, type, name, local exec) {
|
|
|
135
143
|
*/
|
|
136
144
|
|
|
137
145
|
closure ExecutorContext(exec, contextID, local context, util) {
|
|
146
|
+
global(apply)
|
|
138
147
|
context = new(object, this)
|
|
139
148
|
util = modlist().Util.exports
|
|
140
149
|
|
|
@@ -212,12 +221,13 @@ closure ExecutorContext(exec, contextID, local context, util) {
|
|
|
212
221
|
applyf(eval(proc), eargs)
|
|
213
222
|
} (pop(args), reverse(args))
|
|
214
223
|
}
|
|
224
|
+
|
|
215
225
|
// rpc
|
|
216
226
|
// Execute a remote procedure call without package translation, to reduce overhead. This will not
|
|
217
227
|
// properly transfer Naan-specific types like symbols, and the results will be native JavaScript.
|
|
218
228
|
// The procedure must be specified as a symbol or string.
|
|
219
229
|
|
|
220
|
-
context.rpc = closure rpc(proc, args, local data, result) {
|
|
230
|
+
context.rpc = closure rpc(proc, args, local data, pending, result) {
|
|
221
231
|
data = {
|
|
222
232
|
contextID: contextID
|
|
223
233
|
proc: proc
|
|
@@ -260,20 +270,22 @@ closure ExecutorContext(exec, contextID, local context, util) {
|
|
|
260
270
|
*
|
|
261
271
|
* Allowable options are:
|
|
262
272
|
* {
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
273
|
+
* spawnLoc: <string> // e.g. "Local" (default) or "Host"
|
|
274
|
+
* maxcount: <integer> // maximum workers, default 4
|
|
275
|
+
* initeval: `(<expr>, <put>, <get>) // initializes each new worker
|
|
276
|
+
* basename: <string> // worker label for UI, default "batch"
|
|
266
277
|
* }
|
|
267
278
|
*
|
|
268
279
|
*/
|
|
269
280
|
|
|
270
|
-
closure ExecutorParallel(options, local maxcount,
|
|
281
|
+
closure ExecutorParallel(track, options, local maxcount, parallel, exqueue, crValue) {
|
|
282
|
+
global()
|
|
283
|
+
options = merge({
|
|
284
|
+
spawnLoc: "Local"
|
|
285
|
+
maxcount: 4
|
|
286
|
+
basename: "batch"
|
|
287
|
+
}, options)
|
|
271
288
|
maxcount = options.maxcount
|
|
272
|
-
if !maxcount
|
|
273
|
-
maxcount = 4 // default is 4 workers
|
|
274
|
-
basename = options.basename
|
|
275
|
-
if !string(basename)
|
|
276
|
-
basename = "batch"
|
|
277
289
|
exqueue = [] // waiting for execution
|
|
278
290
|
parallel = new(object, this)
|
|
279
291
|
parallel.workers = [] // array of worker executors
|
|
@@ -284,36 +296,41 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
284
296
|
//
|
|
285
297
|
// Return the next available worker. If no workers are available and we haven't hit the maximum
|
|
286
298
|
// then create an additional worker and return it. If we cannot allocate another worker then this
|
|
287
|
-
// returns
|
|
299
|
+
// returns { wait: true }.
|
|
288
300
|
|
|
289
301
|
closure acquireWorker(local workdex, name, worker, context, result) {
|
|
290
302
|
if parallel.available.length > 0
|
|
291
|
-
return (parallel.available.pop())
|
|
303
|
+
return (list(false, parallel.available.pop()))
|
|
292
304
|
workdex = parallel.workers.length
|
|
293
305
|
if workdex >= maxcount
|
|
294
|
-
return (false)
|
|
306
|
+
return (list(false, { wait: true }))
|
|
295
307
|
parallel.workers[workdex] = false // reserve our spot
|
|
296
|
-
name = basename.concat("-", workdex+1)
|
|
297
|
-
worker =
|
|
298
|
-
|
|
308
|
+
name = options.basename.concat("-", workdex+1)
|
|
309
|
+
worker = track.spawn(options.spawnLoc, name, {
|
|
310
|
+
workerID: "ExecutorParallel"
|
|
311
|
+
})
|
|
312
|
+
if worker.0 {
|
|
313
|
+
parallel.workers.splice(workdex, 1)
|
|
299
314
|
debuglog("execParallel: cannot spawn worker:", ErrorString(worker.0))
|
|
300
|
-
return (
|
|
315
|
+
return (list(worker.0))
|
|
301
316
|
}
|
|
302
317
|
worker = worker.1
|
|
303
318
|
context = worker.context()
|
|
304
319
|
if context.0 {
|
|
305
|
-
|
|
320
|
+
parallel.workers.splice(workdex, 1)
|
|
306
321
|
worker.destroy()
|
|
307
|
-
|
|
322
|
+
debuglog("execParallel: cannot create worker context:", ErrorString(context.0))
|
|
323
|
+
return (list(context.0))
|
|
308
324
|
}
|
|
309
325
|
context = context.1
|
|
310
326
|
parallel.workers[workdex] = worker
|
|
311
327
|
parallel.contexts[worker] = context
|
|
312
328
|
if tuple(options.initeval) {
|
|
313
329
|
result = apply(context.eval, options.initeval)
|
|
314
|
-
if result.0
|
|
315
|
-
debuglog("execParallel: cannot initialize worker", name, ErrorString(result.0))
|
|
316
|
-
|
|
330
|
+
if result.0 {
|
|
331
|
+
debuglog("execParallel: cannot initialize worker", name, ErrorString(result.0))
|
|
332
|
+
return (list(result.0)) } }
|
|
333
|
+
return (list(false, worker))
|
|
317
334
|
}
|
|
318
335
|
|
|
319
336
|
// releaseWorker
|
|
@@ -333,23 +350,26 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
333
350
|
// don't remove work from the queue until we already have a worker.
|
|
334
351
|
//
|
|
335
352
|
|
|
336
|
-
closure execNext(local worker, result) {
|
|
353
|
+
closure execNext(local error, worker, result) {
|
|
337
354
|
if exqueue.length > 0 {
|
|
338
|
-
worker = acquireWorker()
|
|
339
|
-
if
|
|
340
|
-
if maxcount > 0 && parallel.workers.length == 0
|
|
341
|
-
|
|
342
|
-
|
|
355
|
+
`(error, worker) = acquireWorker()
|
|
356
|
+
if error {
|
|
357
|
+
if maxcount > 0 && parallel.workers.length == 0 {
|
|
358
|
+
exqueue = []
|
|
359
|
+
throw("execParallel: cannot allocate any workers at all") }
|
|
360
|
+
return // one failed, so try again later
|
|
343
361
|
}
|
|
362
|
+
if worker.wait
|
|
363
|
+
return // we're busy, so try again later
|
|
344
364
|
future(function(local next, context) {
|
|
345
365
|
next = exqueue.splice(0, 1).0 // remove oldest entry, from start
|
|
346
366
|
if !next {
|
|
347
367
|
releaseWorker(worker) // someone else already processed this
|
|
348
368
|
return
|
|
349
|
-
|
|
369
|
+
}
|
|
350
370
|
context = parallel.contexts[worker]
|
|
351
371
|
if next.eval
|
|
352
|
-
result = apply(context.eval, next.
|
|
372
|
+
result = apply(context.eval, next.eval)
|
|
353
373
|
else if next.proc
|
|
354
374
|
result = context.rpc(next.proc, next.args)
|
|
355
375
|
else
|
|
@@ -368,7 +388,7 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
368
388
|
//
|
|
369
389
|
|
|
370
390
|
parallel.eval = closure evalf(expr, put, get, local pending) {
|
|
371
|
-
if
|
|
391
|
+
if maxcount == 0
|
|
372
392
|
return (crValue) // already destroyed
|
|
373
393
|
pending = new(nonce)
|
|
374
394
|
exqueue.push({
|
|
@@ -388,13 +408,55 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
388
408
|
evalf(expr, eval(put), eval(get))
|
|
389
409
|
}
|
|
390
410
|
|
|
411
|
+
// exBatch
|
|
412
|
+
//
|
|
413
|
+
// Remote helper to execute a batch function.
|
|
414
|
+
//
|
|
415
|
+
|
|
416
|
+
closure exBatch(expr, local pending) {
|
|
417
|
+
// evaluate the expression in batch mode
|
|
418
|
+
function execbat() {
|
|
419
|
+
try {
|
|
420
|
+
pending.signal(list(false, evalactive(expr)))
|
|
421
|
+
} catch {
|
|
422
|
+
pending.signal(list(Error(exception)))
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
pending = new(nonce)
|
|
427
|
+
exec(list(execbat))
|
|
428
|
+
pending.wait()
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// batch
|
|
432
|
+
//
|
|
433
|
+
// Execute eval above in a remote in batch mode, waiting until it is complete.
|
|
434
|
+
//
|
|
435
|
+
|
|
436
|
+
parallel.batch = closure batchf(expr, put, get, local result) {
|
|
437
|
+
result = evalf(list(exBatch, list(quote, expr)), `(exBatch).append(put), get)
|
|
438
|
+
if result.0 // unpack our error wrapper
|
|
439
|
+
result
|
|
440
|
+
else
|
|
441
|
+
result.1
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// batchq
|
|
445
|
+
//
|
|
446
|
+
// Evaluate the specified QUOTED expression in a remote in batch mode.
|
|
447
|
+
//
|
|
448
|
+
|
|
449
|
+
parallel.batchq = macro batchq(expr, put, get) {
|
|
450
|
+
batchf(expr, eval(put), eval(get))
|
|
451
|
+
}
|
|
452
|
+
|
|
391
453
|
// rpc
|
|
392
454
|
//
|
|
393
455
|
// Execute a procedure call in a remote worker.
|
|
394
456
|
//
|
|
395
457
|
|
|
396
458
|
parallel.rpc = closure rpc(proc, args, local pending) {
|
|
397
|
-
if
|
|
459
|
+
if maxcount == 0
|
|
398
460
|
return (crValue) // already destroyed
|
|
399
461
|
pending = new(nonce)
|
|
400
462
|
exqueue.push({
|
|
@@ -406,13 +468,36 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
406
468
|
pending.wait()
|
|
407
469
|
}
|
|
408
470
|
|
|
471
|
+
// status
|
|
472
|
+
//
|
|
473
|
+
// Report status of workers. Each worker has a dictionary:
|
|
474
|
+
// {
|
|
475
|
+
// state: <string> // "active" or "idle"
|
|
476
|
+
// status: <dict> // like runaverage(1)
|
|
477
|
+
// }
|
|
478
|
+
//
|
|
479
|
+
|
|
480
|
+
parallel.status = function status(local output, worker) {
|
|
481
|
+
output = []
|
|
482
|
+
for worker in parallel.workers {
|
|
483
|
+
output.push({
|
|
484
|
+
name: worker.name
|
|
485
|
+
type: worker.type
|
|
486
|
+
state: if parallel.available.indexOf(worker) >= 0
|
|
487
|
+
"idle" else "active"
|
|
488
|
+
status: worker.xstatus
|
|
489
|
+
})
|
|
490
|
+
}
|
|
491
|
+
output
|
|
492
|
+
}
|
|
493
|
+
|
|
409
494
|
// destroy
|
|
410
495
|
//
|
|
411
496
|
// Destroy the object by destroying the workers and failing pending requests with cancelResult.
|
|
412
497
|
//
|
|
413
498
|
|
|
414
499
|
parallel.destroy = closure destroy(cancelResult, local worker, next) {
|
|
415
|
-
if
|
|
500
|
+
if maxcount == 0
|
|
416
501
|
return (false) // already destroyed
|
|
417
502
|
crValue = cancelResult
|
|
418
503
|
maxcount = 0
|
|
@@ -444,6 +529,7 @@ closure ExecutorParallel(options, local maxcount, basename, parallel, exqueue, c
|
|
|
444
529
|
*/
|
|
445
530
|
|
|
446
531
|
closure ExecutorTracker(local xtrak) {
|
|
532
|
+
global()
|
|
447
533
|
xtrak = new(object, this)
|
|
448
534
|
xtrak.instances = []
|
|
449
535
|
xtrak.watchers = []
|
|
@@ -494,7 +580,7 @@ closure ExecutorTracker(local xtrak) {
|
|
|
494
580
|
// enumlist
|
|
495
581
|
// Enumerate the list of executors.
|
|
496
582
|
|
|
497
|
-
xtrak.enumlist = function enumlist(local results) {
|
|
583
|
+
xtrak.enumlist = function enumlist(local results, instance) {
|
|
498
584
|
results = []
|
|
499
585
|
for instance in xtrak.instances
|
|
500
586
|
results.push(instance.executor)
|
|
@@ -537,6 +623,13 @@ closure ExecutorTracker(local xtrak) {
|
|
|
537
623
|
} (pop(args), args)
|
|
538
624
|
}
|
|
539
625
|
|
|
626
|
+
// parallel
|
|
627
|
+
// Return a new parallel executor with specified options.
|
|
628
|
+
|
|
629
|
+
xtrak.parallel = function parallel(options) {
|
|
630
|
+
ExecutorParallel(xtrak, options)
|
|
631
|
+
}
|
|
632
|
+
|
|
540
633
|
xtrak.register(execLambda, "Lambda")
|
|
541
634
|
|
|
542
635
|
// finis
|
|
@@ -552,6 +645,7 @@ closure ExecutorTracker(local xtrak) {
|
|
|
552
645
|
*/
|
|
553
646
|
|
|
554
647
|
closure execLambda(track, url, name, workerID, local target, nlregex, clientID, serverID) {
|
|
648
|
+
global()
|
|
555
649
|
target = ExecutorBase(track, "Lambda", name)
|
|
556
650
|
clientID = "DebugWorkers"
|
|
557
651
|
serverID = "Workers"
|
|
@@ -800,7 +894,6 @@ closure execLambda(track, url, name, workerID, local target, nlregex, clientID,
|
|
|
800
894
|
*/
|
|
801
895
|
|
|
802
896
|
function execInit(local manifest) {
|
|
803
|
-
|
|
804
897
|
manifest = `(ExecutorBase, ExecutorContext, ExecutorParallel, ExecutorTracker, execLambda, execInit)
|
|
805
898
|
|
|
806
899
|
Naan.module.build(module.id, "executors", function(modobj, compobj) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* column positioning: // // !
|
|
7
7
|
*
|
|
8
|
-
* Copyright (c) 2021-
|
|
8
|
+
* Copyright (c) 2021-2024 by Richard C. Zulch
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
closure TaskDispatcher(replier, local contexts, gohome, util) {
|
|
23
|
+
global()
|
|
23
24
|
contexts = { }
|
|
24
25
|
gohome = makeActivator()
|
|
25
26
|
util = modlist().Util.exports
|
|
26
|
-
closure(data, local reply, restorens, expr, roots, proc, args, result) {
|
|
27
|
+
closure(data, local reply, restorens, context, expr, roots, proc, args, result) {
|
|
27
28
|
reply = {
|
|
28
29
|
xmsg: "error"
|
|
29
30
|
xid: data.xid
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
closure MakePSMutil(fs, local util) {
|
|
23
|
+
global()
|
|
23
24
|
util = new(object, this)
|
|
24
25
|
util.fs = fs
|
|
25
26
|
|
|
@@ -310,7 +311,7 @@ closure MakePSMutil(fs, local util) {
|
|
|
310
311
|
//
|
|
311
312
|
if options.erase {
|
|
312
313
|
asyncArray(keys(folders).toarray, 10, closure eraser(destpath
|
|
313
|
-
local error, outfolder, folder, namesin, removes, delopt) {
|
|
314
|
+
local error, outfolder, folder, namesin, node, removes, delopt) {
|
|
314
315
|
`(error, outfolder) = outfs.dirList(destpath) // existing files in our destination
|
|
315
316
|
if error
|
|
316
317
|
return
|
|
@@ -45,6 +45,14 @@ closure FSview(table, rootpath, local view) {
|
|
|
45
45
|
view.rootpath = rootpath
|
|
46
46
|
view.path = JSpath.posix // for view.path.join(), etc.
|
|
47
47
|
|
|
48
|
+
// dirPath
|
|
49
|
+
//
|
|
50
|
+
// True iff the path is a dirpath. If the path is empty this checks the rootpath.
|
|
51
|
+
|
|
52
|
+
function dirPath(path) {
|
|
53
|
+
path.slice(-1) == "/" || path == "" && rootpath.slice(-1) == "/"
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
// dirName
|
|
49
57
|
//
|
|
50
58
|
// Return the directory portion of the specified path.
|
|
@@ -163,7 +171,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
163
171
|
else
|
|
164
172
|
proc = view.table.get
|
|
165
173
|
`(error, data) = proc(path)
|
|
166
|
-
if error && error.status == 404 && path
|
|
174
|
+
if error && error.status == 404 && !dirPath(path)
|
|
167
175
|
`(error, data) = proc(path.concat("/"))
|
|
168
176
|
callback(error, data)
|
|
169
177
|
}
|
|
@@ -200,7 +208,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
200
208
|
birthtime: nowstr
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
|
-
if path
|
|
211
|
+
if dirPath(path)
|
|
204
212
|
metadata.finfo.type = "directory"
|
|
205
213
|
else
|
|
206
214
|
metadata.finfo.type = "file"
|
|
@@ -268,7 +276,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
268
276
|
return (asyncResult(callback, false, { created: false })) // root always already exists
|
|
269
277
|
if checkPath(path, callback)
|
|
270
278
|
return
|
|
271
|
-
if path
|
|
279
|
+
if !dirPath(path)
|
|
272
280
|
path = path.concat("/")
|
|
273
281
|
view.table.get(path, function(error, data, local pathdirs, buildpath, item) {
|
|
274
282
|
if !error
|
|
@@ -286,7 +294,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
286
294
|
name: "conflict"
|
|
287
295
|
path: buildpath
|
|
288
296
|
})))
|
|
289
|
-
if buildpath
|
|
297
|
+
if !dirPath(buildpath)
|
|
290
298
|
buildpath = buildpath.concat("/")
|
|
291
299
|
`(error, data) = view.table.head(buildpath) // get desired directory
|
|
292
300
|
if error.status == 404
|
|
@@ -311,7 +319,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
311
319
|
if dest.indexOf("/") < 0
|
|
312
320
|
newpath = dirName(srcpath).concat(dest) // renaming within same directory
|
|
313
321
|
else {
|
|
314
|
-
if dest
|
|
322
|
+
if dirPath(dest) // moving to new directory location:
|
|
315
323
|
newpath = dest.concat(baseName(srcpath)) // new path is new pathname
|
|
316
324
|
else { // moving and renaming:
|
|
317
325
|
newpath = dest // new path is new pathname
|
|
@@ -361,7 +369,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
361
369
|
//
|
|
362
370
|
closure copyDirectory(srcpath, dest, options,
|
|
363
371
|
local error, nodes, data, destpath, errors, docpath, newpath, srcroot, item) {
|
|
364
|
-
if srcpath
|
|
372
|
+
if !dirPath(srcpath)
|
|
365
373
|
srcpath = srcpath.concat("/") // normalize source as directory
|
|
366
374
|
`(error, nodes) = view.table.records({ prefix: srcpath }) // each item has key/_id/_rev, not doc
|
|
367
375
|
if error
|
|
@@ -380,13 +388,13 @@ closure FSview(table, rootpath, local view) {
|
|
|
380
388
|
destpath = dirName(srcpath).concat(dest) // new directory name in same parent directory
|
|
381
389
|
dest = dirName(srcpath) } // dest is new parent pathname
|
|
382
390
|
else {
|
|
383
|
-
if dest
|
|
391
|
+
if dirPath(dest)
|
|
384
392
|
destpath = dest.concat(baseName(srcpath)) // same name; new location
|
|
385
393
|
else {
|
|
386
394
|
destpath = dest // new full pathname
|
|
387
395
|
dest = dirName(dest) } // dest is new parent pathname
|
|
388
396
|
}
|
|
389
|
-
if destpath != "" && destpath
|
|
397
|
+
if destpath != "" && !dirPath(destpath)
|
|
390
398
|
destpath = destpath.concat("/") // get actual path of new directory
|
|
391
399
|
//
|
|
392
400
|
// Change srcpath to destpath for all records. Note that dest is the name of our new parent
|
|
@@ -489,13 +497,13 @@ closure FSview(table, rootpath, local view) {
|
|
|
489
497
|
finfo.length = data.length
|
|
490
498
|
else if data._length
|
|
491
499
|
finfo.length = data._length
|
|
492
|
-
if
|
|
500
|
+
if dirPath(path)
|
|
501
|
+
finfo.type = "directory"
|
|
502
|
+
else if finfo.length
|
|
493
503
|
finfo.type = "file" }
|
|
494
504
|
else if path == "" {
|
|
495
505
|
error = false // we were asked for info on superoot
|
|
496
506
|
finfo = {
|
|
497
|
-
md5: HashMD5("")
|
|
498
|
-
length: 0
|
|
499
507
|
type: "directory"
|
|
500
508
|
} }
|
|
501
509
|
callback(error, finfo)
|
|
@@ -553,7 +561,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
553
561
|
return
|
|
554
562
|
if !content
|
|
555
563
|
return (asyncResult(callback, Error("content required")))
|
|
556
|
-
if path
|
|
564
|
+
if dirPath(path)
|
|
557
565
|
return (asyncResult(callback, Error("cannot write to a directory", { path: path })))
|
|
558
566
|
if !validName(path, true)
|
|
559
567
|
return (asyncResult(callback, Error("invalid filename", { path: path })))
|
|
@@ -631,7 +639,7 @@ closure FSview(table, rootpath, local view) {
|
|
|
631
639
|
name: "forbidden"
|
|
632
640
|
path: path
|
|
633
641
|
})))
|
|
634
|
-
if path
|
|
642
|
+
if !dirPath(path)
|
|
635
643
|
path = path.concat("/") // avoid deleting longer filenames with same parent and prefix
|
|
636
644
|
`(error, data) = dbDirRecords(path, true)
|
|
637
645
|
if error
|
|
@@ -739,6 +747,8 @@ closure FSview(table, rootpath, local view) {
|
|
|
739
747
|
prefix: path
|
|
740
748
|
deep: true
|
|
741
749
|
}
|
|
750
|
+
if name == "" && rootpath != ""
|
|
751
|
+
name = rootpath.split("/").slice(0,-1).pop() || ""
|
|
742
752
|
treedict = {
|
|
743
753
|
name: name
|
|
744
754
|
data: {
|
package/lib/browser/env_web.js
CHANGED
|
@@ -526,7 +526,7 @@ exports.NaanControllerWeb = function() {
|
|
|
526
526
|
statedoc.curversion = kStateCurrentVersion;
|
|
527
527
|
statedoc.firstver = kStateFirstVersion;
|
|
528
528
|
statedoc.licensee = "MIT-License";
|
|
529
|
-
statedoc.verstring = "1.1
|
|
529
|
+
statedoc.verstring = "1.2.1+1";
|
|
530
530
|
statedoc.date = new Date().toISOString();
|
|
531
531
|
statedoc.prefs = prefs;
|
|
532
532
|
statedoc.naan = naanlib.saveState(false); // true to optimize, which is a bit slower
|
|
@@ -544,7 +544,7 @@ exports.NaanControllerWeb = function() {
|
|
|
544
544
|
|| statedoc.firstver > kStateCurrentVersion
|
|
545
545
|
|| statedoc.curversion < kStateFirstVersion
|
|
546
546
|
|| statedoc.licensee != "MIT-License"
|
|
547
|
-
|| statedoc.verstring != "1.1
|
|
547
|
+
|| statedoc.verstring != "1.2.1+1")
|
|
548
548
|
{
|
|
549
549
|
localStorage.removeItem("NaanState_Hosted");
|
|
550
550
|
return (false);
|
|
@@ -603,7 +603,7 @@ exports.NaanControllerWeb = function() {
|
|
|
603
603
|
op: "VsiteOpen",
|
|
604
604
|
name: vsiteName,
|
|
605
605
|
naancont: contSelf,
|
|
606
|
-
title: vsiteName + " 1.1
|
|
606
|
+
title: vsiteName + " 1.2.1+1"
|
|
607
607
|
});
|
|
608
608
|
}
|
|
609
609
|
} catch (e) {
|
|
@@ -617,7 +617,7 @@ exports.NaanControllerWeb = function() {
|
|
|
617
617
|
op: "VsiteClose",
|
|
618
618
|
name: vsiteName,
|
|
619
619
|
naancont: contSelf,
|
|
620
|
-
title: vsiteName + " 1.1
|
|
620
|
+
title: vsiteName + " 1.2.1+1"
|
|
621
621
|
});
|
|
622
622
|
termTextOut("\x1b[90m\x1b[3m".concat("\nwindow closed", "\x1b[0m\n"));
|
|
623
623
|
}
|
|
@@ -632,8 +632,8 @@ exports.NaanControllerWeb = function() {
|
|
|
632
632
|
naanlib.banner();
|
|
633
633
|
var hostpath = naanlib.js.r("path").dirname(window.location.href);
|
|
634
634
|
naanlib.start({
|
|
635
|
-
cmd: 'App.version = "1.1
|
|
636
|
-
+ 'App.cache = "
|
|
635
|
+
cmd: 'App.version = "1.2.1+1";;\r\n'
|
|
636
|
+
+ 'App.cache = "f22e60a842b7a65ac309da378d469eed";;\r\n'
|
|
637
637
|
+ 'Naan.module.requireQuery({ naanver: App.cache });;\r\n'
|
|
638
638
|
+ 'Naan.module.webparse("naan_init.nlg", "' + hostpath + '", { naanver: App.cache });;\r\n'
|
|
639
639
|
});
|