@naanlang/naan 1.0.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 (98) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +46 -0
  3. package/dist/env_web.js +431 -0
  4. package/dist/naan.min.js +73 -0
  5. package/frameworks/browser/browser.nlg +30 -0
  6. package/frameworks/browser/pouchdb/pouchdb.min.js +7 -0
  7. package/frameworks/browser/spark-md5/spark-md5.min.js +1 -0
  8. package/frameworks/browser/sworker.js +192 -0
  9. package/frameworks/browser/terminals.nlg +787 -0
  10. package/frameworks/browser/workers.nlg +386 -0
  11. package/frameworks/client/apiclient.nlg +183 -0
  12. package/frameworks/client/client.nlg +29 -0
  13. package/frameworks/client/psm_client.nlg +572 -0
  14. package/frameworks/common/common.nlg +464 -0
  15. package/frameworks/common/preferences.nlg +131 -0
  16. package/frameworks/common/repltools.nlg +100 -0
  17. package/frameworks/common/watching.nlg +97 -0
  18. package/frameworks/node/apiserver.nlg +399 -0
  19. package/frameworks/node/filesystem.nlg +1012 -0
  20. package/frameworks/node/gitter.nlg +234 -0
  21. package/frameworks/node/node.nlg +81 -0
  22. package/frameworks/node/psm_server.nlg +465 -0
  23. package/frameworks/node/worker.nlg +560 -0
  24. package/frameworks/project/build.nlg +1229 -0
  25. package/frameworks/project/jszip.js +30 -0
  26. package/frameworks/project/jszip.nlg +87 -0
  27. package/frameworks/project/proj_cliser.nlg +139 -0
  28. package/frameworks/project/proj_console.nlg +137 -0
  29. package/frameworks/project/proj_folder.nlg +143 -0
  30. package/frameworks/project/proj_lambda.nlg +137 -0
  31. package/frameworks/project/proj_static.nlg +138 -0
  32. package/frameworks/project/project.nlg +29 -0
  33. package/frameworks/project/projects.nlg +587 -0
  34. package/frameworks/project/uglifyjs.js +1 -0
  35. package/frameworks/project/uglifyjs.nlg +79 -0
  36. package/frameworks/running/debugcom.nlg +163 -0
  37. package/frameworks/running/debugnub.nlg +565 -0
  38. package/frameworks/running/debugutil.nlg +510 -0
  39. package/frameworks/running/executors.nlg +767 -0
  40. package/frameworks/running/running.nlg +151 -0
  41. package/frameworks/running/sourcecode.nlg +346 -0
  42. package/frameworks/running/taskexec.nlg +196 -0
  43. package/frameworks/storage/dbt_pouch.nlg +773 -0
  44. package/frameworks/storage/file_manager.nlg +772 -0
  45. package/frameworks/storage/psm.nlg +326 -0
  46. package/frameworks/storage/psm_dbtables.nlg +814 -0
  47. package/frameworks/storage/resources.nlg +445 -0
  48. package/frameworks/storage/storage.nlg +52 -0
  49. package/lib/browser/env_web.js +431 -0
  50. package/lib/browser/env_webworker.js +146 -0
  51. package/lib/browser/require.js +1653 -0
  52. package/lib/core/naanlib.js +73 -0
  53. package/lib/env_node.js +282 -0
  54. package/lib/env_nodeworker.js +165 -0
  55. package/lib/node_repl.js +25 -0
  56. package/lib/node_repl_init.nlg +52 -0
  57. package/package.json +13 -0
  58. package/plugins/gitClient/clientops.nlg +317 -0
  59. package/plugins/gitClient/gitClient.nlg +63 -0
  60. package/plugins/gitClient/gitutils.nlg +1331 -0
  61. package/plugins/gitClient/minimatch.js +945 -0
  62. package/plugins/gitClient/minimatch_license.txt +15 -0
  63. package/plugins/gitClient/minimatch_readme.md +208 -0
  64. package/plugins/nodeLib/nodeLib.nlg +26 -0
  65. package/plugins/nodeLib/node_cp.nlg +65 -0
  66. package/plugins/nodeLib/node_fs.nlg +137 -0
  67. package/plugins/nodeLib/node_https.nlg +172 -0
  68. package/plugins/nodeLib/node_util.nlg +180 -0
  69. package/plugins/serviceAws/aws/aws-sdk.min.js +88 -0
  70. package/plugins/serviceAws/aws/lambda_rest_index.js +122 -0
  71. package/plugins/serviceAws/aws/lambda_rest_init.nlg +58 -0
  72. package/plugins/serviceAws/aws/lambda_ws_index.js +498 -0
  73. package/plugins/serviceAws/aws/lambda_ws_init.nlg +49 -0
  74. package/plugins/serviceAws/aws_cloudwatchlogs.nlg +122 -0
  75. package/plugins/serviceAws/aws_cognito.nlg +76 -0
  76. package/plugins/serviceAws/aws_dynamo.nlg +509 -0
  77. package/plugins/serviceAws/aws_lambda.nlg +95 -0
  78. package/plugins/serviceAws/aws_s3.nlg +134 -0
  79. package/plugins/serviceAws/aws_utils.nlg +86 -0
  80. package/plugins/serviceAws/dbt_aws.nlg +769 -0
  81. package/plugins/serviceAws/lambda_naan_control.nlg +175 -0
  82. package/plugins/serviceAws/psm_aws.nlg +258 -0
  83. package/plugins/serviceAws/serviceAws.nlg +38 -0
  84. package/plugins/serviceGitHub/gitops.nlg +522 -0
  85. package/plugins/serviceGitHub/psm_github.nlg +205 -0
  86. package/plugins/serviceGitHub/serviceGitHub.nlg +65 -0
  87. package/plugins/serviceGitLab/gitops.nlg +528 -0
  88. package/plugins/serviceGitLab/psm_gitlab.nlg +205 -0
  89. package/plugins/serviceGitLab/serviceGitLab.nlg +65 -0
  90. package/test/harness.nlg +312 -0
  91. package/test/node_test.js +33 -0
  92. package/test/test_01_core.nlg +768 -0
  93. package/test/test_02_context.nlg +269 -0
  94. package/test/test_03_jsinterop.nlg +137 -0
  95. package/test/test_04_numerics.nlg +450 -0
  96. package/test/test_05_strings.nlg +63 -0
  97. package/test/test_06_lingoparse.nlg +500 -0
  98. package/test/test_07_lingo.nlg +623 -0
@@ -0,0 +1,587 @@
1
+ /*
2
+ * projects.nlg
3
+ * Naanlib/frameworks/project/
4
+ *
5
+ * Project management.
6
+ *
7
+ * column positioning: // // !
8
+ *
9
+ * Copyright (c) 2016-2021 by Richard C. Zulch
10
+ *
11
+ */
12
+
13
+
14
+ /*
15
+ * ProjectManager
16
+ *
17
+ * Create a new Project manager for the specified resource locate tracker and database. This
18
+ * returns a standard error tuple with the project manager object on success.
19
+ *
20
+ */
21
+
22
+ closure ProjectManager(locate, track, dbname, local error, proj) {
23
+ `(error, proj) = storageResources.ResourceManager(dbname, "Projects/")
24
+ if error
25
+ return(list(error))
26
+ proj.locate = locate // storage locations
27
+ proj.track = track // execution tracking
28
+ proj.types = []
29
+ proj.types.push(proj_cliserType(proj)) // register client server projects
30
+ proj.types.push(proj_consoleType(proj)) // register console projects
31
+ proj.types.push(proj_folderType(proj)) // register folder projects
32
+ proj.types.push(proj_lambdaType(proj)) // register lambda projects
33
+ proj.types.push(proj_staticType(proj)) // register static projects
34
+
35
+ // tracker
36
+ //
37
+ // Create a resource tracker that is customized for projects.
38
+
39
+ proj.tracker = function tracker() {
40
+ projTracker(proj)
41
+ }
42
+
43
+ // finis
44
+ list(false, proj)
45
+ };
46
+
47
+
48
+ /*
49
+ * projTracker
50
+ *
51
+ * Make a resource tracker with project additions. The tracker provides the service of tracking
52
+ * known projects and making them available for instantiation. Interested watchers can sign up for
53
+ * notification of changes to the project list.
54
+ *
55
+ */
56
+
57
+ closure projTracker(reman, local petor) {
58
+ petor = storageResources.ResourceTracker(reman)
59
+
60
+ // findTypeForLocation
61
+ //
62
+ // Given a location, return the best projectType for handling it. The name and typeID of the
63
+ // found project are updated into the where object.
64
+ //
65
+ // Type objects returns a score for how well they can handle the specified project:
66
+ //
67
+ // Score Description
68
+ // false Can't handle that project type
69
+ // 100 Would provide generic project access
70
+ // 80 Could translate the specified project to our project type
71
+ // 50 Could downgrade the project for support
72
+ // 40 Could upgrade the project for support
73
+ // 20 Knows this type and version
74
+ // 10 Knows this type and version and can build and deploy
75
+ // 0 We are already working with this project somehow
76
+ //
77
+ //
78
+
79
+ petor.findTypeForLocation = function findTypeForLocation(where, local type, where1, score, bestScore, bestType, bestWhere) {
80
+ for type in reman.types {
81
+ where1 = { // make a copy with no name or type (to be wildcards)
82
+ locationID: where.locationID
83
+ path: where.path
84
+ }
85
+ score = type.testActiveLocation(where1)
86
+ if numeric(score) && (!bestScore || score < bestScore) {
87
+ bestScore = score
88
+ bestType = type
89
+ bestWhere = where1
90
+ }
91
+ }
92
+ if bestWhere.typeID
93
+ where.typeID = bestWhere.typeID
94
+ if bestWhere.name
95
+ where.name = bestWhere.name
96
+ bestType.classID
97
+ }
98
+
99
+ // findByLocation
100
+ //
101
+ // Given a location, return a projID for it or false if it does not exist.
102
+
103
+ petor.findByLocation = function findByLocation(where, local type) {
104
+ for type in reman.types
105
+ if type.connect.findResource(where)
106
+ return
107
+ false
108
+ }
109
+
110
+ // ensureExistsByLocation
111
+ //
112
+ // Given the location of an existing project, return a projID for it or false if not possible.
113
+ // We try in order:
114
+ // 1. Look for a known project with that location, or
115
+ // 2. Look for the best type to handle it and create a projID.
116
+
117
+ petor.ensureExistsByLocation = function ensureExistsByLocation(where, local classID) {
118
+ if findByLocation(where)
119
+ return
120
+ where = new(where)
121
+ classID = findTypeForLocation(where) // where modified by this call
122
+ if !classID
123
+ list(Error("unsupported project location", where))
124
+ else
125
+ petor.ensureExists(classID, where)
126
+ }
127
+
128
+ // finis
129
+ petor
130
+ };
131
+
132
+
133
+ /*
134
+ * projConnector
135
+ *
136
+ * Make a generic project connector for a project type. Project connectors are responsible for
137
+ * creating, deleting, providing info for, and instantiating projects of a particular type. The
138
+ * specified projectType object must provide the following methods/data:
139
+ * .classLabel - user visible typename of the project type
140
+ * .classID - stable typeID of the project type
141
+ * .instantiate(where, args) - where is name/location/path
142
+ *
143
+ * Unless otherwise noted all methods return (error, data) tuples.
144
+ *
145
+ */
146
+
147
+ closure projConnector(projman, projtype, local connector, watch) {
148
+ connector = new(object, this)
149
+ connector.projman = projman
150
+ connector.label = projtype.classLabel
151
+ connector.vault = projman.vault(projtype.classID)
152
+ watch = projman.watchable(connector)
153
+
154
+ // hashResourceID
155
+ //
156
+ // Make a stable hash based on the resource credentials that we can persist or share between
157
+ // different domains accessing the same resource.
158
+ connector.hashResourceID = function hashResourceID(resource, local ident) {
159
+ ident = resource.name.concat(resource.locationID, resource.path)
160
+ HashSHA256(ident)
161
+ }
162
+
163
+ // findResource
164
+ //
165
+ // Find a resource with the specified contents, returning the resID or false. The loose criteria
166
+ // is: if added, would the specified contents be redundant to an existing resource?
167
+ connector.findResource = function findResource(resource, local resID, resInfo) {
168
+ for resID in listResources().1 {
169
+ resInfo = access(resID).1
170
+ if resource.name == resInfo.name
171
+ && resource.locationID == resInfo.locationID
172
+ && resource.path == resInfo.path
173
+ return (resID)
174
+ }
175
+ false
176
+ }
177
+
178
+ // addResource
179
+ //
180
+ // Add credentials for a named resource. The resource is a dictionary comprising these keys:
181
+ // name: <string> - the user visible name of the project
182
+ // locationID: <string> - resID of location resource where this project resides
183
+ // path: <string> - path to project within location
184
+ // Error, if non-false, is a dictionary of field keys and error diagnostic strings.
185
+ connector.addResource = function addResource(resource, local errors, error, resID, data) {
186
+ function badField(str) { !string(str) || str.trim().length == 0 }
187
+ errors = { }
188
+ if badField(resource.name)
189
+ errors.name = "invalid name"
190
+ if !resource.locationID
191
+ errors.locationID = "required field"
192
+ if !string(resource.path)
193
+ errors.path = "required field"
194
+ if length(errors) == 0 {
195
+ if findResource(resource)
196
+ errors.name = "project already exists" }
197
+ if length(errors) > 0
198
+ error = errors
199
+ else {
200
+ resID = hashResourceID(resource)
201
+ `(error, data) = connector.vault.addResource(resID, resource)
202
+ if data {
203
+ watch.notify(projtype.classID, { added: [resID] })
204
+ data = resID }
205
+ }
206
+ list(error, data)
207
+ }
208
+
209
+ // deleteResource
210
+ //
211
+ // Delete information for a project. The return value is (error, result) tuple.
212
+ connector.deleteResource = function deleteResource(resID, local error, creds, db) {
213
+ connector.vault.deleteResource(resID)
214
+ watch.notify(projtype.classID, { deleted: [resID] })
215
+ list(false, { ok: true})
216
+ }
217
+
218
+ // listResources
219
+ //
220
+ // List saved resources in our database
221
+ connector.listResources = function listResources() {
222
+ connector.vault.listResources()
223
+ }
224
+
225
+ // info
226
+ //
227
+ // Return info for a project given its resID.
228
+ connector.info = function info(resID, local info, error, where) {
229
+ info = {
230
+ classID: projtype.classID
231
+ type: projtype.classLabel
232
+ services: ["NideProject"]
233
+ }
234
+ `(error, where) = connector.vault.accessResource(resID)
235
+ if where {
236
+ info.name = where.name
237
+ info.locationID = where.locationID
238
+ info.path = where.path }
239
+ list(false, info)
240
+ }
241
+
242
+ // access
243
+ //
244
+ // Return an access object, which is the "where" data to open a project.
245
+ connector.access = function access(resID) {
246
+ connector.vault.accessResource(resID)
247
+ }
248
+
249
+ // connect
250
+ //
251
+ // Returning a project instance.
252
+ connector.connect = function connect(resID, service, args, local error, where) {
253
+ `(error, where) = connector.access(resID)
254
+ if error
255
+ list(error)
256
+ else if service == "NideProject"
257
+ list(false, projtype.instantiate(where, resID, args)) // create project instance
258
+ else
259
+ list(Error("unsupported service", service))
260
+ }
261
+
262
+ // finis
263
+
264
+ projman.register(projtype.classID, connector)
265
+ connector
266
+ };
267
+
268
+
269
+ /*
270
+ * projConfig
271
+ *
272
+ * Manage a project configuration folder, including the creation, loading updating, and removal
273
+ * thereof. Having a project configuration folder is standard for projects based on filesystems, but
274
+ * is not required. The precise structure of a project folder depends on the specific project type,
275
+ * but this controller manages the standard parts, which include the following contents:
276
+ *
277
+ * Nide.proj/
278
+ * nide_cliser.cfg - JSON definition of the project (see below)
279
+ * NaanIDE_version.txt - [default] substitution file defining 1.0.0-1 etc.
280
+ * NaanIDE_version_builds.txt - [default] contains current build number as decimal string
281
+ * build/ - [optional] default build output location
282
+ * NaanIDE.lic - [optional] defines Zulch Laboratories, Inc. and other license info
283
+ *
284
+ * The nide_cliser.cfg content is JSON for a dictionary that includes:
285
+ * {
286
+ * ident: "Nide Project Configuration"
287
+ * name: <project name>
288
+ * nide-type: <project typeID>
289
+ * build: <build instructions dictionary>
290
+ * }
291
+ *
292
+ * Given a new projConfig instance, you can either load (which fails of the project is not valid)
293
+ * or create (which fails if the project already exists.) The load operation will update the where
294
+ * argument with the actual name and type found. Unless other noted the methods all return standard
295
+ * (error, data) result tuples.
296
+ *
297
+ */
298
+
299
+ proj_configDataFolder = "Nide.proj/";
300
+ proj_cliserConfigFile = "nide_cliser.cfg";
301
+
302
+ closure projConfig(projman, where, local procon, fs, configpath) {
303
+ procon = new(object, this)
304
+ procon.name = where.name
305
+
306
+ // validate
307
+ //
308
+ // Ensure the location arguments are valid and load the filesystem. If this returns non-false
309
+ // then the caller should just return that value as a result-error tuple.
310
+ //
311
+ closure validate(name, local error) {
312
+ if !name
313
+ name = where.name // default is to use original location
314
+ if name && (!string(name) || name.length < 1)
315
+ return (list(Error("invalid project name", name)))
316
+ `(error, fs) = projman.locate.connect(where.locationID, "NideFS", where.path)
317
+ if error
318
+ return (list(Error("can't access project filesystem", error)))
319
+ configpath = fs.path.join(proj_configDataFolder, proj_cliserConfigFile)
320
+ procon.fs = fs
321
+ false
322
+ }
323
+
324
+ // readConfig
325
+ //
326
+ // Read our configuration file into procon.configDict, returning a result tuple. If previously
327
+ // read then this checks for changes since the last read of the config file and returns a result
328
+ // of false if it is unchanged.
329
+ //
330
+ closure readConfig(local error, info, data) {
331
+ `(error, info) = fs.info(configpath)
332
+ if !error {
333
+ if procon.configMs && procon.configMs == info.mtimeMs
334
+ return (`(false, false)) // unchanged
335
+ `(error, data) = fs.readFile(configpath) }
336
+ if error
337
+ return (list(Error("can't read project configuration", where.path, error)))
338
+ if procon.configMD5 && procon.configMD5 == HashMD5(data)
339
+ return (`(false, false)) // unchanged
340
+ procon.configMs = info.mtimeMs
341
+ procon.configMD5 = HashMD5(data)
342
+ try {
343
+ data = JSONparse(data)
344
+ if xobject(data)
345
+ procon.configDict = new(data, 500)
346
+ else
347
+ return (list(Error("invalid project configuration", where.path)))
348
+ if !where.name
349
+ where.name = procon.configDict.name
350
+ else if procon.configDict.name != where.name
351
+ return (list(Error("project name mismatch", where.path, procon.configDict.name, where.name)))
352
+ if !where.typeID
353
+ where.typeID = procon.configDict["nide-type"]
354
+ else if procon.configDict["nide-type"] != where.typeID
355
+ return (list(Error("project type mismatch", where.path, procon.configDict["nide-type"], where.typeID)))
356
+ }
357
+ catch {
358
+ if true
359
+ return (list(Error("can't parse project configuration", where.path, exception))) }
360
+ procon.where_name = where.name // copy name to config
361
+ procon.where_typeID = where.typeID // copy typeID to config
362
+ list(false, procon.configDict)
363
+ }
364
+
365
+ // writeConfig
366
+ //
367
+ // Write procon.configDict to our configuration file, returning a result tuple.
368
+ //
369
+ closure writeConfig(local error, info, data) {
370
+ `(error, data) = fs.writeFile(configpath, JSONstringify(procon.configDict))
371
+ if !error {
372
+ procon.configMD5 = data
373
+ `(error, info) = fs.info(configpath)
374
+ if !error
375
+ procon.configMs = info.mtimeMs }
376
+ if error
377
+ list(Error("can't write project configuration", where.path, error))
378
+ else
379
+ list(false, { ok: true })
380
+ }
381
+
382
+ // create
383
+ //
384
+ // Create the project with the specified name, and leave it loaded if no error. The project must
385
+ // not already be loaded. The provided name overrides any name in the where argument above, but
386
+ // path and locationID must be specified. Returns a standard result tuple.
387
+ //
388
+ procon.create = closure create(name, local error, data, configpath) {
389
+ if procon.loaded
390
+ return (list(Error("Project.create: project already loaded")))
391
+ if validate(name)
392
+ return // validation failed
393
+ `(error, data) = fs.mkdir(proj_configDataFolder)
394
+ if error
395
+ return (list(Error("Project.create initialization failed", error)))
396
+ `(error, data) = readConfig()
397
+ if !error
398
+ return (list(Error("Project.create failed: a project already exists at that location")))
399
+ procon.configDict = {
400
+ ident: "Nide Project Configuration",
401
+ "nide-type": where.typeID,
402
+ build: {
403
+ verfile: "Nide.proj/NaanIDE_version.txt"
404
+ buildno: "Nide.proj/NaanIDE_version_builds.txt"
405
+ run: {
406
+ open: "",
407
+ args: []
408
+ },
409
+ groups: [] } }
410
+ procon.configDict.name = name
411
+ `(error, data) = writeConfig()
412
+ if !error {
413
+ `(error, data) = fs.writeFile(fs.path.join(proj_configDataFolder, "NaanIDE_version.txt"),
414
+ "#\n"
415
+ "# NaanIDE_version.txt\n"
416
+ "#\n\n"
417
+ "$".concat("Version$\n"
418
+ "0.1.$BuildNumber$\n")) }
419
+ if !error
420
+ `(error, data) = fs.writeFile(fs.path.join(proj_configDataFolder, "NaanIDE_version_builds.txt"), "0")
421
+ if error
422
+ return (list(Error("Project.create failed", error)))
423
+ procon.loaded = true
424
+ list(false, procon.configDict)
425
+ }
426
+
427
+ // load
428
+ //
429
+ // Load the project, i.e. read the project configuration if valid. This is non-destructive.
430
+ // The result is a standard error tuple with a dictionary result on success.
431
+ //
432
+ procon.load = closure load(local error, data, info, configpath) {
433
+ if procon.loaded
434
+ return (list(false, procon.configDict))
435
+ if validate()
436
+ return // validation failed
437
+ `(error, info) = fs.info(proj_configDataFolder)
438
+ if !error {
439
+ if info.type != "directory"
440
+ error = Error("project configuration not a directory", where.path)
441
+ else
442
+ `(error, data) = readConfig() }
443
+ if error
444
+ return (list(Error("Project.load failed", error)))
445
+ procon.loaded = true
446
+ list(false, procon.configDict)
447
+ }
448
+
449
+ // changed
450
+ //
451
+ // Test if the configuration has changed on disk since it was read. If it has changed then
452
+ // re-read it (discarding any changes in memory) and return a copy of the new configuration. If
453
+ // unchanged then return a result of false. This returns a standard result tuple.
454
+ //
455
+ procon.changed = closure changed(local error, config) {
456
+ if !procon.loaded
457
+ return (list(Error("project not loaded")))
458
+ `(error, config) = readConfig()
459
+ if !error
460
+ config = new(config)
461
+ list(error, config)
462
+ }
463
+
464
+ // update
465
+ //
466
+ // Update the configuration to be the one specified. If the files has changed on disk then
467
+ // this returns a result of { conflict: true } and you must call procon.changed() to clear it.
468
+ // This ignores errors reading the existing configuration so that we can rewrite it if possible.
469
+ //
470
+ procon.update = closure update(newconfig, local error, info, data) {
471
+ if !procon.loaded
472
+ return (list(Error("project not loaded")))
473
+ `(error, info) = fs.info(configpath)
474
+ if !error && procon.configMs && procon.configMs != info.mtimeMs { // ignore read errors
475
+ `(error, data) = fs.readFile(configpath)
476
+ if !error && procon.configMD5 && procon.configMD5 != HashMD5(data)
477
+ return (list(false, { conflict: true })) }
478
+ if newconfig
479
+ procon.configDict = newconfig
480
+ `(error, data) = writeConfig()
481
+ }
482
+
483
+ // buildrules
484
+ //
485
+ // Get the current build rules.
486
+ //
487
+ function buildrules(local rules) {
488
+ rules = procon.configDict."build-rules".default // "default" will be switchable later
489
+ if !rules
490
+ rules = procon.configDict.build // fallback to old config structure
491
+ rules
492
+ }
493
+
494
+ // run
495
+ //
496
+ // Run the project by building and then launching.
497
+ //
498
+ procon.run = closure run(buildonly, local rules, builder, buildpath, error, buildnum) {
499
+ if !procon.loaded
500
+ return (list(Error("project not loaded")))
501
+ rules = buildrules()
502
+ if !rules || !rules.products
503
+ return (list(Error("build rules missing or incomplete")))
504
+ buildpath = fs.path.join(proj_configDataFolder, rules.products)
505
+ rules.name = procon.where_name
506
+ rules.typeID = procon.where_typeID
507
+ `(error, builder) = Builder(rules, "debug", fs, "", buildpath)
508
+ if error
509
+ return (list(error))
510
+ `(error, buildnum) = builder.increment()
511
+ if error {
512
+ ErrorDebuglog("build number increment failed", error)
513
+ return (list(error))
514
+ }
515
+ `(error) = builder.make()
516
+ if !error {
517
+ if buildonly
518
+ builder.refresh(projman.track)
519
+ else
520
+ `(error) = builder.run(projman.track)
521
+ }
522
+ builder.destroy()
523
+ if error
524
+ list(error)
525
+ else
526
+ list(false, buildnum)
527
+ }
528
+
529
+ // publish
530
+ //
531
+ // Publish the project to its configured location.
532
+ //
533
+ procon.publish = closure publish(local rules, publish, error, outfs, inpath) {
534
+ rules = buildrules()
535
+ publish = procon.configDict.publish
536
+ if !rules || !publish.where
537
+ return (list(Error("no project publish location configured")))
538
+ `(error, outfs) = projman.locate.connect(publish.where.locationID, "NideFS", publish.where.path)
539
+ if error
540
+ return (list(Error("can't access publishing filesystem", error)))
541
+ inpath = fs.path.join(proj_configDataFolder, rules.products, publish.input)
542
+ fs.util.deepcopy(inpath, publish.sources, outfs, publish.output)
543
+ }
544
+
545
+ // close
546
+ //
547
+ // Close the project.
548
+
549
+ procon.close = function close() {
550
+ procon.loaded = false
551
+ procon.fs = fs = false
552
+ procon.configDict = false
553
+ procon.configMs = false
554
+ procon.configMD5 = false
555
+ }
556
+
557
+ // finis
558
+
559
+ procon
560
+ };
561
+
562
+
563
+ /*
564
+ * projInit
565
+ *
566
+ * Initialize the proj component.
567
+ *
568
+ */
569
+
570
+ function projInit(local manifest) {
571
+
572
+ manifest = `(ProjectManager, projTracker, projConnector, projConfig, projInit)
573
+
574
+ Naan.module.build(module.id, "projects", function(modobj, compobj) {
575
+ require("./project.nlg")
576
+ require("./proj_cliser.nlg")
577
+ require("./proj_console.nlg")
578
+ require("./proj_folder.nlg")
579
+ require("./proj_lambda.nlg")
580
+ require("./proj_static.nlg")
581
+ require("./build.nlg")
582
+ storageResources = require("../storage/resources.nlg")
583
+ compobj.manifest = manifest
584
+ module.exports.ProjectManager = ProjectManager
585
+ })
586
+
587
+ }();