дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +02:00
feat(remote): open WSL projects through a WSL transport (#989)
* perf(vfs): list directories off the main thread and reuse the repository lookup Opening a folder on a network share (\\wsl.localhost\<distro>\...) is slow because every listing ran on the main thread and walked up to the repository root and ran a repository discovery again. - fs_read_dir runs on the blocking pool. - GitignoreStack::cached keeps the repository root and the repo-level rules for a few seconds. An edit of .git/info/exclude is still seen at once (its mtime and size are checked) and every .gitignore / .ignore is read fresh. Refs #916 * feat(remote): open WSL projects through a WSL transport A folder of a WSL distro (\\wsl.localhost\<distro>\... or \\wsl$\...) now opens as a remote project whose openidea-server runs inside the distro, so the terminal, SDK discovery, run, language servers and git are native Linux. - RemoteTarget (ssh | wsl) replaces the SSH configuration id in the remote launch, connection, session and recents; old recents are read as SSH and a WSL target never inherits the legacy trust migration. - remote_wsl: probe the distro, stream the server into ~/.openidea/server and start it with `wsl.exe -d <distro> --exec <bin> --stdio`. Distro names are validated and every command goes through --exec with positional arguments. - wsl_distros / wsl_resolve commands; File > Open, the CLI and recents route WSL folders to the distro and focus the window that already has them. - Remote Development dialog: SSH/WSL choice with the detected distros; the status bar shows `WSL: <distro>` / `SSH: <host>`. - ide-jsonrpc: skip the NUL left at the start of a line by UTF-16 output of wsl.exe, which made the first message of the server disappear. Not run on Windows yet: only a stand-in for wsl.exe is tested. Refs #925, #327, #721 * fix(remote): satisfy clippy in WSL output decoding * style(run): format run types * fix: regenerate bindings and drop untranslated WSL catalog entry * test(i18n): list WSL as an untranslated product name * fix(run): pick build wrappers and shell quoting by the execution host A remote window runs commands on its Linux or macOS server, so a Windows desktop no longer selects gradlew.bat, mvnw.cmd or Windows quoting for it. * fix(welcome): open legacy WSL UNC recents and sessions through the distro Recents and the restored session called the local openProject for a \\wsl.localhost folder saved before WSL projects, which fails with OS error 123. They now resolve it like the other entry points. * fix(windows): keep WSL files out of remote project launches path_launch tested the WSL share before is_dir, so a first-instance CLI launch with a WSL file opened a remote project instead of LightEdit. * fix(remote): run-command OS comes from the remote host, not an assumption The server's OS was dropped after connect, so a restored session had none and isWindows() assumed every remote host is Unix. Keep it on the connection and the session, and resolve it through hostOs(). --------- Co-authored-by: NguyenBang <[email protected]> Co-authored-by: NguyenBang <[email protected]> Co-authored-by: l0ng-ai <[email protected]>
Цей коміт міститься в:
47 files changed
+1512
-220
No files matched your search
@@ -16,6 +16,7 @@ vi.mock("@/platform/ipc", async (orig) => {
|
||||
};
|
||||
});
|
||||
|
||||
const { usePlatform } = await import("@/platform/platformInfo");
|
||||
const { parseJavaArgs, joinJavaArgs } = await import("@/platform/javaLaunch");
|
||||
const { parseArgs } = await import("./configs");
|
||||
const { jdwpLaunch } = await import("./javaDebug");
|
||||
@@ -247,3 +248,34 @@ describe("Maven / Gradle: VM options of the forked JVM", () => {
|
||||
await expect(gradle().prepareLaunch!(remote)).rejects.toThrow(/run targets/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("build wrapper per execution host", () => {
|
||||
const wrapperCommands = () =>
|
||||
(["gradle", "maven"] as const).map((t) => typeFor(t)!.commandLine({ wrapper: "true", tasks: "test" })!.command);
|
||||
const WINDOWS = ["gradlew.bat", "mvnw.cmd"];
|
||||
const UNIX = ["./gradlew", "./mvnw"];
|
||||
|
||||
beforeEach(() => registerBuiltinTypes());
|
||||
afterEach(async () => {
|
||||
(await import("@/platform/remote")).disableRemote();
|
||||
usePlatform.setState({ os: "macos" });
|
||||
});
|
||||
|
||||
it("follows the desktop OS in a local window", () => {
|
||||
usePlatform.setState({ os: "windows" });
|
||||
expect(wrapperCommands()).toEqual(WINDOWS);
|
||||
usePlatform.setState({ os: "linux" });
|
||||
expect(wrapperCommands()).toEqual(UNIX);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ desktop: "windows", host: "linux", target: { kind: "wsl", distro: "Ubuntu" }, expected: UNIX },
|
||||
{ desktop: "windows", host: "macos", target: { kind: "ssh", config: "box" }, expected: UNIX },
|
||||
{ desktop: "macos", host: "windows", target: { kind: "ssh", config: "win" }, expected: WINDOWS },
|
||||
] as const)("follows the $host server of a remote window opened from $desktop", async (c) => {
|
||||
usePlatform.setState({ os: c.desktop });
|
||||
const { enableRemote } = await import("@/platform/remote");
|
||||
enableRemote({ target: c.target, root: "/app", host: "h", os: c.host, commands: [] });
|
||||
expect(wrapperCommands()).toEqual(c.expected);
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
import { call, commands, type RunConfig } from "@/platform/ipc";
|
||||
import { CLASSPATH, parseJavaArgs, TEST_CLASSPATH } from "@/platform/javaLaunch";
|
||||
import { hostOs } from "@/platform/remote";
|
||||
import { basename, useProject } from "@/platform/project";
|
||||
import { useBuildPresentation } from "@/platform/projectPresentation";
|
||||
import type { RunConfigTypeContribution, RunConfigTypeField } from "@/workbench/contributions";
|
||||
@@ -13,7 +14,8 @@ import { formatArgs, parseArgs } from "./configs";
|
||||
import { commandName } from "./commandName";
|
||||
import { updatePolicyDefaults, updatePolicyFields } from "./updatePolicies";
|
||||
|
||||
export const isWindows = () => typeof navigator !== "undefined" && /win/i.test(navigator.platform);
|
||||
/** Whether this window's commands run on Windows: the remote server's OS in a remote window, else the desktop's. */
|
||||
export const isWindows = () => hostOs() === "windows";
|
||||
|
||||
/** VM options / program arguments as typed; on Windows a backslash is a path separator. */
|
||||
export const splitJvmArgs = (text: string | undefined, windows = isWindows()) => parseArgs(text ?? "", windows);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Rust come from SDK discovery and everything else resolves at launch.
|
||||
*/
|
||||
import { call, commands, isTauri } from "@/platform/ipc";
|
||||
import { isWindows } from "./jvmTypes";
|
||||
import type { LocatedTool, ToolEnv } from "./producers";
|
||||
|
||||
const TTL = 60_000;
|
||||
@@ -15,7 +16,6 @@ interface Entry {
|
||||
}
|
||||
|
||||
const cache = new Map<string, Entry>();
|
||||
const isWindows = typeof navigator !== "undefined" && /Win/i.test(navigator.platform || navigator.userAgent);
|
||||
let compileDir: string | null = null;
|
||||
let locateUnavailable = false;
|
||||
|
||||
@@ -115,7 +115,7 @@ export async function toolEnv(
|
||||
return {
|
||||
tool: (n) => tools.get(n),
|
||||
compileDir: compileDir ?? "/tmp/openidea-run",
|
||||
windows: isWindows,
|
||||
windows: isWindows(),
|
||||
python: py,
|
||||
...markers,
|
||||
};
|
||||
|
||||
Reference in new issue
Заблокувати користувача