@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.
- package/LICENSE.md +21 -0
- package/README.md +46 -0
- package/dist/env_web.js +431 -0
- package/dist/naan.min.js +73 -0
- package/frameworks/browser/browser.nlg +30 -0
- package/frameworks/browser/pouchdb/pouchdb.min.js +7 -0
- package/frameworks/browser/spark-md5/spark-md5.min.js +1 -0
- package/frameworks/browser/sworker.js +192 -0
- package/frameworks/browser/terminals.nlg +787 -0
- package/frameworks/browser/workers.nlg +386 -0
- package/frameworks/client/apiclient.nlg +183 -0
- package/frameworks/client/client.nlg +29 -0
- package/frameworks/client/psm_client.nlg +572 -0
- package/frameworks/common/common.nlg +464 -0
- package/frameworks/common/preferences.nlg +131 -0
- package/frameworks/common/repltools.nlg +100 -0
- package/frameworks/common/watching.nlg +97 -0
- package/frameworks/node/apiserver.nlg +399 -0
- package/frameworks/node/filesystem.nlg +1012 -0
- package/frameworks/node/gitter.nlg +234 -0
- package/frameworks/node/node.nlg +81 -0
- package/frameworks/node/psm_server.nlg +465 -0
- package/frameworks/node/worker.nlg +560 -0
- package/frameworks/project/build.nlg +1229 -0
- package/frameworks/project/jszip.js +30 -0
- package/frameworks/project/jszip.nlg +87 -0
- package/frameworks/project/proj_cliser.nlg +139 -0
- package/frameworks/project/proj_console.nlg +137 -0
- package/frameworks/project/proj_folder.nlg +143 -0
- package/frameworks/project/proj_lambda.nlg +137 -0
- package/frameworks/project/proj_static.nlg +138 -0
- package/frameworks/project/project.nlg +29 -0
- package/frameworks/project/projects.nlg +587 -0
- package/frameworks/project/uglifyjs.js +1 -0
- package/frameworks/project/uglifyjs.nlg +79 -0
- package/frameworks/running/debugcom.nlg +163 -0
- package/frameworks/running/debugnub.nlg +565 -0
- package/frameworks/running/debugutil.nlg +510 -0
- package/frameworks/running/executors.nlg +767 -0
- package/frameworks/running/running.nlg +151 -0
- package/frameworks/running/sourcecode.nlg +346 -0
- package/frameworks/running/taskexec.nlg +196 -0
- package/frameworks/storage/dbt_pouch.nlg +773 -0
- package/frameworks/storage/file_manager.nlg +772 -0
- package/frameworks/storage/psm.nlg +326 -0
- package/frameworks/storage/psm_dbtables.nlg +814 -0
- package/frameworks/storage/resources.nlg +445 -0
- package/frameworks/storage/storage.nlg +52 -0
- package/lib/browser/env_web.js +431 -0
- package/lib/browser/env_webworker.js +146 -0
- package/lib/browser/require.js +1653 -0
- package/lib/core/naanlib.js +73 -0
- package/lib/env_node.js +282 -0
- package/lib/env_nodeworker.js +165 -0
- package/lib/node_repl.js +25 -0
- package/lib/node_repl_init.nlg +52 -0
- package/package.json +13 -0
- package/plugins/gitClient/clientops.nlg +317 -0
- package/plugins/gitClient/gitClient.nlg +63 -0
- package/plugins/gitClient/gitutils.nlg +1331 -0
- package/plugins/gitClient/minimatch.js +945 -0
- package/plugins/gitClient/minimatch_license.txt +15 -0
- package/plugins/gitClient/minimatch_readme.md +208 -0
- package/plugins/nodeLib/nodeLib.nlg +26 -0
- package/plugins/nodeLib/node_cp.nlg +65 -0
- package/plugins/nodeLib/node_fs.nlg +137 -0
- package/plugins/nodeLib/node_https.nlg +172 -0
- package/plugins/nodeLib/node_util.nlg +180 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +88 -0
- package/plugins/serviceAws/aws/lambda_rest_index.js +122 -0
- package/plugins/serviceAws/aws/lambda_rest_init.nlg +58 -0
- package/plugins/serviceAws/aws/lambda_ws_index.js +498 -0
- package/plugins/serviceAws/aws/lambda_ws_init.nlg +49 -0
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +122 -0
- package/plugins/serviceAws/aws_cognito.nlg +76 -0
- package/plugins/serviceAws/aws_dynamo.nlg +509 -0
- package/plugins/serviceAws/aws_lambda.nlg +95 -0
- package/plugins/serviceAws/aws_s3.nlg +134 -0
- package/plugins/serviceAws/aws_utils.nlg +86 -0
- package/plugins/serviceAws/dbt_aws.nlg +769 -0
- package/plugins/serviceAws/lambda_naan_control.nlg +175 -0
- package/plugins/serviceAws/psm_aws.nlg +258 -0
- package/plugins/serviceAws/serviceAws.nlg +38 -0
- package/plugins/serviceGitHub/gitops.nlg +522 -0
- package/plugins/serviceGitHub/psm_github.nlg +205 -0
- package/plugins/serviceGitHub/serviceGitHub.nlg +65 -0
- package/plugins/serviceGitLab/gitops.nlg +528 -0
- package/plugins/serviceGitLab/psm_gitlab.nlg +205 -0
- package/plugins/serviceGitLab/serviceGitLab.nlg +65 -0
- package/test/harness.nlg +312 -0
- package/test/node_test.js +33 -0
- package/test/test_01_core.nlg +768 -0
- package/test/test_02_context.nlg +269 -0
- package/test/test_03_jsinterop.nlg +137 -0
- package/test/test_04_numerics.nlg +450 -0
- package/test/test_05_strings.nlg +63 -0
- package/test/test_06_lingoparse.nlg +500 -0
- 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
|
+
}();
|