profoundjs 6.0.0-beta.3 → 6.0.0-beta.7

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/setup/setup.js CHANGED
@@ -1,257 +1,499 @@
1
1
 
2
- const htdocs_download_url = 'http://resources.profoundjs.com/profoundui_htdocs.zip';
3
- const pjsBaseInstance = '/profoundjs-base/instances/';
4
-
5
- const child_process = require('child_process');
6
- const fs = require('fs');
7
- const fse = require('fs-extra');
8
- const path = require('path');
9
- const extract = require('extract-zip');
10
- const crypto = require('crypto');
11
- const os = require('os');
12
-
13
- var IBMi = (os.type() === 'OS400');
14
- var setupDir = __dirname;
15
- var dirSep = path.sep;
16
- var dirParts = __dirname.split(dirSep);
17
- while (dirParts.length > 0 && dirParts.pop() !== "node_modules") {};
18
- if (dirParts.length === 0) {
19
- console.log("Can't find deployment directory.");
20
- process.exit(1);
21
- }
22
- var deployDir = dirParts.join(dirSep);
23
- var silent = process.argv.includes("--silent");
24
- if (process.env.SILENT_INSTALL) silent = true;
2
+ "use strict";
25
3
 
26
- var portNumber = "8081"; // default port
27
- if (process.env.PORT) portNumber = process.env.PORT;
4
+ /*
28
5
 
29
- function downloadHtdocs(htdocsDir, callback) {
30
- var zipFile = setupDir + dirSep + 'htdocs.zip';
31
- console.log("");
32
- console.log("Starting Download...")
33
- console.log("");
6
+ This is NPM script: npm run setup
34
7
 
35
- const profound = require('profoundjs');
8
+ * Performs additional installation.
9
+ * Kicked off from 'complete_install.js' which is manually run by user.
10
+ * Can also be run directly for advanced/automated installation.
36
11
 
37
- profound.utils.downloadProgress(htdocs_download_url, zipFile, (err) => {
12
+ */
38
13
 
39
- if (err) {
40
- console.error("Download ended in error:");
41
- console.error(err);
42
- if (typeof callback === "function") callback();
43
- }
44
- else {
45
- console.log("");
46
- console.log("Download completed. Extracting...")
47
- extract(zipFile, { dir: htdocsDir })
48
- .then(
49
- function() {
50
- try {
51
- fs.unlinkSync(zipFile); // delete zip file after it's unzipped
52
- }
53
- catch (error) {}
54
- console.log("Directory " + htdocsDir + " restored.");
14
+ const htdocs_download_url = "http://resources.profoundjs.com/profoundui_htdocs.zip";
15
+
16
+ // Platform-specific dependency versions.
17
+ const idb_connector_version = "1.2.16";
18
+ const node_pty_version = "^2";
19
+
20
+ const child_process = require("child_process");
21
+ const compareVersions = require("compare-versions");
22
+ const crypto = require("crypto");
23
+ const extract = require("extract-zip");
24
+ const fs = require("fs-extra");
25
+ const iutils = require("./install_utils.js");
26
+ const os = require("os");
27
+ const minimist = require("minimist");
28
+ const path = require("path");
29
+ const util = require("util");
30
+ const uuidv4 = require("uuid").v4;
31
+
32
+ const IBMi = os.type() === "OS400";
33
+
34
+ const RED = "\x1b[31m";
35
+ const CYAN = "\x1b[36m";
36
+ const RESET = "\x1b[0m";
37
+
38
+ const logDir = path.join(os.tmpdir(), "profoundjs-" + uuidv4());
39
+ const logPath = path.join(logDir, "setup.log");
40
+ let logFile;
41
+
42
+ (async () => {
43
+ try {
44
+
45
+ // Parse arguments.
46
+ const args = minimist(
47
+ process.argv.slice(2),
48
+ {
49
+ alias: {
50
+ "c": "config-file",
51
+ "h": "help"
55
52
  },
56
- function (err) {
57
- console.error("Extraction ended in error:");
58
- console.error(err);
53
+ boolean: [
54
+ "h",
55
+ "ibmi-connector-library",
56
+ "ibmi-instance-autostart",
57
+ "nodegit",
58
+ "static-files"
59
+ ],
60
+ string: [
61
+ "c",
62
+ "ibmi-instance",
63
+ "ibmi-instance-ccsid",
64
+ "ibmi-instance-node-path",
65
+ "nodegit-version"
66
+ ],
67
+ unknown: function(arg) {
68
+ console.error("Unknown argument:", arg);
69
+ process.exit(1);
59
70
  }
60
- )
61
- .finally(function() {
62
- if (typeof callback === "function") process.nextTick(callback);
63
- });
71
+ }
72
+ );
73
+
74
+ // Show help and quit, if requested.
75
+ if (args["help"]) {
76
+ const HELP = `Usage: npm run setup -- [OPTION]
77
+ -c, --config-file=<file> Alternate config file.
78
+ -h, --help Print this help and exit.
79
+ --nodegit Install nodegit.
80
+ --nodegit-version=version Override nodegit version.
81
+ --static-files Install static files.
82
+ --ibmi-connector-library Install IBM i Connector library.
83
+ --ibmi-instance=<name> Create/update STRTCPSVR instance config.
84
+ --ibmi-instance-autostart Autostart flag for STRTCPSVR instance.
85
+ --ibmi-instance-ccsid=<ccsid> CCSID for STRTCPSVR instance.
86
+ --ibmi-instance-node-path=<path> Node.js binary path for STRTCPSVR instance.
87
+
88
+ Performs additional installation using config values and CLI options.
89
+ Default config file is <INSTALL_DIRECTORY>/config.js.
90
+
91
+ --config-file can be an absolute path or path relative to working directory.
92
+ --static-files are installed to directory specified in config file.
93
+ --static-files is invalid if directory exists or if a URL is specified.
94
+ --nodegit-version is ignored if --nodegit is not used.
95
+ --nodegit-version can accept an NPM package version, tag, or version range.
96
+
97
+ IBM i-related values are invalid when not installing on IBM i.
98
+ IBM i instance-related values are ignored unless --ibmi-instance is specified.
99
+
100
+ --ibmi-connector-library installs to library specified in config file.
101
+ --ibmi-instance creates or replaces STRTCPSVR config.
102
+ --ibmi-instance-autostart sets "autostart=1" in STRTCPSVR config.
103
+ --ibmi-instance-ccsid sets "ccsid" in STRTCPSVR config.
104
+ --ibmi-instance-node-path sets "nodePath" in STRTCPSVR config.
105
+ `;
106
+ console.log(HELP);
107
+ process.exit(0);
64
108
  }
65
- });
66
- }
67
109
 
68
- function ask(questionParm, defaultAnswer, validationFunction, callback) {
69
- var question = questionParm;
70
- if (defaultAnswer == null) defaultAnswer = "";
71
- if (typeof defaultAnswer !== "string") defaultAnswer = String(defaultAnswer);
72
-
73
- if (silent) {
74
- callback(defaultAnswer);
75
- return;
76
- }
77
-
78
- if (defaultAnswer !== "") {
79
- var lastChar = question.substr(question.length - 1, 1);
80
- if (lastChar === ":" || lastChar === "?") {
81
- question = question.substr(0, question.length - 1) + " (" + defaultAnswer + ")" + lastChar;
110
+ // Initialize log file.
111
+ fs.mkdirSync(logDir);
112
+ logFile = fs.openSync(logPath, "w");
113
+
114
+ // Validate arguments.
115
+ if (args._.length > 0) {
116
+ logError("Unknown argument:", args._[0]);
117
+ die();
118
+ }
119
+
120
+ const deployDir = iutils.getDeployDir();
121
+ if (!deployDir) {
122
+ logError("Can't find deployment directory.");
123
+ die();
124
+ }
125
+
126
+ const configPath = args["config-file"] !== undefined ? path.resolve(args["config-file"]) : iutils.getConfigPath();
127
+ if (!fileExists(configPath)) {
128
+ logError(`Configuration file ${configPath} not found.`);
129
+ die();
130
+ }
131
+ const config = require(configPath);
132
+
133
+ if (args["static-files"]) {
134
+ if (typeof config.staticFilesDirectory !== "string") {
135
+ logError("staticFilesDirectory is missing from config or is invalid.");
136
+ die();
137
+ }
138
+ if (/^https?:\/\//i.test(config.staticFilesDirectory)) {
139
+ logError("--static-files is not valid when staticFilesDirectory is a URL.");
140
+ die();
141
+ }
142
+ const staticDir = path.resolve(deployDir, config.staticFilesDirectory);
143
+ let exists = false;
144
+ try {
145
+ fs.statSync(staticDir);
146
+ exists = true;
147
+ }
148
+ catch (error) {}
149
+ if (exists) {
150
+ logError(`staticFilesDirectory ${staticDir} already exists.`);
151
+ die();
152
+ }
153
+ }
154
+ if (args["ibmi-connector-library"]) {
155
+ if (!IBMi) {
156
+ logError(`--ibmi-connector-library is not valid on ${os.platform()}`);
157
+ die();
158
+ }
159
+ if (typeof config.connectorLibrary !== "string") {
160
+ logError("connectorLibrary is missing from config or is invalid.");
161
+ die();
162
+ }
163
+ let error = iutils.validateIBMiName(config.connectorLibrary);
164
+ if (error) {
165
+ logError("connectorLibrary is invalid: " + error);
166
+ die();
167
+ }
168
+ if (config.connectorIASP !== undefined) {
169
+ error = iutils.validateIBMiIASP(config.connectorIASP);
170
+ if (error) {
171
+ logError("connectorIASP is invalid: " + error);
172
+ die();
173
+ }
174
+ }
175
+ }
176
+ if (args["ibmi-instance"] !== undefined) {
177
+ if (!IBMi) {
178
+ logError(`--ibmi-instance is not valid on ${os.platform()}`);
179
+ die();
180
+ }
181
+ let error = iutils.validateIBMiName(args["ibmi-instance"]);
182
+ if (error) {
183
+ logError("--ibmi-instance is invalid: " + error);
184
+ die();
185
+ }
186
+ if (args["ibmi-instance-ccsid"] !== undefined) {
187
+ error = iutils.validateIBMiCCSID(parseInt(args["ibmi-instance-ccsid"], 10));
188
+ if (error) {
189
+ logError("--ibmi-instance-ccsid is invalid: " + error);
190
+ die();
191
+ }
192
+ }
193
+ if (args["ibmi-instance-node-path"] !== undefined) {
194
+ const nodePath = args["ibmi-instance-node-path"].trim();
195
+ if (!fileExists(nodePath)) {
196
+ logError("--ibmi-instance-node-path is invalid: " + nodePath + " does not exist.");
197
+ die();
198
+ }
199
+ }
200
+ }
201
+
202
+ // Install platform-specific dependencies.
203
+ if (IBMi) {
204
+ log(`Installing idb-connector...`);
205
+ child_process.execSync(
206
+ `npm install --no-package-lock idb-connector@"${idb_connector_version}"`,
207
+ {
208
+ cwd: iutils.getPackageDir(),
209
+ stdio: ["ignore", logFile, logFile]
210
+ }
211
+ );
82
212
  }
83
213
  else {
84
- question = question + " (" + defaultAnswer + ")" + ":";
214
+ log(`Installing profoundjs-node-pty...`);
215
+ child_process.execSync(
216
+ `npm install --save-optional --no-package-lock profoundjs-node-pty@"${node_pty_version}"`,
217
+ {
218
+ cwd: iutils.getPackageDir(),
219
+ stdio: ["ignore", logFile, logFile]
220
+ }
221
+ );
85
222
  }
86
- }
87
- question += " ";
88
223
 
89
-
90
- var readlineInterface = require('readline').createInterface({
91
- input: process.stdin,
92
- output: process.stdout,
93
- terminal: false
94
- });
224
+ // Install nodegit, if necessary.
225
+ if (args["nodegit"]) {
226
+ let version;
227
+ if (args["nodegit-version"]) {
228
+ version = args["nodegit-version"];
229
+ }
230
+ else {
231
+ // Current stable version of nodegit doesn't have pre-built binaries for Node > 14.
232
+ // If installing on Node > 14, use alpha version with pre-built binaries.
233
+ version = "0.27.0"; // Current stable version.
234
+ if (compareVersions("14.*.*", process.versions.node) === -1) {
235
+ version = "0.28.0-alpha.18";
236
+ }
237
+ }
238
+ log(`Installing nodegit...`);
239
+ try {
240
+ child_process.execSync(
241
+ `npm install --no-package-lock nodegit@"${version}"`,
242
+ {
243
+ cwd: iutils.getPackageDir(),
244
+ stdio: ["ignore", logFile, logFile]
245
+ }
246
+ );
247
+ }
248
+ catch (error) {
249
+ logError("nodegit installation failed.");
250
+ die();
251
+ }
252
+ }
95
253
 
96
- readlineInterface.question(question, function(answer) {
97
- readlineInterface.close();
98
- if (answer == "") answer = defaultAnswer;
99
- answer = answer.trim();
100
- if (typeof validationFunction === "function" && validationFunction(answer) === false) {
101
- ask(questionParm, defaultAnswer, validationFunction, callback);
254
+ // Create modules directory.
255
+ if (directoryExists(path.join(deployDir, "modules"))) {
256
+ log("modules directory exists.");
102
257
  }
103
258
  else {
104
- callback(answer);
259
+ log("Creating modules directory.");
260
+ fs.mkdirSync(path.join(deployDir, "modules"));
105
261
  }
106
- });
107
- }
108
262
 
109
- function fileExists(file) {
110
- var exists = false;
111
- try {
112
- var stat = fs.statSync(file);
113
- if (stat && stat.isFile()) exists = true;
114
- }
115
- catch (err) {
116
- exists = false;
117
- }
118
- return exists;
119
- }
263
+ // Grant PROFOUNDJS user all permissions to modules directory tree.
264
+ if (IBMi) {
265
+ runCommand("CHGAUT OBJ('" + deployDir + "') USER(PROFOUNDJS) DTAAUT(*RWX) OBJAUT(*ALL)");
266
+ runCommand("CHGAUT OBJ('" + path.join(deployDir, "modules") + "') USER(PROFOUNDJS) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL)");
267
+ }
120
268
 
121
- function directoryExists(dir) {
122
- var exists = false;
123
- try {
124
- var stat = fs.statSync(dir);
125
- if (stat && stat.isDirectory()) exists = true;
126
- }
127
- catch (err) {
128
- exists = false;
129
- }
130
- return exists;
131
- }
269
+ // Create puiscreens.json.
270
+ createPuiscreens(deployDir);
132
271
 
133
- function copyFile(file, destination, type, process) {
134
- if (type == null) type = "binary";
135
- var fileParts = file.split(dirSep);
136
- var fileName = fileParts[fileParts.length - 1];
137
- if (directoryExists(destination))
138
- var toFile = destination + dirSep + fileName;
139
- else
140
- var toFile = destination;
141
- var content = fs.readFileSync(file, type);
142
- if (typeof process === "function") content = process(content);
143
- fs.writeFileSync(toFile, content, type);
144
- }
272
+ // Create puiuplexit.js.
273
+ if (fileExists(path.join(deployDir, "modules", "puiuplexit.js"))) {
274
+ log("puiuplexit.js file exists.");
275
+ }
276
+ else {
277
+ log("Creating puiuplexit.js.");
278
+ copyFile(path.join(__dirname, "modules", "puiuplexit.js"), path.join(deployDir, "modules"), "utf8");
279
+ }
145
280
 
146
- function copyDir(dir, destinationDir) {
147
- var dirParts = dir.split(dirSep);
148
- var dirName = dirParts[dirParts.length - 1];
149
- fs.mkdirSync(destinationDir + dirSep + dirName);
150
- files = fs.readdirSync(dir);
151
- files.forEach(function(file, index) {
152
- if(fs.lstatSync(dir + dirSep + file).isDirectory()) { // recurse
153
- copyDir(dir + dirSep + file, destinationDir + dirSep + dirName);
154
- }
281
+ // Create puidnlexit.js.
282
+ if (fileExists(path.join(deployDir, "modules", "puidnlexit.js"))) {
283
+ log("puidnlexit.js file exists.");
284
+ }
155
285
  else {
156
- copyFile(dir + dirSep + file, destinationDir + dirSep + dirName, null, null);
286
+ log("Creating puidnlexit.js.");
287
+ copyFile(path.join(__dirname, "modules", "puidnlexit.js"), path.join(deployDir, "modules"), "utf8");
157
288
  }
158
- });
159
- }
160
289
 
290
+ // Create samples directory.
291
+ if (directoryExists(path.join(deployDir, "modules", "pjssamples"))) {
292
+ fs.removeSync(path.join(deployDir, "modules", "pjssamples"));
293
+ }
294
+ log("Copying pjssamples.");
295
+ copyDir(path.join(__dirname, "modules", "pjssamples"), path.join(deployDir, "modules"));
161
296
 
162
- function createPackageFile() {
163
- if (IBMi)
164
- runCommand("CHGAUT OBJ('" + deployDir + "') USER(PROFOUNDJS) DTAAUT(*RWX) OBJAUT(*ALL)");
297
+ // Create store_credentials.js.
298
+ if (fileExists(path.join(deployDir, "store_credentials.js"))) {
299
+ log("store_credentials.js file exists.");
300
+ }
301
+ else {
302
+ copyFile(path.join(__dirname, "store_credentials.js"), deployDir, "utf8");
303
+ log("store_credentials.js created.");
304
+ }
165
305
 
166
- if (fileExists(deployDir + dirSep + "package.json")) {
167
- console.log("package.json file exists.");
168
- }
169
- else {
170
- copyFile(setupDir + dirSep + "package.json", deployDir, "utf8");
171
- console.log("package.json created automatically with defaults.");
172
- }
173
- }
306
+ // Create updatepui.js.
307
+ if (!IBMi) {
308
+ // This file is not needed on IBM i because the proper way to install Profound UI on IBM i is to download the full version from the web site
309
+ if (fileExists(path.join(deployDir, "updatepui.js"))) {
310
+ log("updatepui.js file exists.");
311
+ }
312
+ else {
313
+ copyFile(path.join(__dirname, "updatepui.js"), deployDir, "utf8");
314
+ log("updatepui.js created.");
315
+ }
316
+ }
174
317
 
175
- function createStart(callback) {
176
- if (fileExists(deployDir + dirSep + "start.js")) {
177
- console.log("start.js file exists.");
318
+ // Create call.js.
319
+ if (fileExists(path.join(deployDir, "call.js"))) {
320
+ log("call.js file exists.");
321
+ }
322
+ else {
323
+ copyFile(path.join(__dirname, "call.js"), deployDir, "utf8");
324
+ log("call.js created.");
325
+ }
326
+
327
+ // Convert start.js to Promises, if necessary.
178
328
  const convertStartJS = require("./convertStartJS.js");
179
- const changed = convertStartJS(deployDir + dirSep + "start.js");
180
- if (changed) {
181
- console.log("start.js file converted to Promises.");
329
+ if (convertStartJS(path.join(deployDir, "start.js"))) {
330
+ log("start.js file converted to Promises.");
182
331
  }
183
- callback();
184
- }
185
- else {
186
- copyFile(setupDir + dirSep + "start.js", deployDir, "utf8");
187
- console.log("start.js created.");
188
- callback();
189
- }
190
- }
191
332
 
192
- function createCall(callback) {
193
- if (fileExists(deployDir + dirSep + "call.js")) {
194
- console.log("call.js file exists.");
195
- callback();
196
- }
197
- else {
198
- copyFile(setupDir + dirSep + "call.js", deployDir, "utf8");
199
- console.log("call.js created.");
200
- callback();
201
- }
202
- }
333
+ // Install Profound UI static files, if necessary.
334
+ if (args["static-files"]) {
335
+ log("");
336
+ log("Downloading Profound UI static files...")
337
+ const profound = require("profoundjs");
338
+ const zipFile = path.join(__dirname, "htdocs.zip");
339
+ const opts = {
340
+ follow_max: 15 // Follow redirects.
341
+ };
342
+ try {
343
+ await profound.utils.download(htdocs_download_url, zipFile, opts, process.stdout.isTTY ? process.stdout : null);
344
+ log("Download completed. Extracting...");
345
+ await extract(zipFile, { dir: path.resolve(deployDir, config.staticFilesDirectory) });
346
+ log("Directory " + config.staticFilesDirectory + " extracted.");
347
+ }
348
+ finally {
349
+ try {
350
+ fs.unlinkSync(zipFile);
351
+ }
352
+ catch {
353
+ }
354
+ }
355
+ }
356
+
357
+ // Install native IBM i components, if necessary.
358
+ if (IBMi) {
359
+ log("");
360
+ if (args["ibmi-connector-library"] || args["ibmi-instance"] !== undefined) {
361
+ let portNumber = config.port || 8081;
362
+ let connectorLibrary = "*NONE";
363
+ let connectorIASP;
364
+ if (args["ibmi-connector-library"]) {
365
+ connectorLibrary = config.connectorLibrary;
366
+ connectorIASP = config.connectorIASP || "*SYSBAS";
367
+ }
368
+ let svrname = "*NONE";
369
+ let autostart = true;
370
+ let ccsid = 37;
371
+ let nodePath = process.argv[0];
372
+ if (args["ibmi-instance"] !== undefined) {
373
+ svrname = args["ibmi-instance"].toUpperCase();
374
+ if (process.argv.find(arg => arg.includes("ibmi-instance-autostart"))) { // minimist sets booleans to false if not passed.
375
+ autostart = args["ibmi-instance-autostart"];
376
+ }
377
+ if (args["ibmi-instance-ccsid"] !== undefined) {
378
+ ccsid = args["ibmi-instance-ccsid"];
379
+ }
380
+ if (args["ibmi-instance-node-path"] !== undefined) {
381
+ nodePath = args["ibmi-instance-node-path"];
382
+ }
383
+ }
384
+ // First, try copying the save file
385
+ var success = runCommand("CPYFRMSTMF FROMSTMF('" + __dirname + "/pjsdist.savf') TOMBR('/QSYS.LIB/QGPL.LIB/PJSDIST.FILE') MBROPT(*REPLACE)");
386
+ if (!success) {
387
+ logError("Unable to create installer save file.");
388
+ die();
389
+ }
390
+ // Now, try restoring the PJSINSTALL program
391
+ success = runCommand("RSTOBJ OBJ(PJSINSTALL) SAVLIB(QTEMP) DEV(*SAVF) OBJTYPE(*ALL) SAVF(QGPL/PJSDIST) RSTLIB(QGPL)");
392
+ if (!success) {
393
+ // Clean up save file
394
+ log("");
395
+ log("Cleaning up...");
396
+ runCommand("DLTF FILE(QGPL/PJSDIST)");
397
+ logError("Unable to restore installer save file.");
398
+ die();
399
+ }
400
+ // Now, try running PJSINSTALL
401
+ var command = "QGPL/PJSINSTALL CONNLIB(" + connectorLibrary + ")";
402
+ if (connectorLibrary != "*NONE")
403
+ command += " CONNIASP(" + connectorIASP + ") CONNHOST('localhost') CONNPORT(" + portNumber + ")";
404
+ command += " SVRNAME(" + svrname + ")";
405
+ if (svrname != "*NONE")
406
+ command += " SVRDIR('" + deployDir + "') " +
407
+ "SVRAUTO(" + ((autostart) ? "*YES" : "*NO") + ") CCSID(" + ccsid + ") NODEPATH('" + nodePath + "')";
408
+ success = runCommand(command, "-Ke");
409
+ // Clean up program and save file
410
+ log("");
411
+ log("Cleaning up...");
412
+ runCommand("DLTPGM PGM(QGPL/PJSINSTALL)");
413
+ runCommand("DLTCMD CMD(QGPL/PJSINSTALL)");
414
+ runCommand("DLTPNLGRP PNLGRP(QGPL/PJSINSTALL)");
415
+ runCommand("DLTMSGF MSGF(QGPL/PJSINSTALL)");
416
+ runCommand("DLTF FILE(QGPL/PJSDIST)");
417
+ if (!success) {
418
+ logError("PJSINSTALL command failed.");
419
+ die();
420
+ }
421
+ }
422
+ if (args["ibmi-instance"] === undefined) {
423
+ // Instance is restarted by PJSINSTALL command only when config is created/replaced.
424
+ const instances = iutils.getIBMiInstances(deployDir);
425
+ if (instances.length > 0) {
426
+ const instance = instances[0];
427
+ log("");
428
+ runCommand(`ENDTCPSVR SERVER(*PJS) INSTANCE(${instance.name})`);
429
+ log("Waiting for instance to end...");
430
+ // This should generally work as shutdown is relatively fast.
431
+ await new Promise(resolve => setTimeout(resolve, 10000));
432
+ runCommand(`STRTCPSVR SERVER(*PJS) INSTANCE(${instance.name})`);
433
+ }
434
+ }
435
+ }
436
+ log(`\n${CYAN}Profound.js installation complete.${RESET}\n`);
203
437
 
204
- function createUpdatepui(callback) {
205
- if (IBMi) {
206
- // This file is not needed on IBM i because the proper way to install Profound UI on IBM i is to download the full version from the web site
207
- callback();
208
- return;
209
438
  }
210
- if (fileExists(deployDir + dirSep + "updatepui.js")) {
211
- console.log("updatepui.js file exists.");
212
- callback();
213
- }
214
- else {
215
- copyFile(setupDir + dirSep + "updatepui.js", deployDir, "utf8");
216
- console.log("updatepui.js created.");
217
- callback();
439
+ catch (error) {
440
+ logError(error);
441
+ die();
218
442
  }
443
+ })();
444
+
445
+ function log(...args) {
446
+ console.log(...args);
447
+ logToFile(...args);
219
448
  }
220
449
 
221
- function createStoreCredentials(callback) {
450
+ function logError(...args) {
451
+ console.error(...args);
452
+ logToFile(...args);
453
+ }
222
454
 
223
- if (fileExists(deployDir + dirSep + "store_credentials.js")) {
224
- console.log("store_credentials.js file exists.");
225
- callback();
226
- }
227
- else {
228
- copyFile(setupDir + dirSep + "store_credentials.js", deployDir, "utf8");
229
- console.log("store_credentials.js created.");
230
- callback();
231
- }
232
-
455
+ function logToFile(...args) {
456
+ let output = `${util.format(...args)}\n`; // Mimic console.log().
457
+ output = output.replace(/\x1b\[[0-9]+m/g, ""); // Strip terminal escape codes for colors.
458
+ fs.writeFileSync(logFile, output, { flag: "a" });
233
459
  }
234
460
 
235
- function createModulesDirectory() {
236
- if (directoryExists(deployDir + dirSep + "modules")) {
237
- console.log("modules directory exists.");
238
- }
239
- else {
240
- console.log("Creating modules directory.");
241
- fs.mkdirSync(deployDir + dirSep + "modules");
242
- }
461
+ function die() {
462
+ logError(`\n${RED}Profound.js installation failed.${RESET}`);
463
+ console.error(`${RED}See installation log:${RESET} ${logPath}\n`);
464
+ process.exit(1);
465
+ }
466
+
467
+ function copyDir(dir, destinationDir) {
468
+ const dirName = path.basename(dir);
469
+ fs.mkdirSync(path.join(destinationDir, dirName));
470
+ const files = fs.readdirSync(dir);
471
+ files.forEach(function(file, index) {
472
+ if(fs.lstatSync(path.join(dir, file)).isDirectory()) { // recurse
473
+ copyDir(path.join(dir, file), path.join(destinationDir, dirName));
474
+ }
475
+ else {
476
+ copyFile(path.join(dir, file), path.join(destinationDir, dirName), null, null);
477
+ }
478
+ });
479
+ }
243
480
 
244
- // Make sure on IBMi that user PROFOUNDJS has full access everything within the Modules directory
245
- if (IBMi)
246
- runCommand("CHGAUT OBJ('" + deployDir + dirSep + "modules') USER(PROFOUNDJS) DTAAUT(*RWX) OBJAUT(*ALL) SUBTREE(*ALL)");
481
+ function copyFile(file, destination, type) {
482
+ if (type == null) type = "binary";
483
+ if (directoryExists(destination))
484
+ var toFile = path.join(destination, path.basename(file));
485
+ else
486
+ var toFile = destination;
487
+ var content = fs.readFileSync(file, type);
488
+ fs.writeFileSync(toFile, content, type);
247
489
  }
248
490
 
249
- function createPuiscreens() {
491
+ function createPuiscreens(deployDir) {
250
492
  function copyFileOldVersionIs(version, compareStr){
251
493
  compareStr = compareStr || "=";
252
- console.log("Found Standard puiscreens.json file version "+compareStr+" "+version+", replacing with current version...");
253
- copyFile(setupDir + dirSep + "modules" + dirSep + "puiscreens.json", targetPuiScreensFile, "utf8");
254
- console.log("puiscreens.json file was replaced.");
494
+ log("Found Standard puiscreens.json file version "+compareStr+" "+version+", replacing with current version...");
495
+ copyFile(path.join(__dirname, "modules", "puiscreens.json"), targetPuiScreensFile, "utf8");
496
+ log("puiscreens.json file was replaced.");
255
497
  }
256
498
 
257
499
  // Check which version of puiscreens.json is installed.
@@ -260,14 +502,14 @@ function createPuiscreens() {
260
502
  // 1. Check the SHA key of existing puiscreens.json.
261
503
  // 2. If it's an official PJS screen, no customizations have been made, so it's safe to replace with this version.
262
504
  // 3. If it's not an official version, check if we have lower case User & Password. If not, then backup existing version to puiscreens_bak.json and install this official version.
263
- // 4. Otherwise it's not an official version but should work OK. So leave existing puiscreens.json, and check if we already have a puiscreens_orig.json, and
505
+ // 4. Otherwise it's not an official version but should work OK. So leave existing puiscreens.json, and check if we already have a puiscreens_orig.json, and
264
506
  // create it if not.
265
- var targetPuiScreensFile = deployDir + dirSep + "modules" + dirSep + "puiscreens.json";
507
+ var targetPuiScreensFile = path.join(deployDir, "modules", "puiscreens.json");
266
508
  if (fileExists(targetPuiScreensFile)) {
267
509
 
268
510
  var data = fs.readFileSync(targetPuiScreensFile);
269
- var checksum = crypto.createHash('sha512').update(data).digest('hex'); // sha512 best for 64-bit
270
-
511
+ var checksum = crypto.createHash("sha512").update(data).digest("hex"); // sha512 best for 64-bit
512
+
271
513
  switch (checksum) {
272
514
  case "4fb38daa851aacd21cf3aeaa92304df4e0353cae2b6dab3a5fd53c0cf4d42875b5efadbb4bb29642cbff07bfdd8e1c7a9c107f582905f7fc798c3841e888ee61":
273
515
  copyFileOldVersionIs("4.6.1", "<=");
@@ -275,7 +517,7 @@ function createPuiscreens() {
275
517
  case "2e63c0e9816f52b515c45479ada102af806bc73b79d14109567500c529bfaa166fb981ddb6062a1ba0a7f8e36a11d674a955d2f003806f21165cb26ad0fbdf33":
276
518
  copyFileOldVersionIs("4.7.0");
277
519
  break;
278
-
520
+
279
521
  case "b5eadc2df96e97de184cc331f133933c5f2945ab6c84997cfb30f2e6b478dfa6c8753bdb328b8257382f16a6d8e85b469af09f6d0eb872642300225590031c83":
280
522
  copyFileOldVersionIs("4.8.0");
281
523
  break;
@@ -284,7 +526,7 @@ function createPuiscreens() {
284
526
  case "b5e4d420d49d48c1dd08d0f50b88018fb64ee77248edcd9a656aee9f8ba723d0a91b18751f34cfc2efcd905f71834d5c2ac5cbff552fd85d164b710c3c2e079d":
285
527
  copyFileOldVersionIs("4.9.1");
286
528
  break;
287
-
529
+
288
530
  case "1d469f6d2e4549dc259155a4b00d8f278ea89dc3566e18860ed9f6ccd406db8a47b0b3cbc359b397c59feac6faeb6a7fdc6ce2edbd3f120e295464dd41dd28f8":
289
531
  copyFileOldVersionIs("4.11.1");
290
532
  break;
@@ -307,22 +549,26 @@ function createPuiscreens() {
307
549
  break;
308
550
 
309
551
  case "af04803ac52709fd25f6fc87ff3ea309ad03ee6a9631f32511a5aa32c5ae50f34fd0e38e0d47dea223ac0c5dfb595199c623a83772af830edd21378055403e5c":
310
- console.log("Found Standard puiscreens.json file version >= 6.0.0, no need for update.");
552
+ copyFileOldVersionIs("6.0.0");
553
+ break;
554
+
555
+ case "cd3e32138fbf1dac7755c233e1b5fc0d14f800694184c92989ddc5e62bacf86306013bcf423bf837183c979f61d6b323e0581363297ca6cf7f1b15435e0fbff5":
556
+ log("Found Standard puiscreens.json file version >= 6.0.0-beta.5, no need for update.");
311
557
  break;
312
-
558
+
313
559
  default:
314
560
  var puiScreens = JSON.parse(data);
315
- console.log("Found Customized puiscreens.json file, analyzing contents...");
561
+ log("Found Customized puiscreens.json file, analyzing contents...");
316
562
 
317
563
  // We need to check the signon screen and make sure we have lower case bound fields
318
564
  var goodUser = false, goodPassword = false, goodSubmit = false, goodError = false;
319
565
 
320
566
  formats:
321
- for (i in puiScreens.formats) {
567
+ for (var i in puiScreens.formats) {
322
568
  var format = puiScreens.formats[i];
323
569
 
324
570
  if (format.screen["record format name"].toLowerCase() === "signonscrn") {
325
- for (j in format.items) {
571
+ for (var j in format.items) {
326
572
  var itemValue = format.items[j].value;
327
573
  if (itemValue && typeof itemValue === "object") {
328
574
  if (itemValue.fieldName === "ssuser") goodUser = true;
@@ -344,680 +590,84 @@ function createPuiscreens() {
344
590
  }
345
591
 
346
592
  if (goodUser && goodPassword && goodSubmit && goodError) {
347
- console.log("The Customized puiscreens.json file is compatible, so leaving it in place. Creating puiscreens_orig.json");
348
- copyFile(setupDir + dirSep + "modules" + dirSep + "puiscreens.json", deployDir + dirSep + "modules" + dirSep + "puiscreens_orig.json", "utf8");
349
- console.log("puiscreens_orig.json created. For latest functionality, please migrate standard fields into your customized version.");
593
+ log("The Customized puiscreens.json file is compatible, so leaving it in place. Creating puiscreens_orig.json");
594
+ copyFile(path.join(__dirname, "modules", "puiscreens.json"), path.join(deployDir, "modules", "puiscreens_orig.json"), "utf8");
595
+ log("puiscreens_orig.json created. For latest functionality, please migrate standard fields into your customized version.");
350
596
  }
351
597
  else {
352
- console.log("The Customized puiscreens.json file is NOT compatible, backing it up to puiscreens_bak.json...");
353
- copyFile(deployDir + dirSep + "modules" + dirSep + "puiscreens.json", deployDir + dirSep + "modules" + dirSep + "puiscreens_bak.json", "utf8");
354
- console.log("puiscreens_bak.json created. Creating puiscreens.json ...");
355
- copyFile(setupDir + dirSep + "modules" + dirSep + "puiscreens.json", targetPuiScreensFile, "utf8");
356
- console.log("puiscreens.json created. Please migrate standard fields into your customized version.");
598
+ log("The Customized puiscreens.json file is NOT compatible, backing it up to puiscreens_bak.json...");
599
+ copyFile(path.join(deployDir, "modules", "puiscreens.json"), path.join(deployDir, "modules", "puiscreens_bak.json"), "utf8");
600
+ log("puiscreens_bak.json created. Creating puiscreens.json ...");
601
+ copyFile(path.join(__dirname, "modules", "puiscreens.json"), targetPuiScreensFile, "utf8");
602
+ log("puiscreens.json created. Please migrate standard fields into your customized version.");
357
603
  }
358
604
  }
359
605
  }
360
606
  else {
361
- console.log("Creating puiscreens.json.");
362
- copyFile(setupDir + dirSep + "modules" + dirSep + "puiscreens.json", targetPuiScreensFile, "utf8");
363
- }
364
- }
365
-
366
- function createPUIUPLEXIT() {
367
- if (fileExists(deployDir + dirSep + "modules" + dirSep + "puiuplexit.js")) {
368
- console.log("puiuplexit.js file exists.");
369
- }
370
- else {
371
- console.log("Creating puiuplexit.js.");
372
- copyFile(setupDir + dirSep + "modules" + dirSep + "puiuplexit.js", deployDir + dirSep + "modules", "utf8");
373
- }
374
- }
375
-
376
- function createPUIDNLEXIT() {
377
- if (fileExists(deployDir + dirSep + "modules" + dirSep + "puidnlexit.js")) {
378
- console.log("puidnlexit.js file exists.");
379
- }
380
- else {
381
- console.log("Creating puidnlexit.js.");
382
- copyFile(setupDir + dirSep + "modules" + dirSep + "puidnlexit.js", deployDir + dirSep + "modules", "utf8");
607
+ log("Creating puiscreens.json.");
608
+ copyFile(path.join(__dirname, "modules", "puiscreens.json"), targetPuiScreensFile, "utf8");
383
609
  }
384
610
  }
385
611
 
386
- function copyPjssamples() {
387
- if (directoryExists(deployDir + dirSep + "modules" + dirSep + "pjssamples"))
388
- fse.removeSync(deployDir + dirSep + "modules" + dirSep + "pjssamples");
389
- console.log("Copying pjssamples.");
390
- copyDir(setupDir + dirSep + "modules" + dirSep + "pjssamples", deployDir + dirSep + "modules");
391
- }
392
-
393
- function validateName(name) {
394
-
395
- name = name.trim().toUpperCase();
396
- var firstChar = name.substr(0, 1);
397
-
398
- if ((firstChar < "A" || firstChar > "Z") && firstChar != "#" && firstChar != "@" && firstChar != "$") {
399
- console.log("Name must start with an alpha character.");
400
- return false;
401
- }
402
- for (var i = 1; i < name.length; i++) {
403
- var chr = name.substr(i, 1);
404
- if ((chr < "A" || chr > "Z") && (chr < "0" || chr > "9") && chr != "#" && chr != "@" && chr != "$" && chr != "_" && chr != ".") {
405
- console.log("Name contains invalid characters.");
406
- return false;
407
- }
408
- }
409
-
410
- if (name.length > 10) {
411
- console.log("Name must be 10 characters or less.");
412
- return false;
612
+ function directoryExists(dir) {
613
+ var exists = false;
614
+ try {
615
+ var stat = fs.statSync(dir);
616
+ if (stat && stat.isDirectory()) exists = true;
413
617
  }
414
-
415
- return true;
416
- }
417
-
418
- function validateIASP(name) {
419
-
420
- if (name.trim().toUpperCase() == "*SYSBAS")
421
- return true;
422
- else return validateName(name);
423
-
424
- }
425
-
426
- function isURL(path) {
427
- if (typeof path !== "string") return false;
428
- path = path.toLowerCase();
429
- if (path.substr(0, 7) === "http://") return true;
430
- if (path.substr(0, 8) === "https://") return true;
431
- return false;
432
- }
433
-
434
- function validateDirectory(directory) {
435
- if (IBMi) {
436
- var ch = directory.substr(0, 1);
437
- if (ch !== "/" && ch !== "\\" && !isURL(directory)) {
438
- directory = deployDir + dirSep + directory;
439
- }
440
- if (!directoryExists(directory) && !isURL(directory)) {
441
- console.log("WARNING: The specified directory was not found. You can create it later or modify the staticFilesDirectory property in config.js.");
442
- console.log("");
443
- }
618
+ catch (err) {
619
+ exists = false;
444
620
  }
445
- return true; // accept any entry - if directory doesn't exist, simply warn
446
- }
447
-
448
- function validatePort(port) {
449
- if (port === "0") return true;
450
- port = Number(port);
451
- if (!isNaN(port) && port >= 1 && port <= 65535) return true;
452
- console.log("Invalid port number. Valid range is 0-65535.");
453
- return false;
621
+ return exists;
454
622
  }
455
623
 
456
-
457
- function isValidNodePath(nodePath) {
458
-
459
- if (!fileExists(nodePath)) {
460
- console.log("Path " + nodePath + " does not exist. A valid path name must be entered.");
461
- return false;
624
+ function fileExists(file) {
625
+ var exists = false;
626
+ try {
627
+ var stat = fs.statSync(file);
628
+ if (stat && stat.isFile()) exists = true;
462
629
  }
463
- return true;
464
- }
465
-
466
-
467
- function isValidCcsid(ccsid) {
468
-
469
- ccsid = Number(ccsid);
470
- if (isNaN(ccsid)) {
471
- console.log("Invalid CCSID. A numeric value is required.");
472
- return false;
630
+ catch (err) {
631
+ exists = false;
473
632
  }
474
-
475
- // Here's the list of valid CCSID's that can be used for jobs on IBM i
476
- if ([37, 256, 273, 277, 278, 280, 284, 285, 290, 297, 420, 423, 424, 425, 500, 833, 836, 838, 870, 871, 875, 880,
477
- 905, 918, 924, 930, 933, 935, 937, 939, 1025, 1026, 1027, 1047, 1097, 1112, 1122, 1123, 1130, 1132, 1137,
478
- 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1153, 1154, 1155, 1156, 1157, 1158, 1160, 1164,
479
- 1166, 1175, 1364, 1371, 1377, 1388, 1399, 4971, 5026, 5035, 5123, 5233, 8612, 9030, 12708, 13121, 13124,
480
- 28709, 57777, 61175, 62211, 62224, 62235, 62245, 62251].indexOf(ccsid) > -1)
481
- return true;
482
-
483
- console.log("Value " + ccsid + " is not a valid CCSID for the SBMJOB command.");
484
-
485
- return false;
486
- }
487
-
488
- function validateYesNo(answer) {
489
- answer = answer.toUpperCase();
490
- if (answer === "Y" || answer === "YES" || answer === "N" || answer === "NO") return true;
491
- console.log("Invalid answer. Use y or n.");
492
- return false;
633
+ return exists;
493
634
  }
494
635
 
495
- function getConnectorLibrary() {
496
-
497
- var ret = {};
498
- if (fileExists(deployDir + dirSep + "config.js")) {
499
-
500
- const config = require(deployDir + dirSep + "config.js");
636
+ function runCommand(command, switches) {
501
637
 
502
- if (config.connectorLibrary) {
503
- ret.name = config.connectorLibrary;
504
- if (config.connectorIASP)
505
- ret.IASP = config.connectorIASP;
506
- }
638
+ log("Executing IBM i command: " + command);
639
+ var args = [command];
640
+ if (typeof switches == "string") {
641
+ args.unshift(switches);
507
642
  }
508
-
509
- return ret;
510
- }
511
-
512
- function createConfig(profounduiLibrary, connectorLibrary, connectorIASP, callback) {
513
-
514
- if (fileExists(deployDir + dirSep + "config.js")) {
515
-
516
- // If the config already exists, check if any settings need to be updated
517
-
518
- if (!IBMi) {
519
- console.log("config.js file exists.");
520
- callback();
521
- return;
522
- }
523
-
524
- const config = require(deployDir + dirSep + "config.js");
525
- var isConfigChanged = false;
526
-
527
- // Check if it contains a profounduiLibrary setting
528
- if (profounduiLibrary) {
529
-
530
- var configProfounduiLibrary = getProfounduiLibrary();
531
-
532
- if (configProfounduiLibrary) {
533
-
534
- if (configProfounduiLibrary !== profounduiLibrary) {
535
- isConfigChanged = true;
536
- console.log("Updating profounduiLibrary setting in config.js from " + configProfounduiLibrary + " to " + profounduiLibrary + "...");
537
- config.profounduiLibrary = profounduiLibrary;
538
- }
539
-
540
- }
541
- else {
542
- isConfigChanged = true;
543
- console.log("config.js file exists, but does not have a profounduiLibrary setting, creating one now...");
544
- config.profounduiLibrary = profounduiLibrary;
545
- }
546
- }
547
-
548
-
549
- // Check if it contains a connectorLibrary setting
550
- if (connectorLibrary && connectorLibrary !== "*NONE") {
551
-
552
- var configConnectorLibrary = getConnectorLibrary();
553
-
554
- if (configConnectorLibrary.name) {
555
-
556
- if (configConnectorLibrary.name !== connectorLibrary) {
557
- isConfigChanged = true;
558
- console.log("Updating connectorLibrary setting in config.js from " + configConnectorLibrary.name + " to " + connectorLibrary + "...");
559
- config.connectorLibrary = connectorLibrary;
560
- }
561
-
562
- }
563
- else {
564
- isConfigChanged = true;
565
- console.log("config.js file exists, but does not have a connectorLibrary setting, creating one now...");
566
- config.connectorLibrary = connectorLibrary;
567
- }
568
-
569
- // Check if it contains a connectorIASP setting
570
- if (connectorIASP) {
571
-
572
- if (configConnectorLibrary.IASP) {
573
-
574
- if (configConnectorLibrary.IASP !== connectorIASP) {
575
- isConfigChanged = true;
576
- console.log("Updating connectorIASP setting in config.js from " + configConnectorLibrary.IASP + " to " + connectorIASP + "...");
577
- if (connectorIASP == "*SYSBAS")
578
- delete config.connectorIASP;
579
- else
580
- config.connectorIASP = connectorIASP;
581
- }
582
-
583
- }
584
- else if (connectorIASP != "*SYSBAS") {
585
- isConfigChanged = true;
586
- console.log("config.js file exists, but does not have a connectorIASP setting, creating one now...");
587
- config.connectorIASP = connectorIASP;
588
- }
589
- }
590
-
591
- }
592
-
593
-
594
-
595
- // Update config.js if we made any chanegs
596
- if (isConfigChanged) {
597
-
598
- fs.writeFile(deployDir + dirSep + "config.js", stringifyConfig(config), (err) => {
599
- if (err)
600
- console.log('An error occurred updating config.js file : ' + err);
601
- else
602
- console.log('config.js file has been updated.');
603
- callback();
604
- });
605
- }
606
- else
607
- callback();
643
+ else {
644
+ args.unshift("-e");
608
645
  }
609
- else {
610
-
611
- var defaultStaticDir = "htdocs";
612
- if (IBMi) {
613
- defaultStaticDir = "/www/profoundui/htdocs";
614
- if (!directoryExists(defaultStaticDir)) {
615
- console.log("WARNING: Profound UI Installation not found in default location.");
616
- }
617
- }
618
- else {
619
- console.log("");
620
- 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.");
621
- console.log("");
622
- }
623
-
624
- ask("Specify Profound UI static files directory", defaultStaticDir, validateDirectory, function(staticDir) {
625
- ask("Specify port number for Profound.js server", portNumber, validatePort, function(newPortNumber) {
626
- copyFile(setupDir + dirSep + "config.js", deployDir, "utf8", function(content) {
627
- var config = content.substr(content.indexOf("{"));
628
- eval("config = " + config);
629
- config.staticFilesDirectory = staticDir;
630
- config.port = Number(newPortNumber);
631
- if (connectorLibrary && connectorLibrary !== "*NONE") {
632
- config.connectorLibrary = connectorLibrary;
633
- if (connectorIASP != "*SYSBAS")
634
- config.connectorIASP = connectorIASP;
635
- }
636
- if (profounduiLibrary)
637
- config.profounduiLibrary = profounduiLibrary;
638
-
639
- if (IBMi)
640
- config.showIBMiParmDefn = true;
641
-
642
- // Check if this is a workspace (if so, default to mysql)
643
- if (!IBMi && fileExists(deployDir + dirSep + "modules" + dirSep + "app" + dirSep + ".noderun" + dirSep + "settings.json")) {
644
- if (config.databaseConnections) delete config.databaseConnections; // remove property so that it's appended at the end when we set it
645
- config.databaseConnections = [{
646
- name: "default",
647
- default: true,
648
- driver: "mysql",
649
- driverOptions: {
650
- user: "user-name",
651
- password: "your-password",
652
- host: "localhost",
653
- database: "database-name"
654
- }
655
- }];
656
- }
657
646
 
658
- portNumber = newPortNumber;
659
- content = "\nmodule.exports = ";
660
- content += JSON.stringify(config, null, " ");
661
- content += "\n";
662
- return content;
663
- });
664
- console.log("");
665
- console.log("config.js created.");
666
- console.log("");
667
-
668
- if (!IBMi && !isURL(staticDir)) {
669
- var absoluteStaticDir = path.resolve(deployDir, staticDir);
670
- if (!directoryExists(absoluteStaticDir)) {
671
- console.log("");
672
- console.log("The specified directory for Profound UI was not found.");
673
- ask("Should the installer create the directory and download a copy of Profound UI static files?", "y", validateYesNo, function(answer) {
674
- if (answer.toUpperCase() == "Y") {
675
- downloadHtdocs(absoluteStaticDir, callback);
676
- }
677
- else {
678
- callback();
679
- }
680
- });
681
- }
682
- else {
683
- callback();
684
- }
685
- }
686
- else {
687
- callback();
688
- }
689
- });
690
- });
691
- }
692
- }
647
+ const options = {
648
+ stdio: ["ignore", logFile, logFile],
649
+ cwd: __dirname,
650
+ env: {
651
+ QIBM_USE_DESCRIPTOR_STDIO: "Y",
652
+ QIBM_MULTI_THREADED: "N" // Many IBM commands cannot run in multi-threaded mode...
653
+ }};
693
654
 
694
- function finish() {
695
- process.stdin.destroy();
696
- console.log("");
697
- process.exit(0);
698
- }
655
+ const results = child_process.spawnSync("system", args, options);
699
656
 
700
- function runCommand(command, switches) {
701
- console.log("");
702
- console.log("Executing command: " + command);
703
- const child_process = require("child_process");
704
- var args = [command];
705
- if (typeof switches == "string")
706
- args.unshift(switches);
707
- else
708
- args.unshift("-e");
709
-
710
- // Many IBM commands cannot run in multi-threaded mode...
711
- var options = {stdio: "inherit", cwd: setupDir, env: {QIBM_USE_DESCRIPTOR_STDIO:"Y", QIBM_MULTI_THREADED:"N"}};
712
-
713
- var results = child_process.spawnSync(
714
- "system",
715
- args,
716
- options);
717
-
718
- var code = results.status;
719
- var signal = results.signal;
720
-
721
- if (code != null) {
657
+ const code = results.status;
658
+ const signal = results.signal;
659
+ if (code != null) {
722
660
  if (code === 0) {
723
- console.log("Command finished successfully.");
724
661
  return true;
725
662
  }
726
663
  else {
727
- console.log("Process exited, code %d", code);
664
+ logError("Process exited, code %d", code);
728
665
  }
729
666
  }
730
667
  else {
731
- console.log("Process ended due to signal %s", signal);
732
- console.log(results); // show full results including detailed error
668
+ logError("Process ended due to signal %s", signal);
669
+ logError(results); // show full results including detailed error
733
670
  }
734
671
  return false;
735
- }
736
-
737
-
738
- function getProfounduiLibrary() {
739
-
740
- if (fileExists(deployDir + dirSep + "config.js")) {
741
-
742
- const config = require(deployDir + dirSep + "config.js");
743
-
744
- if (config.profounduiLibrary) {
745
- return config.profounduiLibrary;
746
- }
747
- }
748
-
749
- return null;
750
- }
751
-
752
-
753
- function askPuiLibrary(callback) {
754
-
755
- var defaultProfounduiLibrary = getProfounduiLibrary();
756
-
757
- ask("Specify Profound UI installation library", (defaultProfounduiLibrary) ? defaultProfounduiLibrary : "PROFOUNDUI", validateName, function(puiLibrary) {
758
- callback(puiLibrary.trim().toUpperCase());
759
- });
760
-
761
- }
762
-
763
-
764
- function askConnector(callback) {
765
-
766
- ask("Install Profound.js Connector IBM i ILE components?", "y", validateYesNo, function(answer) {
767
-
768
- if (answer.toUpperCase() == "Y") {
769
-
770
- var connectorLibrary = getConnectorLibrary();
771
- ask("Enter Profound.js Connector library name:", (connectorLibrary.name) ? connectorLibrary.name : "PROFOUNDJS", validateName, function(answer) {
772
-
773
- var name = answer.trim().toUpperCase();
774
- ask("Enter Profound.js Connector library IASP:", (connectorLibrary.IASP) ? connectorLibrary.IASP : "*SYSBAS", validateIASP, function(answer) {
775
-
776
- callback(name, answer.trim().toUpperCase());
777
-
778
- });
779
-
780
- });
781
-
782
- }
783
- else {
784
-
785
- callback("*NONE");
786
-
787
- }
788
-
789
- });
790
- }
791
-
792
-
793
- function getServerInstances(instanceRootDir) {
794
-
795
- const serverInstances = [];
796
- if (directoryExists(pjsBaseInstance)) {
797
-
798
- const instanceDirs = fs.readdirSync(pjsBaseInstance);
799
- instanceDirs.forEach((instanceDir) => {
800
-
801
- let data
802
- try {
803
-
804
- data = fs.readFileSync(path.join(pjsBaseInstance, instanceDir, "/conf"), "utf8");
805
-
806
- }
807
- catch (error) {
808
-
809
- return;
810
-
811
- }
812
- let options = data.split('\n');
813
- let config = { name: instanceDir, autostart: "n", ccsid: 37, nodePath: "/QOpenSys/pkgs/bin/node" };
814
-
815
- options.forEach(option => {
816
-
817
- let parts = option.split('=');
818
- let configOption = parts[0].trim();
819
-
820
- switch (configOption) {
821
- case 'path':
822
- config.path = parts[1].trim();
823
- break;
824
- case 'nodePath':
825
- config.nodePath = parts[1].trim();
826
- break;
827
- case 'nodeArgs':
828
- config.nodeArgs = parts[1].trim();
829
- break;
830
- case 'autostart':
831
- config.autostart = (parts[1].trim() === '1') ? 'y' : 'n';
832
- break;
833
- case 'ccsid':
834
- config.ccsid = parts[1].trim();
835
- break;
836
- case '':
837
- break;
838
- default:
839
- break;
840
- }
841
- });
842
- if (config.path === instanceRootDir + dirSep + 'start.js')
843
- serverInstances.push(config);
844
-
845
- });
846
-
847
- }
848
- if (serverInstances.length === 0)
849
- serverInstances.push({ name: "PROFOUNDJS", autostart: "y", ccsid: 37, nodePath: "/QOpenSys/pkgs/bin/node" });
850
- return serverInstances;
851
-
852
- }
853
-
854
-
855
- function askServerInstance(callback) {
856
-
857
- serverInstances = getServerInstances(deployDir);
858
-
859
- if (serverInstances.length > 1) {
860
- console.log('\nWARNING - Multiple STRTCPSVR/ENDTCPSVR instances found for this server in ' + pjsBaseInstance + ' : -\n');
861
- serverInstances.forEach(serverInstance => {
862
- console.log(JSON.stringify(serverInstance));
863
- });
864
- }
865
-
866
- ask("\nCreate/replace server instance configuration for STRTCPSVR/ENDTCPSVR commands?", "y", validateYesNo, function(answer) {
867
-
868
- if (answer.toUpperCase() == "Y") {
869
-
870
- ask("Server instance name:", serverInstances[0].name.toUpperCase(), validateName, function(answer) {
871
-
872
- var svrname = answer.trim().toUpperCase();
873
-
874
- ask("Specify CCSID for instance " + svrname, serverInstances[0].ccsid, isValidCcsid, function(ccsid) {
875
-
876
- ask("Specify Node.js path for instance " + svrname, serverInstances[0].nodePath, isValidNodePath, function(nodePath) {
877
-
878
- ask("Autostart server instance " + svrname + " when TCP/IP starts?", serverInstances[0].autostart, validateYesNo, function(answer) {
879
-
880
- var autostart = (answer.toUpperCase() == "Y");
881
- callback(svrname, autostart, ccsid, nodePath);
882
-
883
- });
884
- });
885
- });
886
- });
887
-
888
- }
889
- else {
890
-
891
- callback("*NONE");
892
-
893
- }
894
-
895
- });
896
- }
897
-
898
-
899
- function stringifyConfig(config) {
900
-
901
- // JavaScript functions (like connectorIPFilter) will be lost when doing JSON.stringify,
902
- // so we need to do some magic to preserve them.
903
-
904
- let funkz = [];
905
- let configString = "\nmodule.exports = ";
906
-
907
- configString += JSON.stringify(config, (key, val) => {
908
- if (typeof val === 'function') {
909
- let n = funkz.length;
910
- funkz.push(val.toString());
911
- return `___function${n}___`;
912
- }
913
- return val;
914
- }, " ");
915
-
916
- configString += "\n";
917
-
918
- for (var i=0; i<funkz.length; i++) {
919
- configString = configString.replace(`"___function${i}___"`, funkz[i]);
920
- }
921
-
922
- return configString;
923
-
924
- }
925
-
926
-
927
- if (["win32", "darwin", "linux"].includes(os.platform()))
928
- installNodeGit();
929
- createPackageFile();
930
- createModulesDirectory();
931
- createPuiscreens();
932
- createPUIUPLEXIT();
933
- createPUIDNLEXIT();
934
- copyPjssamples();
935
-
936
- createStoreCredentials(function() {
937
- createUpdatepui(function() {
938
- createCall(function() {
939
- createStart(function() {
940
- if (IBMi && !silent) {
941
- console.log("");
942
- askPuiLibrary(function(profounduiLibrary) {
943
- askConnector(function(connectorLibrary, connectorIASP) {
944
- createConfig(profounduiLibrary, connectorLibrary, connectorIASP, function() {
945
- askServerInstance(function(svrname, autostart, ccsid, nodePath) {
946
- if (connectorLibrary != "*NONE" || svrname != "*NONE") {
947
- // First, try copying the save file
948
- var success = runCommand("CPYFRMSTMF FROMSTMF('" + setupDir + dirSep + "pjsdist.savf') TOMBR('/QSYS.LIB/QGPL.LIB/PJSDIST.FILE') MBROPT(*REPLACE)");
949
- if (success) {
950
- // Now, try restoring the PJSINSTALL program
951
- success = runCommand("RSTOBJ OBJ(PJSINSTALL) SAVLIB(QTEMP) DEV(*SAVF) OBJTYPE(*ALL) SAVF(QGPL/PJSDIST) RSTLIB(QGPL)");
952
- if (success) {
953
- // Now, try running PJSINSTALL
954
- var command = "QGPL/PJSINSTALL CONNLIB(" + connectorLibrary + ")";
955
- if (connectorLibrary != "*NONE")
956
- command += " CONNIASP(" + connectorIASP + ") CONNHOST('localhost') CONNPORT(" + portNumber + ")";
957
- command += " SVRNAME(" + svrname + ")";
958
- if (svrname != "*NONE")
959
- command += " SVRDIR('" + deployDir + "') " +
960
- "SVRAUTO(" + ((autostart) ? "*YES" : "*NO") + ") CCSID(" + ccsid + ") NODEPATH('" + nodePath + "')";
961
- success = runCommand(command, "-Ke");
962
- // Clean up program and save file
963
- console.log("");
964
- console.log("Cleaning up...");
965
- runCommand("DLTPGM PGM(QGPL/PJSINSTALL)");
966
- runCommand("DLTCMD CMD(QGPL/PJSINSTALL)");
967
- runCommand("DLTPNLGRP PNLGRP(QGPL/PJSINSTALL)");
968
- runCommand("DLTMSGF MSGF(QGPL/PJSINSTALL)");
969
- runCommand("DLTF FILE(QGPL/PJSDIST)");
970
- console.log("");
971
- if (success) {
972
- console.log("Profound.js successfully installed.");
973
- }
974
- else {
975
- console.log("Profound.js did NOT install successfully! Check messages above.");
976
- }
977
- }
978
- else {
979
- // Clean up save file
980
- console.log("");
981
- console.log("Cleaning up...");
982
- runCommand("DLTF FILE(QGPL/PJSDIST)");
983
- console.log("");
984
- console.log("Profound.js did NOT install successfully! Check messages above.");
985
- }
986
- }
987
- else {
988
- console.log("");
989
- console.log("Profound.js did NOT install successfully! Check messages above.");
990
- }
991
- finish();
992
- }
993
- else {
994
- finish();
995
- }
996
- });
997
- });
998
- });
999
- });
1000
- }
1001
- else {
1002
- createConfig(null, null, null, function() {
1003
- console.log("");
1004
- console.log("Installation completed.");
1005
- finish();
1006
- });
1007
- }
1008
- });
1009
- });
1010
- });
1011
- });
1012
-
1013
- function installNodeGit() {
1014
-
1015
- child_process.execSync(
1016
- "npm install nodegit",
1017
- {
1018
- cwd: path.resolve(__dirname, ".."),
1019
- stdio: ["ignore", "inherit", "inherit"]
1020
- }
1021
- );
1022
672
 
1023
673
  }