@naanlang/naan 1.6.0 → 1.7.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.
Files changed (50) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +1 -1
  3. package/bin/index.js +2 -2
  4. package/dist/env_web.js +3 -31
  5. package/dist/naan.min.js +10 -10
  6. package/frameworks/browser/sworker.js +23 -23
  7. package/frameworks/browser/terminals.nlg +44 -122
  8. package/frameworks/browser/worker.nlg +64 -24
  9. package/frameworks/browser/workers.nlg +1 -1
  10. package/frameworks/client/apiclient.nlg +73 -43
  11. package/frameworks/client/psm_client.nlg +10 -14
  12. package/frameworks/common/common.nlg +2 -0
  13. package/frameworks/node/apiserver.nlg +0 -1
  14. package/frameworks/node/node.nlg +1 -0
  15. package/frameworks/node/pty.nlg +21 -21
  16. package/frameworks/node/shell.nlg +26 -3
  17. package/frameworks/node/worker.nlg +153 -79
  18. package/frameworks/project/build.nlg +55 -13
  19. package/frameworks/project/projects.nlg +1 -1
  20. package/frameworks/running/debugcom.nlg +20 -3
  21. package/frameworks/running/debugnub.nlg +16 -7
  22. package/frameworks/running/executors.nlg +14 -12
  23. package/frameworks/running/instances.nlg +1 -0
  24. package/frameworks/running/remote_req.nlg +4 -8
  25. package/frameworks/running/remote_res.nlg +1 -1
  26. package/frameworks/running/sourcecode.nlg +3 -2
  27. package/frameworks/running/taskexec.nlg +14 -57
  28. package/frameworks/service/imp.nlg +15 -0
  29. package/frameworks/service/nubnode.nlg +35 -4
  30. package/frameworks/service/nubweb.nlg +22 -4
  31. package/frameworks/storage/file_manager.nlg +3 -2
  32. package/lib/browser/env_web.js +10 -38
  33. package/lib/browser/env_webworker.js +1 -30
  34. package/lib/core/naanlib.js +10 -10
  35. package/lib/env_node.js +5 -22
  36. package/lib/env_nodeworker.js +8 -43
  37. package/lib/node_server_init.nlg +149 -0
  38. package/lib/node_worker.js +36 -0
  39. package/lib/node_worker_init.nlg +43 -0
  40. package/package.json +1 -1
  41. package/plugins/openSearch/openSearch.nlg +3 -2
  42. package/plugins/openSearch/os_dynamo.nlg +3 -2
  43. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +44 -2
  44. package/plugins/serviceAws/aws_dynamo.nlg +144 -63
  45. package/plugins/serviceAws/aws_utils.nlg +6 -11
  46. package/plugins/serviceAws/serviceAws.nlg +3 -2
  47. package/test/test_01_core.nlg +2 -2
  48. package/test/test_02_context.nlg +8 -8
  49. package/test/test_03_jsinterop.nlg +3 -3
  50. package/test/test_07_lingo.nlg +1 -1
@@ -10,13 +10,6 @@
10
10
  *
11
11
  */
12
12
 
13
- /*
14
- * globals
15
- *
16
- */
17
-
18
- gWorkerController = false;
19
-
20
13
 
21
14
  /*
22
15
  * CurBot
@@ -46,7 +39,6 @@ closure CurBot(options, local curbot) {
46
39
  debugtext: ONdebugText.proc
47
40
  status: ONstatus.proc
48
41
  debugout: ONdebugOut.proc
49
- messageout: ONmessageOut.proc
50
42
  ioctl: ONioctl.proc
51
43
  })
52
44
  curbot.guid = 1
@@ -86,12 +78,46 @@ closure CurBot(options, local curbot) {
86
78
  //
87
79
  // Send the message to all our subscribers.
88
80
  //
89
- function notifyAll(message, exceptID, local topDestID) {
81
+ curbot.notifyAll = function notifyAll(message, exceptID, local topDestID) {
90
82
  for topDestID in curbot.topsubs
91
83
  if topDestID != exceptID
92
84
  curbot.sender(topDestID, message)
93
85
  }
94
86
 
87
+ // textEntry
88
+ //
89
+ // Simulate text entry for subprocess support.
90
+ //
91
+ curbot.textEntry = function textEntry(text) {
92
+ curbot.host.DispatchMessage({
93
+ id: "keyline"
94
+ text: text
95
+ })
96
+ }
97
+
98
+ // rawStart
99
+ //
100
+ // Configure ioctls for raw terminal operation using the spawned PTY process.
101
+ //
102
+ curbot.rawStart = closure rawStart(ptySpawned, local dokey, doresize, doattach) {
103
+ dokey = xnew(function(msg, arg) { ptySpawned.write(arg.key) })
104
+ js.t.ioctl_add_listener("raw-key", dokey)
105
+ doresize = xnew(function(msg, dim) { ptySpawned.resize(dim.cols, dim.rows) })
106
+ js.t.ioctl_add_listener("term-resize", doresize)
107
+ js.t.ioctl("raw", true)
108
+ doattach = xnew(function(msg, arg) { js.t.ioctl("raw", true) }) // restore raw mode when we are attached
109
+ js.t.ioctl_add_listener("term-attach", doattach)
110
+
111
+ curbot.rawStop = function rawStop() {
112
+ js.t.ioctl("raw")
113
+ js.t.ioctl_remove_listener("raw-key", dokey)
114
+ js.t.ioctl_remove_listener("term-resize", doresize)
115
+ js.t.ioctl_remove_listener("term-attach", doattach)
116
+ dokey = doresize = doattach = false
117
+ curbot.rawStop = undefined
118
+ }
119
+ }
120
+
95
121
  // impReceive
96
122
  //
97
123
  // Received a payload.
@@ -104,11 +130,14 @@ closure CurBot(options, local curbot) {
104
130
  subscribe(sourceID)
105
131
  else if message.id == "unsubscribe"
106
132
  unsubscribe(sourceID)
107
- else if message.id == "typed"
108
- notifyAll(message, sourceID)
109
133
  else {
110
- message.data._guid = sourceID
111
- curbot.host.DispatchMessage(message)
134
+ subscribe(sourceID) // auto-subscribe
135
+ if message.id == "typed"
136
+ notifyAll(message, sourceID)
137
+ else if message.id == "keyline" && curbot.keyin
138
+ curbot.keyin(message.text) // terminal keyboard -> pty subprocess
139
+ else
140
+ curbot.host.DispatchMessage(message)
112
141
  }
113
142
  }
114
143
 
@@ -117,7 +146,7 @@ closure CurBot(options, local curbot) {
117
146
  // Received an unknown destination notice.
118
147
  //
119
148
  curbot.impUnknown = function impUnknown(unknownID, sourceID, gateway) {
120
- if curbot.topsubs[unknownID] { // did not have courtesy to unsubscribe!
149
+ if curbot.topsubs.indexOf(unknownID) >= 0 { // did not have courtesy to unsubscribe!
121
150
  unsubscribe(unknownID)
122
151
  return
123
152
  }
@@ -125,28 +154,15 @@ closure CurBot(options, local curbot) {
125
154
  debuglog("CurBot.impUnknownID:", unknownID, "sourceID:", sourceID)
126
155
  }
127
156
 
128
- // replyHook
129
- //
130
- // Intercept the ReplyMessage function to see if we should handle it.
131
- //
132
- function replyHook(data) {
133
- // js.g.console.log("CurBot.replyHook:\n", Dialect.print(new(data)))
134
- // debuglog("CurBot.replyHook:\n", Dialect.print(new(data)))
135
- /* ###
136
- if data._guid
137
- workco.uworkers[data._guid].msgport.postMessage({
138
- id: "targetreceive"
139
- data: data
140
- })
141
- */
142
- }
143
- curbot.host.OnReplyHook(replyHook.proc)
144
-
145
157
  // ONtextOut
146
158
  //
147
159
  // Process console text output by Naan.
148
160
  //
149
161
  function ONtextOut(text) {
162
+ if curbot.naanin {
163
+ curbot.naanin(text) // naan output -> pty subprocess
164
+ return
165
+ }
150
166
  notifyAll({
151
167
  id: "textout",
152
168
  text: text,
@@ -187,22 +203,6 @@ closure CurBot(options, local curbot) {
187
203
  })
188
204
  }
189
205
 
190
- // ONmessageOut
191
- //
192
- // Process message output.
193
- //
194
- function ONmessageOut(data, local _guid) {
195
- if data._guid {
196
- _guid = data._guid
197
- data._guid = undefined
198
- curbot.sender(_guid, {
199
- id: "targetout",
200
- data: data
201
- })
202
- return
203
- }
204
- }
205
-
206
206
  // ONioctl
207
207
  //
208
208
  // Process ioctl.
@@ -236,11 +236,17 @@ closure CurBot(options, local curbot) {
236
236
  * type: <string> // target category, e.g. "Local"
237
237
  * startup: <dictionary> // startup options
238
238
  * topOriginID: <string> // so top can route to us through IMP
239
+ * rootPath: <string> // root path of worker's folder, must have lib/node_worker_init.nlg
240
+ * node: {
241
+ * // see NodeJS docs
242
+ * workerData: { // passed to node_worker.js
243
+ * }
244
+ * }
239
245
  * }
240
246
  *
241
247
  */
242
248
 
243
- closure NowBot(options, local nowbot, subChannel) {
249
+ closure NowBot(options, local nowbot, nodeops, subChannel, ptySpawned) {
244
250
  global(App, js, threads, JSpath)
245
251
  nowbot = new(object, this)
246
252
  nowbot.topsubs = []
@@ -248,8 +254,14 @@ closure NowBot(options, local nowbot, subChannel) {
248
254
  type: "node-worker"
249
255
  }, options)
250
256
 
251
- // options = { execArgv: ["--inspect-brk"] } // uncomment for NodeJS debugging
252
- nowbot.thread = xnew(threads.Worker, JSpath.resolve(js.d, "lib/node_worker.js"), options)
257
+ nodeops = merge({
258
+ // execArgv: ["--inspect-brk"] // unfortunately doesn't work; use VS Code instead
259
+ }, options.node)
260
+ if options.rootPath
261
+ nodeops.workerData = merge({
262
+ rootPath: options.rootPath
263
+ }, nodeops.workerData)
264
+ nowbot.thread = xnew(threads.Worker, JSpath.resolve(js.d, "lib/node_worker.js"), nodeops)
253
265
  subChannel = xnew(threads.MessageChannel)
254
266
  nowbot.thread.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1])
255
267
  nowbot.msgport = subChannel.port2
@@ -303,6 +315,43 @@ closure NowBot(options, local nowbot, subChannel) {
303
315
  nowbot.sender(topDestID, message)
304
316
  }
305
317
 
318
+ // textEntry
319
+ //
320
+ // Simulate text entry for subprocess support.
321
+ //
322
+ nowbot.textEntry = function textEntry(text) {
323
+ nowbot.msgport.postMessage({
324
+ id: "keyline"
325
+ text: text
326
+ })
327
+ }
328
+
329
+ // ioctl
330
+ //
331
+ // Send an ioctl to the terminal.
332
+ //
333
+ nowbot.ioctl = function ioctl(op, arg) {
334
+ notifyAll({
335
+ id: "ioctl"
336
+ op: op
337
+ arg: arg
338
+ })
339
+ }
340
+
341
+ // rawMode
342
+ //
343
+ // Configure ioctls for raw terminal operation using the spawned PTY process.
344
+ //
345
+ nowbot.rawStart = function rawStart(ptys) {
346
+ ptySpawned = ptys
347
+ ioctl("raw", true)
348
+ nowbot.rawStop = function rawStop() {
349
+ ioctl("raw", false)
350
+ nowbot.rawStop = undefined
351
+ ptySpawned = false
352
+ }
353
+ }
354
+
306
355
  // impReceive
307
356
  //
308
357
  // Received a payload.
@@ -314,22 +363,35 @@ closure NowBot(options, local nowbot, subChannel) {
314
363
  subscribe(sourceID)
315
364
  else if message.id == "unsubscribe"
316
365
  unsubscribe(sourceID)
317
- else if message.id == "typed"
318
- notifyAll(message, sourceID)
319
366
  else {
367
+ subscribe(sourceID) // auto-subscribe
368
+ if message.id == "typed" {
369
+ notifyAll(message, sourceID)
370
+ return
371
+ }
372
+ if ptySpawned { // raw mode: kludgey, but works
373
+ if message.id == "ioctl-event" {
374
+ if message.msg == "raw-key"
375
+ ptySpawned.write(message.arg.key)
376
+ else if message.msg == "term-resize"
377
+ ptySpawned.resize(message.arg.cols, message.arg.rows)
378
+ }
379
+ if (message.id == "attached")
380
+ ioctl("raw", true) // restore raw mode after terminal attach
381
+ }
320
382
  if message.id == "keyline" && nowbot.keyin
321
383
  nowbot.keyin(message.text) // terminal keyboard -> pty subprocess
322
384
  else
323
385
  nowbot.msgport.postMessage(message)
324
386
  }
325
387
  }
326
-
388
+
327
389
  // impUnknown
328
390
  //
329
391
  // Received an unknown destination notice.
330
392
  //
331
393
  nowbot.impUnknown = function impUnknown(unknownID, sourceID, gateway) {
332
- if nowbot.topsubs[unknownID] { // did not have courtesy to unsubscribe!
394
+ if nowbot.topsubs.indexOf(unknownID) >= 0 { // did not have courtesy to unsubscribe!
333
395
  unsubscribe(unknownID)
334
396
  return
335
397
  }
@@ -348,9 +410,11 @@ closure NowBot(options, local nowbot, subChannel) {
348
410
  id: "terminated"
349
411
  error: error
350
412
  })
413
+ nowbot.dispatchEvent("terminated", nowbot.instanceID, { error: error })
414
+ nowbot.thread = false
351
415
  destroy()
352
416
  })
353
-
417
+
354
418
  // onexit
355
419
  //
356
420
  // Note that the worker thread has terminated.
@@ -360,9 +424,11 @@ closure NowBot(options, local nowbot, subChannel) {
360
424
  id: "terminated"
361
425
  exitCode: exitCode
362
426
  })
427
+ nowbot.dispatchEvent("terminated", nowbot.instanceID, { exitCode: exitCode })
428
+ nowbot.thread = false
363
429
  destroy()
364
430
  })
365
-
431
+
366
432
  // destroy
367
433
  //
368
434
  // Ensure the worker is destroyed.
@@ -370,7 +436,7 @@ closure NowBot(options, local nowbot, subChannel) {
370
436
  nowbot.destroy = function destroy() {
371
437
  terminate()
372
438
  nowbot.thread = false
373
- nowbot.impconn.close()
439
+ nowbot.impconn.destroy()
374
440
  nowbot.impconn = false
375
441
  App.imp.unregister(nowbot.instanceID)
376
442
  }
@@ -387,35 +453,28 @@ closure NowBot(options, local nowbot, subChannel) {
387
453
  startmsg = {
388
454
  id: "start"
389
455
  state: false // resume state, if we have any
390
- altcmd: false
456
+ altcmd: options.startup.initcmds
391
457
  dirpath: js.d
392
458
  workerID: workerID
393
- workerGUID: worker.guid
394
459
  metadata: {
395
460
  mainInstanceID: App.imp.us.instanceID
396
461
  name: options.name
462
+ maintext: options.startup.maintext.concat("\n")
397
463
  }
398
464
  }
399
- if options.startup.initcmds
400
- startmsg.altcmd = options.startup.initcmds.concat("\n")
401
465
  if options.startup.dirpath
402
466
  startmsg.dirpath = options.startup.dirpath
403
467
  nowbot.msgport.postMessage(startmsg)
404
468
  notifyAll({
405
469
  id: "started"
406
470
  })
407
- } else if msg.id == "targetsend" {
408
- msg.data._guid = nowbot.guid
409
- js.t.DispatchMessage({
410
- id: "targetin"
411
- data: msg.data
412
- }) }
413
- else if msg.id == "textout" && nowbot.naanin
471
+ nowbot.dispatchEvent("started", nowbot.instanceID)
472
+ } else if msg.id == "textout" && nowbot.naanin
414
473
  nowbot.naanin(msg.text) // naan output -> pty subprocess
415
474
  else
416
475
  notifyAll(msg)
417
476
  })
418
-
477
+
419
478
  // terminate
420
479
  //
421
480
  // Terminate this worker asap.
@@ -440,6 +499,7 @@ closure NowBot(options, local nowbot, subChannel) {
440
499
  }
441
500
 
442
501
  nowbot.subprocess = MakeSubProcessor(nowbot) // Enable PTY subprocesses on our terminal
502
+ Events(nowbot)
443
503
 
444
504
  // finis
445
505
 
@@ -518,7 +578,9 @@ closure NobBot(options, local nobbot)
518
578
  * return value is a result tuple with an object that can be used to kill or monitor the
519
579
  * subprocess.
520
580
  *
521
- * The subprocess can be connected in a variety of ways:
581
+ * exec.subprocess(executable, args, options)
582
+ *
583
+ * The subprocess can be connected to the terminal raw, or in a variety of ways:
522
584
  *
523
585
  * term-keyboard | term-display | worker-in | worker-out
524
586
  * -------------------------------------|---------------|------------|-----------
@@ -527,29 +589,28 @@ closure NobBot(options, local nobbot)
527
589
  *
528
590
  * Options:
529
591
  * {
530
- * input: false | "keyboard" | "pipe"
531
- * output: false | "display" | "pipe" | "tee"
532
- * spawn: <PtyManager.spawn options>
592
+ * input: false | "keyboard" | "pipe"
593
+ * output: false | "display" | "pipe" | "tee"
594
+ * raw: <boolean>
595
+ * spawn: <PtyManager.spawn options>
533
596
  * }
534
597
  *
535
598
  */
536
599
 
537
600
  closure MakeSubProcessor(execbot) {
601
+ global()
538
602
  closure subprocess(
539
603
  executable, args, options, local error, pty) {
540
604
 
541
605
  // ptyData - text has been returned from the subprocess
542
606
  function ptyData(text) {
543
607
  if options.output == "display" || options.output == "tee"
544
- notifyAll({ // send to display
608
+ execbot.notifyAll({ // send to display
545
609
  id: "textout",
546
610
  text: text
547
611
  })
548
612
  if options.output == "pipe" || options.output == "tee"
549
- msg({ // send to NaaN worker
550
- id: "keyline"
551
- text: text
552
- })
613
+ execbot.textEntry(text) // send to NaaN worker
553
614
  }
554
615
 
555
616
  // ptyKilled - the subprocess has terminated
@@ -558,6 +619,10 @@ closure MakeSubProcessor(execbot) {
558
619
  execbot.keyin = false
559
620
  if execbot.naanin === naanin
560
621
  execbot.naanin = false
622
+ if options.raw {
623
+ execbot.rawStop()
624
+ execbot.textEntry("\x15mu();;\n") // send to NaaN worker
625
+ }
561
626
  }
562
627
 
563
628
  // keyin - the terminal has generated text for the subprocess
@@ -570,6 +635,7 @@ closure MakeSubProcessor(execbot) {
570
635
  pty.write(text)
571
636
  }
572
637
 
638
+ require("./pty.nlg") // load on demand
573
639
  `(error, pty) = PtyManager().spawn(executable, args, {
574
640
  ptyData: ptyData
575
641
  ptyKilled: ptyKilled
@@ -577,9 +643,17 @@ closure MakeSubProcessor(execbot) {
577
643
  if error
578
644
  return (list(error))
579
645
  if options.input == "keyboard"
580
- nowbot.keyin = keyin // replace existing
646
+ execbot.keyin = keyin // replace existing
581
647
  else if options.input == "pipe"
582
648
  execbot.naanin = naanin // replace existing
649
+ if options.raw
650
+ execbot.rawStart(pty)
651
+
652
+ // our worker has terminated
653
+ execbot.addEventListener("terminated", function() {
654
+ pty.kill()
655
+ })
656
+
583
657
  list(false, pty)
584
658
  }
585
659
  };
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * column positioning: // // !
8
8
  *
9
- * Copyright (c) 2019-2024 by Richard C. Zulch
9
+ * Copyright (c) 2019-2026 by Richard C. Zulch
10
10
  *
11
11
  */
12
12
 
@@ -426,7 +426,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
426
426
  // autoquoted to itself, a symbol. This can be used to detect build time vs. runtime.
427
427
 
428
428
  function parseAndPack1(text, fpath, options, operation,
429
- local util, lib, penv, naansym, dlogsym, pmod, pcomp, output, textout, annerror, annotations, package)
429
+ local util, lib, penv, naansym, dlogsym, pmod, pcomp, ournn, output, textout, annerror, annotations, package)
430
430
  {
431
431
  //
432
432
  // textline
@@ -445,20 +445,39 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
445
445
  lib = Naan.module.modlist().Lib.exports
446
446
  if !util || !lib
447
447
  return (list("Build packager cannot access support functions"))
448
+ //
449
+ // The following crazy rigmarole is about customizing the ParsEnvironment so we can glean
450
+ // enough information to build a package without actually executing the code. To do this we
451
+ // replace the entire Naan.module collection of functions with just build, so the others do
452
+ // nothing. From that we collect the module and component names, plus the manifest. This
453
+ // also sets up a benign "exports" dictionary so module build can "go through the mtions"
454
+ // without modification.
455
+ //
448
456
  penv = lib.ParsEnvironment(Dialect, "build-".concat(operation))
449
457
  penv.evalq(letlocal(App)) // make local copy of App
450
458
  penv.evalq(letlocal(js)) // make local copy of js
451
- naansym = penv.evalq(letlocal(Naan).0) // make local copy of Naan
452
- penv.evalq(assign(naansym,new(Naan))) // make it modifiable
459
+ ournn = new(Naan) // get modifiable Naan
453
460
  pmod = { } // our module object
454
461
  pcomp = { } // our component object
455
- car(naansym).module = {
462
+ ournn.module = {
456
463
  build: function(modname, compname, proc) {
457
- pmod.id = module
464
+ pmod.id = module.id
465
+ pmod.exports = { }
458
466
  pcomp.name = compname
459
467
  call(proc, pmod, pcomp) // obtain manifest
460
468
  }
461
469
  }
470
+ naansym = penv.evalq(function(nn) {
471
+ assign(letlocal(Naan).0,nn)
472
+ `Naan
473
+ }(ournn)) // make Naan modifiable
474
+ penv.evalq(assign(letlocal(module).0, { // make local copy of module
475
+ exports: { }
476
+ }))
477
+ //
478
+ // Here we make a custom debuglog function that identifies the text without color and will
479
+ // write the output to the build log.
480
+ //
462
481
  dlogsym = penv.evalq(letlocal(debuglog).0) // make local copy of debuglog
463
482
  penv.evalq(function \.debuglog args { // redefine debuglog for capture
464
483
  let (arg, spaced) {
@@ -471,8 +490,19 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
471
490
  apply(textline, reverse(spaced))
472
491
  } () })
473
492
  penv.evalq(putproc(car(dlogsym), \.debuglog.proc))
493
+ //
494
+ // The NideBuild symbol is "debug" or "release", etc. or is simply autoquoted as the symbol
495
+ // itself when not building. This is used if the source needs different behavior at build
496
+ // time or run time.
497
+ //
474
498
  penv.eval(append(quote(assign(compress("NideBuild"))), operation)) // NideBuild symbol is operation name string
499
+ //
500
+ // This is the actual meat of the matter, the parsing of the program text.
501
+ //
475
502
  output = penv.parse(text) // parse and evaluate
503
+ //
504
+ // Output processing and error logging
505
+ //
476
506
  textout = ""
477
507
  try {
478
508
  if !pcomp.name
@@ -507,20 +537,30 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
507
537
  }
508
538
  if output.errors.length > 0
509
539
  return (list("errors in ".concat(fpath), false, annotations, textout))
540
+ //
541
+ // Build the package, if not just doing syntax checking
542
+ //
510
543
  if options.naanpack || options.jspack { // actually building a package?
511
544
  if !pcomp.name {
512
- pcomp = penv.evalq(car(compress(NaanBuildComponent))) // fallback for building Module.nlg itself
545
+ //
546
+ // Some components cannot use a build function because they are too early in the
547
+ // boot process, but we still need a component. We look for NaanBuildComponent
548
+ // to define a dictionary with filename, name and manifest fields. For example,
549
+ // see Util:Module.nlg
550
+ //
551
+ pcomp = penv.evalq(car(compress(NaanBuildComponent)))
513
552
  if !pcomp || !fpath.endsWith("/".concat(pcomp.filename))
514
553
  return (list("Build cannot package without component in ".concat(fpath), false, annotations, textout))
515
554
  }
516
- package = penv.evalq(util.pkgSave(compress(pcomp.name), pcomp.manifest))
555
+ package = util.pkgSave(compress(pcomp.name), pcomp.manifest)
556
+ if string(package)
557
+ return (list("Build cannot generate package for ".concat(fpath), false, annotations, textout))
517
558
  }
518
559
  } catch {
519
560
  if true
520
561
  return (list("Packaging exception in ".concat(fpath, ": ", tostring(exception)), false, annotations, textout))
521
562
  } finally {
522
563
  penv.destroy() // remove the namespace
523
- debuglog("parseAndPack1 done", fpath)
524
564
  }
525
565
  if options.naanpack
526
566
  package = (js.w||js.s||js.g).JSON.stringify(package) // doesn't have frameworks/common available
@@ -546,7 +586,7 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
546
586
  build.parallel = ExecutorParallel(track, { // create worker pool
547
587
  basename: "build"
548
588
  initeval: `(false, (parseAndPack1))
549
- })
589
+ })
550
590
  result = build.parallel.rpc(parseAndPack1, list(text, fpath, options, operation))
551
591
  if !result.0 {
552
592
  result = result.1 // unpeel RPC result
@@ -1211,17 +1251,19 @@ closure Builder(rules, operation, fs, srcpath, destpath, track, local build, gro
1211
1251
  //
1212
1252
  // Run the current build product by spawning a new worker.
1213
1253
  //
1214
- build.runSpawn = function runSpawn(local error, maintext, executor, vpath, site) {
1254
+ build.runSpawn = function runSpawn(local error, maintext, executor, vpath, site, dirpath) {
1215
1255
  `(error, maintext) = fs.readFile(JSpath.join(build.destpath, build.runway.main))
1216
1256
  if error
1217
1257
  error = Error("Builder: cannot read main file", error)
1218
1258
  else {
1259
+ dirpath = fs.path.resolve("/", fs.rootpath, build.destpath, build.runway.path || "")
1219
1260
  `(error, executor) = track.spawn(build.runway.spawn.0, "${rules.name} ${build.version}", {
1220
1261
  workerID: "Run-${build.version}+${build.buildnum}"
1221
1262
  startup: {
1222
- initcmds: maintext
1223
- dirpath: fs.path.resolve("/", fs.rootpath, build.destpath)
1263
+ maintext: maintext
1264
+ dirpath: dirpath
1224
1265
  }
1266
+ rootPath: dirpath
1225
1267
  })
1226
1268
  if error
1227
1269
  error = Error("Builder: cannot spawn executor instance", error)
@@ -296,7 +296,7 @@ closure projConnector(projman, projtype, local connector, watch) {
296
296
  *
297
297
  * Nide.proj/
298
298
  * nide_cliser.cfg - JSON definition of the project (see below)
299
- * NaanIDE_version.txt - [default] substitution file defining 1.6.0+1 etc.
299
+ * NaanIDE_version.txt - [default] substitution file defining 1.7.0+1 etc.
300
300
  * NaanIDE_version_builds.txt - [default] contains current build number as decimal string
301
301
  * build/ - [optional] default build output location
302
302
  * NaanIDE.lic - [optional] defines Zulch Laboratories, Inc. and other license info
@@ -19,9 +19,6 @@
19
19
 
20
20
  closure DebugCommand(executor, notify, local decom, excon) {
21
21
  decom = new(object, this)
22
- executor.DebugCmd({
23
- op: "attach"
24
- })
25
22
  decom.executor = executor
26
23
 
27
24
  // debugData
@@ -96,6 +93,24 @@ closure DebugCommand(executor, notify, local decom, excon) {
96
93
  status
97
94
  }
98
95
 
96
+ // query
97
+ // Send a status update back.
98
+ //
99
+ decom.query = function query() {
100
+ decom.executor.DebugCmd({
101
+ op: "query"
102
+ })
103
+ }
104
+
105
+ // attach
106
+ // Attach our GUI to the low-level debugger
107
+ //
108
+ decom.attach = function attach() {
109
+ executor.DebugCmd({
110
+ op: "attach"
111
+ })
112
+ }
113
+
99
114
  //
100
115
  // Run control.
101
116
  //
@@ -138,6 +153,8 @@ closure DebugCommand(executor, notify, local decom, excon) {
138
153
  notify.runState(debugStatus())
139
154
  }
140
155
 
156
+ attach()
157
+
141
158
  // finis
142
159
 
143
160
  decom
@@ -35,6 +35,7 @@ closure DebugNub(local nub, debug, paused) {
35
35
  nub.watches = []
36
36
  nub.stacks = { }
37
37
  nub.usage = { }
38
+ paused = { }
38
39
 
39
40
  // debugDepth
40
41
  // Return the recursive debugging depth as an integer.
@@ -45,6 +46,18 @@ closure DebugNub(local nub, debug, paused) {
45
46
  curdepth = 0
46
47
  curdepth
47
48
  }
49
+
50
+ // sendStatus
51
+ // Send current status to the far end.
52
+ //
53
+ function sendStatus() {
54
+ js.t.ReplyDebugger({
55
+ op: "status"
56
+ depth: debugDepth()
57
+ bpenable: debug.bpenable
58
+ exenable: nub.exenable
59
+ })
60
+ }
48
61
 
49
62
  // onDebugger proc
50
63
  // Process an incoming debugger command.
@@ -52,17 +65,13 @@ closure DebugNub(local nub, debug, paused) {
52
65
  function onDebugger(msg) {
53
66
  if msg.op == "attach" {
54
67
  debug.setCommander(nub)
55
- js.t.ReplyDebugger({
56
- op: "status"
57
- depth: debugDepth()
58
- bpenable: debug.bpenable
59
- exenable: nub.exenable
60
- })
68
+ sendStatus()
61
69
  }
62
70
  else if msg.op == "detach" {
63
71
  debug.setCommander(false)
64
72
  paused.wait = false // false: go back to ndb
65
- }
73
+ } else if msg.op == "query"
74
+ sendStatus()
66
75
  else if msg.op == "pause"
67
76
  debugger()
68
77
  else if msg.op == "resume" || msg.op == "stop"