@naanlang/naan 1.0.2 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +10 -8
- package/bin/index.js +2 -2
- package/dist/env_web.js +172 -22
- package/dist/naan.min.js +6 -6
- package/frameworks/browser/https_request.nlg +120 -0
- package/frameworks/browser/sworker.js +299 -91
- package/frameworks/browser/terminals.nlg +28 -13
- package/frameworks/browser/workers.nlg +27 -12
- package/frameworks/client/apiclient.nlg +17 -4
- package/frameworks/client/psm_client.nlg +184 -81
- package/frameworks/common/common.nlg +105 -25
- package/frameworks/common/preferences.nlg +1 -0
- package/frameworks/common/watching.nlg +1 -0
- package/frameworks/node/apiserver.nlg +31 -15
- package/frameworks/node/filesystem.nlg +230 -46
- package/frameworks/node/gitter.nlg +27 -6
- package/frameworks/node/https_request.nlg +119 -0
- package/frameworks/node/node.nlg +1 -0
- package/frameworks/node/psm_server.nlg +113 -37
- package/frameworks/project/build.nlg +40 -23
- package/frameworks/project/proj_cliser.nlg +11 -3
- package/frameworks/project/proj_console.nlg +13 -4
- package/frameworks/project/proj_folder.nlg +10 -1
- package/frameworks/project/proj_lambda.nlg +13 -4
- package/frameworks/project/proj_static.nlg +11 -3
- package/frameworks/project/projects.nlg +128 -40
- package/frameworks/running/debugnub.nlg +2 -5
- package/frameworks/running/executors.nlg +1 -0
- package/frameworks/storage/csv.nlg +120 -0
- package/frameworks/storage/dbt_pouch.nlg +41 -25
- package/frameworks/storage/psm.nlg +108 -28
- package/frameworks/storage/psm_dbtables.nlg +7 -3
- package/frameworks/storage/resources.nlg +30 -2
- package/lib/browser/env_web.js +170 -20
- package/lib/browser/env_webworker.js +1 -1
- package/lib/browser/require.js +1 -1
- package/lib/core/naanlib.js +6 -6
- package/package.json +2 -1
- package/plugins/serviceAws/aws/aws-sdk-node.min.js +2 -0
- package/plugins/serviceAws/aws/aws-sdk.min.js +2 -88
- package/plugins/serviceAws/aws_cloudwatchlogs.nlg +8 -7
- package/plugins/serviceAws/aws_dynamo.nlg +715 -148
- package/plugins/serviceAws/aws_dynextra.nlg +294 -0
- package/plugins/serviceAws/aws_lambda.nlg +11 -4
- package/plugins/serviceAws/aws_s3.nlg +44 -14
- package/plugins/serviceAws/dbt_aws.nlg +58 -45
- package/plugins/serviceAws/psm_aws.nlg +61 -40
- package/plugins/serviceAws/serviceAws.nlg +7 -4
- package/plugins/serviceGitHub/psm_github.nlg +41 -25
- package/plugins/serviceGitLab/psm_gitlab.nlg +41 -25
- package/test/harness.nlg +3 -1
- package/test/test_01_core.nlg +5 -5
- package/test/test_02_context.nlg +4 -4
- package/test/test_03_jsinterop.nlg +9 -3
- package/plugins/serviceAws/aws_cognito.nlg +0 -76
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2022 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -36,6 +36,7 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
36
36
|
server.psm = require("./psm_server.nlg").MakeServerPSM(server)
|
|
37
37
|
server.root = chroot
|
|
38
38
|
server.app = express()
|
|
39
|
+
server.guid = options.guid
|
|
39
40
|
server.notifyq = []
|
|
40
41
|
server.responseq = []
|
|
41
42
|
server.projects = { }
|
|
@@ -99,8 +100,9 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
99
100
|
// body parsing
|
|
100
101
|
//
|
|
101
102
|
|
|
102
|
-
server.app.use(bodyParser.
|
|
103
|
-
server.app.use(bodyParser.
|
|
103
|
+
server.app.use(bodyParser.json({limit: "5mb"}))
|
|
104
|
+
server.app.use(bodyParser.text({limit: "25mb"}))
|
|
105
|
+
server.app.use(bodyParser.raw({limit: "25mb"}))
|
|
104
106
|
|
|
105
107
|
//
|
|
106
108
|
// Express.js endpoints
|
|
@@ -108,8 +110,12 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
108
110
|
|
|
109
111
|
server.app.use(function(req,res,next) {
|
|
110
112
|
res.header("Access-Control-Allow-Origin", "*")
|
|
111
|
-
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
|
|
112
|
-
|
|
113
|
+
res.header("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS")
|
|
114
|
+
res.header("Access-Control-Allow-Headers", "x-naanlang-api-guid")
|
|
115
|
+
if req.method == "OPTIONS"
|
|
116
|
+
res.sendStatus(200)
|
|
117
|
+
else
|
|
118
|
+
next()
|
|
113
119
|
})
|
|
114
120
|
|
|
115
121
|
server.app.use("", express.static(chroot))
|
|
@@ -121,15 +127,18 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
121
127
|
// "/"
|
|
122
128
|
|
|
123
129
|
server.app.get("/", function(req, res) {
|
|
124
|
-
res.send("<u>
|
|
130
|
+
res.send("<u>naan-server API</u><br>\r\n"
|
|
125
131
|
" /readfile?path=<i>filepath</i><br>\r\n"
|
|
126
132
|
" /status?timeout=<i>msec</i>&after=<i>stamp</i><br>\r\n")
|
|
127
133
|
})
|
|
128
134
|
|
|
129
135
|
// "/readfile"
|
|
130
136
|
|
|
131
|
-
server.app.get("/readfile", closure(req, res) {
|
|
132
|
-
|
|
137
|
+
server.app.get("/readfile", closure(req, res, local guid) {
|
|
138
|
+
guid = req.get("x-naanlang-api-guid")
|
|
139
|
+
if server.guid && guid != server.guid
|
|
140
|
+
res.status(403).send("unauthorized")
|
|
141
|
+
else if not string(req.query.path)
|
|
133
142
|
res.status(400).send("Invalid filename")
|
|
134
143
|
else if RegExp("^\\.\\.[/\\\\]|[/\\\\]\\.\\.$|[/\\\\]\\.\\.[/\\\\]").test(req.query.path)
|
|
135
144
|
res.status(403).send("\"Parent path references forbidden\"")
|
|
@@ -156,7 +165,10 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
156
165
|
|
|
157
166
|
// "/status"
|
|
158
167
|
|
|
159
|
-
server.app.get("/status", closure(req,res, local timeoutms, after, responder) {
|
|
168
|
+
server.app.get("/status", closure(req, res, local guid, timeoutms, after, responder) {
|
|
169
|
+
guid = req.get("x-naanlang-api-guid")
|
|
170
|
+
if server.guid && guid != server.guid
|
|
171
|
+
res.status(403).send("unauthorized")
|
|
160
172
|
timeoutms = toint(req.query.timeout)
|
|
161
173
|
after = toint(req.query.after)
|
|
162
174
|
if not integer(timeoutms) or timeoutms > 10000
|
|
@@ -187,8 +199,11 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
187
199
|
|
|
188
200
|
// "/psm"
|
|
189
201
|
|
|
190
|
-
server.app.all("/psm", closure(req, res) {
|
|
191
|
-
|
|
202
|
+
server.app.all("/psm", closure(req, res, local guid) {
|
|
203
|
+
guid = req.get("x-naanlang-api-guid")
|
|
204
|
+
if server.guid && guid != server.guid && req.method !== "OPTIONS"
|
|
205
|
+
res.status(403).send("unauthorized")
|
|
206
|
+
else if !server.hostfs
|
|
192
207
|
res.status(503).send("host filesystem not available")
|
|
193
208
|
else
|
|
194
209
|
server.hostfs.api(req, res)
|
|
@@ -227,7 +242,6 @@ closure MakeAPI(port, options, callback, local chroot, server) {
|
|
|
227
242
|
server.ws = WebSocketServer(server)
|
|
228
243
|
server.port = port
|
|
229
244
|
callback(false, port, server) // notify of success
|
|
230
|
-
debuglog("server open on port", port)
|
|
231
245
|
result = server.psm.conns.NodeFS.connect("Host", "NideFS", list("")) // ### this should go through resource tracker
|
|
232
246
|
if result.0
|
|
233
247
|
ErrorDebuglog(Error("can't access HostFS", result.0))
|
|
@@ -264,7 +278,7 @@ closure WebSocketServer(server, local websocks) {
|
|
|
264
278
|
// Event handlers
|
|
265
279
|
|
|
266
280
|
websocks.wss.on("connection", function(socket, request) {
|
|
267
|
-
websocks.conns.push(WesCon(websocks, socket, request))
|
|
281
|
+
websocks.conns.push(WesCon(server, websocks, socket, request))
|
|
268
282
|
})
|
|
269
283
|
|
|
270
284
|
server.wss.on("error", function(error) {
|
|
@@ -303,7 +317,7 @@ closure WebSocketServer(server, local websocks) {
|
|
|
303
317
|
*
|
|
304
318
|
*/
|
|
305
319
|
|
|
306
|
-
closure WesCon(websocks, socket, request, local wescon) {
|
|
320
|
+
closure WesCon(server, websocks, socket, request, local wescon) {
|
|
307
321
|
wescon = new(object, this)
|
|
308
322
|
wescon.socket = socket
|
|
309
323
|
wescon.serverIDs = []
|
|
@@ -315,7 +329,9 @@ closure WesCon(websocks, socket, request, local wescon) {
|
|
|
315
329
|
socket.on("message", function onmessage(text, local message, error) {
|
|
316
330
|
try {
|
|
317
331
|
message = new(js.g.JSON.parse(text))
|
|
318
|
-
if
|
|
332
|
+
if server.guid && message.guid != server.guid
|
|
333
|
+
error = Error("unauthorized")
|
|
334
|
+
else if message.clientID && websocks.subsystems[message.serverID] {
|
|
319
335
|
wescon.serverIDs.push(message.serverID) // ### track subsystems for closing
|
|
320
336
|
websocks.subsystems[message.serverID].wsReceive(message, wescon)
|
|
321
337
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* column positioning: // // !
|
|
8
8
|
*
|
|
9
|
-
* Copyright (c) 2017-
|
|
9
|
+
* Copyright (c) 2017-2022 by Richard C. Zulch
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
23
23
|
if !rootpath
|
|
24
24
|
return (list(Error("mandatory rootpath missing")))
|
|
25
25
|
else if rootpath == ""
|
|
26
|
-
rootpath =
|
|
26
|
+
rootpath = JSpath.sep
|
|
27
27
|
files = new(object, this)
|
|
28
28
|
files.rootpath = rootpath
|
|
29
29
|
files.path = JSpath
|
|
@@ -54,24 +54,31 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
54
54
|
// Convert a path argument to a local path, returning a standard result tuple. If the path is
|
|
55
55
|
// invalid this will report why. Otherwise this returns the correct localpath, which is the path
|
|
56
56
|
// we use with the underlying API.
|
|
57
|
+
// Win32 driver letters are annoying here. If the rootpath specifies a drive letter then the
|
|
58
|
+
// paths must match it. If the rootpath doesn't specify a drive letter then path can have any
|
|
59
|
+
// drive letter, or none.
|
|
57
60
|
|
|
58
61
|
badCreatePathRegEx = RegExp("[:]|[/\\\\][/\\\\]|[/\\\\]$|(^|[/\\\\])[.][.]?$")
|
|
59
62
|
|
|
60
|
-
closure localPath(path, create, local pattern, testpath) {
|
|
63
|
+
files.localPath = closure localPath(path, create, local pattern, testpath, locroot) {
|
|
61
64
|
if !path
|
|
62
65
|
return (list(Error("filesystem path false")))
|
|
63
66
|
else if !string(path)
|
|
64
67
|
return (list(Error("filesystem path invalid:", typeof(path))))
|
|
68
|
+
if JSpath === JSpath.win32 {
|
|
69
|
+
locroot = JSpath.resolve(path, rootpath) // use path's drive letter if we don't have one
|
|
70
|
+
pattern = "\\:\\" // unchanged and unique on win32
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
locroot = rootpath
|
|
74
|
+
pattern = "/:/" // unchanged and unique on posix
|
|
75
|
+
}
|
|
65
76
|
if JSpath.isAbsolute(path)
|
|
66
|
-
path = JSpath.resolve(path)
|
|
77
|
+
path = JSpath.resolve(locroot, path) // add drive letter to absolute path
|
|
67
78
|
else
|
|
68
79
|
path = JSpath.normalize(path) // normalize for current platform
|
|
69
|
-
if
|
|
70
|
-
|
|
71
|
-
else
|
|
72
|
-
pattern = "/:/" // unchanged and unique on posix
|
|
73
|
-
if ((testpath = commonParents(path, rootpath)) != "")
|
|
74
|
-
list(false, JSpath.resolve(rootpath, path)) // ### shouldn't be so lax on this test
|
|
80
|
+
if (commonParents(path, locroot) != "")
|
|
81
|
+
list(false, JSpath.resolve(locroot, path))
|
|
75
82
|
else if ((testpath = JSpath.resolve(pattern, path)).indexOf(pattern.slice(0,-1)) < 0)
|
|
76
83
|
list(Error("filesystem path reaches above root:", path))
|
|
77
84
|
else if create && testpath.indexOf(pattern) < 0
|
|
@@ -79,7 +86,31 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
79
86
|
else if create && badCreatePathRegEx.test(path)
|
|
80
87
|
list(Error("filesystem create path invalid", path))
|
|
81
88
|
else
|
|
82
|
-
list(false, JSpath.resolve(
|
|
89
|
+
list(false, JSpath.resolve(locroot, path))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// folderPath
|
|
93
|
+
//
|
|
94
|
+
// Return a folder path for the specified folderID, relative to our root. If the folder path is
|
|
95
|
+
// not within our root then it is returned as an absolute path.
|
|
96
|
+
|
|
97
|
+
files.folderPath = function folderPath(folderID, callback, local envID, path) {
|
|
98
|
+
if !callback
|
|
99
|
+
return (syncAdapter(folderPath, folderID))
|
|
100
|
+
envID = {
|
|
101
|
+
"HomeDir": "HOME",
|
|
102
|
+
"TempDir": "TMPDIR",
|
|
103
|
+
"PackageDir": "npm_config_prefix"
|
|
104
|
+
}[folderID]
|
|
105
|
+
if envID {
|
|
106
|
+
path = js.g.process.env[envID]
|
|
107
|
+
if path.startsWith(rootpath)
|
|
108
|
+
path = path.slice(rootpath.length) // remove rootpath from beginning
|
|
109
|
+
}
|
|
110
|
+
if path
|
|
111
|
+
callback(false, path)
|
|
112
|
+
else
|
|
113
|
+
callback(Error("unknown folderID:", folderID))
|
|
83
114
|
}
|
|
84
115
|
|
|
85
116
|
// winDrives
|
|
@@ -273,11 +304,48 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
273
304
|
callback(false, { md5: md5data })
|
|
274
305
|
})
|
|
275
306
|
}
|
|
276
|
-
|
|
307
|
+
|
|
308
|
+
// readlink
|
|
309
|
+
//
|
|
310
|
+
// Read the contents of a symbolic link.
|
|
311
|
+
|
|
312
|
+
files.readlink = closure readlink(path, callback, local error, localpath) {
|
|
313
|
+
if !callback
|
|
314
|
+
return (syncAdapter(readlink, path))
|
|
315
|
+
`(error, localpath) = localPath(path)
|
|
316
|
+
if error
|
|
317
|
+
return (asyncResult(callback, error))
|
|
318
|
+
fs.readlink(localpath, function(err, linkString) {
|
|
319
|
+
if err
|
|
320
|
+
callback(Error("fs.readlink failed:", localpath, err))
|
|
321
|
+
else
|
|
322
|
+
callback(false, linkString)
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// symlink
|
|
327
|
+
//
|
|
328
|
+
// Create a symbolic link "path" that points to "target". No options are currently supported.
|
|
329
|
+
|
|
330
|
+
files.symlink = closure symlink(target, path, options, callback,
|
|
331
|
+
local error, localpath) {
|
|
332
|
+
if !callback
|
|
333
|
+
return (syncAdapter(symlink, target, path, options))
|
|
334
|
+
`(error, localpath) = localPath(path)
|
|
335
|
+
if error
|
|
336
|
+
return (asyncResult(callback, error))
|
|
337
|
+
fs.symlink(target, localpath, function(err) {
|
|
338
|
+
if err
|
|
339
|
+
callback(Error("fs.symlink failed:", target, localpath, err))
|
|
340
|
+
else
|
|
341
|
+
callback(false, { ok: true })
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
277
345
|
// delete
|
|
278
346
|
//
|
|
279
347
|
// Delete the file at the specified path, or a directory if the options dictionary includes:
|
|
280
|
-
// recursive: true --
|
|
348
|
+
// recursive: true -- recursively delete directory and children
|
|
281
349
|
|
|
282
350
|
files.delete = closure delete(path, options, callback, local error, localpath) {
|
|
283
351
|
if !callback
|
|
@@ -286,9 +354,9 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
286
354
|
if error
|
|
287
355
|
return (asyncResult(callback, error))
|
|
288
356
|
if options.recursive
|
|
289
|
-
fs.
|
|
357
|
+
fs.rm(localpath, { recursive: true, force: true }, function(err) {
|
|
290
358
|
if err
|
|
291
|
-
callback(Error("fs.
|
|
359
|
+
callback(Error("fs.rm failed:", localpath, err))
|
|
292
360
|
else
|
|
293
361
|
callback(false, { ok: true })
|
|
294
362
|
})
|
|
@@ -303,15 +371,22 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
303
371
|
|
|
304
372
|
// info
|
|
305
373
|
//
|
|
306
|
-
// Report info on a file or directory.
|
|
374
|
+
// Report info on a file or directory. The options are:
|
|
375
|
+
// {
|
|
376
|
+
// follow: <boolean> // follow links
|
|
377
|
+
// }
|
|
307
378
|
|
|
308
|
-
files.info = closure info(path, callback, local error, localpath) {
|
|
379
|
+
files.info = closure info(path, options, callback, local error, localpath, fsop) {
|
|
309
380
|
if !callback
|
|
310
|
-
return (syncAdapter(info, path))
|
|
381
|
+
return (syncAdapter(info, path, options))
|
|
311
382
|
`(error, localpath) = localPath(path)
|
|
312
383
|
if error
|
|
313
384
|
return (asyncResult(callback, error))
|
|
314
|
-
|
|
385
|
+
if options.follow
|
|
386
|
+
fsop = `stat
|
|
387
|
+
else
|
|
388
|
+
fsop = `lstat
|
|
389
|
+
fs[fsop](localpath, function(err, stat, local data, info, nodetype) {
|
|
315
390
|
if err
|
|
316
391
|
return (callback(Error("fs.stat failed:", localpath, err)))
|
|
317
392
|
info = {
|
|
@@ -336,9 +411,102 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
336
411
|
})
|
|
337
412
|
}
|
|
338
413
|
|
|
414
|
+
// setInfo
|
|
415
|
+
//
|
|
416
|
+
// Set selected info on a file or directory. The info dictionary has the same layout as that
|
|
417
|
+
// returned by files.info(), and every applicable key defined in the dictionary is set. To omit
|
|
418
|
+
// setting some of the information, remove its key from the info dictionary. The applicable keys
|
|
419
|
+
// are:
|
|
420
|
+
// {
|
|
421
|
+
// mtimeMs: <milliseconds>
|
|
422
|
+
// mtime: <date>
|
|
423
|
+
// nodejs_stat: {
|
|
424
|
+
// mode: <number>
|
|
425
|
+
// uid: <uid>
|
|
426
|
+
// gid: <gid>
|
|
427
|
+
// atimeMs: <milliseconds>
|
|
428
|
+
// atime: <date>
|
|
429
|
+
// mtimeMs: <milliseconds>
|
|
430
|
+
// mtime: <date>
|
|
431
|
+
// }
|
|
432
|
+
// }
|
|
433
|
+
// If more than one timestamp exists of a certain type, the millisecond version is used. Some
|
|
434
|
+
// values are set together by the OS, like uid & guid, or mtime & atime. Specifying just one of
|
|
435
|
+
// these will cause setInfo to use the same value for both.
|
|
436
|
+
|
|
437
|
+
files.setInfo = closure setInfo(path, info, callback,
|
|
438
|
+
local error, localpath, mtime, atime, uid, gid) {
|
|
439
|
+
if !callback
|
|
440
|
+
return (syncAdapter(setInfo, path, info))
|
|
441
|
+
if !dictionary(info) && !xobject(info)
|
|
442
|
+
error = Error("setInfo: invalid argument:", typeof(info))
|
|
443
|
+
else
|
|
444
|
+
`(error, localpath) = localPath(path)
|
|
445
|
+
if error
|
|
446
|
+
return (asyncResult(callback, error))
|
|
447
|
+
atime = info.nodejs_stat.atimeMs/1000.0 || info.nodejs_stat.atime
|
|
448
|
+
mtime = info.mtimeMs/1000.0 || info.mtime
|
|
449
|
+
if !mtime
|
|
450
|
+
mtime = info.nodejs_stat.mtimeMs/1000.0 || info.nodejs_stat.mtime
|
|
451
|
+
if atime || mtime {
|
|
452
|
+
atime = atime || mtime
|
|
453
|
+
mtime = mtime || atime
|
|
454
|
+
`(error) = setTimes(path, atime, mtime)
|
|
455
|
+
}
|
|
456
|
+
if !error && info.nodejs_stat.mode
|
|
457
|
+
`(error) = setMode(path, info.nodejs_stat.mode)
|
|
458
|
+
uid = info.nodejs_stat.uid
|
|
459
|
+
gid = info.nodejs_stat.gid
|
|
460
|
+
if !error && (uid || gid) {
|
|
461
|
+
uid = uid || gid
|
|
462
|
+
gid = gid || uid
|
|
463
|
+
`(error) = setOwnerGroup(path, uid, gid)
|
|
464
|
+
}
|
|
465
|
+
if error
|
|
466
|
+
callback(Error("setInfo failed:", localpath, error))
|
|
467
|
+
else
|
|
468
|
+
callback(false, { ok: true})
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// setOwnerGroup
|
|
472
|
+
//
|
|
473
|
+
// Set owner/group on a file or directory.
|
|
474
|
+
|
|
475
|
+
files.setOwnerGroup = closure setOwnerGroup(path, uid, gid, callback, local error, localpath) {
|
|
476
|
+
if !callback
|
|
477
|
+
return (syncAdapter(setOwnerGroup, path, uid, gid))
|
|
478
|
+
`(error, localpath) = localPath(path)
|
|
479
|
+
if error
|
|
480
|
+
return (asyncResult(callback, error))
|
|
481
|
+
fs.chown(localpath, uid, gid, function(err, stat) {
|
|
482
|
+
if err
|
|
483
|
+
callback(Error("fs.chown failed:", localpath, err))
|
|
484
|
+
else
|
|
485
|
+
callback(false, { ok: true})
|
|
486
|
+
})
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// setMode
|
|
490
|
+
//
|
|
491
|
+
// Set mode bits on a file or directory.
|
|
492
|
+
|
|
493
|
+
files.setMode = closure setMode(path, mode, callback, local error, localpath) {
|
|
494
|
+
if !callback
|
|
495
|
+
return (syncAdapter(setMode, path, mode))
|
|
496
|
+
`(error, localpath) = localPath(path)
|
|
497
|
+
if error
|
|
498
|
+
return (asyncResult(callback, error))
|
|
499
|
+
fs.chmod(localpath, mode, function(err, stat) {
|
|
500
|
+
if err
|
|
501
|
+
callback(Error("fs.chmod failed:", localpath, err))
|
|
502
|
+
else
|
|
503
|
+
callback(false, { ok: true})
|
|
504
|
+
})
|
|
505
|
+
}
|
|
506
|
+
|
|
339
507
|
// setTimes
|
|
340
508
|
//
|
|
341
|
-
// Set timestamps on a file or directory.
|
|
509
|
+
// Set timestamps on a file or directory. The timestamps can be dates or numeric seconds.
|
|
342
510
|
|
|
343
511
|
files.setTimes = closure setTimes(path, atime, mtime, callback, local error, localpath) {
|
|
344
512
|
if !callback
|
|
@@ -346,9 +514,6 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
346
514
|
`(error, localpath) = localPath(path)
|
|
347
515
|
if error
|
|
348
516
|
return (asyncResult(callback, error))
|
|
349
|
-
if !numeric(atime, mtime)
|
|
350
|
-
return (asyncResult(callback, Error("invalid arguments:", atime, mtime)))
|
|
351
|
-
localpath = JSpath.resolve(rootpath, localpath)
|
|
352
517
|
fs.utimes(localpath, atime, mtime, function(err, stat) {
|
|
353
518
|
if err
|
|
354
519
|
callback(Error("fs.utimes failed:", localpath, err))
|
|
@@ -375,7 +540,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
375
540
|
if name { // this record is fetchable
|
|
376
541
|
++pending.active
|
|
377
542
|
filepath = JSpath.join(parentpath, name)
|
|
378
|
-
files.info(filepath, function(error, info) {
|
|
543
|
+
files.info(filepath, false, function(error, info) {
|
|
379
544
|
if error
|
|
380
545
|
input[kdex].error = error // this record failed
|
|
381
546
|
else
|
|
@@ -398,7 +563,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
398
563
|
|
|
399
564
|
// dirList
|
|
400
565
|
//
|
|
401
|
-
// Return array of files in a directory if it exists. If options.
|
|
566
|
+
// Return array of files in a directory if it exists. If options.stat is true then this reads
|
|
402
567
|
// info for each file as well.
|
|
403
568
|
|
|
404
569
|
files.dirList = closure dirList(path, options, callback, local error, localpath, output, nodelist, file) {
|
|
@@ -426,7 +591,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
426
591
|
output.children.push({
|
|
427
592
|
name: file
|
|
428
593
|
})
|
|
429
|
-
if options.
|
|
594
|
+
if options.stat
|
|
430
595
|
statfetch(output.children, localpath) // read all the info records
|
|
431
596
|
callback(false, output)
|
|
432
597
|
})
|
|
@@ -505,8 +670,10 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
505
670
|
// Recursively build the tree
|
|
506
671
|
|
|
507
672
|
closure recurTree(localpath, depth, parent) {
|
|
508
|
-
if depthlimit && depth >= depthlimit
|
|
673
|
+
if depthlimit && depth >= depthlimit {
|
|
674
|
+
recurNext()
|
|
509
675
|
return
|
|
676
|
+
}
|
|
510
677
|
++pending.active
|
|
511
678
|
fs.readdir(localpath, { }, function(err, nodes, local child, node, stat) {
|
|
512
679
|
if err.code == "ENOTDIR"
|
|
@@ -536,13 +703,21 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
536
703
|
parent: child
|
|
537
704
|
}) } }
|
|
538
705
|
--pending.active
|
|
539
|
-
|
|
540
|
-
node = queue.pop()
|
|
541
|
-
recurTree(node.path, node.depth, node.parent) }
|
|
542
|
-
if pending.active == 0 && queue.length == 0
|
|
543
|
-
pending.signal(list(false, root))
|
|
706
|
+
recurNext()
|
|
544
707
|
})
|
|
545
708
|
}
|
|
709
|
+
|
|
710
|
+
// recurNext
|
|
711
|
+
//
|
|
712
|
+
// Pull more queued items and signal when done.
|
|
713
|
+
|
|
714
|
+
function recurNext(local node) {
|
|
715
|
+
while queue.length > 0 && pending.active < 20 {
|
|
716
|
+
node = queue.pop()
|
|
717
|
+
recurTree(node.path, node.depth, node.parent) }
|
|
718
|
+
if pending.active == 0 && queue.length == 0
|
|
719
|
+
pending.signal(list(false, root))
|
|
720
|
+
}
|
|
546
721
|
|
|
547
722
|
`(error, localpath) = localPath(path)
|
|
548
723
|
if error
|
|
@@ -638,7 +813,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
638
813
|
if dest.slice(-1) == JSpath.sep // new location, else entirely new pathname
|
|
639
814
|
localdest = JSpath.join(localdest, JSpath.basename(srcpath))
|
|
640
815
|
}
|
|
641
|
-
fs.
|
|
816
|
+
fs.stat(localdest, closure(err, stat, local cmd, args) {
|
|
642
817
|
if !err && !options.overwrite
|
|
643
818
|
callback(Error("copy destination already exists",
|
|
644
819
|
{
|
|
@@ -649,6 +824,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
649
824
|
existing: localdest
|
|
650
825
|
}))
|
|
651
826
|
else {
|
|
827
|
+
debuglog("==> Warning: files.copy needs to be rewritten with fs primitives")
|
|
652
828
|
if options.move {
|
|
653
829
|
cmd = "mv"
|
|
654
830
|
args = [localsrc, localdest] }
|
|
@@ -717,6 +893,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
717
893
|
files.minimize = closure minimize(input, callback, local child, stdinStream) {
|
|
718
894
|
if !callback
|
|
719
895
|
return (syncAdapter(minimize, input))
|
|
896
|
+
debuglog("==> Warning: files.minimize is deprecated")
|
|
720
897
|
child = nodecp.execFile("uglifyjs",
|
|
721
898
|
["--compress", "drop_debugger=false", "--mangle", "eval"], // ### uglifyjs options should be parameterized
|
|
722
899
|
function(err, stdout, stderr) {
|
|
@@ -742,6 +919,7 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
742
919
|
files.unzip = closure unzip(inpath, outpath, callback) {
|
|
743
920
|
if !callback
|
|
744
921
|
return (syncAdapter(unzip, inpath, outpath))
|
|
922
|
+
debuglog("==> Warning: files.unzip is deprecated")
|
|
745
923
|
nodecp.execFile("unzip",
|
|
746
924
|
["-qo", inpath, "-d", outpath], // quiet; no queries
|
|
747
925
|
{ }, // execution options
|
|
@@ -757,21 +935,27 @@ closure Filesystem(rootpath, local files, badCreatePathRegEx) {
|
|
|
757
935
|
//
|
|
758
936
|
// touch
|
|
759
937
|
//
|
|
760
|
-
//
|
|
938
|
+
// Touch the specified file or directory, returning the result as a standard result tuple
|
|
939
|
+
// `(error, result). When only the path is specified this sets the last-access and last-modified
|
|
940
|
+
// times to the current Date(). Otherwise the dates are set to the specified value(s). Note that
|
|
941
|
+
// this sets the times of a symbolic link file itself, not the file the link points to.
|
|
761
942
|
//
|
|
762
|
-
files.touch = closure touch(
|
|
943
|
+
files.touch = closure touch(path, atime, mtime, callback, local localpath) {
|
|
763
944
|
if !callback
|
|
764
|
-
return (syncAdapter(touch,
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
945
|
+
return (syncAdapter(touch, path, atime, mtime))
|
|
946
|
+
`(error, localpath) = localPath(path)
|
|
947
|
+
if error
|
|
948
|
+
return (asyncResult(callback, error))
|
|
949
|
+
if !atime && !mtime
|
|
950
|
+
atime = mtime = Date()
|
|
951
|
+
else if atime && !mtime
|
|
952
|
+
mtime = atime
|
|
953
|
+
fs.lutimes(localpath, atime, mtime, function(err) {
|
|
954
|
+
if err
|
|
955
|
+
callback(Error("touch failed", err))
|
|
956
|
+
else
|
|
957
|
+
callback(false, { ok: true })
|
|
958
|
+
})
|
|
775
959
|
}
|
|
776
960
|
|
|
777
961
|
//
|
|
@@ -23,6 +23,28 @@ closure Gitter(fs, local gitt) {
|
|
|
23
23
|
gitt = new(object, this)
|
|
24
24
|
gitt.roots = {}
|
|
25
25
|
|
|
26
|
+
// gitPath
|
|
27
|
+
//
|
|
28
|
+
// Convert a Windows path to a posix (git) path if needed.
|
|
29
|
+
//
|
|
30
|
+
function gitPath(fspath) {
|
|
31
|
+
if fs.path.sep == "/"
|
|
32
|
+
fspath
|
|
33
|
+
else
|
|
34
|
+
fspath.split(fs.path.sep).join("/")
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// fsPath
|
|
38
|
+
//
|
|
39
|
+
// Convert a posix (git) path to a filesystem path if needed.
|
|
40
|
+
//
|
|
41
|
+
function fsPath(gitpath) {
|
|
42
|
+
if fs.path.sep == "/"
|
|
43
|
+
gitpath
|
|
44
|
+
else
|
|
45
|
+
gitpath.split("/").join(fs.path.sep)
|
|
46
|
+
}
|
|
47
|
+
|
|
26
48
|
// repoRoot
|
|
27
49
|
//
|
|
28
50
|
// Compute the path from the fs root to the repo root.
|
|
@@ -54,11 +76,10 @@ closure Gitter(fs, local gitt) {
|
|
|
54
76
|
// Compute the bridge path to an absolute repopath (which can point inside a repo) from the
|
|
55
77
|
// phyiscal repo root. If these are the same, or an error occurs, then the result is "".
|
|
56
78
|
//
|
|
57
|
-
|
|
58
79
|
function bridgePath(repopath, local top) {
|
|
59
80
|
top = repoRoot(repopath).1
|
|
60
81
|
if top && repopath.startsWith(top) && repopath.length > top.length
|
|
61
|
-
top = repopath.slice(top.length+1).concat(
|
|
82
|
+
top = repopath.slice(top.length+1).concat(fs.path.sep) // move leading "/" of bridge path to trailing
|
|
62
83
|
else
|
|
63
84
|
"" // we are looking at the root, or an error
|
|
64
85
|
}
|
|
@@ -151,12 +172,12 @@ closure Gitter(fs, local gitt) {
|
|
|
151
172
|
outLE: "\x00" // lines delimited by nulls
|
|
152
173
|
}
|
|
153
174
|
if options.pathspec
|
|
154
|
-
execOptions.cmdargs = execOptions.cmdargs.concat("--", options.pathspec)
|
|
175
|
+
execOptions.cmdargs = execOptions.cmdargs.concat("--", gitPath(options.pathspec))
|
|
155
176
|
result = []
|
|
156
177
|
execOptions.outproc = function(output, liner, kill, local line, path) {
|
|
157
178
|
while (line = liner.read())
|
|
158
179
|
if line != "" {
|
|
159
|
-
path = line.substring(3)
|
|
180
|
+
path = fsPath(line.substring(3))
|
|
160
181
|
if path.startsWith(bridge) { // must start with bridge to be within repopath
|
|
161
182
|
path = path.slice(bridge.length)
|
|
162
183
|
result.push({
|
|
@@ -183,7 +204,7 @@ closure Gitter(fs, local gitt) {
|
|
|
183
204
|
// Retrieve the content of a specific file and revision. The file pathspec must be the path of
|
|
184
205
|
// the file within the repo.
|
|
185
206
|
|
|
186
|
-
gitt.showfile = closure showfile(repopath, options, callback, local execOptions
|
|
207
|
+
gitt.showfile = closure showfile(repopath, options, callback, local execOptions) {
|
|
187
208
|
if !callback
|
|
188
209
|
return (syncAdapter(showfile, repopath, options))
|
|
189
210
|
if !string(repopath)
|
|
@@ -192,7 +213,7 @@ closure Gitter(fs, local gitt) {
|
|
|
192
213
|
return (asyncResult(callback, Error("both pathspec and hash required:", options.pathspec, options.hash)))
|
|
193
214
|
repopath = fs.path.resolve(fs.rootpath, repopath)
|
|
194
215
|
execOptions = {
|
|
195
|
-
cmdargs: ["show", options.hash.concat(":", bridgePath(repopath), options.pathspec)]
|
|
216
|
+
cmdargs: ["show", options.hash.concat(":", bridgePath(repopath), gitPath(options.pathspec))]
|
|
196
217
|
execops: {
|
|
197
218
|
cwd: repopath
|
|
198
219
|
}
|