Skip to content

Commit 4770fdb

Browse files
Allow configuring rbenv executable path (#2875)
* Allow configuring rbenv executable path * Remove useless eslint-disable instruction * Fix linting offenses
1 parent baf6599 commit 4770fdb

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

vscode/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,10 @@
345345
"description": "The path to the Mise executable, if not installed in ~/.local/bin/mise",
346346
"type": "string"
347347
},
348+
"rbenvExecutablePath": {
349+
"description": "The path to the rbenv executable, if not installed on one of the standard locations",
350+
"type": "string"
351+
},
348352
"chrubyRubies": {
349353
"description": "An array of extra directories to search for Ruby installations when using chruby. Equivalent to the RUBIES environment variable",
350354
"type": "array"

vscode/src/ruby/rbenv.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ import { VersionManager, ActivationResult } from "./versionManager";
88
// Learn more: https://github.com/rbenv/rbenv
99
export class Rbenv extends VersionManager {
1010
async activate(): Promise<ActivationResult> {
11-
const rbenvExec = await this.findExec(
12-
[vscode.Uri.file("/opt/homebrew/bin"), vscode.Uri.file("/usr/local/bin")],
13-
"rbenv",
14-
);
11+
const rbenvExec = await this.findRbenv();
1512

1613
const parsedResult = await this.runEnvActivationScript(
1714
`${rbenvExec} exec ruby`,
@@ -24,4 +21,35 @@ export class Rbenv extends VersionManager {
2421
gemPath: parsedResult.gemPath,
2522
};
2623
}
24+
25+
private async findRbenv(): Promise<string> {
26+
const config = vscode.workspace.getConfiguration("rubyLsp");
27+
const configuredRbenvPath = config.get<string | undefined>(
28+
"rubyVersionManager.rbenvExecutablePath",
29+
);
30+
31+
if (configuredRbenvPath) {
32+
return this.ensureRbenvExistsAt(configuredRbenvPath);
33+
} else {
34+
return this.findExec(
35+
[
36+
vscode.Uri.file("/opt/homebrew/bin"),
37+
vscode.Uri.file("/usr/local/bin"),
38+
],
39+
"rbenv",
40+
);
41+
}
42+
}
43+
44+
private async ensureRbenvExistsAt(path: string): Promise<string> {
45+
try {
46+
await vscode.workspace.fs.stat(vscode.Uri.file(path));
47+
48+
return path;
49+
} catch (error: any) {
50+
throw new Error(
51+
`The Ruby LSP version manager is configured to be rbenv, but ${path} does not exist`,
52+
);
53+
}
54+
}
2755
}

vscode/src/test/suite/ruby/rbenv.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from "assert";
22
import path from "path";
33
import os from "os";
4+
import fs from "fs";
45

56
import * as vscode from "vscode";
67
import sinon from "sinon";
@@ -59,6 +60,66 @@ suite("Rbenv", () => {
5960
execStub.restore();
6061
});
6162

63+
test("Allows configuring where rbenv is installed", async () => {
64+
const workspacePath = fs.mkdtempSync(
65+
path.join(os.tmpdir(), "ruby-lsp-test-"),
66+
);
67+
const workspaceFolder = {
68+
uri: vscode.Uri.from({ scheme: "file", path: workspacePath }),
69+
name: path.basename(workspacePath),
70+
index: 0,
71+
};
72+
const outputChannel = new WorkspaceChannel("fake", common.LOG_CHANNEL);
73+
const rbenv = new Rbenv(workspaceFolder, outputChannel);
74+
75+
const envStub = {
76+
env: { ANY: "true" },
77+
yjit: true,
78+
version: "3.0.0",
79+
};
80+
81+
const execStub = sinon.stub(common, "asyncExec").resolves({
82+
stdout: "",
83+
stderr: `${ACTIVATION_SEPARATOR}${JSON.stringify(envStub)}${ACTIVATION_SEPARATOR}`,
84+
});
85+
86+
const rbenvPath = path.join(workspacePath, "rbenv");
87+
fs.writeFileSync(rbenvPath, "fakeRbenvBinary");
88+
89+
const configStub = sinon
90+
.stub(vscode.workspace, "getConfiguration")
91+
.returns({
92+
get: (name: string) => {
93+
if (name === "rubyVersionManager.rbenvExecutablePath") {
94+
return rbenvPath;
95+
}
96+
return "";
97+
},
98+
} as any);
99+
100+
const { env, version, yjit } = await rbenv.activate();
101+
102+
assert.ok(
103+
execStub.calledOnceWithExactly(
104+
`${rbenvPath} exec ruby -W0 -rjson -e '${rbenv.activationScript}'`,
105+
{
106+
cwd: workspacePath,
107+
shell: vscode.env.shell,
108+
// eslint-disable-next-line no-process-env
109+
env: process.env,
110+
},
111+
),
112+
);
113+
114+
assert.strictEqual(version, "3.0.0");
115+
assert.strictEqual(yjit, true);
116+
assert.deepStrictEqual(env.ANY, "true");
117+
118+
execStub.restore();
119+
configStub.restore();
120+
fs.rmSync(workspacePath, { recursive: true, force: true });
121+
});
122+
62123
test("Reports invalid JSON environments", async () => {
63124
// eslint-disable-next-line no-process-env
64125
const workspacePath = process.env.PWD!;

0 commit comments

Comments
 (0)