Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to activate Ruby #1586

Closed
1 task
adao789 opened this issue Apr 26, 2023 · 21 comments · Fixed by Shopify/vscode-ruby-lsp#712
Closed
1 task

Failed to activate Ruby #1586

adao789 opened this issue Apr 26, 2023 · 21 comments · Fixed by Shopify/vscode-ruby-lsp#712
Labels
bug Something isn't working pinned This issue or pull request is pinned and won't be marked as stale transferred This issue was transferred from vscode-ruby-lsp

Comments

@adao789
Copy link

adao789 commented Apr 26, 2023

Operating System

Linux

Ruby version

3.1.2

Project has a bundle

  • Has bundle

Ruby version manager being used

rvm

Description

I am using: vscode 1.73.1, Windows 10, Vagrant 2.2.19, Linux Ubuntu 20.04.4 LTS, Ruby 3.1.2, Rails 7.0.4. The vsCode is installed on Windows, while Ruby and Rails are installed on Linux. Communication is done through Vagrant and is working well, I have been working like this for over 5 months now. I want to use the Ruby LSP extension, but after installing it, the following error message appears: "Failed to activate rvm environment: Command failed: 'rvm-auto-ruby --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"' ''rvm-auto-ruby' is not recognized as an internal or external command, operable program or batch file." I have already specified the default Ruby manager, which is rvm, through configuration in vsCode. However, it still did not solve the problem.

Adão

@adao789 adao789 added the bug Something isn't working label Apr 26, 2023
@vinistock
Copy link
Member

Thank you for the report. Have you tried using the official remote extension I linked here #1552?

My understanding is that the remote extension allows you to connect VS Code to any virtual/remote machine and then all extensions run seamlessly as if they were being executed in the container.

@adao789
Copy link
Author

adao789 commented Apr 27, 2023

Unfortunately I'm not using it, but I will. If there's a problem, I'll report back.

@wapablos
Copy link

wapablos commented May 6, 2023

The line 144 concats the command to run the ruby activation but it's a literal string closed with single quotes and the command with single quotes going to be run on the shell, but Windows (cmd and powershell) recognizes single quote as part of the command and Ubuntu (maybe other Linux dists) recognizes the content inside as a single command and will fail or not run since the expected output will be undefined.

https://github.com/Shopify/vscode-ruby-lsp/blob/8c2afe885921d4d8eff4909549fdf167058b68dc/src/ruby.ts#L142-L153

Since the string literal is a string, removing the single quotes might solve the bug, but I don't know if it would run on Mac

command += `${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"`;

@bgmat
Copy link

bgmat commented May 9, 2023

I get a similar error on Windows 11 with rbenv:

Failed to activate rbenv environment: Command failed: 'rbenv exec ruby --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"' ''rbenv' is not recognized as an internal or external command, operable program or batch file.

@blm768
Copy link

blm768 commented May 11, 2023

I'm seeing similar errors with plain Ruby on Windows (version manager set to "none"). Looking at the context in vscode-ruby-lsp/src/ruby.ts, as noted above, the command being wrapped in single quotes does seem suspicious. It's fine when $SHELL is set because the shell then "unwraps" the quotes, but if $SHELL is unset (which is the default on Windows), the quotes will cause issues. Perhaps the quotes should only be there when $SHELL is set.

The best solution when invoking $SHELL might be to use child_process.execFile, which sidesteps many of the quoting issues by requiring an explicit JavaScript string for each argument, bypassing the normal shell argument parsing logic. Then the single quotes would be entirely unnecessary.

@tangorri
Copy link

Hi, so this bug won't be fix ?
how can I edit myself the code ? I could fork it but how to install from the fork then ?

@vinistock
Copy link
Member

I think it's reasonable to not add the single quotes if this.shell is undefined. They're used to indicate the command being passed to the shell, but since there's no shell defined on Windows, there's no point in having them.

Should just be a matter of changing these two lines to not add the quotes if shell is undefined. Does anyone want to put a PR together for this?

If you can test on Windows, I can verify it still works on Mac and Linux.

@wapablos
Copy link

The change of these two lines solves this bug (#587), but when the code reaches at line 211 of client.ts
https://github.com/Shopify/vscode-ruby-lsp/blob/95f014e0418a93c0ac88f1026cb25e9decc25d2b/src/client.ts#L211
It shows the message
Ruby LSP client: couldn't create connection to server.

I think it could be an error caused, only on Windows, by executables setup
https://github.com/Shopify/vscode-ruby-lsp/blob/95f014e0418a93c0ac88f1026cb25e9decc25d2b/src/client.ts#L92-L107

or by the clientOptions starting at line 110
https://github.com/Shopify/vscode-ruby-lsp/blob/95f014e0418a93c0ac88f1026cb25e9decc25d2b/src/client.ts#L110-L111

@blm768
Copy link

blm768 commented May 29, 2023

The following patch allows Ruby to start (I think), although, as noted above, running Bundler seems to have an issue of some kind that will need further investigation.

diff --git a/src/ruby.ts b/src/ruby.ts
index 182eaaf..692fd90 100644
--- a/src/ruby.ts
+++ b/src/ruby.ts
@@ -1,4 +1,4 @@
-import { exec } from "child_process";
+import { exec, execFile } from "child_process";
 import { promisify } from "util";
 import path from "path";
 import fs from "fs";
@@ -6,6 +6,7 @@ import fs from "fs";
 import * as vscode from "vscode";
 
 const asyncExec = promisify(exec);
+const asyncExecFile = promisify(execFile);
 
 export enum VersionManager {
   Asdf = "asdf",
@@ -140,10 +141,14 @@ export class Ruby {
   }
 
   private async activate(ruby: string) {
-    let command = this.shell ? `${this.shell} -ic ` : "";
-    command += `'${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"'`;
+    const command = `${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"`;
 
-    const result = await asyncExec(command, { cwd: this.workingFolder });
+    let result;
+    if (this.shell) {
+      result = await asyncExecFile(this.shell, ["-ic", command]);
+    } else {
+      result = await asyncExec(command, { cwd: this.workingFolder });
+    }
 
     const envJson = result.stdout.match(
       /RUBY_ENV_ACTIVATE(.*)RUBY_ENV_ACTIVATE/

@lsegal
Copy link

lsegal commented Jun 12, 2023

Still seeing this issue with a plain non-version-managed Ruby install on Windows:

Failed to activate none environment: Command failed: 'ruby --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"'
''ruby' is not recognized as an internal or external command,
operable program or batch file.

Ruby is installed on my machine via scoop:

❯ where ruby.exe
C:\tools\scoop\apps\ruby\current\bin\ruby.exe

I've seen some PRs flow through but I'm unsure what the resolution has been on this issue.

@dbalagansky
Copy link

dbalagansky commented Jun 14, 2023

The following patch allows Ruby to start (I think), although, as noted above, running Bundler seems to have an issue of some kind that will need further investigation.

diff --git a/src/ruby.ts b/src/ruby.ts
index 182eaaf..692fd90 100644
--- a/src/ruby.ts
+++ b/src/ruby.ts
@@ -1,4 +1,4 @@
-import { exec } from "child_process";
+import { exec, execFile } from "child_process";
 import { promisify } from "util";
 import path from "path";
 import fs from "fs";
@@ -6,6 +6,7 @@ import fs from "fs";
 import * as vscode from "vscode";
 
 const asyncExec = promisify(exec);
+const asyncExecFile = promisify(execFile);
 
 export enum VersionManager {
   Asdf = "asdf",
@@ -140,10 +141,14 @@ export class Ruby {
   }
 
   private async activate(ruby: string) {
-    let command = this.shell ? `${this.shell} -ic ` : "";
-    command += `'${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"'`;
+    const command = `${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"`;
 
-    const result = await asyncExec(command, { cwd: this.workingFolder });
+    let result;
+    if (this.shell) {
+      result = await asyncExecFile(this.shell, ["-ic", command]);
+    } else {
+      result = await asyncExec(command, { cwd: this.workingFolder });
+    }
 
     const envJson = result.stdout.match(
       /RUBY_ENV_ACTIVATE(.*)RUBY_ENV_ACTIVATE/

Looks like adding shell: true, to executableOptions allows LSP to start, so the resulting patch would be:

diff --git a/src/client.ts b/src/client.ts
index e862951..9fe12cd 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -92,6 +92,7 @@ export default class Client implements ClientInterface {
     const executableOptions = {
       cwd: this.workingFolder,
       env: this.ruby.env,
+      shell: true,
     };
 
     const executable: Executable = {
diff --git a/src/ruby.ts b/src/ruby.ts
index 182eaaf..692fd90 100644
--- a/src/ruby.ts
+++ b/src/ruby.ts
@@ -1,4 +1,4 @@
-import { exec } from "child_process";
+import { exec, execFile } from "child_process";
 import { promisify } from "util";
 import path from "path";
 import fs from "fs";
@@ -6,6 +6,7 @@ import fs from "fs";
 import * as vscode from "vscode";
 
 const asyncExec = promisify(exec);
+const asyncExecFile = promisify(execFile);
 
 export enum VersionManager {
   Asdf = "asdf",
@@ -140,10 +141,14 @@ export class Ruby {
   }
 
   private async activate(ruby: string) {
-    let command = this.shell ? `${this.shell} -ic ` : "";
-    command += `'${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"'`;
+    const command = `${ruby} --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"`;
 
-    const result = await asyncExec(command, { cwd: this.workingFolder });
+    let result;
+    if (this.shell) {
+      result = await asyncExecFile(this.shell, ["-ic", command]);
+    } else {
+      result = await asyncExec(command, { cwd: this.workingFolder });
+    }
 
     const envJson = result.stdout.match(
       /RUBY_ENV_ACTIVATE(.*)RUBY_ENV_ACTIVATE/

@blm768
Copy link

blm768 commented Jun 15, 2023

That seems to let bundle install run. At least on my machine, something seems to be closing the LSP connection, though:

[Error - 7:04:52 PM] Server initialization failed.
  Message: Pending response rejected since connection got disposed
  Code: -32097 
[Info  - 7:04:52 PM] Connection to server got closed. Server will restart.
true

@dbalagansky
Copy link

That seems to let bundle install run. At least on my machine, something seems to be closing the LSP connection, though:

[Error - 7:04:52 PM] Server initialization failed.
  Message: Pending response rejected since connection got disposed
  Code: -32097 
[Info  - 7:04:52 PM] Connection to server got closed. Server will restart.
true

That's strange, as with your patch: #1586, bundle install was working fine, and I was getting this error:

...
BUNDLER> Bundle complete! 5 Gemfile dependencies, 67 gems now installed.
BUNDLER> Use `bundle info [gemname]` to see where a bundled gem is installed.
>> `bundle install` exited with code 0
[Error - 22:24:46] Ruby LSP client: couldn't create connection to server.
Launching server using command bundle [object Object] failed. Error: spawn bundle ENOENT

Which I've fixed with this:

diff --git a/src/client.ts b/src/client.ts
index e862951..9fe12cd 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -92,6 +92,7 @@ export default class Client implements ClientInterface {
     const executableOptions = {
       cwd: this.workingFolder,
       env: this.ruby.env,
+      shell: true,
     };
 
     const executable: Executable = {

That's with latest main branch.

@Andoreatta
Copy link

Still seeing this issue with a plain non-version-managed Ruby install on Windows:

Failed to activate none environment: Command failed: 'ruby --disable-gems -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"'
''ruby' is not recognized as an internal or external command,
operable program or batch file.

Ruby is installed on my machine via scoop:

❯ where ruby.exe
C:\tools\scoop\apps\ruby\current\bin\ruby.exe

I've seen some PRs flow through but I'm unsure what the resolution has been on this issue.

Same is happening to me, installed using scoop, but I guess this isnt the problem.

@vinistock vinistock added the pinned This issue or pull request is pinned and won't be marked as stale label Jul 20, 2023
@vinistock
Copy link
Member

I put up Shopify/vscode-ruby-lsp#712 which I believe should address the issues based on what was reported here.

I'd appreciate it if someone could confirm that the PR makes it work on Windows, so that we can finally get it shipped 🙏.

@pawelma
Copy link

pawelma commented Oct 24, 2023

Leaving a note for future visitors:
Got this error on M1 Mac:

Failed to activate asdf environment: Command failed: /bin/sh -ic 'asdf exec ruby -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"' sh: no job control in this shell sh: asdf: command not found

To fix I had to give full disk access to my VS Code instance:
Go to System Settings -> Privacy & Security -> Full Disk Access -> Toggle Visual Studio Code on
After that and editor restart, it started indexing.

@spectre037
Copy link

Infinity thanks @pawelma

@davideluque
Copy link

Leaving a note for future visitors: Got this error on M1 Mac:

Failed to activate asdf environment: Command failed: /bin/sh -ic 'asdf exec ruby -rjson -e "printf(%{RUBY_ENV_ACTIVATE%sRUBY_ENV_ACTIVATE}, JSON.dump(ENV.to_h))"' sh: no job control in this shell sh: asdf: command not found

To fix I had to give full disk access to my VS Code instance: Go to System Settings -> Privacy & Security -> Full Disk Access -> Toggle Visual Studio Code on After that and editor restart, it started indexing.

This works, but I'm wondering if it's the best way to do it.

So far, I've been using VSCode without this setup and haven't encountered any problems with other extensions.

I'm concerned whether this could potentially lead to security issues by giving VSCode full disk access.

Is the Ruby-LSP team considering any alternative solutions to prevent the need for this workaround?

Thanks for the hard work!

@vinistock
Copy link
Member

vinistock commented Jan 8, 2024

Giving full disk access is not necessary. My VS Code doesn't have full disk access and the Ruby LSP works fine.

What might potentially be happening is that VS Code prompted at some point asking for access to certain directories and permissions to those specific directories were denied by the user.

For example, the Ruby LSP server needs to read gems in order to index their files and provide features like go to definition. If the process doesn't have permission to read the directory where gems are installed, then it won't be able to do it.

I don't understand why the permission issues lead to VS Code selecting /bin/sh as the shell instead of the default configured shell. It'd be nice to understand exactly which permission has to be denied to lead to this behaviour. That way we can detect it and prompt the user to change only the relevant permissions.

@davideluque
Copy link

Giving full disk access is not necessary. My VS Code doesn't have full disk access and the Ruby LSP works fine.

What might potentially be happening is that VS Code prompted at some point asking for access to certain directories and permissions to those specific directories was denied by the user.

For example, the Ruby LSP server needs to read gems in order to index their files and provide features like go to definition. If the process doesn't have permission to read the directory where gems are installed, then it won't be able to do it.

I don't understand why the permission issues lead to VS Code selecting /bin/sh as the shell instead of the default configured shell. It'd be nice to understand exactly which permission has to be denied to lead to this behaviour. That way we can detect it and prompt the user to change only the relevant permissions.

I removed the full disk access, restarted VS Code and it is still working. If this happens again I will try to post what has lead to this behavior.

@aimdevlee
Copy link

aimdevlee commented Jan 18, 2024

You saved my day! thanks @pawelma

@vinistock vinistock added the transferred This issue was transferred from vscode-ruby-lsp label Mar 12, 2024
@vinistock vinistock transferred this issue from Shopify/vscode-ruby-lsp Mar 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working pinned This issue or pull request is pinned and won't be marked as stale transferred This issue was transferred from vscode-ruby-lsp
Projects
None yet
Development

Successfully merging a pull request may close this issue.