mirror of
https://github.com/logos-storage/logos-storage-installer.git
synced 2026-01-05 06:53:06 +00:00
Implements and adds tests for installer
This commit is contained in:
parent
10e1a33cc4
commit
574d4febe2
@ -18,6 +18,18 @@ export const mockFsService = {
|
||||
getAvailableRoots: vi.fn(),
|
||||
pathJoin: vi.fn(),
|
||||
isDir: vi.fn(),
|
||||
isFile: vi.fn(),
|
||||
readDir: vi.fn(),
|
||||
makeDir: vi.fn(),
|
||||
};
|
||||
|
||||
export const mockShellService = {
|
||||
run: vi.fn(),
|
||||
};
|
||||
|
||||
export const mockOsService = {
|
||||
isWindows: vi.fn(),
|
||||
isDarwin: vi.fn(),
|
||||
isLinux: vi.fn(),
|
||||
getWorkingDir: vi.fn(),
|
||||
};
|
||||
|
||||
@ -135,14 +135,6 @@ async function performInstall(config) {
|
||||
try {
|
||||
if (platform === "win32") {
|
||||
try {
|
||||
try {
|
||||
await runCommand("curl --version");
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
"curl is not available. Please install curl or update your Windows version.",
|
||||
);
|
||||
}
|
||||
|
||||
await runCommand(
|
||||
"curl -LO --ssl-no-revoke https://get.codex.storage/install.cmd",
|
||||
);
|
||||
|
||||
@ -1,9 +1,130 @@
|
||||
export class Installer {
|
||||
constructor(configService) {
|
||||
constructor(configService, shellService, osService, fsService) {
|
||||
this.config = configService.get();
|
||||
this.configService = configService;
|
||||
this.shell = shellService;
|
||||
this.os = osService;
|
||||
this.fs = fsService;
|
||||
}
|
||||
|
||||
isCodexInstalled = async () => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
await this.getCodexVersion();
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
getCodexVersion = async () => {
|
||||
if (this.config.codexExe.length < 1)
|
||||
throw new Error("Codex not installed.");
|
||||
const version = await this.shell.run(`"${this.config.codexExe}" --version`);
|
||||
if (version.length < 1) throw new Error("Version info not found.");
|
||||
return version;
|
||||
};
|
||||
|
||||
installCodex = async (processCallbacks) => {
|
||||
if (!(await this.arePrerequisitesCorrect(processCallbacks))) return;
|
||||
|
||||
processCallbacks.installStarts();
|
||||
if (this.os.isWindows()) {
|
||||
await this.installCodexWindows(processCallbacks);
|
||||
} else {
|
||||
await this.installCodexUnix(processCallbacks);
|
||||
}
|
||||
|
||||
if (!(await this.isCodexInstalled()))
|
||||
throw new Error("Codex installation failed.");
|
||||
processCallbacks.installSuccessful();
|
||||
};
|
||||
|
||||
arePrerequisitesCorrect = async (processCallbacks) => {
|
||||
if (await this.isCodexInstalled()) {
|
||||
processCallbacks.warn("Codex is already installed.");
|
||||
return false;
|
||||
}
|
||||
if (this.config.codexInstallPath.length < 1) {
|
||||
processCallbacks.warn("Install path not set.");
|
||||
return false;
|
||||
}
|
||||
if (!(await this.isCurlAvailable())) {
|
||||
processCallbacks.warn("Curl is not available.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
isCurlAvailable = async () => {
|
||||
const curlVersion = await this.shell.run("curl --version");
|
||||
return curlVersion.length > 0;
|
||||
};
|
||||
|
||||
installCodexWindows = async (processCallbacks) => {
|
||||
await this.shell.run(
|
||||
"curl -LO --ssl-no-revoke https://get.codex.storage/install.cmd",
|
||||
);
|
||||
processCallbacks.downloadSuccessful();
|
||||
await this.shell.run(
|
||||
`set "INSTALL_DIR=${this.config.codexInstallPath}" && ` +
|
||||
`"${this.os.getWorkingDir()}\\install.cmd"`,
|
||||
);
|
||||
await this.saveCodexInstallPath("codex.exe");
|
||||
await this.shell.run("del /f install.cmd");
|
||||
};
|
||||
|
||||
installCodexUnix = async (processCallbacks) => {
|
||||
await this.ensureUnixDependencies();
|
||||
await this.shell.run(
|
||||
"curl -# --connect-timeout 10 --max-time 60 -L https://get.codex.storage/install.sh -o install.sh && chmod +x install.sh",
|
||||
);
|
||||
processCallbacks.downloadSuccessful();
|
||||
|
||||
if (this.os.isDarwin()) {
|
||||
await this.runInstallerDarwin();
|
||||
} else {
|
||||
await this.runInstallerLinux();
|
||||
}
|
||||
|
||||
await this.saveCodexInstallPath("codex");
|
||||
await this.shell.run("rm -f install.sh");
|
||||
};
|
||||
|
||||
runInstallerDarwin = async () => {
|
||||
const timeoutCommand = `perl -e '
|
||||
eval {
|
||||
local $SIG{ALRM} = sub { die "timeout\\n" };
|
||||
alarm(120);
|
||||
system("INSTALL_DIR=\\"${this.config.codexInstallPath}\\" bash install.sh");
|
||||
alarm(0);
|
||||
};
|
||||
die if $@;
|
||||
'`;
|
||||
await this.shell.run(timeoutCommand);
|
||||
};
|
||||
|
||||
runInstallerLinux = async () => {
|
||||
await this.shell.run(
|
||||
`INSTALL_DIR="${this.config.codexInstallPath}" timeout 120 bash install.sh`,
|
||||
);
|
||||
};
|
||||
|
||||
ensureUnixDependencies = async (processCallbacks) => {
|
||||
const libgompCheck = await this.shell.run("ldconfig -p | grep libgomp");
|
||||
if (libgompCheck.length < 1) {
|
||||
processCallbacks.warn("libgomp not found.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
saveCodexInstallPath = async (codexExe) => {
|
||||
this.config.codexExe = this.fs.pathJoin([
|
||||
this.config.codexInstallPath,
|
||||
codexExe,
|
||||
]);
|
||||
if (!this.fs.isFile(this.config.codexExe))
|
||||
throw new Error("Codex executable not found.");
|
||||
await this.configService.saveConfig();
|
||||
};
|
||||
}
|
||||
|
||||
372
src/handlers/installer.test.js
Normal file
372
src/handlers/installer.test.js
Normal file
@ -0,0 +1,372 @@
|
||||
import { describe, beforeEach, it, expect, vi } from "vitest";
|
||||
import {
|
||||
mockShellService,
|
||||
mockOsService,
|
||||
mockFsService,
|
||||
} from "../__mocks__/service.mocks.js";
|
||||
import { mockConfigService } from "../__mocks__/service.mocks.js";
|
||||
import { Installer } from "./installer.js";
|
||||
|
||||
describe("Installer", () => {
|
||||
const config = {
|
||||
codexInstallPath: "/install-codex",
|
||||
};
|
||||
const workingDir = "/working-dir";
|
||||
const processCallbacks = {
|
||||
installStarts: vi.fn(),
|
||||
downloadSuccessful: vi.fn(),
|
||||
installSuccessful: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
};
|
||||
let installer;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
mockConfigService.get.mockReturnValue(config);
|
||||
mockOsService.getWorkingDir.mockReturnValue(workingDir);
|
||||
|
||||
installer = new Installer(
|
||||
mockConfigService,
|
||||
mockShellService,
|
||||
mockOsService,
|
||||
mockFsService,
|
||||
);
|
||||
});
|
||||
|
||||
describe("getCodexVersion", () => {
|
||||
it("throws when codex exe is not set", async () => {
|
||||
config.codexExe = "";
|
||||
await expect(installer.getCodexVersion()).rejects.toThrow(
|
||||
"Codex not installed.",
|
||||
);
|
||||
});
|
||||
|
||||
it("throws when version info is not found", async () => {
|
||||
config.codexExe = "codex.exe";
|
||||
mockShellService.run.mockResolvedValueOnce("");
|
||||
await expect(installer.getCodexVersion()).rejects.toThrow(
|
||||
"Version info not found.",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns version info", async () => {
|
||||
const versionInfo = "versionInfo";
|
||||
config.codexExe = "codex.exe";
|
||||
mockShellService.run.mockResolvedValueOnce(versionInfo);
|
||||
const version = await installer.getCodexVersion();
|
||||
expect(version).toBe(versionInfo);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isCodexInstalled", () => {
|
||||
it("return true when getCodexVersion succeeds", async () => {
|
||||
installer.getCodexVersion = vi.fn();
|
||||
expect(await installer.isCodexInstalled()).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when getCodexVersion fails", async () => {
|
||||
installer.getCodexVersion = vi.fn(() => {
|
||||
throw new Error("Codex not installed.");
|
||||
});
|
||||
expect(await installer.isCodexInstalled()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("installCodex", () => {
|
||||
beforeEach(() => {
|
||||
installer.arePrerequisitesCorrect = vi.fn();
|
||||
installer.installCodexWindows = vi.fn();
|
||||
installer.installCodexUnix = vi.fn();
|
||||
installer.isCodexInstalled = vi.fn();
|
||||
});
|
||||
|
||||
it("returns early when prerequisites are not correct", async () => {
|
||||
installer.arePrerequisitesCorrect.mockResolvedValue(false);
|
||||
await installer.installCodex(processCallbacks);
|
||||
expect(processCallbacks.installStarts).not.toHaveBeenCalled();
|
||||
expect(processCallbacks.installSuccessful).not.toHaveBeenCalled();
|
||||
expect(processCallbacks.downloadSuccessful).not.toHaveBeenCalled();
|
||||
expect(installer.isCodexInstalled).not.toHaveBeenCalled();
|
||||
expect(installer.installCodexWindows).not.toHaveBeenCalled();
|
||||
expect(installer.installCodexUnix).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("prerequisites OK", () => {
|
||||
beforeEach(() => {
|
||||
installer.arePrerequisitesCorrect.mockResolvedValue(true);
|
||||
installer.isCodexInstalled.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
it("calls installStarts when prerequisites are correct", async () => {
|
||||
await installer.installCodex(processCallbacks);
|
||||
expect(processCallbacks.installStarts).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls installCodexWindows when OS is Windows", async () => {
|
||||
mockOsService.isWindows.mockReturnValue(true);
|
||||
await installer.installCodex(processCallbacks);
|
||||
expect(installer.installCodexWindows).toHaveBeenCalledWith(
|
||||
processCallbacks,
|
||||
);
|
||||
});
|
||||
|
||||
it("calls installCodexUnix when OS is not Windows", async () => {
|
||||
mockOsService.isWindows.mockReturnValue(false);
|
||||
await installer.installCodex(processCallbacks);
|
||||
expect(installer.installCodexUnix).toHaveBeenCalledWith(
|
||||
processCallbacks,
|
||||
);
|
||||
});
|
||||
|
||||
it("throws when codex is not installed after installation", async () => {
|
||||
installer.isCodexInstalled.mockResolvedValue(false);
|
||||
await expect(installer.installCodex(processCallbacks)).rejects.toThrow(
|
||||
"Codex installation failed.",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls installSuccessful when installation is successful", async () => {
|
||||
await installer.installCodex(processCallbacks);
|
||||
expect(processCallbacks.installSuccessful).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("arePrerequisitesCorrect", () => {
|
||||
beforeEach(() => {
|
||||
installer.isCodexInstalled = vi.fn();
|
||||
installer.isCurlAvailable = vi.fn();
|
||||
config.codexInstallPath = "/install-codex";
|
||||
});
|
||||
|
||||
it("returns false when codex is already installed", async () => {
|
||||
installer.isCodexInstalled.mockResolvedValue(true);
|
||||
expect(await installer.arePrerequisitesCorrect(processCallbacks)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(processCallbacks.warn).toHaveBeenCalledWith(
|
||||
"Codex is already installed.",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns false when install path is not set", async () => {
|
||||
config.codexInstallPath = "";
|
||||
expect(await installer.arePrerequisitesCorrect(processCallbacks)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(processCallbacks.warn).toHaveBeenCalledWith(
|
||||
"Install path not set.",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns false when curl is not available", async () => {
|
||||
installer.isCodexInstalled.mockResolvedValue(false);
|
||||
installer.isCurlAvailable.mockResolvedValue(false);
|
||||
expect(await installer.arePrerequisitesCorrect(processCallbacks)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(processCallbacks.warn).toHaveBeenCalledWith(
|
||||
"Curl is not available.",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns true when all prerequisites are correct", async () => {
|
||||
installer.isCodexInstalled.mockResolvedValue(false);
|
||||
installer.isCurlAvailable.mockResolvedValue(true);
|
||||
const result = await installer.arePrerequisitesCorrect(processCallbacks);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isCurlAvailable", () => {
|
||||
it("returns true when curl version is found", async () => {
|
||||
mockShellService.run.mockResolvedValueOnce("curl version");
|
||||
const result = await installer.isCurlAvailable();
|
||||
expect(mockShellService.run).toHaveBeenCalledWith("curl --version");
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false when curl version is not found", async () => {
|
||||
mockShellService.run.mockResolvedValueOnce("");
|
||||
const result = await installer.isCurlAvailable();
|
||||
expect(mockShellService.run).toHaveBeenCalledWith("curl --version");
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("install functions", () => {
|
||||
beforeEach(() => {
|
||||
installer.saveCodexInstallPath = vi.fn();
|
||||
});
|
||||
|
||||
describe("installCodexWindows", () => {
|
||||
it("runs the curl command to download the installer", async () => {
|
||||
await installer.installCodexWindows(processCallbacks);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
"curl -LO --ssl-no-revoke https://get.codex.storage/install.cmd",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls downloadSuccessful", async () => {
|
||||
await installer.installCodexWindows(processCallbacks);
|
||||
expect(processCallbacks.downloadSuccessful).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs installer script", async () => {
|
||||
await installer.installCodexWindows(processCallbacks);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
`set "INSTALL_DIR=${config.codexInstallPath}" && "${workingDir}\\install.cmd"`,
|
||||
);
|
||||
});
|
||||
|
||||
it("saves the codex install path", async () => {
|
||||
await installer.installCodexWindows(processCallbacks);
|
||||
expect(installer.saveCodexInstallPath).toHaveBeenCalledWith(
|
||||
"codex.exe",
|
||||
);
|
||||
});
|
||||
|
||||
it("deletes the installer script", async () => {
|
||||
await installer.installCodexWindows(processCallbacks);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith("del /f install.cmd");
|
||||
});
|
||||
});
|
||||
|
||||
describe("installCodexUnix", () => {
|
||||
beforeEach(() => {
|
||||
installer.ensureUnixDependencies = vi.fn();
|
||||
installer.runInstallerDarwin = vi.fn();
|
||||
installer.runInstallerLinux = vi.fn();
|
||||
});
|
||||
|
||||
it("ensures Unix dependencies", async () => {
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(installer.ensureUnixDependencies).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs the curl command to download the installer", async () => {
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
"curl -# --connect-timeout 10 --max-time 60 -L https://get.codex.storage/install.sh -o install.sh && chmod +x install.sh",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls downloadSuccessful", async () => {
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(processCallbacks.downloadSuccessful).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs installer for darwin ", async () => {
|
||||
mockOsService.isDarwin.mockReturnValue(true);
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(installer.runInstallerDarwin).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("runs installer for linux", async () => {
|
||||
mockOsService.isDarwin.mockReturnValue(false);
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(installer.runInstallerLinux).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("saves the codex install path", async () => {
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(installer.saveCodexInstallPath).toHaveBeenCalledWith("codex");
|
||||
});
|
||||
|
||||
it("deletes the installer script", async () => {
|
||||
await installer.installCodexUnix(processCallbacks);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith("rm -f install.sh");
|
||||
});
|
||||
});
|
||||
|
||||
describe("runInstallerDarwin", () => {
|
||||
it("runs the installer script for darwin with custom timeout command", async () => {
|
||||
const timeoutCommand = `perl -e '
|
||||
eval {
|
||||
local $SIG{ALRM} = sub { die "timeout\\n" };
|
||||
alarm(120);
|
||||
system("INSTALL_DIR=\\"${config.codexInstallPath}\\" bash install.sh");
|
||||
alarm(0);
|
||||
};
|
||||
die if $@;
|
||||
'`;
|
||||
await installer.runInstallerDarwin();
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(timeoutCommand);
|
||||
});
|
||||
});
|
||||
|
||||
describe("runInstallerLinux", () => {
|
||||
it("runs the installer script using unix timeout command", async () => {
|
||||
await installer.runInstallerLinux();
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
`INSTALL_DIR="${config.codexInstallPath}" timeout 120 bash install.sh`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureUnixDependencies", () => {
|
||||
it("returns true when libgomp is installed", async () => {
|
||||
mockShellService.run.mockResolvedValueOnce("yes");
|
||||
expect(await installer.ensureUnixDependencies(processCallbacks)).toBe(
|
||||
true,
|
||||
);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
"ldconfig -p | grep libgomp",
|
||||
);
|
||||
});
|
||||
|
||||
it("returns false when libgomp is not found", async () => {
|
||||
mockShellService.run.mockResolvedValue("");
|
||||
expect(await installer.ensureUnixDependencies(processCallbacks)).toBe(
|
||||
false,
|
||||
);
|
||||
expect(mockShellService.run).toHaveBeenCalledWith(
|
||||
"ldconfig -p | grep libgomp",
|
||||
);
|
||||
});
|
||||
|
||||
it("it calls warn in processCallbacks when libgomp is not found", async () => {
|
||||
mockShellService.run.mockResolvedValue("");
|
||||
await installer.ensureUnixDependencies(processCallbacks);
|
||||
expect(processCallbacks.warn).toHaveBeenCalledWith("libgomp not found.");
|
||||
});
|
||||
});
|
||||
|
||||
describe("saveCodexInstallPath", () => {
|
||||
const codexExe = "_codex_.exe";
|
||||
const pathJointResult = "/path-to-codex/_codex_.exe";
|
||||
|
||||
beforeEach(() => {
|
||||
mockFsService.pathJoin.mockReturnValue(pathJointResult);
|
||||
});
|
||||
|
||||
it("combines the install path with the exe", async () => {
|
||||
mockFsService.isFile.mockReturnValue(true);
|
||||
await installer.saveCodexInstallPath(codexExe);
|
||||
expect(mockFsService.pathJoin).toHaveBeenCalledWith([
|
||||
config.codexInstallPath,
|
||||
codexExe,
|
||||
]);
|
||||
});
|
||||
|
||||
it("sets the codex exe path", async () => {
|
||||
mockFsService.isFile.mockReturnValue(true);
|
||||
await installer.saveCodexInstallPath(codexExe);
|
||||
expect(config.codexExe).toBe(pathJointResult);
|
||||
});
|
||||
|
||||
it("throws when file does not exist", async () => {
|
||||
mockFsService.isFile.mockReturnValue(false);
|
||||
await expect(installer.saveCodexInstallPath(codexExe)).rejects.toThrow(
|
||||
"Codex executable not found.",
|
||||
);
|
||||
});
|
||||
|
||||
it("saves the config", async () => {
|
||||
mockFsService.isFile.mockReturnValue(true);
|
||||
await installer.saveCodexInstallPath(codexExe);
|
||||
expect(mockConfigService.saveConfig).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -112,7 +112,7 @@ export async function main() {
|
||||
new MenuLoop(),
|
||||
installMenu,
|
||||
configMenu,
|
||||
new DataDirMover(fsService, uiService)
|
||||
new DataDirMover(fsService, uiService),
|
||||
);
|
||||
|
||||
await mainMenu.show();
|
||||
|
||||
@ -31,6 +31,14 @@ export class FsService {
|
||||
}
|
||||
};
|
||||
|
||||
isFile = (path) => {
|
||||
try {
|
||||
return fs.lstatSync(path).isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
readDir = (dir) => {
|
||||
return fs.readdirSync(dir);
|
||||
};
|
||||
|
||||
23
src/services/osService.js
Normal file
23
src/services/osService.js
Normal file
@ -0,0 +1,23 @@
|
||||
import os from "os";
|
||||
|
||||
export class OsService {
|
||||
constructor() {
|
||||
this.platform = os.platform();
|
||||
}
|
||||
|
||||
isWindows = () => {
|
||||
return this.platform === "win32";
|
||||
};
|
||||
|
||||
isDarwin = () => {
|
||||
return this.platform === "darwin";
|
||||
};
|
||||
|
||||
isLinux = () => {
|
||||
return this.platform === "linux";
|
||||
};
|
||||
|
||||
getWorkingDir = () => {
|
||||
return process.cwd();
|
||||
};
|
||||
}
|
||||
18
src/services/shellService.js
Normal file
18
src/services/shellService.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
export class ShellService {
|
||||
constructor() {
|
||||
this.execAsync = promisify(exec);
|
||||
}
|
||||
|
||||
async run(command) {
|
||||
try {
|
||||
const { stdout, stderr } = await this.execAsync(command);
|
||||
return stdout;
|
||||
} catch (error) {
|
||||
console.error("Error:", error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@ export class InstallMenu {
|
||||
show = async () => {
|
||||
await this.ui.askMultipleChoice("Configure your Codex installation", [
|
||||
{
|
||||
label: "Install path: " + this.config.codexPath,
|
||||
label: "Install path: " + this.config.codexInstallPath,
|
||||
action: this.selectInstallPath,
|
||||
},
|
||||
{
|
||||
@ -28,8 +28,8 @@ export class InstallMenu {
|
||||
};
|
||||
|
||||
selectInstallPath = async () => {
|
||||
this.config.codexPath = await this.pathSelector.show(
|
||||
this.config.codexPath,
|
||||
this.config.codexInstallPath = await this.pathSelector.show(
|
||||
this.config.codexInstallPath,
|
||||
false,
|
||||
);
|
||||
this.configService.saveConfig();
|
||||
|
||||
@ -6,7 +6,7 @@ import { mockPathSelector } from "../__mocks__/utils.mocks.js";
|
||||
|
||||
describe("InstallMenu", () => {
|
||||
const config = {
|
||||
codexPath: "/codex",
|
||||
codexInstallPath: "/codex",
|
||||
};
|
||||
let installMenu;
|
||||
|
||||
@ -27,7 +27,7 @@ describe("InstallMenu", () => {
|
||||
"Configure your Codex installation",
|
||||
[
|
||||
{
|
||||
label: "Install path: " + config.codexPath,
|
||||
label: "Install path: " + config.codexInstallPath,
|
||||
action: installMenu.selectInstallPath,
|
||||
},
|
||||
{
|
||||
@ -47,14 +47,14 @@ describe("InstallMenu", () => {
|
||||
});
|
||||
|
||||
it("allows selecting the install path", async () => {
|
||||
const originalPath = config.codexPath;
|
||||
const originalPath = config.codexInstallPath;
|
||||
const newPath = "/new/path";
|
||||
mockPathSelector.show.mockResolvedValue(newPath);
|
||||
|
||||
await installMenu.selectInstallPath();
|
||||
|
||||
expect(mockPathSelector.show).toHaveBeenCalledWith(originalPath, false);
|
||||
expect(config.codexPath).toBe(newPath);
|
||||
expect(config.codexInstallPath).toBe(newPath);
|
||||
expect(mockConfigService.saveConfig).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
import { exec } from "child_process";
|
||||
import { promisify } from "util";
|
||||
|
||||
export const execAsync = promisify(exec);
|
||||
|
||||
export async function runCommand(command) {
|
||||
try {
|
||||
const { stdout, stderr } = await execAsync(command);
|
||||
return stdout;
|
||||
} catch (error) {
|
||||
console.error("Error:", error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user