mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 04:43:36 +00:00
Fix tmux detection for non-POSIX shells (#1030)
This commit is contained in:
@@ -1,20 +1,52 @@
|
|||||||
|
import { EventEmitter } from "node:events";
|
||||||
|
import type { Client } from "ssh2";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import { tmuxCommand, withTmuxPath } from "./tmux-helper.js";
|
import { detectTmux, tmuxCommand, withTmuxPath } from "./tmux-helper.js";
|
||||||
|
|
||||||
describe("tmux command path handling", () => {
|
describe("tmux command path handling", () => {
|
||||||
it("adds common non-login shell tmux paths", () => {
|
it("adds common non-login shell tmux paths", () => {
|
||||||
const command = withTmuxPath("command -v tmux");
|
const command = withTmuxPath("command -v tmux");
|
||||||
|
|
||||||
|
expect(command).toMatch(/^\/bin\/sh -c '/);
|
||||||
expect(command).toContain("/opt/homebrew/bin");
|
expect(command).toContain("/opt/homebrew/bin");
|
||||||
expect(command).toContain("/usr/local/bin");
|
expect(command).toContain("/usr/local/bin");
|
||||||
expect(command).toContain("/opt/bin");
|
expect(command).toContain("/opt/bin");
|
||||||
expect(command).toContain("/usr/pkg/bin");
|
expect(command).toContain("/usr/pkg/bin");
|
||||||
expect(command).toContain(":$PATH; command -v tmux");
|
expect(command).toContain(":$PATH; export PATH; command -v tmux");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("wraps tmux invocations with the same path", () => {
|
it("wraps tmux invocations with the same path", () => {
|
||||||
expect(tmuxCommand("list-sessions")).toMatch(
|
expect(tmuxCommand("list-sessions")).toMatch(
|
||||||
/^PATH=.*:\$PATH; tmux list-sessions$/,
|
/^\/bin\/sh -c 'PATH=.*:\$PATH; export PATH; tmux list-sessions'$/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("detects suffixed tmux versions without parsing the version number", async () => {
|
||||||
|
const commands: string[] = [];
|
||||||
|
const conn = {
|
||||||
|
exec(command: string, callback: (error: null, stream: never) => void) {
|
||||||
|
commands.push(command);
|
||||||
|
const stream = new EventEmitter() as EventEmitter & {
|
||||||
|
stderr: EventEmitter;
|
||||||
|
};
|
||||||
|
stream.stderr = new EventEmitter();
|
||||||
|
callback(null, stream as never);
|
||||||
|
|
||||||
|
queueMicrotask(() => {
|
||||||
|
if (commands.length === 1) {
|
||||||
|
stream.emit("data", Buffer.from("tmux 3.7b\n"));
|
||||||
|
stream.emit("close", 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stream.emit("close", 1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
} as unknown as Client;
|
||||||
|
|
||||||
|
await expect(detectTmux(conn)).resolves.toEqual({
|
||||||
|
available: true,
|
||||||
|
sessions: [],
|
||||||
|
});
|
||||||
|
expect(commands[0]).toContain("tmux -V");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ const TMUX_PATH_DIRS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export function withTmuxPath(command: string): string {
|
export function withTmuxPath(command: string): string {
|
||||||
return `PATH=${TMUX_PATH_DIRS.join(":")}:$PATH; ${command}`;
|
const script = `PATH=${TMUX_PATH_DIRS.join(":")}:$PATH; export PATH; ${command}`;
|
||||||
|
return `/bin/sh -c ${shellEscape(script)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tmuxCommand(args: string): string {
|
export function tmuxCommand(args: string): string {
|
||||||
@@ -69,7 +70,7 @@ export function execCommand(conn: Client, command: string): Promise<string> {
|
|||||||
*/
|
*/
|
||||||
export async function detectTmux(conn: Client): Promise<TmuxDetectionResult> {
|
export async function detectTmux(conn: Client): Promise<TmuxDetectionResult> {
|
||||||
try {
|
try {
|
||||||
await execCommand(conn, withTmuxPath("command -v tmux"));
|
await execCommand(conn, tmuxCommand("-V"));
|
||||||
} catch {
|
} catch {
|
||||||
return { available: false, sessions: [] };
|
return { available: false, sessions: [] };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
} from "../utils/socks5-helper.js";
|
} from "../utils/socks5-helper.js";
|
||||||
import { withConnection } from "./ssh-connection-pool.js";
|
import { withConnection } from "./ssh-connection-pool.js";
|
||||||
import { resolveSshConnectConfigHost } from "./ssh-dns.js";
|
import { resolveSshConnectConfigHost } from "./ssh-dns.js";
|
||||||
import { execCommand, tmuxCommand, withTmuxPath } from "./tmux-helper.js";
|
import { execCommand, tmuxCommand } from "./tmux-helper.js";
|
||||||
import {
|
import {
|
||||||
SEP,
|
SEP,
|
||||||
parseSessions,
|
parseSessions,
|
||||||
@@ -246,7 +246,7 @@ async function withHostConnection<T>(
|
|||||||
|
|
||||||
async function tmuxAvailable(conn: Client): Promise<boolean> {
|
async function tmuxAvailable(conn: Client): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
await execCommand(conn, withTmuxPath("command -v tmux"));
|
await execCommand(conn, tmuxCommand("-V"));
|
||||||
return true;
|
return true;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user