profoundjs 6.0.0-beta.6 → 6.0.0-beta.8

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.
@@ -0,0 +1,479 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ /*
6
+
7
+ * This is NPM run script 'completeInstall'
8
+
9
+ * This script is intended to be run by the user at a shell after 'npm install', via 'complete_intall.js'.
10
+
11
+ * Prompts for configuration values and other installation options, if necessary, and creates config.js.
12
+ * Kicks off 'npm run setup' to complete installation.
13
+
14
+ */
15
+
16
+ const child_process = require("child_process");
17
+ const fs = require("fs");
18
+ const minimist = require("minimist");
19
+ const os = require("os");
20
+ const path = require("path");
21
+ const readline = require("readline");
22
+ const iutils = require("./install_utils.js");
23
+
24
+ const IBMi = iutils.isIBMi();
25
+
26
+ const RED = "\x1b[31m";
27
+ const RESET = "\x1b[0m";
28
+
29
+ (async () => {
30
+ try {
31
+
32
+ // Parse arguments.
33
+ const args = minimist(
34
+ process.argv.slice(2),
35
+ {
36
+ alias: {
37
+ "h": "help",
38
+ "c": "configure"
39
+ },
40
+ boolean: [
41
+ "h",
42
+ "c"
43
+ ],
44
+ unknown: function(arg) {
45
+ console.error("Unknown argument:", arg);
46
+ process.exit(1);
47
+ }
48
+ }
49
+ );
50
+
51
+ // Show help and quit, if requested.
52
+ if (args["help"]) {
53
+ const HELP = `Usage: node complete_install.js [OPTION]
54
+ -h, --help Print this help and exit.
55
+ -c, --configure Prompt for configuration values.
56
+
57
+ Creates config.js and completes installation.
58
+ If config.js is not present, this script prompts for values and creates it.
59
+ If config.js is already present, installation proceeds silently by default.
60
+ In this case, --configure can be used to prompt and update config.js first.
61
+ `;
62
+ console.log(HELP);
63
+ process.exit(0);
64
+ }
65
+
66
+ // Validate arguments.
67
+ if (args._.length > 0) {
68
+ console.error("Unknown argument:", args._[0]);
69
+ process.exit(1);
70
+ }
71
+
72
+ const deployDir = iutils.getDeployDir();
73
+ if (!deployDir) {
74
+ console.error("Can't find deployment directory.");
75
+ process.exit(1);
76
+ }
77
+
78
+ const nodeMajorVersion = Number(process.versions.node.split(".")[0]);
79
+ const gitSupported = ["win32", "darwin", "linux"].includes(os.platform());
80
+
81
+ const configPath = iutils.getConfigPath();
82
+ let config = fileExists(configPath) ? require(configPath) : {};
83
+
84
+ let downloadStaticFiles;
85
+ let svrname, autostart, ccsid, nodePath;
86
+
87
+
88
+ // If config.js doesn't exist, or if --configure is passed, prompt and create/update config.js.
89
+ if (!fileExists(configPath) || args["configure"] === true) {
90
+
91
+ if (gitSupported && nodeMajorVersion >= 18) {
92
+ console.log("");
93
+ console.log(`${RED}WARNING: Git integration not supported on Node.js ${nodeMajorVersion}${RESET}`);
94
+ console.log("");
95
+ }
96
+
97
+ let staticFilesDirectory, port, gitSupport;
98
+ let profounduiLibrary, connectorLibrary, connectorIASP;
99
+
100
+ let defaultStaticDir;
101
+ if (IBMi) {
102
+ defaultStaticDir = config.staticFilesDirectory || "/www/profoundui/htdocs"
103
+ if (!directoryExists(defaultStaticDir)) {
104
+ console.log("");
105
+ console.log("WARNING: Profound UI Installation not found in default location.");
106
+ console.log("");
107
+ }
108
+ }
109
+ else {
110
+ defaultStaticDir = config.staticFilesDirectory || "htdocs";
111
+ console.log("");
112
+ console.log("You can provide the Profound UI directory as a remote URL (e.g. http://myibmi:8080) or as a local directory name. If the directory does not exist, the installer can create it for you.");
113
+ console.log("");
114
+ }
115
+ staticFilesDirectory = await ask("Specify Profound UI static files directory", defaultStaticDir, validateDirectory);
116
+ if (!IBMi && !isURL(staticFilesDirectory) && !directoryExists(path.resolve(deployDir, staticFilesDirectory))) {
117
+ console.log("");
118
+ console.log("The specified directory for Profound UI was not found.");
119
+ console.log("");
120
+ let answer = (await ask("Should the installer create the directory and download a copy of Profound UI static files?", "y", validateYesNo)).toUpperCase();
121
+ downloadStaticFiles = (answer === "Y");
122
+ }
123
+ port = Number(await ask("Specify port number for Profound.js server", config.port || 8081, validatePort));
124
+
125
+
126
+ if (gitSupported && nodeMajorVersion < 18) {
127
+ let answer = (await ask("Install with Git integration?", config.gitSupport === false ? "n" : "y" , validateYesNo)).toUpperCase();
128
+ gitSupport = (answer === "Y");
129
+ }
130
+ if (IBMi) {
131
+ console.log("");
132
+ profounduiLibrary = (await ask("Specify Profound UI installation library", config.profounduiLibrary || "PROFOUNDUI", validateName)).toUpperCase();
133
+ let answer = (await ask("Install Profound.js Connector IBM i ILE components?", "y", validateYesNo)).toUpperCase();
134
+ if (answer === "Y") {
135
+ connectorLibrary = (await ask("Enter Profound.js Connector library name:", config.connectorLibrary || "PROFOUNDJS", validateName)).toUpperCase();
136
+ connectorIASP = (await ask("Enter Profound.js Connector library IASP:", config.connectorIASP || "*SYSBAS", validateIASP)).toUpperCase();
137
+ }
138
+ const serverInstances = iutils.getIBMiInstances(deployDir);
139
+ if (serverInstances.length > 1) {
140
+ console.log("\nWARNING - Multiple STRTCPSVR/ENDTCPSVR instances found for this server in /profoundjs-base/instances:\n");
141
+ serverInstances.forEach(serverInstance => {
142
+ console.log(JSON.stringify(serverInstance));
143
+ });
144
+ }
145
+ answer = (await ask("\nCreate/replace server instance configuration for STRTCPSVR/ENDTCPSVR commands?", "y", validateYesNo)).toUpperCase();
146
+ if (answer === "Y") {
147
+ let defaultName = "PROFOUNDJS";
148
+ const defaultOpts = {
149
+ ccsid: "37",
150
+ nodePath: process.argv[0],
151
+ autostart: "1"
152
+ };
153
+ const serverInstance = serverInstances[0];
154
+ if (serverInstance) {
155
+ defaultName = serverInstance.name;
156
+ defaultOpts.autostart = "0";
157
+ for (const name in defaultOpts) {
158
+ const opt = serverInstance.options.find(option => option.name === name);
159
+ if (opt) {
160
+ defaultOpts[name] = opt.value.trim();
161
+ }
162
+ }
163
+ }
164
+ svrname = (await ask("Server instance name:", defaultName, validateName)).toUpperCase();
165
+ ccsid = await ask("Specify CCSID for instance " + svrname, defaultOpts.ccsid, isValidCcsid);
166
+ nodePath = await ask("Specify Node.js path for instance " + svrname, defaultOpts.nodePath, isValidNodePath);
167
+ autostart = (await ask("Autostart server instance " + svrname + " when TCP/IP starts?", defaultOpts.autostart === "1" ? "y" : "n", validateYesNo)).toUpperCase();
168
+ autostart = (autostart === "Y");
169
+ }
170
+ }
171
+
172
+ // Create/update configuration file.
173
+ if (fileExists(configPath)) {
174
+
175
+ config.staticFilesDirectory = staticFilesDirectory;
176
+ config.port = port;
177
+ if (gitSupport === false) {
178
+ config.gitSupport = false;
179
+ }
180
+ else if (config.hasOwnProperty("gitSupport")) {
181
+ delete config.gitSupport;
182
+ }
183
+ if (IBMi) {
184
+ config.profounduiLibrary = profounduiLibrary;
185
+ if (connectorLibrary) {
186
+ config.connectorLibrary = connectorLibrary;
187
+ }
188
+ else {
189
+ if (config.hasOwnProperty("connectorLibrary")) {
190
+ delete config.connectorLibrary;
191
+ }
192
+ if (config.hasOwnProperty("connectorIASP")) {
193
+ delete config.connectorIASP;
194
+ }
195
+ }
196
+ if (connectorIASP && connectorIASP !== "*SYSBAS") {
197
+ config.connectorIASP = connectorIASP;
198
+ }
199
+ else if (config.hasOwnProperty("connectorIASP")) {
200
+ delete config.connectorIASP;
201
+ }
202
+ }
203
+ fs.writeFileSync(configPath, stringifyConfig(config));
204
+ console.log("");
205
+ console.log("config.js updated.");
206
+ console.log("");
207
+
208
+ }
209
+ else {
210
+
211
+ let content = fs.readFileSync(path.join(iutils.getSetupDir(), "config.js"), "utf8");
212
+ eval("config = " + content.substr(content.indexOf("{")));
213
+ config.staticFilesDirectory = staticFilesDirectory;
214
+ config.port = port;
215
+ if (connectorLibrary) {
216
+ config.connectorLibrary = connectorLibrary;
217
+ if (connectorIASP !== "*SYSBAS") {
218
+ config.connectorIASP = connectorIASP;
219
+ }
220
+ }
221
+ if (profounduiLibrary) {
222
+ config.profounduiLibrary = profounduiLibrary;
223
+ }
224
+ if (IBMi) {
225
+ config.showIBMiParmDefn = true;
226
+ }
227
+ if (gitSupport === false) {
228
+ config.gitSupport = false;
229
+ }
230
+ // Check if this is a workspace (if so, default to mysql)
231
+ if (!IBMi && fileExists(path.join(deployDir, "modules", "app", ".noderun", "settings.json"))) {
232
+ if (config.databaseConnections) delete config.databaseConnections; // remove property so that it's appended at the end when we set it
233
+ config.databaseConnections = [{
234
+ name: "default",
235
+ default: true,
236
+ driver: "mysql",
237
+ driverOptions: {
238
+ user: "user-name",
239
+ password: "your-password",
240
+ host: "localhost",
241
+ database: "database-name"
242
+ }
243
+ }];
244
+ }
245
+ content = "\nmodule.exports = ";
246
+ content += JSON.stringify(config, null, " ");
247
+ content += "\n";
248
+ fs.writeFileSync(configPath, content);
249
+ console.log("");
250
+ console.log("config.js created.");
251
+ console.log("");
252
+
253
+ }
254
+
255
+ }
256
+
257
+ // Complete installation.
258
+ process.stdin.destroy();
259
+ let setupArgs = [];
260
+ if (IBMi) {
261
+ if (config.connectorLibrary !== undefined) {
262
+ setupArgs.push("--ibmi-connector-library");
263
+ }
264
+ if (svrname) {
265
+ setupArgs.push("--ibmi-instance=" + svrname);
266
+ if (autostart) {
267
+ setupArgs.push("--ibmi-instance-autostart");
268
+ }
269
+ else {
270
+ setupArgs.push("--no-ibmi-instance-autostart");
271
+ }
272
+ if (ccsid) {
273
+ setupArgs.push("--ibmi-instance-ccsid=" + ccsid);
274
+ }
275
+ if (nodePath) {
276
+ setupArgs.push("--ibmi-instance-node-path=" + nodePath);
277
+ }
278
+ }
279
+ }
280
+ if (downloadStaticFiles) {
281
+ setupArgs.push("--static-files");
282
+ }
283
+ if (gitSupported && config.gitSupport !== false && nodeMajorVersion < 18) {
284
+ setupArgs.push("--nodegit");
285
+ }
286
+ if (setupArgs.length === 0) {
287
+ setupArgs = "";
288
+ }
289
+ else {
290
+ setupArgs = "-- " + setupArgs.join(" ");
291
+ }
292
+ try {
293
+ child_process.execSync(
294
+ `npm run setup ${setupArgs}`,
295
+ {
296
+ cwd: iutils.getPackageDir(),
297
+ stdio: ["ignore", "inherit", "inherit"]
298
+ }
299
+ );
300
+ }
301
+ catch {
302
+ process.exit(1);
303
+ }
304
+
305
+ }
306
+ catch (error) {
307
+ process.stdin.destroy();
308
+ console.error(error);
309
+ process.exit(1);
310
+ }
311
+ })();
312
+
313
+ async function ask(questionParm, defaultAnswer, validationFunction) {
314
+
315
+ let question = questionParm;
316
+ if (defaultAnswer == null) defaultAnswer = "";
317
+ if (typeof defaultAnswer !== "string") defaultAnswer = String(defaultAnswer);
318
+
319
+ if (defaultAnswer !== "") {
320
+ let lastChar = question.substr(question.length - 1, 1);
321
+ if (lastChar === ":" || lastChar === "?") {
322
+ question = question.substr(0, question.length - 1) + " (" + defaultAnswer + ")" + lastChar;
323
+ }
324
+ else {
325
+ question = question + " (" + defaultAnswer + ")" + ":";
326
+ }
327
+ }
328
+ question += " ";
329
+
330
+ const readlineInterface = readline.createInterface({
331
+ input: process.stdin,
332
+ output: process.stdout,
333
+ terminal: false
334
+ });
335
+ let answer = await new Promise(resolve => {
336
+ readlineInterface.question(question, function(answer) {
337
+ readlineInterface.close();
338
+ resolve(answer);
339
+ });
340
+ });
341
+
342
+ if (answer == "") answer = defaultAnswer;
343
+ answer = answer.trim();
344
+ if (typeof validationFunction === "function" && validationFunction(answer) === false) {
345
+ answer = await ask(questionParm, defaultAnswer, validationFunction);
346
+ }
347
+ return answer;
348
+
349
+ }
350
+
351
+ function fileExists(file) {
352
+ var exists = false;
353
+ try {
354
+ var stat = fs.statSync(file);
355
+ if (stat && stat.isFile()) exists = true;
356
+ }
357
+ catch (err) {
358
+ exists = false;
359
+ }
360
+ return exists;
361
+ }
362
+
363
+ function directoryExists(dir) {
364
+ var exists = false;
365
+ try {
366
+ var stat = fs.statSync(dir);
367
+ if (stat && stat.isDirectory()) exists = true;
368
+ }
369
+ catch (err) {
370
+ exists = false;
371
+ }
372
+ return exists;
373
+ }
374
+
375
+ function validateName(name) {
376
+
377
+ const error = iutils.validateIBMiName(name);
378
+ if (error) {
379
+ console.log(error);
380
+ return false;
381
+ }
382
+ return true;
383
+
384
+ }
385
+
386
+ function validateIASP(name) {
387
+
388
+ const error = iutils.validateIBMiIASP(name);
389
+ if (error) {
390
+ console.log(error);
391
+ return false;
392
+ }
393
+ return true;
394
+
395
+ }
396
+
397
+ function isURL(path) {
398
+ if (typeof path !== "string") return false;
399
+ path = path.toLowerCase();
400
+ if (path.substr(0, 7) === "http://") return true;
401
+ if (path.substr(0, 8) === "https://") return true;
402
+ return false;
403
+ }
404
+
405
+ function validateDirectory(directory) {
406
+ if (IBMi) {
407
+ var ch = directory.substr(0, 1);
408
+ if (ch !== "/" && ch !== "\\" && !isURL(directory)) {
409
+ directory = path.join(iutils.getDeployDir(), path.sep, directory);
410
+ }
411
+ if (!directoryExists(directory) && !isURL(directory)) {
412
+ console.log("WARNING: The specified directory was not found. You can create it later or modify the staticFilesDirectory property in config.js.");
413
+ console.log("");
414
+ }
415
+ }
416
+ return true; // accept any entry - if directory doesn't exist, simply warn
417
+ }
418
+
419
+ function validatePort(port) {
420
+ if (port === "0") return true;
421
+ port = Number(port);
422
+ if (!isNaN(port) && port >= 1 && port <= 65535) return true;
423
+ console.log("Invalid port number. Valid range is 0-65535.");
424
+ return false;
425
+ }
426
+
427
+ function isValidNodePath(nodePath) {
428
+
429
+ if (!fileExists(nodePath)) {
430
+ console.log("Path " + nodePath + " does not exist. A valid path name must be entered.");
431
+ return false;
432
+ }
433
+ return true;
434
+ }
435
+
436
+ function isValidCcsid(ccsid) {
437
+
438
+ const error = iutils.validateIBMiCCSID(parseInt(ccsid, 10));
439
+ if (error) {
440
+ console.log(error);
441
+ return false;
442
+ }
443
+ return true;
444
+
445
+ }
446
+
447
+ function validateYesNo(answer) {
448
+ answer = answer.toUpperCase();
449
+ if (answer === "Y" || answer === "YES" || answer === "N" || answer === "NO") return true;
450
+ console.log("Invalid answer. Use y or n.");
451
+ return false;
452
+ }
453
+
454
+ function stringifyConfig(config) {
455
+
456
+ // JavaScript functions (like connectorIPFilter) will be lost when doing JSON.stringify,
457
+ // so we need to do some magic to preserve them.
458
+
459
+ let funkz = [];
460
+ let configString = "\nmodule.exports = ";
461
+
462
+ configString += JSON.stringify(config, (key, val) => {
463
+ if (typeof val === 'function') {
464
+ let n = funkz.length;
465
+ funkz.push(val.toString());
466
+ return `___function${n}___`;
467
+ }
468
+ return val;
469
+ }, " ");
470
+
471
+ configString += "\n";
472
+
473
+ for (var i=0; i<funkz.length; i++) {
474
+ configString = configString.replace(`"___function${i}___"`, funkz[i]);
475
+ }
476
+
477
+ return configString;
478
+
479
+ }