From 79cb99749b4f48500d81bd7ee2233b556514f9a6 Mon Sep 17 00:00:00 2001 From: thatben Date: Wed, 19 Feb 2025 14:56:22 +0100 Subject: [PATCH] debug path selecting --- package.json | 3 +- src/configmenu.js | 105 +++++++++++++++++++++++++++ src/handlers/installationHandlers.js | 5 +- src/main.js | 47 ++++++------ src/utils/pathSelector.js | 92 +++++++++++++++-------- 5 files changed, 196 insertions(+), 56 deletions(-) create mode 100644 src/configmenu.js diff --git a/package.json b/package.json index 60cfb88..75013ec 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "chalk": "^5.3.0", "inquirer": "^9.2.12", "mime-types": "^2.1.35", - "nanospinner": "^1.1.0" + "nanospinner": "^1.1.0", + "fs-extra": "^11.3.0" } } diff --git a/src/configmenu.js b/src/configmenu.js new file mode 100644 index 0000000..140b076 --- /dev/null +++ b/src/configmenu.js @@ -0,0 +1,105 @@ +import inquirer from 'inquirer'; +import chalk from 'chalk'; +import { showErrorMessage, showInfoMessage } from './utils/messages.js'; +import { isDir, showPathSelector } from './utils/pathSelector.js'; +import { saveConfig } from './services/config.js'; +import fs from 'fs-extra'; + +export async function showConfigMenu(config) { + var newDataDir = config.dataDir; + try { + while (true) { + console.log(showInfoMessage("Codex Configuration")); + const { choice } = await inquirer.prompt([ + { + type: 'list', + name: 'choice', + message: 'Select to edit:', + choices: [ + `1. Data path = "${newDataDir}"`, + `2. Logs path = "${config.logsDir}"`, + '3. Storage quota = TODO', + '4. Discovery port = TODO', + '5. P2P listen port = TODO', + '6. API port = TODO', + '7. Save changes and exit', + '8. Discard changes and exit' + ], + pageSize: 8, + loop: true + } + ]).catch(() => { + return; + }); + + switch (choice.split('.')[0]) { + case '1': + newDataDir = await showPathSelector(config.dataDir, false); + if (isDir(newDataDir)) { + console.log(showInfoMessage("Warning: The new data path already exists. Make sure you know what you're doing.")); + } + break; + case '2': + config.logsDir = await showPathSelector(config.logsDir, true); + break; + case '3': + break; + case '4': + break; + case '5': + break; + case '6': + break; + case '7': + // save changes, back to main menu + config = updateDataDir(config, newDataDir); + saveConfig(config); + return; + case '8': + // discard changes, back to main menu + return; + } + } + } catch (error) { + console.error(chalk.red('An error occurred:', error.message)); + return; + } +} + +function updateDataDir(config, newDataDir) { + if (config.dataDir == newDataDir) return config; + + // The Codex dataDir is a little strange: + // If the old one is empty: The new one should not exist, so that codex creates it + // with the correct security permissions. + // If the old one does exist: We move it. + + if (isDir(config.dataDir)) { + console.log(showInfoMessage( + 'Moving Codex data folder...\n' + + `From: "${config.dataDir}"\n` + + `To: "${newDataDir}"` + )); + + try { + fs.moveSync(config.dataDir, newDataDir); + } catch (error) { + console.log(showErrorMessage("Error while moving dataDir: " + error.message)); + throw error; + } + } else { + // Old data dir does not exist. + if (isDir(newDataDir)) { + console.log(showInfoMessage( + "Warning: the selected data path already exists.\n" + + `New data path = "${newDataDir}"\n` + + "Codex may overwrite data in this folder.\n" + + "Codex will fail to start if this folder does not have the required\n" + + "security permissions." + )); + } + } + + config.dataDir = newDataDir; + return config; +} diff --git a/src/handlers/installationHandlers.js b/src/handlers/installationHandlers.js index 9141bc0..af36b62 100644 --- a/src/handlers/installationHandlers.js +++ b/src/handlers/installationHandlers.js @@ -117,7 +117,6 @@ export async function installCodex(config, showNavigationMenu) { const spinner = createSpinner('Installing Codex...').start(); try { - if (platform === 'win32') { try { try { @@ -198,6 +197,10 @@ export async function installCodex(config, showNavigationMenu) { } catch (error) { throw new Error('Installation completed but Codex command is not available. Please restart your terminal and try again.'); } + + console.log(showInfoMessage( + "Please review the configuration before starting Codex." + )); spinner.success(); await showNavigationMenu(); diff --git a/src/main.js b/src/main.js index 9997f79..deea6a3 100644 --- a/src/main.js +++ b/src/main.js @@ -10,6 +10,7 @@ import { checkCodexInstallation, installCodex, uninstallCodex } from './handlers import { runCodex, checkNodeStatus } from './handlers/nodeHandlers.js'; import { showInfoMessage } from './utils/messages.js'; import { loadConfig } from './services/config.js'; +import { showConfigMenu } from './configmenu.js'; async function showNavigationMenu() { console.log('\n') @@ -78,57 +79,59 @@ export async function main() { message: 'Select an option:', choices: [ '1. Download and install Codex', - '2. Run Codex node', - '3. Check node status', - '4. Upload a file', - '5. Download a file', - '6. Show local data', - '7. Uninstall Codex node', - '8. Submit feedback', - '9. Exit' + '2. Edit Codex configuration', + '3. Run Codex node', + '4. Check node status', + '5. Upload a file', + '6. Download a file', + '7. Show local data', + '8. Uninstall Codex node', + '9. Submit feedback', + '10. Exit' ], - pageSize: 9, + pageSize: 10, loop: true } ]).catch(() => { handleExit(); - return { choice: '9' }; + return; }); - - if (choice.startsWith('9')) { - handleExit(); - break; - } - + switch (choice.split('.')[0]) { case '1': await checkCodexInstallation(config, showNavigationMenu); break; case '2': + await showConfigMenu(config); + break; + case '3': await runCodex(config, showNavigationMenu); return; - case '3': + case '4': await checkNodeStatus(showNavigationMenu); break; - case '4': + case '5': await uploadFile(null, handleCommandLineOperation, showNavigationMenu); break; - case '5': + case '6': await downloadFile(null, handleCommandLineOperation, showNavigationMenu); break; - case '6': + case '7': await showLocalFiles(showNavigationMenu); break; - case '7': + case '8': await uninstallCodex(config, showNavigationMenu); break; - case '8': + case '9': const { exec } = await import('child_process'); const url = 'https://docs.google.com/forms/d/1U21xp6shfDkJWzJSKHhUjwIE7fsYk94gmLUKAbxUMcw/edit'; const command = process.platform === 'win32' ? `start ${url}` : process.platform === 'darwin' ? `open ${url}` : `xdg-open ${url}`; exec(command); console.log(showInfoMessage('Opening feedback form in your browser...')); break; + case '10': + handleExit(); + return; } console.log('\n'); diff --git a/src/utils/pathSelector.js b/src/utils/pathSelector.js index 172734f..fa6da7c 100644 --- a/src/utils/pathSelector.js +++ b/src/utils/pathSelector.js @@ -18,9 +18,31 @@ function splitPath(str) { return str.replaceAll("\\", "/").split("/"); } +function dropEmptyParts(parts) { + var result = []; + parts.forEach(function(part) { + if (part.length > 0) { + result.push(part); + } + }) + return result; +} + +function combine(parts) { + const toJoin = dropEmptyParts(parts); + if (toJoin.length == 1) return toJoin[0]; + return path.join(...toJoin); +} + +function combineWith(parts, extra) { + const toJoin = dropEmptyParts(parts); + if (toJoin.length == 1) return path.join(toJoin[0], extra); + return path.join(...toJoin, extra); +} + function showCurrent(currentPath) { const len = currentPath.length; - showMsg(`Current path: [${len}]\n` + path.join(...currentPath)); + showMsg(`Current path: [${len}]\n` + combine(currentPath)); } async function showMain(currentPath) { @@ -34,10 +56,9 @@ async function showMain(currentPath) { '1. Enter path', '2. Go up one', '3. Go down one', - '4. Check path exists', - '5. Create new folder here', - '6. Select this path', - '7. Cancel' + '4. Create new folder here', + '5. Select this path', + '6. Cancel' ], pageSize: 6, loop: true @@ -50,15 +71,15 @@ async function showMain(currentPath) { return choice; } -export async function selectPath() { - var currentPath = splitPath(process.cwd()); +export async function showPathSelector(startingPath, pathMustExist) { + var currentPath = splitPath(startingPath); while (true) { const choice = await showMain(currentPath); switch (choice.split('.')[0]) { case '1': - currentPath = await enterPath(); + currentPath = await enterPath(currentPath, pathMustExist); break; case '2': currentPath = upOne(currentPath); @@ -67,24 +88,22 @@ export async function selectPath() { currentPath = await downOne(currentPath); break; case '4': - await checkExists(currentPath); + currentPath = await createSubDir(currentPath, pathMustExist); break; case '5': - currentPath = await createSubDir(currentPath); - break; - case '6': - if (!isDir(currentPath)) { + if (pathMustExist && !isDir(combine(currentPath))) { console.log("Current path does not exist."); + break; } else { - return currentPath; + return combine(currentPath); } - case '7': - return ""; + case '6': + return combine(currentPath); } } } -async function enterPath() { +async function enterPath(currentPath, pathMustExist) { const response = await inquirer.prompt([ { type: 'input', @@ -92,6 +111,11 @@ async function enterPath() { message: 'Enter Path:' }]); + const newPath = response.path; + if (pathMustExist && !isDir(newPath)) { + console.log("The entered path does not exist."); + return currentPath; + } return splitPath(response.path); } @@ -99,20 +123,30 @@ function upOne(currentPath) { return currentPath.slice(0, currentPath.length - 1); } -function isDir(dir) { - return fs.lstatSync(dir).isDirectory(); +export function isDir(dir) { + try { + return fs.lstatSync(dir).isDirectory(); + } catch { + return false; + } } function isSubDir(currentPath, entry) { - const newPath = path.join(...currentPath, entry); + const newPath = combineWith(currentPath, entry); return isDir(newPath); } function getSubDirOptions(currentPath) { - const entries = fs.readdirSync(path.join(...currentPath)); + const fullPath = combine(currentPath); + currentPath.forEach(function(part) { + console.log("part: '" + part + "'"); + }); + console.log("current: '" + fullPath + "'"); + const entries = fs.readdirSync(fullPath); var result = []; var counter = 1; entries.forEach(function(entry) { + console.log("entry: " + entry); if (isSubDir(currentPath, entry)) { result.push(counter + ". " + entry); } @@ -144,15 +178,7 @@ async function downOne(currentPath) { return [...currentPath, subDir]; } -async function checkExists(currentPath) { - if (!isDir(path.join(...currentPath))) { - console.log("Current path does not exist."); - } else{ - console.log("Current path exists."); - } -} - -async function createSubDir(currentPath) { +async function createSubDir(currentPath, pathMustExist) { const response = await inquirer.prompt([ { type: 'input', @@ -163,7 +189,9 @@ async function createSubDir(currentPath) { const name = response.name; if (name.length < 1) return; - const fullDir = path.join(...currentPath, name); - fs.mkdirSync(fullDir); + const fullDir = combineWith(currentPath, name); + if (pathMustExist && !isDir(fullDir)) { + fs.mkdirSync(fullDir); + } return [...currentPath, name]; }