+
Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

fix(vscode): ignore incompatible versions of the binary and improve the restart logic #4022

Merged
merged 1 commit into from
Dec 9, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 83 additions & 25 deletions editors/vscode/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ChildProcess, spawn } from "child_process";
import { connect, type Socket } from "net";
import { promisify } from "util";
import { promisify, TextDecoder } from "util";
import {
ExtensionContext,
languages,
Expand Down Expand Up @@ -36,7 +36,10 @@ let client: LanguageClient;
const IN_ROME_PROJECT = "inRomeProject";

export async function activate(context: ExtensionContext) {
const command = await getServerPath(context);
const outputChannel = window.createOutputChannel("Rome");
const traceOutputChannel = window.createOutputChannel("Rome Trace");

const command = await getServerPath(context, outputChannel);

if (!command) {
await window.showErrorMessage(
Expand All @@ -49,9 +52,6 @@ export async function activate(context: ExtensionContext) {

const statusBar = new StatusBar();

const outputChannel = window.createOutputChannel("Rome");
const traceOutputChannel = window.createOutputChannel("Rome Trace");

const serverOptions: ServerOptions = createMessageTransports.bind(
undefined,
outputChannel,
Expand Down Expand Up @@ -85,10 +85,16 @@ export async function activate(context: ExtensionContext) {
session.registerCommand(Commands.ServerStatus, () => {
traceOutputChannel.show();
});
session.registerCommand(Commands.RestartLspServer, () => {
client.restart().catch((error) => {
session.registerCommand(Commands.RestartLspServer, async () => {
try {
if (client.isRunning()) {
await client.restart();
} else {
await client.start();
}
} catch (error) {
client.error("Restarting client failed", error, "force");
});
}
});

context.subscriptions.push(
Expand Down Expand Up @@ -130,45 +136,46 @@ const PLATFORMS: PlatformTriplets = {
win32: {
x64: {
triplet: "x86_64-pc-windows-msvc",
package: "@rometools/cli-win32-x64/rome.exe",
package: "@rometools/cli-win32-x64",
},
arm64: {
triplet: "aarch64-pc-windows-msvc",
package: "@rometools/cli-win32-arm64/rome.exe",
package: "@rometools/cli-win32-arm64",
},
},
darwin: {
x64: {
triplet: "x86_64-apple-darwin",
package: "@rometools/cli-darwin-x64/rome",
package: "@rometools/cli-darwin-x64",
},
arm64: {
triplet: "aarch64-apple-darwin",
package: "@rometools/cli-darwin-arm64/rome",
package: "@rometools/cli-darwin-arm64",
},
},
linux: {
x64: {
triplet: "x86_64-unknown-linux-gnu",
package: "@rometools/cli-linux-x64/rome",
package: "@rometools/cli-linux-x64",
},
arm64: {
triplet: "aarch64-unknown-linux-gnu",
package: "@rometools/cli-linux-arm64/rome",
package: "@rometools/cli-linux-arm64",
},
},
};

async function getServerPath(
context: ExtensionContext,
outputChannel: OutputChannel,
): Promise<string | undefined> {
// Only allow the bundled Rome binary in untrusted workspaces
if (!workspace.isTrusted) {
return getBundledBinary(context);
return getBundledBinary(context, outputChannel);
}

if (process.env.DEBUG_SERVER_PATH) {
window.showInformationMessage(
outputChannel.appendLine(
`Rome DEBUG_SERVER_PATH detected: ${process.env.DEBUG_SERVER_PATH}`,
);
return process.env.DEBUG_SERVER_PATH;
Expand All @@ -180,7 +187,10 @@ async function getServerPath(
return getWorkspaceRelativePath(explicitPath);
}

return (await getWorkspaceDependency()) ?? getBundledBinary(context);
return (
(await getWorkspaceDependency(outputChannel)) ??
(await getBundledBinary(context, outputChannel))
);
}

// Resolve `path` as relative to the workspace root
Expand All @@ -200,28 +210,70 @@ async function getWorkspaceRelativePath(path: string) {
}

// Tries to resolve a path to `@rometools/cli-*` binary package from the root of the workspace
async function getWorkspaceDependency(): Promise<string | undefined> {
async function getWorkspaceDependency(
outputChannel: OutputChannel,
): Promise<string | undefined> {
const packageName = PLATFORMS[process.platform]?.[process.arch]?.package;

const manifestName = `${packageName}/package.json`;
const binaryName =
process.platform === "win32"
? `${packageName}/rome.exe`
: `${packageName}/rome`;

for (const workspaceFolder of workspace.workspaceFolders) {
try {
const result = await resolveAsync(packageName, {
const options = {
basedir: workspaceFolder.uri.fsPath,
});
};

if (result) {
return result;
const [manifestPath, binaryPath] = await Promise.all([
resolveAsync(manifestName, options),
resolveAsync(binaryName, options),
]);

if (!(manifestPath && binaryPath)) {
continue;
}

// Load the package.json manifest of the resolved package
const manifestUri = Uri.file(manifestPath);
const manifestData = await workspace.fs.readFile(manifestUri);

const { version } = JSON.parse(new TextDecoder().decode(manifestData));
if (typeof version !== "string") {
continue;
}

// Ignore versions lower than "0.9.0" as they did not embed the language server
if (version.startsWith("0.")) {
const [minor] = version.substring(2).split(".");
const minorVal = parseInt(minor);
if (minorVal < 9) {
outputChannel.appendLine(
`Ignoring incompatible Rome version "${version}"`,
);
continue;
}
}

return binaryPath;
} catch {}
}

return undefined;
}

// Returns the path of the binary distribution of Rome included in the bundle of the extension
async function getBundledBinary(context: ExtensionContext) {
async function getBundledBinary(
context: ExtensionContext,
outputChannel: OutputChannel,
) {
const triplet = PLATFORMS[process.platform]?.[process.arch]?.triplet;
if (!triplet) {
outputChannel.appendLine(
`Unsupported platform ${process.platform} ${process.arch}`,
);
return undefined;
}

Expand All @@ -230,16 +282,22 @@ async function getBundledBinary(context: ExtensionContext) {

const bundlePath = Uri.joinPath(context.extensionUri, "server", binaryName);
const bundleExists = await fileExists(bundlePath);
if (!bundleExists) {
outputChannel.appendLine(
"Extension bundle does not include the prebuilt binary",
);
return undefined;
}

return bundleExists ? bundlePath.fsPath : undefined;
return bundlePath.fsPath;
}

async function fileExists(path: Uri) {
try {
await workspace.fs.stat(path);
return true;
} catch (err) {
if (err.code === "ENOENT") {
if (err.code === "ENOENT" || err.code === "FileNotFound") {
return false;
} else {
throw err;
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载