From 69107373741447db774cd89877e625042b407177 Mon Sep 17 00:00:00 2001 From: jake87 Date: Mon, 25 Oct 2021 21:58:56 +1100 Subject: [PATCH 01/45] Added function in lib/file_ops.js to return a temp filename with salt --- packages/lib/file_ops.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index bc5fe91e..cbb36c97 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -4,7 +4,7 @@ "use strict"; const fs = require("fs-extra"); const path = require("path"); - +const crypto = require("crypto"); // needed for getTempFile /** * Returns the newest file in a directory * @@ -68,8 +68,29 @@ async function findUnusedName(directory, name, extension = "") { } } } +/** + * Returns a path to a temporary file. + * + * Warning: this function should not be relied upon to be accurate for + * security sensitive applications. The selection process is inherently + * racy and a file or folder may have been created in the folder by the time + * this function returns. + * + * @param {string} prefix - prefix for file + * @param {string} suffix - suffix for file + * @param {string} tmpdir - directory for file + */ +async function getTempFile(prefix, suffix, tmpdir) { + prefix = (typeof prefix !== "undefined") ? prefix : "tmp."; + suffix = (typeof suffix !== "undefined") ? suffix : ""; + tmpdir = tmpdir ? tmpdir : os.tmpdir(); + return path.join(tmpdir, prefix + crypto.randomBytes(16).toString("hex") + suffix); + // IMO, 16 bytes of random hex should be fine, and hex is allowable in any filesystem, but if + // some other system is better, please inform +} module.exports = { getNewestFile, findUnusedName, + getTempFile, }; From 4f9a8fb45c141b3719e1b727150c6e034bb068d5 Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 26 Oct 2021 17:50:39 +1100 Subject: [PATCH 02/45] Rewrote temp function to be safer, using findUnusedName --- packages/lib/file_ops.js | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index cbb36c97..82cc9846 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -68,29 +68,19 @@ async function findUnusedName(directory, name, extension = "") { } } } -/** - * Returns a path to a temporary file. - * - * Warning: this function should not be relied upon to be accurate for - * security sensitive applications. The selection process is inherently - * racy and a file or folder may have been created in the folder by the time - * this function returns. - * - * @param {string} prefix - prefix for file - * @param {string} suffix - suffix for file - * @param {string} tmpdir - directory for file - */ + async function getTempFile(prefix, suffix, tmpdir) { prefix = (typeof prefix !== "undefined") ? prefix : "tmp."; suffix = (typeof suffix !== "undefined") ? suffix : ""; tmpdir = tmpdir ? tmpdir : os.tmpdir(); - return path.join(tmpdir, prefix + crypto.randomBytes(16).toString("hex") + suffix); - // IMO, 16 bytes of random hex should be fine, and hex is allowable in any filesystem, but if - // some other system is better, please inform + let fullname = path.join(prefix + crypto.randomBytes(16).toString("hex") + suffix); + let fullpath = path.join(tmpdir, findUnusedName(tmpdir, fullname)); + // If the path is not still zero, return the path, but otherwise return -1 to indicate failure } module.exports = { getNewestFile, findUnusedName, getTempFile, + checkIfFileExists, }; From ed73e3ad1ed735e7cca10ae859afa03a1fc07d75 Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 26 Oct 2021 18:43:21 +1100 Subject: [PATCH 03/45] Fixed variable naming issue with file_ops.getTempFile --- packages/lib/file_ops.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index 82cc9846..d14f87f1 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -73,14 +73,13 @@ async function getTempFile(prefix, suffix, tmpdir) { prefix = (typeof prefix !== "undefined") ? prefix : "tmp."; suffix = (typeof suffix !== "undefined") ? suffix : ""; tmpdir = tmpdir ? tmpdir : os.tmpdir(); - let fullname = path.join(prefix + crypto.randomBytes(16).toString("hex") + suffix); - let fullpath = path.join(tmpdir, findUnusedName(tmpdir, fullname)); - // If the path is not still zero, return the path, but otherwise return -1 to indicate failure + let fileName = path.join(prefix + crypto.randomBytes(16).toString("hex") + suffix); + let fullPath = path.join(tmpdir, findUnusedName(tmpdir, fullname)); + return fullpath; } module.exports = { getNewestFile, findUnusedName, getTempFile, - checkIfFileExists, }; From f266c441db5ecefd1fb90d4f01ee27afe5d638ce Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 26 Oct 2021 20:43:07 +1100 Subject: [PATCH 04/45] Fixed async logic within lib/file_ops.js --- packages/lib/file_ops.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index d14f87f1..2975df50 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -72,10 +72,11 @@ async function findUnusedName(directory, name, extension = "") { async function getTempFile(prefix, suffix, tmpdir) { prefix = (typeof prefix !== "undefined") ? prefix : "tmp."; suffix = (typeof suffix !== "undefined") ? suffix : ""; - tmpdir = tmpdir ? tmpdir : os.tmpdir(); + tmpdir = (typeof tmpdir !== "undefined") ? tmpdir : "./"; let fileName = path.join(prefix + crypto.randomBytes(16).toString("hex") + suffix); - let fullPath = path.join(tmpdir, findUnusedName(tmpdir, fullname)); - return fullpath; + let freeFile = await findUnusedName(tmpdir, fileName); + let fullPath = path.join(tmpdir, freeFile); + return fullPath; } module.exports = { From 14b3331c8ece2adf8b3358af01b6e521e87c9a49 Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 26 Oct 2021 20:44:15 +1100 Subject: [PATCH 05/45] Added basic logic for config edit command Added groundwork for the ctl master config edit command, including temporary file grabbing and JSON config fetching. --- packages/ctl/ctl.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index ac01a274..610fd352 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -14,6 +14,8 @@ const path = require("path"); const winston = require("winston"); const setBlocking = require("set-blocking"); const phin = require("phin"); +const os = require("os"); +const child_process = require("child_process"); const libLink = require("@clusterio/lib/link"); const libErrors = require("@clusterio/lib/errors"); @@ -104,6 +106,22 @@ masterConfigCommands.add(new libCommand.Command({ await libLink.messages.setMasterConfigProp.send(control, request); }, })); + +masterConfigCommands.add(new libCommand.Command({ + definition: ["edit [editor]", "Edit master configuration", (yargs) => { + yargs.positional("editor", { describe: "Editor to use", + type: "string", + default: "" }); + }], + handler: async function(args, control) { + let response = await libLink.messages.getMasterConfig.send(control); + let jsonConfig = await JSON.stringify(response); + let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); + print(jsonConfig); + print(tmpFile); + }, +})); + masterCommands.add(masterConfigCommands); From 23d8a819af46db94f68979c9c8c281ffad720d1f Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 26 Oct 2021 21:23:23 +1100 Subject: [PATCH 06/45] Added basic framework for edit command Implimented framework for edit command, including ability to get a temp file, open an editor on the file, then resume code execution once the editor exits. --- packages/ctl/ctl.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 610fd352..0396fe26 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -115,10 +115,27 @@ masterConfigCommands.add(new libCommand.Command({ }], handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); - let jsonConfig = await JSON.stringify(response); + let usefulData = response.serialized_config.groups[0]["fields"]; + let configJson = JSON.stringify(usefulData, null, "\t"); + /** + * Indent JSON with a tab for readability; these temp vars are simply + * for readability, they can be removed if wanted + */ let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); - print(jsonConfig); - print(tmpFile); + let done = 0; + let editorSpawn = child_process.spawn("nvim", [tmpFile], { + stdio: "inherit", + detached: true, + }); + editorSpawn.on("data", (data) => { + process.stdout.pipe(data); + }); + editorSpawn.on("err", (err) => { + print(err); + }); + editorSpawn.on("exit", (exit) => { + print("veryline"); + }); }, })); From c9fd99589be211134832d76d4cea7f200b9d7111 Mon Sep 17 00:00:00 2001 From: jake87 Date: Wed, 27 Oct 2021 20:16:37 +1100 Subject: [PATCH 07/45] Added more selection options for the edit ctl master config edit [editor] is the new structure; it can take an optional editor, and will prio this editor over any other editor, such as one set by env vars. Generally, the prio goes like this: argv supplied editor > EDITOR env var > VISUAL env var. Things needing to be done are marked with a TODO. --- packages/ctl/ctl.js | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 0396fe26..e7297b29 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -116,25 +116,41 @@ masterConfigCommands.add(new libCommand.Command({ handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); let usefulData = response.serialized_config.groups[0]["fields"]; - let configJson = JSON.stringify(usefulData, null, "\t"); - /** - * Indent JSON with a tab for readability; these temp vars are simply - * for readability, they can be removed if wanted - */ + // We don't need a significant amount of the response let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); - let done = 0; - let editorSpawn = child_process.spawn("nvim", [tmpFile], { + let editor = 0; + if (args.editor) { + editor = args.editor; + // eslint-disable-next-line + } else if (process.env.EDITOR) { + // eslint-disable-next-line + editor = process.env.EDITOR; + // eslint-disable-next-line + } else if (process.env.VISUAL) { + // eslint-disable-next-line + editor = process.env.VISUAL + // TODO: Don't have eslint-disable comments every line + } else { + print("No editor avalible to use. Checked CLI input, EDITOR env var and VISUAL env var"); + exit(1); // TODO: exit gracefully apon no editor + } + // <-- start process of running editor --> + let editorSpawn = child_process.spawn(editor, [tmpFile], { stdio: "inherit", detached: true, - }); + }); // TODO: Exit gracefully if editor not found editorSpawn.on("data", (data) => { process.stdout.pipe(data); }); editorSpawn.on("err", (err) => { print(err); + exit(1); // TODO: exit gracefully apon error from editor }); + // <-- end process of starting editor --> editorSpawn.on("exit", (exit) => { - print("veryline"); + // from here is when the edit exits, i.e. the user has quit + let mg = libConfig.MasterGroup; + let config_definitions = mg._definitions; }); }, })); From f548ac2ecc15a6771a022f467834569f24274963 Mon Sep 17 00:00:00 2001 From: jake87 Date: Fri, 29 Oct 2021 20:42:32 +1100 Subject: [PATCH 08/45] Added more logic into ctl.js Now prints out a basic approximation of the final look of the config file; with comments on the function of each part. --- packages/ctl/ctl.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index e7297b29..b6038d13 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -116,20 +116,19 @@ masterConfigCommands.add(new libCommand.Command({ handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); let usefulData = response.serialized_config.groups[0]["fields"]; + print(response); // We don't need a significant amount of the response let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = 0; if (args.editor) { editor = args.editor; - // eslint-disable-next-line + /* eslint-disable */ } else if (process.env.EDITOR) { - // eslint-disable-next-line editor = process.env.EDITOR; - // eslint-disable-next-line } else if (process.env.VISUAL) { - // eslint-disable-next-line editor = process.env.VISUAL - // TODO: Don't have eslint-disable comments every line + /* eslint-enable */ + // needed for the process.env statements to not be flagged by eslint } else { print("No editor avalible to use. Checked CLI input, EDITOR env var and VISUAL env var"); exit(1); // TODO: exit gracefully apon no editor @@ -151,6 +150,16 @@ masterConfigCommands.add(new libCommand.Command({ // from here is when the edit exits, i.e. the user has quit let mg = libConfig.MasterGroup; let config_definitions = mg._definitions; + let configElement = null; + let test_str = ""; + for (configElement in usefulData) { + if (usefulData.hasOwnProperty(configElement)) { + let description = config_definitions.get(configElement).description; + let configElementValue = JSON.stringify(usefulData[configElement]); + test_str += `# ${description}\n${configElement} = ${configElementValue} \n\n`; + } + } + print(test_str); }); }, })); From 0564eee400fc5095d3e4ba15360ac5b60afd67b7 Mon Sep 17 00:00:00 2001 From: jake87 Date: Fri, 29 Oct 2021 22:09:01 +1100 Subject: [PATCH 09/45] Experementing with the master config no important work, commit for my own sake --- packages/ctl/ctl.js | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index b6038d13..04d7d568 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -115,9 +115,7 @@ masterConfigCommands.add(new libCommand.Command({ }], handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); - let usefulData = response.serialized_config.groups[0]["fields"]; - print(response); - // We don't need a significant amount of the response + let usefulData = response.serialized_config; let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = 0; if (args.editor) { @@ -133,6 +131,8 @@ masterConfigCommands.add(new libCommand.Command({ print("No editor avalible to use. Checked CLI input, EDITOR env var and VISUAL env var"); exit(1); // TODO: exit gracefully apon no editor } + + // <-- start process of running editor --> let editorSpawn = child_process.spawn(editor, [tmpFile], { stdio: "inherit", @@ -146,20 +146,13 @@ masterConfigCommands.add(new libCommand.Command({ exit(1); // TODO: exit gracefully apon error from editor }); // <-- end process of starting editor --> + + editorSpawn.on("exit", (exit) => { + let masterConfig = new libConfig.MasterConfig("control"); + // eslint-disable-next-line + masterConfig.load(response); // from here is when the edit exits, i.e. the user has quit - let mg = libConfig.MasterGroup; - let config_definitions = mg._definitions; - let configElement = null; - let test_str = ""; - for (configElement in usefulData) { - if (usefulData.hasOwnProperty(configElement)) { - let description = config_definitions.get(configElement).description; - let configElementValue = JSON.stringify(usefulData[configElement]); - test_str += `# ${description}\n${configElement} = ${configElementValue} \n\n`; - } - } - print(test_str); }); }, })); From b6306031dc97e99ce736eb286720b34eda0ad9d7 Mon Sep 17 00:00:00 2001 From: jake87 Date: Fri, 29 Oct 2021 22:21:46 +1100 Subject: [PATCH 10/45] Reworked some of editor logic to work with async functions Now async functions can be used after the editor returns, as before they couldnt be used due to .on being non-async. --- packages/ctl/ctl.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 04d7d568..139dae1a 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -132,6 +132,9 @@ masterConfigCommands.add(new libCommand.Command({ exit(1); // TODO: exit gracefully apon no editor } + async function afterEditorDone() { + print("editordone"); + } // <-- start process of running editor --> let editorSpawn = child_process.spawn(editor, [tmpFile], { @@ -149,9 +152,7 @@ masterConfigCommands.add(new libCommand.Command({ editorSpawn.on("exit", (exit) => { - let masterConfig = new libConfig.MasterConfig("control"); - // eslint-disable-next-line - masterConfig.load(response); + afterEditorDone(); // from here is when the edit exits, i.e. the user has quit }); }, From 77e9b929dc4634c8a7f85e360ba96b76ea82e2ac Mon Sep 17 00:00:00 2001 From: jake87 Date: Sat, 30 Oct 2021 12:31:20 +1100 Subject: [PATCH 11/45] Testing why config not being returned correctly --- packages/ctl/ctl.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 139dae1a..6453d797 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -115,7 +115,6 @@ masterConfigCommands.add(new libCommand.Command({ }], handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); - let usefulData = response.serialized_config; let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); let editor = 0; if (args.editor) { @@ -133,7 +132,11 @@ masterConfigCommands.add(new libCommand.Command({ } async function afterEditorDone() { - print("editordone"); + print(JSON.stringify(response.serialized_config)); + let masterConfig = new libConfig.MasterConfig("control"); + await masterConfig.load(response.serialized_config); + await masterConfig.init(); + print(JSON.stringify(libConfig.MasterConfig.groups)); } // <-- start process of running editor --> @@ -148,13 +151,10 @@ masterConfigCommands.add(new libCommand.Command({ print(err); exit(1); // TODO: exit gracefully apon error from editor }); - // <-- end process of starting editor --> - - editorSpawn.on("exit", (exit) => { afterEditorDone(); - // from here is when the edit exits, i.e. the user has quit }); + // <-- end process of starting editor --> }, })); From 08a8182173b9c26342bc0c56616cf9130d2e524c Mon Sep 17 00:00:00 2001 From: jake87 Date: Mon, 1 Nov 2021 20:40:44 +1100 Subject: [PATCH 12/45] Reworked to use `throw error`, added system for getting config groups Now using `throw error` to exit out, instead of exit(1). Reworked config get system to use the map of configs in libConfig.MasterConfig.groups . --- packages/ctl/ctl.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 6453d797..eb4c04c4 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -106,7 +106,6 @@ masterConfigCommands.add(new libCommand.Command({ await libLink.messages.setMasterConfigProp.send(control, request); }, })); - masterConfigCommands.add(new libCommand.Command({ definition: ["edit [editor]", "Edit master configuration", (yargs) => { yargs.positional("editor", { describe: "Editor to use", @@ -127,33 +126,37 @@ masterConfigCommands.add(new libCommand.Command({ /* eslint-enable */ // needed for the process.env statements to not be flagged by eslint } else { - print("No editor avalible to use. Checked CLI input, EDITOR env var and VISUAL env var"); - exit(1); // TODO: exit gracefully apon no editor + print(); + throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); } async function afterEditorDone() { - print(JSON.stringify(response.serialized_config)); - let masterConfig = new libConfig.MasterConfig("control"); - await masterConfig.load(response.serialized_config); - await masterConfig.init(); - print(JSON.stringify(libConfig.MasterConfig.groups)); + let MainConfig = new libConfig.MasterConfig("exampleonetwothree123"); + await MainConfig.load(response.serialized_config, "exampleonetwothree123"); + let groups = Array.from(libConfig.MasterConfig.groups.keys()); + // convert from MapIterator to array + let mainConfigGroups = []; + for (let i = 0; i < groups.length; i++) { + mainConfigGroups[i] = MainConfig.group(groups[i]); + } } // <-- start process of running editor --> let editorSpawn = child_process.spawn(editor, [tmpFile], { stdio: "inherit", detached: true, - }); // TODO: Exit gracefully if editor not found + }); editorSpawn.on("data", (data) => { process.stdout.pipe(data); }); editorSpawn.on("err", (err) => { print(err); - exit(1); // TODO: exit gracefully apon error from editor + throw new libErrors.CommandError("Editor throwed error."); }); editorSpawn.on("exit", (exit) => { afterEditorDone(); }); + // this is more verbose then it probably needs to be, but IMO this is more readable // <-- end process of starting editor --> }, })); From 92814aa9b32be297bde5f5ef3bd5142f7f590909 Mon Sep 17 00:00:00 2001 From: jake87 Date: Fri, 5 Nov 2021 23:24:13 +1100 Subject: [PATCH 13/45] Reworked to use config list's grabber system Also now using the system described by Hornwitser, in using libConfig.MasterConfig.groups to get definitions. Now all that's needed is to re-read the updated data back into clustorio. --- packages/ctl/ctl.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index eb4c04c4..abf97e1e 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -126,20 +126,26 @@ masterConfigCommands.add(new libCommand.Command({ /* eslint-enable */ // needed for the process.env statements to not be flagged by eslint } else { - print(); throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); } - - async function afterEditorDone() { - let MainConfig = new libConfig.MasterConfig("exampleonetwothree123"); - await MainConfig.load(response.serialized_config, "exampleonetwothree123"); - let groups = Array.from(libConfig.MasterConfig.groups.keys()); - // convert from MapIterator to array - let mainConfigGroups = []; - for (let i = 0; i < groups.length; i++) { - mainConfigGroups[i] = MainConfig.group(groups[i]); + let allConfigElements = ""; + for (let group of response.serialized_config.groups) { + for (let [name, value] of Object.entries(group.fields)) { + // needed for line lenght; IMO this is more readable then using a temp var + // eslint-disable-next-line + allConfigElements += `# ${libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description}\n`; + allConfigElements += `${group.name}.${name} ${JSON.stringify(value)}\n\n`; } } + print(allConfigElements); + fs.writeFile(tmpFile, allConfigElements, (err) => { + if (err) { + throw err; + } + }); + print(allConfigElements); + async function afterEditorDone() { + } // <-- start process of running editor --> let editorSpawn = child_process.spawn(editor, [tmpFile], { From 4398d33fea17389dbaaa93d46f4e943a5f44e9bb Mon Sep 17 00:00:00 2001 From: jake87 Date: Fri, 5 Nov 2021 23:32:18 +1100 Subject: [PATCH 14/45] Fixed definitions to be consistant with bullet points. --- packages/lib/config/definitions.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/lib/config/definitions.js b/packages/lib/config/definitions.js index 0df15e2f..6744e8ff 100644 --- a/packages/lib/config/definitions.js +++ b/packages/lib/config/definitions.js @@ -15,7 +15,7 @@ MasterGroup.groupName = "master"; MasterGroup.define({ name: "name", title: "Name", - description: "Name of the cluster", + description: "Name of the cluster.", type: "string", initial_value: "Your Cluster", }); @@ -83,7 +83,7 @@ MasterGroup.define({ MasterGroup.define({ name: "heartbeat_interval", title: "Heartbeat Interval", - description: "Interval heartbeats are sent out on WebSocket connections", + description: "Interval heartbeats are sent out on WebSocket connections.", type: "number", initial_value: 15, }); @@ -97,21 +97,21 @@ MasterGroup.define({ MasterGroup.define({ name: "metrics_timeout", title: "Metrics Timeout", - description: "Timeout in seconds for metrics gathering from slaves", + description: "Timeout in seconds for metrics gathering from slaves.", type: "number", initial_value: 8, }); MasterGroup.define({ name: "proxy_stream_timeout", title: "Proxy Stream Timeout", - description: "Timeout in seconds for proxy streams to start flowing", + description: "Timeout in seconds for proxy streams to start flowing.", type: "number", initial_value: 15, }); MasterGroup.define({ name: "default_role_id", title: "Default role", - description: "ID of role assigned by default to new users", + description: "ID of role assigned by default to new users.", type: "number", optional: true, initial_value: 1, From 71fb8541d519376905d03bc9eec96be16d65c188 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sat, 6 Nov 2021 14:32:13 +1100 Subject: [PATCH 15/45] Added more comments, added quotes around strings --- packages/ctl/ctl.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index abf97e1e..5a7eddf0 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -125,25 +125,33 @@ masterConfigCommands.add(new libCommand.Command({ editor = process.env.VISUAL /* eslint-enable */ // needed for the process.env statements to not be flagged by eslint + // prio for editors is CLI arg > env.EDITOR > env.VISUAL } else { throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); } + let allConfigElements = ""; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { - // needed for line lenght; IMO this is more readable then using a temp var - // eslint-disable-next-line - allConfigElements += `# ${libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description}\n`; - allConfigElements += `${group.name}.${name} ${JSON.stringify(value)}\n\n`; + if (typeof value === "string") { + value = `\"${value}\"`; + } + // put quotes around value if it's a string + + let desc = libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; + allConfigElements += `# ${desc}\n`; + // split onto two lines for readability and es-lint + + allConfigElements += `${group.name}.${name} ${value}\n\n`; } } - print(allConfigElements); + // use same method as master config list to grab values, with a small modification to add quotes around strings fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; } }); - print(allConfigElements); + async function afterEditorDone() { } @@ -156,8 +164,7 @@ masterConfigCommands.add(new libCommand.Command({ process.stdout.pipe(data); }); editorSpawn.on("err", (err) => { - print(err); - throw new libErrors.CommandError("Editor throwed error."); + throw new libErrors.CommandError(err); }); editorSpawn.on("exit", (exit) => { afterEditorDone(); From 6013fcd5282b88f99a1aea3a13e8bc735b005748 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sat, 6 Nov 2021 17:04:34 +1100 Subject: [PATCH 16/45] Started rework of file loading system --- packages/ctl/ctl.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 5a7eddf0..b41f3a35 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -151,26 +151,6 @@ masterConfigCommands.add(new libCommand.Command({ throw err; } }); - - async function afterEditorDone() { - } - - // <-- start process of running editor --> - let editorSpawn = child_process.spawn(editor, [tmpFile], { - stdio: "inherit", - detached: true, - }); - editorSpawn.on("data", (data) => { - process.stdout.pipe(data); - }); - editorSpawn.on("err", (err) => { - throw new libErrors.CommandError(err); - }); - editorSpawn.on("exit", (exit) => { - afterEditorDone(); - }); - // this is more verbose then it probably needs to be, but IMO this is more readable - // <-- end process of starting editor --> }, })); From bcc25047f2ae59a8dceecb7cb46316894df298ee Mon Sep 17 00:00:00 2001 From: jake87 Date: Sat, 13 Nov 2021 22:35:15 +1100 Subject: [PATCH 17/45] Readded config file editing, working on config file value setting --- packages/ctl/ctl.js | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index b41f3a35..d5d51b06 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -142,15 +142,55 @@ masterConfigCommands.add(new libCommand.Command({ allConfigElements += `# ${desc}\n`; // split onto two lines for readability and es-lint - allConfigElements += `${group.name}.${name} ${value}\n\n`; + allConfigElements += `${group.name}.${name} = ${value}\n\n`; } } // use same method as master config list to grab values, with a small modification to add quotes around strings + // this could be shorter but the lines would have to be very long, so imo this is better for readability fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; } }); + let editorSpawn = child_process.spawn(editor, [tmpFile], { + stdio: "inherit", + detached: false, + }); + editorSpawn.on("data", (data) => { + process.stdout.pipe(data); + }); + function readTmpFile(c2) { + fs.readFile(tmpFile, "utf8", (err, data) => { + if (err) { throw err; } + let splitData = data.split(/\r?\n/); + // split on newlines + let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); + // the last filter removes empty elements left by the first. Not done on one line due to readability. + let final = []; + for (let index in filtered) { + if (index in filtered) { + filtered[index] = filtered[index].split("="); + // split on the = we added eariler + filtered[index][1] = filtered[index][1].replace(/['"]+/g, ""); + // remove quotes we added eariler + final[filtered[index][0].trim()] = filtered[index][1].trim(); + // trim whitespace and put in final array for processing + } + } + for (let element in final) { + if (element in final) { + libLink.messages.setMasterConfigField.send(control, { + field: element, + value: final[element], + }); + } + } + }); + } + editorSpawn.once("exit", (exit) => { + print("once"); + readTmpFile(control); + }); }, })); From 86de5ae151174d7df32e628627b0c84f64946545 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 14 Nov 2021 20:51:06 +1100 Subject: [PATCH 18/45] Fixed config editing, fixed child spawning, fixed config setting Using an event emmiter, the fields can now be set correctly in the master config. Null values are now handled correctly, and numbers are also set correctly. --- packages/ctl/ctl.js | 66 +++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index d5d51b06..a121b100 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -147,7 +147,7 @@ masterConfigCommands.add(new libCommand.Command({ } // use same method as master config list to grab values, with a small modification to add quotes around strings // this could be shorter but the lines would have to be very long, so imo this is better for readability - fs.writeFile(tmpFile, allConfigElements, (err) => { + await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; } @@ -159,38 +159,46 @@ masterConfigCommands.add(new libCommand.Command({ editorSpawn.on("data", (data) => { process.stdout.pipe(data); }); - function readTmpFile(c2) { - fs.readFile(tmpFile, "utf8", (err, data) => { - if (err) { throw err; } - let splitData = data.split(/\r?\n/); - // split on newlines - let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); - // the last filter removes empty elements left by the first. Not done on one line due to readability. - let final = []; - for (let index in filtered) { - if (index in filtered) { - filtered[index] = filtered[index].split("="); - // split on the = we added eariler - filtered[index][1] = filtered[index][1].replace(/['"]+/g, ""); - // remove quotes we added eariler - final[filtered[index][0].trim()] = filtered[index][1].trim(); - // trim whitespace and put in final array for processing + let emmiter = new events.EventEmitter(); + editorSpawn.on("exit", async (exit) => { + const data = await fs.readFile(tmpFile, "utf8"); + let final = []; + let splitData = data.split(/\r?\n/); + // split on newlines + let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); + // the last filter removes empty elements left by the first. Not done on one line due to readability. + for (let index in filtered) { + if (index in filtered) { + filtered[index] = filtered[index].split("="); + // split on the = we added eariler + filtered[index][1] = filtered[index][1].replace(/['"]+/g, ""); + // remove quotes we added eariler + let part = filtered[index][1].trim(); + let finalIndex = filtered[index][0].trim(); + if (part === "undefined") { + } else if (part === "null") { + print("null", part); + final[finalIndex] = ""; + } else { + print("string", part); + final[finalIndex] = part; } + // trim whitespace and put in final array for processing } - for (let element in final) { - if (element in final) { - libLink.messages.setMasterConfigField.send(control, { - field: element, - value: final[element], - }); - } + } + print("final", final); + for (let element in final) { + if (element in final) { + print("parsing", element, final[element], ":", typeof final[element]); + await libLink.messages.setMasterConfigField.send(control, { + field: element, + value: final[element], + }); } - }); - } - editorSpawn.once("exit", (exit) => { - print("once"); - readTmpFile(control); + } + emmiter.emit("dot_on_done"); }); + await events.once(emmiter, "dot_on_done"); }, })); From ae34a86cbf8decdb132647e56162eff391866511 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 14 Nov 2021 20:54:27 +1100 Subject: [PATCH 19/45] Removed debugging prints, and added removing of tmpFile --- packages/ctl/ctl.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index a121b100..7c2e6c8e 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -186,10 +186,8 @@ masterConfigCommands.add(new libCommand.Command({ // trim whitespace and put in final array for processing } } - print("final", final); for (let element in final) { if (element in final) { - print("parsing", element, final[element], ":", typeof final[element]); await libLink.messages.setMasterConfigField.send(control, { field: element, value: final[element], @@ -199,6 +197,7 @@ masterConfigCommands.add(new libCommand.Command({ emmiter.emit("dot_on_done"); }); await events.once(emmiter, "dot_on_done"); + await fs.unlink(tmpFile); }, })); From cc605250dbabe805c656603d82565a7fb8aa0c6d Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 14 Nov 2021 20:55:16 +1100 Subject: [PATCH 20/45] removed final debugging helpers --- packages/ctl/ctl.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 7c2e6c8e..caed3431 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -177,10 +177,8 @@ masterConfigCommands.add(new libCommand.Command({ let finalIndex = filtered[index][0].trim(); if (part === "undefined") { } else if (part === "null") { - print("null", part); final[finalIndex] = ""; } else { - print("string", part); final[finalIndex] = part; } // trim whitespace and put in final array for processing From 46128266648b8b8bbd7c059eb4c3eca405d6a912 Mon Sep 17 00:00:00 2001 From: jake87 Date: Tue, 16 Nov 2021 21:43:59 +1100 Subject: [PATCH 21/45] spelling mistake --- packages/ctl/ctl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index caed3431..0583ff21 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -170,9 +170,9 @@ masterConfigCommands.add(new libCommand.Command({ for (let index in filtered) { if (index in filtered) { filtered[index] = filtered[index].split("="); - // split on the = we added eariler + // split on the = we added earlier filtered[index][1] = filtered[index][1].replace(/['"]+/g, ""); - // remove quotes we added eariler + // remove quotes we added earlier let part = filtered[index][1].trim(); let finalIndex = filtered[index][0].trim(); if (part === "undefined") { From 76882ad1c4413eaa85621180fa41c47ba5d03b23 Mon Sep 17 00:00:00 2001 From: jake87 Date: Wed, 17 Nov 2021 17:42:39 +1100 Subject: [PATCH 22/45] Fix styling to be more consistant with the rest of clustorio --- packages/ctl/ctl.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 0583ff21..f945ec69 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -133,15 +133,13 @@ masterConfigCommands.add(new libCommand.Command({ let allConfigElements = ""; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { - if (typeof value === "string") { - value = `\"${value}\"`; - } // put quotes around value if it's a string - let desc = libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; allConfigElements += `# ${desc}\n`; // split onto two lines for readability and es-lint - + if (String(value) === "null") { + value = ""; + } allConfigElements += `${group.name}.${name} = ${value}\n\n`; } } @@ -171,21 +169,21 @@ masterConfigCommands.add(new libCommand.Command({ if (index in filtered) { filtered[index] = filtered[index].split("="); // split on the = we added earlier - filtered[index][1] = filtered[index][1].replace(/['"]+/g, ""); - // remove quotes we added earlier - let part = filtered[index][1].trim(); - let finalIndex = filtered[index][0].trim(); - if (part === "undefined") { - } else if (part === "null") { - final[finalIndex] = ""; - } else { - final[finalIndex] = part; + let part = ""; + try { + part = filtered[index][1].trim(); + } catch (err) { + part = null; } + print(part, typeof part); + let finalIndex = filtered[index][0].trim(); + final[finalIndex] = part; // trim whitespace and put in final array for processing } } for (let element in final) { if (element in final) { + print(element, final[element], typeof final[element]); await libLink.messages.setMasterConfigField.send(control, { field: element, value: final[element], From eb3b7df390a91a6264f9503bf7f8fe394eb83e4c Mon Sep 17 00:00:00 2001 From: jake87 Date: Wed, 17 Nov 2021 17:45:54 +1100 Subject: [PATCH 23/45] Fix to be more consistant with the rest of clustorio Also made sure "null" is entered as empty as to be consistant with the rest of clustorio. --- packages/ctl/ctl.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index f945ec69..6bd06063 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -175,7 +175,9 @@ masterConfigCommands.add(new libCommand.Command({ } catch (err) { part = null; } - print(part, typeof part); + if (part === "null") { + part = null; + } let finalIndex = filtered[index][0].trim(); final[finalIndex] = part; // trim whitespace and put in final array for processing @@ -183,7 +185,6 @@ masterConfigCommands.add(new libCommand.Command({ } for (let element in final) { if (element in final) { - print(element, final[element], typeof final[element]); await libLink.messages.setMasterConfigField.send(control, { field: element, value: final[element], From 834fc8cf98993e06699451580a97ed7ebcad9666 Mon Sep 17 00:00:00 2001 From: jake87 Date: Wed, 17 Nov 2021 18:16:24 +1100 Subject: [PATCH 24/45] Fixed null value parsing --- packages/ctl/ctl.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 6bd06063..6fccc9b1 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -168,27 +168,33 @@ masterConfigCommands.add(new libCommand.Command({ for (let index in filtered) { if (index in filtered) { filtered[index] = filtered[index].split("="); + let finalIndex = filtered[index][0].trim(); // split on the = we added earlier let part = ""; try { part = filtered[index][1].trim(); } catch (err) { - part = null; + part = ""; } if (part === "null") { - part = null; + print(`Warning: ${finalIndex} has been set to the value null, not the string "null".`); + part = ""; } - let finalIndex = filtered[index][0].trim(); final[finalIndex] = part; // trim whitespace and put in final array for processing } } for (let element in final) { if (element in final) { - await libLink.messages.setMasterConfigField.send(control, { - field: element, - value: final[element], - }); + try { + await libLink.messages.setMasterConfigField.send(control, { + field: element, + value: final[element], + }); + } catch (err) { + // eslint-disable-next-line + print(`Attempt to set ${element} to ${final[element] || String(null)} failed; set back to previous value.`); + } } } emmiter.emit("dot_on_done"); From 31cfc45e586253bc286561a64648d150e0b66d71 Mon Sep 17 00:00:00 2001 From: jake87 Date: Wed, 17 Nov 2021 21:16:22 +1100 Subject: [PATCH 25/45] Fix null processing ( again ) --- packages/ctl/ctl.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 6fccc9b1..fd124e94 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -160,7 +160,6 @@ masterConfigCommands.add(new libCommand.Command({ let emmiter = new events.EventEmitter(); editorSpawn.on("exit", async (exit) => { const data = await fs.readFile(tmpFile, "utf8"); - let final = []; let splitData = data.split(/\r?\n/); // split on newlines let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); @@ -173,23 +172,15 @@ masterConfigCommands.add(new libCommand.Command({ let part = ""; try { part = filtered[index][1].trim(); + // it's a string if we can read it } catch (err) { + // if we can't read it, it's a empty field and therefor null part = ""; } - if (part === "null") { - print(`Warning: ${finalIndex} has been set to the value null, not the string "null".`); - part = ""; - } - final[finalIndex] = part; - // trim whitespace and put in final array for processing - } - } - for (let element in final) { - if (element in final) { try { await libLink.messages.setMasterConfigField.send(control, { - field: element, - value: final[element], + field: finalIndex, + value: part, }); } catch (err) { // eslint-disable-next-line @@ -200,7 +191,14 @@ masterConfigCommands.add(new libCommand.Command({ emmiter.emit("dot_on_done"); }); await events.once(emmiter, "dot_on_done"); - await fs.unlink(tmpFile); + await fs.unlink(tmpFile, (err) => { + if (err) { + print("err: temporary file", tmpFile, "could not be deleted."); + print("This is not fatal, but they may build up over time if the issue persists."); + print("Trace:"); + print(err); + } + }); }, })); From 7126014619d4de70de5e208bab68eb6dcdf7c8d0 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sat, 20 Nov 2021 16:23:21 +1100 Subject: [PATCH 26/45] Added editing for instances Instances require a number of modifications leading to it not being able to be converted into a function. The main one is that there is a list of config elements that cannot be set via the edit command and either have to be set via different means or cannot be set. To stop these fields constantly sending error messages, we disregard adding them to the file in the first place. --- packages/ctl/ctl.js | 121 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index fd124e94..e99d7973 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -184,7 +184,10 @@ masterConfigCommands.add(new libCommand.Command({ }); } catch (err) { // eslint-disable-next-line - print(`Attempt to set ${element} to ${final[element] || String(null)} failed; set back to previous value.`); + print(`Attempt to set ${finalIndex} to ${part || String(null)} failed; set back to previous value.`); + print(err); + // 1. If the string is empty, it's better to just print "" instead of nothing + // 2. In my opinion this line is perfectly readable, and no need to rewright it } } } @@ -195,8 +198,6 @@ masterConfigCommands.add(new libCommand.Command({ if (err) { print("err: temporary file", tmpFile, "could not be deleted."); print("This is not fatal, but they may build up over time if the issue persists."); - print("Trace:"); - print(err); } }); }, @@ -398,6 +399,120 @@ instanceConfigCommands.add(new libCommand.Command({ await libLink.messages.setInstanceConfigProp.send(control, request); }, })); + +instanceConfigCommands.add(new libCommand.Command({ + definition: ["edit [editor]", "Edit instance configuration", (yargs) => { + yargs.positional("instance", { describe: "Instance to set config on", type: "string" }); + yargs.positional("editor", { describe: "Editor to use", + type: "string", + default: "" }); + }], + handler: async function(args, control) { + let instanceId = await libCommand.resolveInstance(control, args.instance); + let response = await libLink.messages.getInstanceConfig.send(control, { instance_id: instanceId }); + let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); + let editor = 0; + if (args.editor) { + editor = args.editor; + /* eslint-disable */ + } else if (process.env.EDITOR) { + editor = process.env.EDITOR; + } else if (process.env.VISUAL) { + editor = process.env.VISUAL + /* eslint-enable */ + // needed for the process.env statements to not be flagged by eslint + // prio for editors is CLI arg > env.EDITOR > env.VISUAL + } else { + throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); + } + + let allConfigElements = ""; + let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; + for (let group of response.serialized_config.groups) { + for (let [name, value] of Object.entries(group.fields)) { + // put quotes around value if it's a string + if (`${group.name}.${name}` in disallowedList) { + continue; + } + let desc = ""; + try { + desc += libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; + } catch (err) { + desc += "No description found"; + } + allConfigElements += `# ${desc}\n`; + // split onto two lines for readability and es-lint + if (String(value) === "null") { + value = ""; + } + allConfigElements += `${group.name}.${name} = ${value}\n\n`; + } + } + // use same method as master config list to grab values, with a small modification to add quotes around strings + // this could be shorter but the lines would have to be very long, so imo this is better for readability + await fs.writeFile(tmpFile, allConfigElements, (err) => { + if (err) { + throw err; + } + }); + let editorSpawn = child_process.spawn(editor, [tmpFile], { + stdio: "inherit", + detached: false, + }); + editorSpawn.on("data", (data) => { + process.stdout.pipe(data); + }); + let emmiter = new events.EventEmitter(); + editorSpawn.on("exit", async (exit) => { + const data = await fs.readFile(tmpFile, "utf8"); + let splitData = data.split(/\r?\n/); + // split on newlines + let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); + // the last filter removes empty elements left by the first. Not done on one line due to readability. + for (let index in filtered) { + if (index in filtered) { + filtered[index] = filtered[index].split("="); + let finalIndex = filtered[index][0].trim(); + // split on the = we added earlier + let part = ""; + try { + part = filtered[index][1].trim(); + // it's a string if we can read it + } catch (err) { + // if we can't read it, it's a empty field and therefor null + part = ""; + } + try { + await libLink.messages.setInstanceConfigField.send(control, { + instance_id: instanceId, + field: finalIndex, + value: part, + }); + } catch (err) { + // eslint-disable-next-line + print(`\n\n\nAttempt to set ${finalIndex} to ${JSON.stringify(part) || String(null)} failed; set back to previous value.`); + // 1. If the string is empty, it's better to just print "" instead of nothing + // 2. In my opinion this line is perfectly readable, and no need to rewright it + print("This message shouldn't normally appear; if the below message does not indicate it"); + print("was a user mistake, please report it to the clustorio devs."); + // added this because it could be a missed entry in disallowedList + // i've added all the vanilla clustorio configs, but there may be + // some modded ones that need to be added. + print(err); + } + } + } + emmiter.emit("dot_on_done"); + }); + await events.once(emmiter, "dot_on_done"); + await fs.unlink(tmpFile, (err) => { + if (err) { + print("err: temporary file", tmpFile, "could not be deleted."); + print("This is not fatal, but they may build up over time if the issue persists."); + } + }); + }, +})); instanceCommands.add(instanceConfigCommands); instanceCommands.add(new libCommand.Command({ From e5994287fbfae29f5ab8e079916daad8019cd705 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sat, 20 Nov 2021 16:33:47 +1100 Subject: [PATCH 27/45] Remove outdated comments --- packages/ctl/ctl.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index e99d7973..01e8c666 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -133,7 +133,6 @@ masterConfigCommands.add(new libCommand.Command({ let allConfigElements = ""; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { - // put quotes around value if it's a string let desc = libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; allConfigElements += `# ${desc}\n`; // split onto two lines for readability and es-lint @@ -186,9 +185,7 @@ masterConfigCommands.add(new libCommand.Command({ // eslint-disable-next-line print(`Attempt to set ${finalIndex} to ${part || String(null)} failed; set back to previous value.`); print(err); - // 1. If the string is empty, it's better to just print "" instead of nothing - // 2. In my opinion this line is perfectly readable, and no need to rewright it - } + // If the string is empty, it's better to just print "" instead of nothing } } } emmiter.emit("dot_on_done"); @@ -430,7 +427,6 @@ instanceConfigCommands.add(new libCommand.Command({ let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { - // put quotes around value if it's a string if (`${group.name}.${name}` in disallowedList) { continue; } @@ -491,8 +487,7 @@ instanceConfigCommands.add(new libCommand.Command({ } catch (err) { // eslint-disable-next-line print(`\n\n\nAttempt to set ${finalIndex} to ${JSON.stringify(part) || String(null)} failed; set back to previous value.`); - // 1. If the string is empty, it's better to just print "" instead of nothing - // 2. In my opinion this line is perfectly readable, and no need to rewright it + // If the string is empty, it's better to just print "" instead of nothing print("This message shouldn't normally appear; if the below message does not indicate it"); print("was a user mistake, please report it to the clustorio devs."); // added this because it could be a missed entry in disallowedList From 375f591fe5140a73cacd10c3de0ecd48c6fa0b33 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sat, 20 Nov 2021 22:28:21 +1100 Subject: [PATCH 28/45] Remove outdated comments --- packages/ctl/ctl.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 01e8c666..be246007 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -142,7 +142,6 @@ masterConfigCommands.add(new libCommand.Command({ allConfigElements += `${group.name}.${name} = ${value}\n\n`; } } - // use same method as master config list to grab values, with a small modification to add quotes around strings // this could be shorter but the lines would have to be very long, so imo this is better for readability await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { @@ -444,7 +443,6 @@ instanceConfigCommands.add(new libCommand.Command({ allConfigElements += `${group.name}.${name} = ${value}\n\n`; } } - // use same method as master config list to grab values, with a small modification to add quotes around strings // this could be shorter but the lines would have to be very long, so imo this is better for readability await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { From 6b10f2ab7d1f7703b6e73fcb4b5f425b6394aab0 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:07:30 +1100 Subject: [PATCH 29/45] Resolve function style --- packages/ctl/ctl.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index be246007..7f0230a1 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -108,9 +108,11 @@ masterConfigCommands.add(new libCommand.Command({ })); masterConfigCommands.add(new libCommand.Command({ definition: ["edit [editor]", "Edit master configuration", (yargs) => { - yargs.positional("editor", { describe: "Editor to use", + yargs.positional("editor", { + describe: "Editor to use", type: "string", - default: "" }); + default: "" + }); }], handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); @@ -399,9 +401,11 @@ instanceConfigCommands.add(new libCommand.Command({ instanceConfigCommands.add(new libCommand.Command({ definition: ["edit [editor]", "Edit instance configuration", (yargs) => { yargs.positional("instance", { describe: "Instance to set config on", type: "string" }); - yargs.positional("editor", { describe: "Editor to use", + yargs.positional("editor", { + describe: "Editor to use", type: "string", - default: "" }); + default: "" + }); }], handler: async function(args, control) { let instanceId = await libCommand.resolveInstance(control, args.instance); From 25ae9b9a0dd477b887cedbfc0b7e642cded142af Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:10:24 +1100 Subject: [PATCH 30/45] Add example to "no editor" error --- packages/ctl/ctl.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 7f0230a1..d0ab66c9 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -129,7 +129,8 @@ masterConfigCommands.add(new libCommand.Command({ // needed for the process.env statements to not be flagged by eslint // prio for editors is CLI arg > env.EDITOR > env.VISUAL } else { - throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); + throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars\ + Try "ctl master config edit "`); } let allConfigElements = ""; @@ -423,7 +424,8 @@ instanceConfigCommands.add(new libCommand.Command({ // needed for the process.env statements to not be flagged by eslint // prio for editors is CLI arg > env.EDITOR > env.VISUAL } else { - throw new libErrors.CommandError("No editor avalible. Checked CLI input, EDITOR and VISUAL env vars"); + throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars\ + Try "ctl instance config edit "`); } let allConfigElements = ""; From 4a628df1086ab40d066fd26e5818cbdd8a911f3f Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:11:18 +1100 Subject: [PATCH 31/45] Remove unneeded backslash --- packages/ctl/ctl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index d0ab66c9..2a8deb2d 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -129,7 +129,7 @@ masterConfigCommands.add(new libCommand.Command({ // needed for the process.env statements to not be flagged by eslint // prio for editors is CLI arg > env.EDITOR > env.VISUAL } else { - throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars\ + throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars Try "ctl master config edit "`); } @@ -424,7 +424,7 @@ instanceConfigCommands.add(new libCommand.Command({ // needed for the process.env statements to not be flagged by eslint // prio for editors is CLI arg > env.EDITOR > env.VISUAL } else { - throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars\ + throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars Try "ctl instance config edit "`); } From 15c3bb81a6a3b9c7868455f59f7ee3adb8c6c782 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:12:54 +1100 Subject: [PATCH 32/45] Fix "emitter" spelling & rename to be more descriptive --- packages/ctl/ctl.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 2a8deb2d..4fd65d95 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -158,7 +158,7 @@ masterConfigCommands.add(new libCommand.Command({ editorSpawn.on("data", (data) => { process.stdout.pipe(data); }); - let emmiter = new events.EventEmitter(); + let doneEmitter = new events.EventEmitter(); editorSpawn.on("exit", async (exit) => { const data = await fs.readFile(tmpFile, "utf8"); let splitData = data.split(/\r?\n/); @@ -190,9 +190,9 @@ masterConfigCommands.add(new libCommand.Command({ // If the string is empty, it's better to just print "" instead of nothing } } } - emmiter.emit("dot_on_done"); + doneEmitter.emit("dot_on_done"); }); - await events.once(emmiter, "dot_on_done"); + await events.once(doneEmitter, "dot_on_done"); await fs.unlink(tmpFile, (err) => { if (err) { print("err: temporary file", tmpFile, "could not be deleted."); @@ -462,7 +462,7 @@ instanceConfigCommands.add(new libCommand.Command({ editorSpawn.on("data", (data) => { process.stdout.pipe(data); }); - let emmiter = new events.EventEmitter(); + let doneEmitter = new events.EventEmitter(); editorSpawn.on("exit", async (exit) => { const data = await fs.readFile(tmpFile, "utf8"); let splitData = data.split(/\r?\n/); @@ -501,9 +501,9 @@ instanceConfigCommands.add(new libCommand.Command({ } } } - emmiter.emit("dot_on_done"); + doneEmitter.emit("dot_on_done"); }); - await events.once(emmiter, "dot_on_done"); + await events.once(doneEmitter, "dot_on_done"); await fs.unlink(tmpFile, (err) => { if (err) { print("err: temporary file", tmpFile, "could not be deleted."); From 6da349c888a32d4011158341385d04b413a325ef Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:14:49 +1100 Subject: [PATCH 33/45] Fix commented out `catch` bracket --- packages/ctl/ctl.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 4fd65d95..92e635b4 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -187,7 +187,8 @@ masterConfigCommands.add(new libCommand.Command({ // eslint-disable-next-line print(`Attempt to set ${finalIndex} to ${part || String(null)} failed; set back to previous value.`); print(err); - // If the string is empty, it's better to just print "" instead of nothing } + // If the string is empty, it's better to just print "" instead of nothing + } } } doneEmitter.emit("dot_on_done"); From 103c0e3820cc47973dfbdae6eab53443749e86bd Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 12:15:46 +1100 Subject: [PATCH 34/45] Fix missing brace from conflict merge --- packages/lib/file_ops.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index 0bc277a1..f31687e2 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -86,7 +86,7 @@ async function getTempFile(prefix, suffix, tmpdir) { let freeFile = await findUnusedName(tmpdir, fileName); let fullPath = path.join(tmpdir, freeFile); return fullPath; - +} /** * Safely write data to a file * From c4f656996e47004ccf80b7163f7a5af12dd9c0ff Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 21 Nov 2021 12:24:00 +1100 Subject: [PATCH 35/45] Fixed linting issues --- packages/ctl/ctl.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 92e635b4..8a380cd9 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -108,10 +108,10 @@ masterConfigCommands.add(new libCommand.Command({ })); masterConfigCommands.add(new libCommand.Command({ definition: ["edit [editor]", "Edit master configuration", (yargs) => { - yargs.positional("editor", { + yargs.positional("editor", { describe: "Editor to use", type: "string", - default: "" + default: "", }); }], handler: async function(args, control) { @@ -187,7 +187,7 @@ masterConfigCommands.add(new libCommand.Command({ // eslint-disable-next-line print(`Attempt to set ${finalIndex} to ${part || String(null)} failed; set back to previous value.`); print(err); - // If the string is empty, it's better to just print "" instead of nothing + // If the string is empty, it's better to just print "" instead of nothing } } } @@ -403,10 +403,10 @@ instanceConfigCommands.add(new libCommand.Command({ instanceConfigCommands.add(new libCommand.Command({ definition: ["edit [editor]", "Edit instance configuration", (yargs) => { yargs.positional("instance", { describe: "Instance to set config on", type: "string" }); - yargs.positional("editor", { + yargs.positional("editor", { describe: "Editor to use", type: "string", - default: "" + default: "", }); }], handler: async function(args, control) { From e825f643e2bfcbc191e9feccb25c9016bd8d1039 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 21 Nov 2021 13:31:12 +1100 Subject: [PATCH 36/45] Refactored string processing to function Previously string processing was done the exact same way for both master and instance; this has now been refactored into a function. --- packages/ctl/ctl.js | 76 +++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 8a380cd9..bfa61fcf 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -36,6 +36,30 @@ function print(...content) { console.log(...content); } +async function configToKeyVal(data) { + let final = {}; + let splitData = data.split(/\r?\n/); + // split on newlines + let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); + // the last filter removes empty elements left by the first. Not done on one line due to readability. + for (let index in filtered) { + if (index in filtered) { + filtered[index] = filtered[index].split("="); + let finalIndex = filtered[index][0].trim(); + // split on the = we added earlier + let part = ""; + try { + part = filtered[index][1].trim(); + // it's a string if we can read it + } catch (err) { + // if we can't read it, it's a empty field and therefor null + part = ""; + } + final[finalIndex] = part; + } + } + return final; +} const masterCommands = new libCommand.CommandTree({ name: "master", description: "Master management" }); const masterConfigCommands = new libCommand.CommandTree({ @@ -161,31 +185,17 @@ masterConfigCommands.add(new libCommand.Command({ let doneEmitter = new events.EventEmitter(); editorSpawn.on("exit", async (exit) => { const data = await fs.readFile(tmpFile, "utf8"); - let splitData = data.split(/\r?\n/); - // split on newlines - let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); - // the last filter removes empty elements left by the first. Not done on one line due to readability. - for (let index in filtered) { - if (index in filtered) { - filtered[index] = filtered[index].split("="); - let finalIndex = filtered[index][0].trim(); - // split on the = we added earlier - let part = ""; - try { - part = filtered[index][1].trim(); - // it's a string if we can read it - } catch (err) { - // if we can't read it, it's a empty field and therefor null - part = ""; - } + const final = await configToKeyVal(data); + for (let index in final) { + if (index in final) { try { await libLink.messages.setMasterConfigField.send(control, { - field: finalIndex, - value: part, + field: index, + value: final[index], }); } catch (err) { // eslint-disable-next-line - print(`Attempt to set ${finalIndex} to ${part || String(null)} failed; set back to previous value.`); + print(`Attempt to set ${index} to ${final[index] || String(null)} failed; set back to previous value.`); print(err); // If the string is empty, it's better to just print "" instead of nothing } @@ -466,32 +476,18 @@ instanceConfigCommands.add(new libCommand.Command({ let doneEmitter = new events.EventEmitter(); editorSpawn.on("exit", async (exit) => { const data = await fs.readFile(tmpFile, "utf8"); - let splitData = data.split(/\r?\n/); - // split on newlines - let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); - // the last filter removes empty elements left by the first. Not done on one line due to readability. - for (let index in filtered) { - if (index in filtered) { - filtered[index] = filtered[index].split("="); - let finalIndex = filtered[index][0].trim(); - // split on the = we added earlier - let part = ""; - try { - part = filtered[index][1].trim(); - // it's a string if we can read it - } catch (err) { - // if we can't read it, it's a empty field and therefor null - part = ""; - } + const final = await configToKeyVal(data); + for (let index in final) { + if (index in final) { try { await libLink.messages.setInstanceConfigField.send(control, { instance_id: instanceId, - field: finalIndex, - value: part, + field: index, + value: final[index], }); } catch (err) { // eslint-disable-next-line - print(`\n\n\nAttempt to set ${finalIndex} to ${JSON.stringify(part) || String(null)} failed; set back to previous value.`); + print(`\n\n\nAttempt to set ${index} to ${final[index] || String(null)} failed; set back to previous value.`); // If the string is empty, it's better to just print "" instead of nothing print("This message shouldn't normally appear; if the below message does not indicate it"); print("was a user mistake, please report it to the clustorio devs."); From 6d5d9ced4706aed8d7942c408a9c4f019bce5cc2 Mon Sep 17 00:00:00 2001 From: jake87 Date: Sun, 21 Nov 2021 13:39:23 +1100 Subject: [PATCH 37/45] Refactored editor selection to function --- packages/ctl/ctl.js | 50 +++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index bfa61fcf..ab06e614 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -36,6 +36,24 @@ function print(...content) { console.log(...content); } +async function getEditor(argsEditor) { + let editor = ""; + if (argsEditor) { + editor = argsEditor; + /* eslint-disable */ + } else if (process.env.EDITOR) { + editor = process.env.EDITOR; + } else if (process.env.VISUAL) { + editor = process.env.VISUAL + /* eslint-enable */ + // needed for the process.env statements to not be flagged by eslint + // prio for editors is CLI arg > env.EDITOR > env.VISUAL + } else { + editor = -1; + } + return editor; +} + async function configToKeyVal(data) { let final = {}; let splitData = data.split(/\r?\n/); @@ -141,22 +159,11 @@ masterConfigCommands.add(new libCommand.Command({ handler: async function(args, control) { let response = await libLink.messages.getMasterConfig.send(control); let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); - let editor = 0; - if (args.editor) { - editor = args.editor; - /* eslint-disable */ - } else if (process.env.EDITOR) { - editor = process.env.EDITOR; - } else if (process.env.VISUAL) { - editor = process.env.VISUAL - /* eslint-enable */ - // needed for the process.env statements to not be flagged by eslint - // prio for editors is CLI arg > env.EDITOR > env.VISUAL - } else { + let editor = await getEditor(args.editor); + if (editor === -1) { throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars Try "ctl master config edit "`); } - let allConfigElements = ""; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { @@ -423,22 +430,11 @@ instanceConfigCommands.add(new libCommand.Command({ let instanceId = await libCommand.resolveInstance(control, args.instance); let response = await libLink.messages.getInstanceConfig.send(control, { instance_id: instanceId }); let tmpFile = await libFileOps.getTempFile("ctl-", "-tmp", os.tmpdir()); - let editor = 0; - if (args.editor) { - editor = args.editor; - /* eslint-disable */ - } else if (process.env.EDITOR) { - editor = process.env.EDITOR; - } else if (process.env.VISUAL) { - editor = process.env.VISUAL - /* eslint-enable */ - // needed for the process.env statements to not be flagged by eslint - // prio for editors is CLI arg > env.EDITOR > env.VISUAL - } else { + let editor = await getEditor(args.editor); + if (editor === -1) { throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars - Try "ctl instance config edit "`); + Try "ctl master config edit "`); } - let allConfigElements = ""; let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; for (let group of response.serialized_config.groups) { From 0bc6cf1178cf5aae9f500a48ad4c3920c0674f85 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 20:25:33 +1100 Subject: [PATCH 38/45] Minified getEditor function. --- packages/ctl/ctl.js | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index ab06e614..00c065a5 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -37,21 +37,11 @@ function print(...content) { } async function getEditor(argsEditor) { - let editor = ""; - if (argsEditor) { - editor = argsEditor; - /* eslint-disable */ - } else if (process.env.EDITOR) { - editor = process.env.EDITOR; - } else if (process.env.VISUAL) { - editor = process.env.VISUAL - /* eslint-enable */ - // needed for the process.env statements to not be flagged by eslint - // prio for editors is CLI arg > env.EDITOR > env.VISUAL - } else { - editor = -1; - } - return editor; + /* eslint-disable */ + return argsEditor || process.ENV.EDITOR || process.env.VISUAL || -1 + /* eslint-enable */ + // needed for the process.env statements to not be flagged by eslint + // prio for editors is CLI arg > env.EDITOR > env.VISUAL } async function configToKeyVal(data) { From baf7dbfe0dc1c5256430ba1e8ae9c3ea62e2fd5e Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Sun, 21 Nov 2021 20:26:17 +1100 Subject: [PATCH 39/45] Fixed linter issue --- packages/lib/file_ops.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/lib/file_ops.js b/packages/lib/file_ops.js index f31687e2..c04077be 100644 --- a/packages/lib/file_ops.js +++ b/packages/lib/file_ops.js @@ -68,7 +68,7 @@ async function findUnusedName(directory, name, extension = "") { } } } -/* +/** * Warning: this function should not be relied upon to be accurate for * security sensitive applications. The selection process is inherently * racy and a file or folder may have been created in the folder by the time @@ -77,7 +77,7 @@ async function findUnusedName(directory, name, extension = "") { * @param {string} prefix - Prefix for file * @param {string} suffix - Suffix for file * @param {string} tmpdir - Directory for temp file -*/ + */ async function getTempFile(prefix, suffix, tmpdir) { prefix = (typeof prefix !== "undefined") ? prefix : "tmp."; suffix = (typeof suffix !== "undefined") ? suffix : ""; From cc064c2fd17572d74b965b50b2c9929dbfdf9c8d Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Mon, 22 Nov 2021 09:36:20 +1100 Subject: [PATCH 40/45] Fix mistake with Instance descriptions Also added warning for description not found in master. --- packages/ctl/ctl.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 00c065a5..51980365 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -157,8 +157,12 @@ masterConfigCommands.add(new libCommand.Command({ let allConfigElements = ""; for (let group of response.serialized_config.groups) { for (let [name, value] of Object.entries(group.fields)) { - let desc = libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; - allConfigElements += `# ${desc}\n`; + let desc = ""; + try { + desc += libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; + } catch (err) { + desc += "No description found"; + } // split onto two lines for readability and es-lint if (String(value) === "null") { value = ""; @@ -434,7 +438,7 @@ instanceConfigCommands.add(new libCommand.Command({ } let desc = ""; try { - desc += libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; + desc += libConfig.InstanceConfig.groups.get(group.name)._definitions.get(name).description; } catch (err) { desc += "No description found"; } From e6e5805a4984a833eb159a5f88ba9e9bfb40f07c Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Tue, 23 Nov 2021 13:12:49 +1100 Subject: [PATCH 41/45] Refactored serializedConfigToString into function I'm unable to test right now, so this is currently not yet tested. Will test asap. --- packages/ctl/ctl.js | 67 ++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 51980365..ceb64137 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -37,11 +37,10 @@ function print(...content) { } async function getEditor(argsEditor) { - /* eslint-disable */ + // eslint-disable-next-line return argsEditor || process.ENV.EDITOR || process.env.VISUAL || -1 - /* eslint-enable */ // needed for the process.env statements to not be flagged by eslint - // prio for editors is CLI arg > env.EDITOR > env.VISUAL + // priority for editors is CLI argument > env.EDITOR > env.VISUAL } async function configToKeyVal(data) { @@ -69,6 +68,29 @@ async function configToKeyVal(data) { return final; } +async function serializedConfigToString(serlializedConfig, configGroup, disallowedList) { + let allConfigElements = ""; + for (let group of serializedConfig.groups) { + for (let [name, value] of Object.entries(group.fields)) { + if (`${group.name}.${name}` in disallowedList) { + continue; + } + let desc = ""; + try { + desc += configGroup.groups.get(group.name)._definitions.get(name).description; + } catch (err) { + desc += "No description found"; + } + // split onto two lines for readability and es-lint + if (String(value) === "null") { + value = ""; + } + allConfigElements += `${group.name}.${name} = ${value}\n\n`; + } + } + return allConfigElements; +} + const masterCommands = new libCommand.CommandTree({ name: "master", description: "Master management" }); const masterConfigCommands = new libCommand.CommandTree({ name: "config", alias: ["c"], description: "master config management", @@ -154,23 +176,7 @@ masterConfigCommands.add(new libCommand.Command({ throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars Try "ctl master config edit "`); } - let allConfigElements = ""; - for (let group of response.serialized_config.groups) { - for (let [name, value] of Object.entries(group.fields)) { - let desc = ""; - try { - desc += libConfig.MasterConfig.groups.get(group.name)._definitions.get(name).description; - } catch (err) { - desc += "No description found"; - } - // split onto two lines for readability and es-lint - if (String(value) === "null") { - value = ""; - } - allConfigElements += `${group.name}.${name} = ${value}\n\n`; - } - } - // this could be shorter but the lines would have to be very long, so imo this is better for readability + let allConfigElements = await serializedConfigToString(respose.serialized_config, libConfig.MasterConfig, {}); await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; @@ -431,26 +437,7 @@ instanceConfigCommands.add(new libCommand.Command({ } let allConfigElements = ""; let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; - for (let group of response.serialized_config.groups) { - for (let [name, value] of Object.entries(group.fields)) { - if (`${group.name}.${name}` in disallowedList) { - continue; - } - let desc = ""; - try { - desc += libConfig.InstanceConfig.groups.get(group.name)._definitions.get(name).description; - } catch (err) { - desc += "No description found"; - } - allConfigElements += `# ${desc}\n`; - // split onto two lines for readability and es-lint - if (String(value) === "null") { - value = ""; - } - allConfigElements += `${group.name}.${name} = ${value}\n\n`; - } - } - // this could be shorter but the lines would have to be very long, so imo this is better for readability + let allConfigElements = await serializedConfigToString(respose.serialized_config, libConfig.InstanceConfig, disallowedList); await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; From 62efc63830c36f56a35935d46806d99aebe62a3b Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Tue, 23 Nov 2021 22:03:36 +1100 Subject: [PATCH 42/45] Fixed variable definition --- packages/ctl/ctl.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index ceb64137..80596427 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -435,7 +435,6 @@ instanceConfigCommands.add(new libCommand.Command({ throw new libErrors.CommandError(`No editor avalible. Checked CLI input, EDITOR and VISUAL env vars Try "ctl master config edit "`); } - let allConfigElements = ""; let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; let allConfigElements = await serializedConfigToString(respose.serialized_config, libConfig.InstanceConfig, disallowedList); await fs.writeFile(tmpFile, allConfigElements, (err) => { From b9e8ffa3d1b237dd8a9fac0046c7c25cd82e0dfc Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Wed, 24 Nov 2021 09:33:08 +1100 Subject: [PATCH 43/45] Fix linting error --- packages/ctl/ctl.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 80596427..c01b74a3 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -436,7 +436,11 @@ instanceConfigCommands.add(new libCommand.Command({ Try "ctl master config edit "`); } let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; - let allConfigElements = await serializedConfigToString(respose.serialized_config, libConfig.InstanceConfig, disallowedList); + let allConfigElements = await serializedConfigToString( + respose.serialized_config, + libConfig.InstanceConfig, + disallowedList + ); await fs.writeFile(tmpFile, allConfigElements, (err) => { if (err) { throw err; From 81e3c9e19b7394d0a9de03c54fd0b76e703963de Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Wed, 24 Nov 2021 14:31:42 +1100 Subject: [PATCH 44/45] Removed unnecessary double negation --- packages/ctl/ctl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index c01b74a3..5d770c69 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -47,13 +47,13 @@ async function configToKeyVal(data) { let final = {}; let splitData = data.split(/\r?\n/); // split on newlines - let filtered = splitData.filter((value) => !(value[0] === "#")).filter((a) => a); + let filtered = splitData.filter((value) => value[0] !== "#").filter((a) => a); // the last filter removes empty elements left by the first. Not done on one line due to readability. for (let index in filtered) { if (index in filtered) { filtered[index] = filtered[index].split("="); let finalIndex = filtered[index][0].trim(); - // split on the = we added earlier + // split on the = we added earlier, giving us both value and key let part = ""; try { part = filtered[index][1].trim(); From dfd0cb2d36d41939a841ada1821695c51a2b8785 Mon Sep 17 00:00:00 2001 From: J87 <68929154+jake-87@users.noreply.github.com> Date: Thu, 25 Nov 2021 07:45:56 +1100 Subject: [PATCH 45/45] Fix linter issue --- packages/ctl/ctl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ctl/ctl.js b/packages/ctl/ctl.js index 5d770c69..293e1555 100755 --- a/packages/ctl/ctl.js +++ b/packages/ctl/ctl.js @@ -437,8 +437,8 @@ instanceConfigCommands.add(new libCommand.Command({ } let disallowedList = {"instance.id": 0, "instance.assigned_slave": 0, "factorio.settings": 0}; let allConfigElements = await serializedConfigToString( - respose.serialized_config, - libConfig.InstanceConfig, + respose.serialized_config, + libConfig.InstanceConfig, disallowedList ); await fs.writeFile(tmpFile, allConfigElements, (err) => {