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

Fix chdir issue for LSP #2171

Merged
merged 1 commit into from
Jan 29, 2025
Merged

Fix chdir issue for LSP #2171

merged 1 commit into from
Jan 29, 2025

Conversation

andyw8
Copy link
Contributor

@andyw8 andyw8 commented Jan 28, 2025

Motivation

After #2081, we began so to see an Error loading add-ons: RuboCop: conflicting chdir during another chdir block.

Implementation

We don't want to run chdir since it may impact other things Ruby LSP is doing, since the path will be wrong.

Tests

Updated.

@alexcrocha has verified on Core.

@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from e6f0fd3 to 5c7fcb7 Compare January 28, 2025 19:13
@andyw8 andyw8 added the bugfix label Jan 28, 2025
@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from e9323ad to 1dfeacf Compare January 28, 2025 19:23
@andyw8 andyw8 requested a review from alexcrocha January 28, 2025 19:24
@@ -45,7 +46,8 @@ def lockfile_changed?

sig { returns(String) }
def fetch_lockfile_diff
@lockfile_diff = File.exist?("Gemfile.lock") ? %x(git diff Gemfile.lock).strip : ""
@lockfile_diff =
File.exist?("#{project_path}/Gemfile.lock") ? %x(cd #{project_path} && git diff Gemfile.lock).strip : ""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(we should probbably use File.join instead of interpolation)

@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from 014d49b to d1116c7 Compare January 29, 2025 13:14
@andyw8 andyw8 changed the title WIP: Fix chdir issue Fix chdir issue for LSP Jan 29, 2025
@andyw8 andyw8 marked this pull request as ready for review January 29, 2025 13:16
@andyw8 andyw8 requested a review from a team as a code owner January 29, 2025 13:16
@andyw8 andyw8 requested review from KaanOzkan and vinistock January 29, 2025 13:16
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/addon.rb Outdated Show resolved Hide resolved
@@ -45,7 +46,8 @@ def lockfile_changed?

sig { returns(String) }
def fetch_lockfile_diff
@lockfile_diff = File.exist?("Gemfile.lock") ? %x(git diff Gemfile.lock).strip : ""
@lockfile_diff =
File.exist?("#{project_path}/Gemfile.lock") ? execute_in_project_path("git diff Gemfile.lock").strip : ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be using Bundler methods to find the lockfile.

Bundler.with_original_env { Bundler.default_lockfile }

lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
lib/ruby_lsp/tapioca/run_gem_rbi_check.rb Outdated Show resolved Hide resolved
@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from f6052b2 to e04572f Compare January 29, 2025 14:51
@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from 169bf19 to cb81ea5 Compare January 29, 2025 18:17
Copy link
Member

@vinistock vinistock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move forward to fix the crash and then we can continue improving the implementation

@andyw8 andyw8 enabled auto-merge January 29, 2025 18:21
@andyw8 andyw8 disabled auto-merge January 29, 2025 18:24
@andyw8 andyw8 force-pushed the andyw8/fix-chdir-issue branch from cb81ea5 to 29cf4ef Compare January 29, 2025 18:25
@andyw8 andyw8 enabled auto-merge January 29, 2025 18:26
sig { returns(T::Boolean) }
def git_repo?
_, status = Open3.capture2e("git rev-parse --is-inside-work-tree")
T.must(status.success?)
!!system("git rev-parse --is-inside-work-tree", chdir: project_path)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get why we are doing a !! here, but it is totally fine for a ? method to return T.nilable(T::Boolean), which would remove the need for this operation.

Predicate methods in Ruby return truthy or falsy values, not booleans.

@@ -82,35 +87,46 @@ def execute_tapioca_gem_command(gems)

sig { params(gems: T::Array[String]).void }
def remove_rbis(gems)
FileUtils.rm_f(Dir.glob("sorbet/rbi/gems/{#{gems.join(",")}}@*.rbi"))
FileUtils.rm_f(Dir.glob("sorbet/rbi/gems/{#{gems.join(",")}}@*.rbi", base: project_path))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct. From the docs:

If optional keyword argument base is given, its value specifies the base directory. Each pattern string specifies entries relative to the base directory; the default is '.'. The base directory is not prepended to the entry names in the result:

Dir.glob(pattern, base: 'lib').take(5)
# => ["abbrev.gemspec", "abbrev.rb", "base64.gemspec", "base64.rb", "benchmark.gemspec"]

You will need to then File.join all the glob results with the project_path before passing them to FileUtils.rm_f.

In any case, for readability, it would be great to pull out the glob result into a local variable.

Comment on lines +96 to +103
untracked_files = execute_in_project_path(
"git",
"ls-files",
"--others",
"--exclude-standard",
"sorbet/rbi/gems/",
).lines.map(&:strip)
deleted_files = execute_in_project_path("git", "ls-files", "--deleted", "sorbet/rbi/gems/").lines.map(&:strip)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like this is missing a git_ls_gem_rbis abstraction:

Suggested change
untracked_files = execute_in_project_path(
"git",
"ls-files",
"--others",
"--exclude-standard",
"sorbet/rbi/gems/",
).lines.map(&:strip)
deleted_files = execute_in_project_path("git", "ls-files", "--deleted", "sorbet/rbi/gems/").lines.map(&:strip)
untracked_files = git_ls_gem_rbis("--others", "--exclude-standard")
deleted_files = git_ls_gem_rbis("--deleted")


delete_files(untracked_files, "Deleted untracked RBIs")
restore_files(deleted_files, "Restored deleted RBIs")
end

sig { params(files: T::Array[String], message: String).void }
def delete_files(files, message)
files.each { |file| File.delete(file) }
FileUtils.rm(files.map { |file| File.join(project_path, file) })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, we are doing this operation in two places, remove_rbis and here in this method. We seem to be missing a common abstraction that will take relative file paths and remove them after mapping them to absolute paths.

log_message("#{message}: #{files.join(", ")}") unless files.empty?
end

sig { params(files: T::Array[String], message: String).void }
def restore_files(files, message)
files.each { |file| %x(git checkout -- #{file}) }
files.each { |file| execute_in_project_path("git", "checkout", "--", file) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to not need to execute multiple commands. If we join all the filenames, it could be too long, but we can stream them into the stdin of the execution, and use the --paths-from-file=- flag of git checkout to do all of this in one operation.

Something like:

Suggested change
files.each { |file| execute_in_project_path("git", "checkout", "--", file) }
execute_in_project_path("git", "checkout", "--pathspec-from-file=-", stdin: files.join("\n"))

Comment on lines +126 to +129
def execute_in_project_path(*parts)
stdout_and_stderr, _status = T.unsafe(Open3).capture2e(*parts, chdir: project_path)
stdout_and_stderr
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of my suggestion above:

Suggested change
def execute_in_project_path(*parts)
stdout_and_stderr, _status = T.unsafe(Open3).capture2e(*parts, chdir: project_path)
stdout_and_stderr
end
def execute_in_project_path(*parts, stdin: nil)
options = {}
options[:chdir] = project_path
options[:stdin_data] = stdin if stdin
stdout_and_stderr, _status = T.unsafe(Open3).capture2e(*parts, options)
stdout_and_stderr
end

@andyw8 andyw8 merged commit 73c476c into main Jan 29, 2025
33 checks passed
@andyw8 andyw8 deleted the andyw8/fix-chdir-issue branch January 29, 2025 18:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants