diff --git a/src/common/vars.ts b/src/common/vars.ts index 58da8bf257..a6ea2653df 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -75,6 +75,11 @@ export const baseBinariesDir = onceCell(() => ( ) )); +export const helmBinaryName = getBinaryName("helm"); +export const helmBinaryPath = onceCell(() => path.join(baseBinariesDir.get(), helmBinaryName)); +export const kubectlBinaryName = getBinaryName("kubectl"); +export const kubectlBinaryPath = onceCell(() => path.join(baseBinariesDir.get(), kubectlBinaryName)); + // Webpack build paths export const contextDir = process.cwd(); export const buildDir = path.join(contextDir, "static", publicPath); diff --git a/src/main/helm/exec.ts b/src/main/helm/exec.ts new file mode 100644 index 0000000000..8d8d0d4340 --- /dev/null +++ b/src/main/helm/exec.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { promiseExecFile } from "../../common/utils/promise-exec"; +import type { BaseEncodingOptions } from "fs"; +import type { ExecFileOptions } from "child_process"; +import { helmBinaryPath } from "../../common/vars"; + +/** + * ExecFile the bundled helm CLI + * @returns STDOUT + */ +export async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFileOptions): Promise { + try { + const { stdout } = await promiseExecFile(helmBinaryPath.get(), args, options); + + return stdout; + } catch (error) { + throw error?.stderr || error; + } +} diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index 5630848f85..5c15bfc6b8 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -8,10 +8,9 @@ import v8 from "v8"; import * as yaml from "js-yaml"; import type { HelmRepo } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExecFile } from "../../common/utils/promise-exec"; -import { helmCli } from "./helm-cli"; import type { RepoHelmChartList } from "../../common/k8s-api/endpoints/helm-charts.api"; import { iter, sortCharts } from "../../common/utils"; +import { execHelm } from "./exec"; interface ChartCacheEntry { data: Buffer; @@ -49,21 +48,13 @@ export class HelmChartManager { } private async executeCommand(args: string[], name: string, version?: string) { - const helm = await helmCli.binaryPath(); - args.push(`${this.repo.name}/${name}`); if (version) { args.push("--version", version); } - try { - const { stdout } = await promiseExecFile(helm, args); - - return stdout; - } catch (error) { - throw error.stderr || error; - } + return execHelm(args); } public async getReadme(name: string, version?: string) { diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts deleted file mode 100644 index 13d4479b35..0000000000 --- a/src/main/helm/helm-cli.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import path from "path"; -import { onceCell } from "../../common/utils/once-cell"; -import { baseBinariesDir, getBinaryName } from "../../common/vars"; - -export const helmBinaryPath = onceCell(() => path.join(baseBinariesDir.get(), getBinaryName("helm"))); - -/** - * @deprecated use `helmBinaryPath` or its injection equivalent instead - */ -export const helmCli = { - binaryPath: (): Promise => Promise.resolve(helmBinaryPath.get()), - getBinaryPath: (): string => helmBinaryPath.get(), - getBinaryDir: (): string => baseBinariesDir.get(), - setLogger: (logger: any): void => void logger, - ensureBinary: (): Promise => Promise.resolve(), -}; - diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 72704eb020..e3de7ab3f7 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -6,23 +6,9 @@ import tempy from "tempy"; import fse from "fs-extra"; import * as yaml from "js-yaml"; -import { promiseExecFile } from "../../common/utils/promise-exec"; -import { helmCli } from "./helm-cli"; import { toCamelCase } from "../../common/utils/camelCase"; -import type { BaseEncodingOptions } from "fs"; -import { execFile, ExecFileOptions } from "child_process"; - -async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFileOptions): Promise { - const helmCliPath = await helmCli.binaryPath(); - - try { - const { stdout } = await promiseExecFile(helmCliPath, args, options); - - return stdout; - } catch (error) { - throw error?.stderr || error; - } -} +import { execFile } from "child_process"; +import { execHelm } from "./exec"; export async function listReleases(pathToKubeconfig: string, namespace?: string): Promise[]> { const args = [ diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index 3674654a29..7f174cfa8e 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -4,14 +4,12 @@ */ import yaml from "js-yaml"; -import { BaseEncodingOptions, readFile } from "fs-extra"; -import { promiseExecFile } from "../../common/utils/promise-exec"; -import { helmCli } from "./helm-cli"; +import { readFile } from "fs-extra"; import { Singleton } from "../../common/utils/singleton"; import { customRequestPromise } from "../../common/request"; import orderBy from "lodash/orderBy"; import logger from "../logger"; -import type { ExecFileOptions } from "child_process"; +import { execHelm } from "./exec"; export type HelmEnv = Record & { HELM_REPOSITORY_CACHE?: string; @@ -34,18 +32,6 @@ export interface HelmRepo { password?: string; } -async function execHelm(args: string[], options?: BaseEncodingOptions & ExecFileOptions): Promise { - const helmCliPath = await helmCli.binaryPath(); - - try { - const { stdout } = await promiseExecFile(helmCliPath, args, options); - - return stdout; - } catch (error) { - throw error?.stderr || error; - } -} - export class HelmRepoManager extends Singleton { protected repos: HelmRepo[]; protected helmEnv: HelmEnv; @@ -63,9 +49,6 @@ export class HelmRepoManager extends Singleton { } private async ensureInitialized() { - helmCli.setLogger(logger); - await helmCli.ensureBinary(); - this.helmEnv ??= await this.parseHelmEnv(); const repos = await this.list(); diff --git a/src/main/kubectl/kubectl.ts b/src/main/kubectl/kubectl.ts index 53efbb0d8a..690b9970b9 100644 --- a/src/main/kubectl/kubectl.ts +++ b/src/main/kubectl/kubectl.ts @@ -9,16 +9,14 @@ import { promiseExecFile } from "../../common/utils/promise-exec"; import logger from "../logger"; import { ensureDir, pathExists } from "fs-extra"; import * as lockFile from "proper-lockfile"; -import { helmCli } from "../helm/helm-cli"; import { getBundledKubectlVersion } from "../../common/utils/app-version"; -import { normalizedPlatform, normalizedArch, getBinaryName, baseBinariesDir } from "../../common/vars"; +import { normalizedPlatform, normalizedArch, kubectlBinaryName, kubectlBinaryPath, baseBinariesDir } from "../../common/vars"; import { SemVer } from "semver"; import { defaultPackageMirror, packageMirrors } from "../../common/user-store/preferences-helpers"; import got from "got/dist/source"; import { promisify } from "util"; import stream from "stream"; import { noop } from "lodash/fp"; -import { onceCell } from "../../common/utils/once-cell"; const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ @@ -40,13 +38,8 @@ const kubectlMap: Map = new Map([ ["1.22", "1.22.6"], ["1.23", bundledVersion], ]); -const binaryName = getBinaryName("kubectl"); const initScriptVersionString = "# lens-initscript v3"; -export const bundledKubectlPath = onceCell(() => ( - path.join(baseBinariesDir.get(), binaryName) -)); - interface Dependencies { directoryForKubectlBinaries: string; @@ -89,13 +82,13 @@ export class Kubectl { logger.debug(`Set kubectl version ${this.kubectlVersion} for cluster version ${clusterVersion} using fallback`); } - this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${normalizedPlatform}/${normalizedArch}/${binaryName}`; + this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${normalizedPlatform}/${normalizedArch}/${kubectlBinaryName}`; this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)); - this.path = path.join(this.dirname, binaryName); + this.path = path.join(this.dirname, kubectlBinaryName); } public getBundledPath() { - return bundledKubectlPath.get(); + return kubectlBinaryPath.get(); } public getPathFromPreferences() { @@ -289,7 +282,7 @@ export class Kubectl { ? this.dirname : path.dirname(this.getPathFromPreferences()); - const helmPath = helmCli.getBinaryDir(); + const binariesDir = baseBinariesDir.get(); const bashScriptPath = path.join(this.dirname, ".bash_set_path"); const bashScript = [ @@ -303,7 +296,7 @@ export class Kubectl { "elif test -f \"$HOME/.profile\"; then", " . \"$HOME/.profile\"", "fi", - `export PATH="${helmPath}:${kubectlPath}:$PATH"`, + `export PATH="${binariesDir}:${kubectlPath}:$PATH"`, 'export KUBECONFIG="$tempkubeconfig"', `NO_PROXY=",\${NO_PROXY:-localhost},"`, `NO_PROXY="\${NO_PROXY//,localhost,/,}"`, @@ -329,12 +322,12 @@ export class Kubectl { // voodoo to replace any previous occurrences of kubectl path in the PATH `kubectlpath="${kubectlPath}"`, - `helmpath="${helmPath}"`, + `binariesDir="${binariesDir}"`, "p=\":$kubectlpath:\"", "d=\":$PATH:\"", `d=\${d//$p/:}`, `d=\${d/#:/}`, - `export PATH="$helmpath:$kubectlpath:\${d/%:/}"`, + `export PATH="$binariesDir:$kubectlpath:\${d/%:/}"`, "export KUBECONFIG=\"$tempkubeconfig\"", `NO_PROXY=",\${NO_PROXY:-localhost},"`, `NO_PROXY="\${NO_PROXY//,localhost,/,}"`, diff --git a/src/main/shell-session/local-shell-session/local-shell-session.ts b/src/main/shell-session/local-shell-session/local-shell-session.ts index 301600bd71..314f8700ec 100644 --- a/src/main/shell-session/local-shell-session/local-shell-session.ts +++ b/src/main/shell-session/local-shell-session/local-shell-session.ts @@ -5,12 +5,12 @@ import type WebSocket from "ws"; import path from "path"; -import { helmCli } from "../../helm/helm-cli"; import { UserStore } from "../../../common/user-store"; import type { Cluster } from "../../../common/cluster/cluster"; import type { ClusterId } from "../../../common/cluster-types"; import { ShellSession } from "../shell-session"; import type { Kubectl } from "../../kubectl/kubectl"; +import { baseBinariesDir } from "../../../common/vars"; export class LocalShellSession extends ShellSession { ShellType = "shell"; @@ -18,9 +18,9 @@ export class LocalShellSession extends ShellSession { constructor(protected shellEnvModify: (clusterId: ClusterId, env: Record) => Record, kubectl: Kubectl, websocket: WebSocket, cluster: Cluster, terminalId: string) { super(kubectl, websocket, cluster, terminalId); } - + protected getPathEntries(): string[] { - return [helmCli.getBinaryDir()]; + return [baseBinariesDir.get()]; } protected get cwd(): string | undefined { @@ -40,17 +40,16 @@ export class LocalShellSession extends ShellSession { } protected async getShellArgs(shell: string): Promise { - const helmpath = helmCli.getBinaryDir(); const pathFromPreferences = UserStore.getInstance().kubectlBinariesPath || this.kubectl.getBundledPath(); const kubectlPathDir = UserStore.getInstance().downloadKubectlBinaries ? await this.kubectlBinDirP : path.dirname(pathFromPreferences); switch(path.basename(shell)) { case "powershell.exe": - return ["-NoExit", "-command", `& {$Env:PATH="${helmpath};${kubectlPathDir};$Env:PATH"}`]; + return ["-NoExit", "-command", `& {$Env:PATH="${baseBinariesDir.get()};${kubectlPathDir};$Env:PATH"}`]; case "bash": return ["--init-file", path.join(await this.kubectlBinDirP, ".bash_set_path")]; case "fish": - return ["--login", "--init-command", `export PATH="${helmpath}:${kubectlPathDir}:$PATH"; export KUBECONFIG="${await this.kubeconfigPathP}"`]; + return ["--login", "--init-command", `export PATH="${baseBinariesDir.get()}:${kubectlPathDir}:$PATH"; export KUBECONFIG="${await this.kubeconfigPathP}"`]; case "zsh": return ["--login"]; default: diff --git a/src/renderer/components/+preferences/kubectl-binaries.tsx b/src/renderer/components/+preferences/kubectl-binaries.tsx index 0f64385067..efcf1f807b 100644 --- a/src/renderer/components/+preferences/kubectl-binaries.tsx +++ b/src/renderer/components/+preferences/kubectl-binaries.tsx @@ -8,13 +8,12 @@ import { observer } from "mobx-react"; import { Input, InputValidators } from "../input"; import { SubTitle } from "../layout/sub-title"; import { UserStore } from "../../../common/user-store"; -import { bundledKubectlPath } from "../../../main/kubectl/kubectl"; import { SelectOption, Select } from "../select"; import { Switch } from "../switch"; import { packageMirrors } from "../../../common/user-store/preferences-helpers"; -import directoryForBinariesInjectable - from "../../../common/app-paths/directory-for-binaries/directory-for-binaries.injectable"; +import directoryForBinariesInjectable from "../../../common/app-paths/directory-for-binaries/directory-for-binaries.injectable"; import { withInjectables } from "@ogre-tools/injectable-react"; +import { kubectlBinaryPath } from "../../../common/vars"; interface Dependencies { defaultPathForKubectlBinaries: string; @@ -80,7 +79,7 @@ const NonInjectedKubectlBinaries: React.FC = observer(({ defaultPa