mirror of
https://github.com/logos-storage/logos-storage-installer.git
synced 2026-01-03 14:03:08 +00:00
wip
This commit is contained in:
parent
2297d01966
commit
769fb06ad7
@ -24,6 +24,7 @@ import { showConfigMenu } from "./configmenu.js";
|
||||
import { openCodexApp } from "./services/codexapp.js";
|
||||
|
||||
import { MainMenu } from "./ui/mainmenu.js";
|
||||
import { InstallMenu } from "./ui/installmenu.js";
|
||||
import { UiService } from "./services/uiservice.js";
|
||||
|
||||
async function showNavigationMenu() {
|
||||
@ -89,14 +90,15 @@ export async function main() {
|
||||
process.on("SIGTERM", handleExit);
|
||||
process.on("SIGQUIT", handleExit);
|
||||
|
||||
const config = loadConfig();
|
||||
const uiService = new UiService();
|
||||
const mainMenu = new MainMenu(uiService);
|
||||
const installMenu = new InstallMenu(uiService, config);
|
||||
const mainMenu = new MainMenu(uiService, installMenu);
|
||||
|
||||
await mainMenu.show();
|
||||
return;
|
||||
|
||||
try {
|
||||
const config = loadConfig();
|
||||
while (true) {
|
||||
console.log("\n" + chalk.cyanBright(ASCII_ART));
|
||||
const { choice } = await inquirer
|
||||
|
||||
@ -2,6 +2,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { getAppDataDir } from "../utils/appdata.js";
|
||||
import {
|
||||
getCodexBinPath,
|
||||
getCodexDataDirDefaultPath,
|
||||
getCodexLogsDefaultPath,
|
||||
} from "../utils/appdata.js";
|
||||
@ -9,6 +10,7 @@ import {
|
||||
const defaultConfig = {
|
||||
codexExe: "",
|
||||
// User-selected config options:
|
||||
codexPath: getCodexBinPath(),
|
||||
dataDir: getCodexDataDirDefaultPath(),
|
||||
logsDir: getCodexLogsDefaultPath(),
|
||||
storageQuota: 8 * 1024 * 1024 * 1024,
|
||||
|
||||
41
src/services/fsservice.js
Normal file
41
src/services/fsservice.js
Normal file
@ -0,0 +1,41 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { filesystemSync } from "fs-filesystem";
|
||||
|
||||
export class FsService {
|
||||
getAvailableRoots = () => {
|
||||
const devices = filesystemSync();
|
||||
var mountPoints = [];
|
||||
Object.keys(devices).forEach(function (key) {
|
||||
var val = devices[key];
|
||||
val.volumes.forEach(function (volume) {
|
||||
mountPoints.push(volume.mountPoint);
|
||||
});
|
||||
});
|
||||
|
||||
if (mountPoints.length < 1) {
|
||||
throw new Error("Failed to detect file system devices.");
|
||||
}
|
||||
return mountPoints;
|
||||
};
|
||||
|
||||
pathJoin = (parts) => {
|
||||
return path.join(...parts);
|
||||
};
|
||||
|
||||
isDir = (dir) => {
|
||||
try {
|
||||
return fs.lstatSync(dir).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
readDir = (dir) => {
|
||||
return fs.readdirSync(dir);
|
||||
};
|
||||
|
||||
makeDir = (dir) => {
|
||||
fs.mkdirSync(dir);
|
||||
};
|
||||
}
|
||||
@ -55,7 +55,7 @@ export class UiService {
|
||||
askMultipleChoice = async (message, choices) => {
|
||||
var counter = 1;
|
||||
var promptChoices = [];
|
||||
choices.forEach(function(choice) {
|
||||
choices.forEach(function (choice) {
|
||||
promptChoices.push(`${counter}. ${choice.label}`);
|
||||
counter++;
|
||||
});
|
||||
@ -67,8 +67,8 @@ export class UiService {
|
||||
message: message,
|
||||
choices: promptChoices,
|
||||
pageSize: counter - 1,
|
||||
loop: true
|
||||
}
|
||||
loop: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const selectStr = choice.split(".")[0];
|
||||
@ -76,4 +76,15 @@ export class UiService {
|
||||
|
||||
await choices[selectIndex].action();
|
||||
};
|
||||
|
||||
askPrompt = async (prompt) => {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "valueStr",
|
||||
message: prompt,
|
||||
},
|
||||
]);
|
||||
return response.valueStr;
|
||||
};
|
||||
}
|
||||
|
||||
38
src/ui/installmenu.js
Normal file
38
src/ui/installmenu.js
Normal file
@ -0,0 +1,38 @@
|
||||
export class InstallMenu {
|
||||
constructor(uiService, config) {
|
||||
this.ui = uiService;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
show = async () => {
|
||||
await this.ui.askMultipleChoice("Configure your Codex installation", [
|
||||
{
|
||||
label: "Install path: " + this.config.codexPath,
|
||||
action: async function () {
|
||||
console.log("run path selector");
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Storage provider module: Disabled (todo)",
|
||||
action: this.storageProviderOption,
|
||||
},
|
||||
{
|
||||
label: "Install!",
|
||||
action: this.performInstall,
|
||||
},
|
||||
{
|
||||
label: "Cancel",
|
||||
action: async function () {},
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
storageProviderOption = async () => {
|
||||
this.ui.showInfoMessage("This option is not currently available.");
|
||||
await this.show();
|
||||
};
|
||||
|
||||
performInstall = async () => {
|
||||
console.log("todo");
|
||||
};
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
export class MainMenu {
|
||||
constructor(uiService) {
|
||||
constructor(uiService, installMenu) {
|
||||
this.ui = uiService;
|
||||
this.installMenu = installMenu;
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
show = async () => {
|
||||
this.ui.showLogo();
|
||||
this.ui.showInfoMessage("hello");
|
||||
|
||||
|
||||
while (this.running) {
|
||||
await this.promptMainMenu();
|
||||
}
|
||||
@ -15,22 +16,20 @@ export class MainMenu {
|
||||
this.ui.showInfoMessage("K-THX-BYE");
|
||||
};
|
||||
|
||||
promptMainMenu = async() => {
|
||||
await this.ui.askMultipleChoice("Select an option",[
|
||||
promptMainMenu = async () => {
|
||||
await this.ui.askMultipleChoice("Select an option", [
|
||||
{
|
||||
label: "optionOne",
|
||||
action: async function() {
|
||||
console.log("A!")
|
||||
}
|
||||
},{
|
||||
label: "optionTwo",
|
||||
action: this.closeMainMenu
|
||||
label: "Install Codex",
|
||||
action: this.installMenu.show,
|
||||
},
|
||||
])
|
||||
{
|
||||
label: "Exit",
|
||||
action: this.closeMainMenu,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
closeMainMenu = async() => {
|
||||
console.log("B!")
|
||||
closeMainMenu = async () => {
|
||||
this.running = false;
|
||||
};
|
||||
}
|
||||
|
||||
51
src/ui/mainmenu.test.js
Normal file
51
src/ui/mainmenu.test.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { describe, beforeEach, it, expect, vi } from "vitest";
|
||||
import { MainMenu } from "./mainmenu.js";
|
||||
|
||||
describe("mainmenu", () => {
|
||||
let mainmenu;
|
||||
const mockUiService = {
|
||||
showLogo: vi.fn(),
|
||||
showInfoMessage: vi.fn(),
|
||||
askMultipleChoice: vi.fn(),
|
||||
};
|
||||
const mockInstallMenu = {
|
||||
show: vi.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
|
||||
mainmenu = new MainMenu(mockUiService, mockInstallMenu);
|
||||
|
||||
// Presents test getting stuck in main loop.
|
||||
const originalPrompt = mainmenu.promptMainMenu;
|
||||
mainmenu.promptMainMenu = async () => {
|
||||
mainmenu.running = false;
|
||||
await originalPrompt();
|
||||
};
|
||||
});
|
||||
|
||||
it("shows the main menu", async () => {
|
||||
await mainmenu.show();
|
||||
|
||||
expect(mockUiService.showLogo).toHaveBeenCalled();
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith("hello"); // example, delete this later.
|
||||
expect(mockUiService.showInfoMessage).toHaveBeenCalledWith("K-THX-BYE"); // example, delete this later.
|
||||
|
||||
expect(mockUiService.askMultipleChoice).toHaveBeenCalledWith(
|
||||
"Select an option",
|
||||
[
|
||||
{ label: "Install Codex", action: mockInstallMenu.show },
|
||||
{ label: "Exit", action: mainmenu.closeMainMenu },
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
it("sets running to false when closeMainMenu is called", async () => {
|
||||
mainmenu.running = true;
|
||||
|
||||
await mainmenu.closeMainMenu();
|
||||
|
||||
expect(mainmenu.running).toEqual(false);
|
||||
});
|
||||
});
|
||||
@ -1,52 +1,49 @@
|
||||
import inquirer from "inquirer";
|
||||
export class NumberSelector {
|
||||
constructor(uiService) {
|
||||
this.uiService = uiService;
|
||||
}
|
||||
|
||||
function getMetricsMult(valueStr, allowMetricPostfixes) {
|
||||
if (!allowMetricPostfixes) return 1;
|
||||
const lower = valueStr.toLowerCase();
|
||||
if (lower.endsWith("tb") || lower.endsWith("t")) return Math.pow(1024, 4);
|
||||
if (lower.endsWith("gb") || lower.endsWith("g")) return Math.pow(1024, 3);
|
||||
if (lower.endsWith("mb") || lower.endsWith("m")) return Math.pow(1024, 2);
|
||||
if (lower.endsWith("kb") || lower.endsWith("k")) return Math.pow(1024, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
function getNumericValue(valueStr) {
|
||||
try {
|
||||
const num = valueStr.match(/\d+/g);
|
||||
const result = parseInt(num);
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
throw new Error("Invalid input received.");
|
||||
showNumberSelector = async (
|
||||
currentValue,
|
||||
promptMessage,
|
||||
allowMetricPostfixes,
|
||||
) => {
|
||||
try {
|
||||
var valueStr = await this.promptForValueStr(promptMessage);
|
||||
valueStr = valueStr.replaceAll(" ", "");
|
||||
const mult = this.getMetricsMult(valueStr, allowMetricPostfixes);
|
||||
const value = this.getNumericValue(valueStr);
|
||||
return value * mult;
|
||||
} catch {
|
||||
return currentValue;
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.log("Failed to parse input: " + error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function promptForValueStr(promptMessage) {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "valueStr",
|
||||
message: promptMessage,
|
||||
},
|
||||
]);
|
||||
return response.valueStr;
|
||||
}
|
||||
getMetricsMult = (valueStr, allowMetricPostfixes) => {
|
||||
if (!allowMetricPostfixes) return 1;
|
||||
const lower = valueStr.toLowerCase();
|
||||
if (lower.endsWith("tb") || lower.endsWith("t")) return Math.pow(1024, 4);
|
||||
if (lower.endsWith("gb") || lower.endsWith("g")) return Math.pow(1024, 3);
|
||||
if (lower.endsWith("mb") || lower.endsWith("m")) return Math.pow(1024, 2);
|
||||
if (lower.endsWith("kb") || lower.endsWith("k")) return Math.pow(1024, 1);
|
||||
return 1;
|
||||
};
|
||||
|
||||
export async function showNumberSelector(
|
||||
currentValue,
|
||||
promptMessage,
|
||||
allowMetricPostfixes,
|
||||
) {
|
||||
try {
|
||||
var valueStr = await promptForValueStr(promptMessage);
|
||||
valueStr = valueStr.replaceAll(" ", "");
|
||||
const mult = getMetricsMult(valueStr, allowMetricPostfixes);
|
||||
const value = getNumericValue(valueStr);
|
||||
return value * mult;
|
||||
} catch {
|
||||
return currentValue;
|
||||
}
|
||||
getNumericValue = (valueStr) => {
|
||||
try {
|
||||
const num = valueStr.match(/\d+/g);
|
||||
const result = parseInt(num);
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
throw new Error("Invalid input received.");
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.log("Failed to parse input: " + error.message);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
promptForValueStr = async (promptMessage) => {
|
||||
return this.uiService.askPrompt(promptMessage);
|
||||
};
|
||||
}
|
||||
|
||||
66
src/utils/numberSelector.test.js
Normal file
66
src/utils/numberSelector.test.js
Normal file
@ -0,0 +1,66 @@
|
||||
import { describe, beforeEach, it, expect, vi } from "vitest";
|
||||
import { NumberSelector } from "./numberSelector.js";
|
||||
|
||||
describe("number selector", () => {
|
||||
let numberSelector;
|
||||
const mockUiService = {
|
||||
askPrompt: vi.fn(),
|
||||
};
|
||||
|
||||
const prompt = "abc??";
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
|
||||
numberSelector = new NumberSelector(mockUiService);
|
||||
});
|
||||
|
||||
it("shows the prompt", async () => {
|
||||
await numberSelector.showNumberSelector(0, prompt, false);
|
||||
|
||||
expect(mockUiService.askPrompt).toHaveBeenCalledWith(prompt);
|
||||
});
|
||||
|
||||
it("returns a number given valid input", async () => {
|
||||
mockUiService.askPrompt.mockResolvedValue("123");
|
||||
|
||||
const number = await numberSelector.showNumberSelector(0, prompt, false);
|
||||
|
||||
expect(number).toEqual(123);
|
||||
});
|
||||
|
||||
it("returns the current number given invalid input", async () => {
|
||||
const currentValue = 321;
|
||||
|
||||
mockUiService.askPrompt.mockResolvedValue("what?!");
|
||||
|
||||
const number = await numberSelector.showNumberSelector(
|
||||
currentValue,
|
||||
prompt,
|
||||
false,
|
||||
);
|
||||
|
||||
expect(number).toEqual(currentValue);
|
||||
});
|
||||
|
||||
async function run(input) {
|
||||
mockUiService.askPrompt.mockResolvedValue(input);
|
||||
return await numberSelector.showNumberSelector(0, prompt, true);
|
||||
}
|
||||
|
||||
it("allows for metric postfixes (k)", async () => {
|
||||
expect(await run("1k")).toEqual(1024);
|
||||
});
|
||||
|
||||
it("allows for metric postfixes (m)", async () => {
|
||||
expect(await run("1m")).toEqual(1024 * 1024);
|
||||
});
|
||||
|
||||
it("allows for metric postfixes (g)", async () => {
|
||||
expect(await run("1g")).toEqual(1024 * 1024 * 1024);
|
||||
});
|
||||
|
||||
it("allows for metric postfixes (t)", async () => {
|
||||
expect(await run("1t")).toEqual(1024 * 1024 * 1024 * 1024);
|
||||
});
|
||||
});
|
||||
@ -1,251 +1,219 @@
|
||||
import path from "path";
|
||||
import inquirer from "inquirer";
|
||||
import boxen from "boxen";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import { filesystemSync } from "fs-filesystem";
|
||||
export class PathSelector {
|
||||
constructor(uiService, fsService) {
|
||||
this.ui = uiService;
|
||||
this.fs = fsService;
|
||||
|
||||
function showMsg(msg) {
|
||||
console.log(
|
||||
boxen(chalk.white(msg), {
|
||||
padding: 1,
|
||||
margin: 1,
|
||||
borderStyle: "round",
|
||||
borderColor: "white",
|
||||
titleAlignment: "center",
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function getAvailableRoots() {
|
||||
const devices = filesystemSync();
|
||||
var mountPoints = [];
|
||||
Object.keys(devices).forEach(function (key) {
|
||||
var val = devices[key];
|
||||
val.volumes.forEach(function (volume) {
|
||||
mountPoints.push(volume.mountPoint);
|
||||
});
|
||||
});
|
||||
|
||||
if (mountPoints.length < 1) {
|
||||
throw new Error("Failed to detect file system devices.");
|
||||
this.pathMustExist = true;
|
||||
}
|
||||
return mountPoints;
|
||||
}
|
||||
|
||||
function splitPath(str) {
|
||||
return str.replaceAll("\\", "/").split("/");
|
||||
}
|
||||
|
||||
function dropEmptyParts(parts) {
|
||||
var result = [];
|
||||
parts.forEach(function (part) {
|
||||
if (part.length > 0) {
|
||||
result.push(part);
|
||||
showPathSelector = async (startingPath, pathMustExist) => {
|
||||
this.pathMustExist = pathMustExist;
|
||||
this.roots = this.fs.getAvailableRoots();
|
||||
this.currentPath = this.splitPath(startingPath);
|
||||
if (!this.hasValidRoot(this.currentPath)) {
|
||||
this.currentPath = [roots[0]];
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
while (true) {
|
||||
this.showCurrent();
|
||||
this.ui.askMultiChoice("Select an option:", [
|
||||
{
|
||||
label: "Enter path",
|
||||
action: this.enterPath,
|
||||
},
|
||||
{
|
||||
label: "Go up one",
|
||||
action: this.upOne,
|
||||
},
|
||||
{
|
||||
label: "Go down one",
|
||||
action: this.downOne,
|
||||
},
|
||||
{
|
||||
label: "Create new folder here",
|
||||
action: this.createSubDir,
|
||||
},
|
||||
{
|
||||
label: "Select this path",
|
||||
action: this.selectThisPath,
|
||||
},
|
||||
{
|
||||
label: "Cancel",
|
||||
action: this.cancel,
|
||||
},
|
||||
]);
|
||||
// var newCurrentPath = currentPath;
|
||||
// switch (choice.split(".")[0]) {
|
||||
// case "1":
|
||||
// newCurrentPath = await enterPath(currentPath, pathMustExist);
|
||||
// break;
|
||||
// case "2":
|
||||
// newCurrentPath = upOne(currentPath);
|
||||
// break;
|
||||
// case "3":
|
||||
// newCurrentPath = await downOne(currentPath);
|
||||
// break;
|
||||
// case "4":
|
||||
// newCurrentPath = await createSubDir(currentPath, pathMustExist);
|
||||
// break;
|
||||
// case "5":
|
||||
// if (pathMustExist && !isDir(combine(currentPath))) {
|
||||
// console.log("Current path does not exist.");
|
||||
// break;
|
||||
// } else {
|
||||
// return combine(currentPath);
|
||||
// }
|
||||
// case "6":
|
||||
// return combine(currentPath);
|
||||
// }
|
||||
|
||||
function combine(parts) {
|
||||
const toJoin = dropEmptyParts(parts);
|
||||
if (toJoin.length == 1) return toJoin[0];
|
||||
return path.join(...toJoin);
|
||||
}
|
||||
// if (hasValidRoot(roots, newCurrentPath)) {
|
||||
// currentPath = newCurrentPath;
|
||||
// } else {
|
||||
// console.log("Selected path has no valid root.");
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
function combineWith(parts, extra) {
|
||||
const toJoin = dropEmptyParts(parts);
|
||||
if (toJoin.length == 1) return path.join(toJoin[0], extra);
|
||||
return path.join(...toJoin, extra);
|
||||
}
|
||||
splitPath = (str) => {
|
||||
return str.replaceAll("\\", "/").split("/");
|
||||
};
|
||||
|
||||
function showCurrent(currentPath) {
|
||||
const len = currentPath.length;
|
||||
showMsg(`Current path: [${len}]\n` + combine(currentPath));
|
||||
dropEmptyParts = (parts) => {
|
||||
var result = [];
|
||||
parts.forEach(function (part) {
|
||||
if (part.length > 0) {
|
||||
result.push(part);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
if (len < 2) {
|
||||
showMsg(
|
||||
"Warning - Known issue:\n" +
|
||||
"Path selection does not work in root paths on some platforms.\n" +
|
||||
'Use "Enter path" or "Create new folder" to navigate and create folders\n' +
|
||||
"if this is the case for you.",
|
||||
combine = (parts) => {
|
||||
const toJoin = this.dropEmptyParts(parts);
|
||||
if (toJoin.length == 1) return toJoin[0];
|
||||
return this.fs.pathJoin(...toJoin);
|
||||
};
|
||||
|
||||
combineWith = (parts, extra) => {
|
||||
const toJoin = this.dropEmptyParts(parts);
|
||||
if (toJoin.length == 1) return this.fs.pathJoin(toJoin[0], extra);
|
||||
return this.fs.pathJoin(...toJoin, extra);
|
||||
};
|
||||
|
||||
showCurrent = () => {
|
||||
const len = this.currentPath.length;
|
||||
this.ui.showInfoMessage(
|
||||
`Current path: [${len}]\n` + this.combine(this.currentPath),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function hasValidRoot(roots, checkPath) {
|
||||
if (checkPath.length < 1) return false;
|
||||
var result = false;
|
||||
roots.forEach(function (root) {
|
||||
if (root.toLowerCase() == checkPath[0].toLowerCase()) {
|
||||
console.log("valid root: " + combine(checkPath));
|
||||
result = true;
|
||||
if (len < 2) {
|
||||
this.ui.showInfoMessage(
|
||||
"Warning - Known issue:\n" +
|
||||
"Path selection does not work in root paths on some platforms.\n" +
|
||||
'Use "Enter path" or "Create new folder" to navigate and create folders\n' +
|
||||
"if this is the case for you.",
|
||||
);
|
||||
}
|
||||
});
|
||||
if (!result) console.log("invalid root: " + combine(checkPath));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
async function showMain(currentPath) {
|
||||
showCurrent(currentPath);
|
||||
const { choice } = await inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "choice",
|
||||
message: "Select an option:",
|
||||
choices: [
|
||||
"1. Enter path",
|
||||
"2. Go up one",
|
||||
"3. Go down one",
|
||||
"4. Create new folder here",
|
||||
"5. Select this path",
|
||||
"6. Cancel",
|
||||
],
|
||||
pageSize: 6,
|
||||
loop: true,
|
||||
},
|
||||
])
|
||||
.catch(() => {
|
||||
handleExit();
|
||||
return { choice: "6" };
|
||||
hasValidRoot = (checkPath) => {
|
||||
if (checkPath.length < 1) return false;
|
||||
var result = false;
|
||||
this.roots.forEach(function (root) {
|
||||
if (root.toLowerCase() == checkPath[0].toLowerCase()) {
|
||||
result = true;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
export async function showPathSelector(startingPath, pathMustExist) {
|
||||
const roots = getAvailableRoots();
|
||||
var currentPath = splitPath(startingPath);
|
||||
if (!hasValidRoot(roots, currentPath)) {
|
||||
currentPath = [roots[0]];
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const choice = await showMain(currentPath);
|
||||
|
||||
var newCurrentPath = currentPath;
|
||||
switch (choice.split(".")[0]) {
|
||||
case "1":
|
||||
newCurrentPath = await enterPath(currentPath, pathMustExist);
|
||||
break;
|
||||
case "2":
|
||||
newCurrentPath = upOne(currentPath);
|
||||
break;
|
||||
case "3":
|
||||
newCurrentPath = await downOne(currentPath);
|
||||
break;
|
||||
case "4":
|
||||
newCurrentPath = await createSubDir(currentPath, pathMustExist);
|
||||
break;
|
||||
case "5":
|
||||
if (pathMustExist && !isDir(combine(currentPath))) {
|
||||
console.log("Current path does not exist.");
|
||||
break;
|
||||
} else {
|
||||
return combine(currentPath);
|
||||
}
|
||||
case "6":
|
||||
return combine(currentPath);
|
||||
updateCurrentIfValidFull = (newFullPath) => {
|
||||
if (this.pathMustExist && !this.fs.isDir(newFullPath)) {
|
||||
console.log("The path does not exist.");
|
||||
}
|
||||
this.updateCurrentIfValidParts(this.splitPath(newFullPath));
|
||||
}
|
||||
|
||||
if (hasValidRoot(roots, newCurrentPath)) {
|
||||
currentPath = newCurrentPath;
|
||||
} else {
|
||||
console.log("Selected path has no valid root.");
|
||||
updateCurrentIfValidParts = (newParts) => {
|
||||
if (!this.hasValidRoot(newParts)) {
|
||||
console.log("The path has no valid root.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function enterPath(currentPath, pathMustExist) {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "path",
|
||||
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);
|
||||
}
|
||||
|
||||
function upOne(currentPath) {
|
||||
return currentPath.slice(0, currentPath.length - 1);
|
||||
}
|
||||
|
||||
export function isDir(dir) {
|
||||
try {
|
||||
return fs.lstatSync(dir).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isSubDir(currentPath, entry) {
|
||||
const newPath = combineWith(currentPath, entry);
|
||||
return isDir(newPath);
|
||||
}
|
||||
|
||||
function getSubDirOptions(currentPath) {
|
||||
const fullPath = combine(currentPath);
|
||||
const entries = fs.readdirSync(fullPath);
|
||||
var result = [];
|
||||
var counter = 1;
|
||||
entries.forEach(function (entry) {
|
||||
if (isSubDir(currentPath, entry)) {
|
||||
result.push(counter + ". " + entry);
|
||||
counter = counter + 1;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async function downOne(currentPath) {
|
||||
const options = getSubDirOptions(currentPath);
|
||||
if (options.length == 0) {
|
||||
console.log("There are no subdirectories here.");
|
||||
return currentPath;
|
||||
this.currentPath = newParts;
|
||||
}
|
||||
|
||||
const { choice } = await inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "choice",
|
||||
message: "Select an subdir:",
|
||||
choices: options,
|
||||
pageSize: options.length,
|
||||
loop: true,
|
||||
},
|
||||
])
|
||||
.catch(() => {
|
||||
return currentPath;
|
||||
enterPath = async () => {
|
||||
const newPath = await this.ui.askPrompt("Enter Path:");
|
||||
this.updateCurrentIfValidFull(newPath);
|
||||
};
|
||||
|
||||
upOne = () => {
|
||||
const newParts = this.currentPath.slice(0, this.currentPath.length - 1);
|
||||
this.updateCurrentIfValidParts(newParts);
|
||||
};
|
||||
|
||||
isSubDir = (entry) => {
|
||||
const newPath = this.combineWith(this.currentPath, entry);
|
||||
return this.fs.isDir(newPath);
|
||||
};
|
||||
|
||||
getSubDirOptions = () => {
|
||||
const fullPath = this.combine(this.currentPath);
|
||||
const entries = this.fs.readDir(fullPath);
|
||||
var result = [];
|
||||
entries.forEach(function (entry) {
|
||||
if (this.isSubDir(entry)) {
|
||||
result.push(entry);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
const subDir = choice.split(". ")[1];
|
||||
return [...currentPath, subDir];
|
||||
}
|
||||
|
||||
async function createSubDir(currentPath, pathMustExist) {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "name",
|
||||
message: "Enter name:",
|
||||
},
|
||||
]);
|
||||
|
||||
const name = response.name;
|
||||
if (name.length < 1) return;
|
||||
|
||||
const fullDir = combineWith(currentPath, name);
|
||||
if (pathMustExist && !isDir(fullDir)) {
|
||||
fs.mkdirSync(fullDir);
|
||||
}
|
||||
return [...currentPath, name];
|
||||
downOne = async () => {
|
||||
const options = this.getSubDirOptions();
|
||||
if (options.length == 0) {
|
||||
console.log("There are no subdirectories here.");
|
||||
}
|
||||
|
||||
var selected = "";
|
||||
const makeSelector = () => {
|
||||
|
||||
};
|
||||
|
||||
const { choice } = await inquirer
|
||||
.prompt([
|
||||
{
|
||||
type: "list",
|
||||
name: "choice",
|
||||
message: "Select an subdir:",
|
||||
choices: options,
|
||||
pageSize: options.length,
|
||||
loop: true,
|
||||
},
|
||||
])
|
||||
.catch(() => {
|
||||
return currentPath;
|
||||
});
|
||||
|
||||
const subDir = choice.split(". ")[1];
|
||||
return [...currentPath, subDir];
|
||||
};
|
||||
|
||||
createSubDir = async (currentPath, pathMustExist) => {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: "input",
|
||||
name: "name",
|
||||
message: "Enter name:",
|
||||
},
|
||||
]);
|
||||
|
||||
const name = response.name;
|
||||
if (name.length < 1) return;
|
||||
|
||||
const fullDir = combineWith(currentPath, name);
|
||||
if (pathMustExist && !isDir(fullDir)) {
|
||||
// fs.mkdirSync(fullDir);
|
||||
}
|
||||
return [...currentPath, name];
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user