Class: RubyLsp::SetupBundler

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/ruby_lsp/setup_bundler.rb

Defined Under Namespace

Classes: BundleInstallFailure, BundleNotLocked

Constant Summary collapse

FOUR_HOURS =
T.let(4 * 60 * 60, Integer)

Instance Method Summary collapse

Constructor Details

#initialize(project_path, **options) ⇒ SetupBundler



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/ruby_lsp/setup_bundler.rb', line 27

def initialize(project_path, **options)
  @project_path = project_path
  @branch = T.let(options[:branch], T.nilable(String))
  @experimental = T.let(options[:experimental], T.nilable(T::Boolean))

  # Regular bundle paths
  @gemfile = T.let(
    begin
      Bundler.default_gemfile
    rescue Bundler::GemfileNotFound
      nil
    end,
    T.nilable(Pathname),
  )
  @lockfile = T.let(@gemfile ? Bundler.default_lockfile : nil, T.nilable(Pathname))

  @gemfile_name = T.let(@gemfile&.basename&.to_s || "Gemfile", String)

  # Custom bundle paths
  @custom_dir = T.let(Pathname.new(".ruby-lsp").expand_path(@project_path), Pathname)
  @custom_gemfile = T.let(@custom_dir + @gemfile_name, Pathname)
  @custom_lockfile = T.let(@custom_dir + (@lockfile&.basename || "Gemfile.lock"), Pathname)
  @lockfile_hash_path = T.let(@custom_dir + "main_lockfile_hash", Pathname)
  @last_updated_path = T.let(@custom_dir + "last_updated", Pathname)

  @dependencies = T.let(load_dependencies, T::Hash[String, T.untyped])
  @rails_app = T.let(rails_app?, T::Boolean)
  @retry = T.let(false, T::Boolean)
end

Instance Method Details

#setup!Object

Raises:



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/ruby_lsp/setup_bundler.rb', line 60

def setup!
  raise BundleNotLocked if @gemfile&.exist? && !@lockfile&.exist?

  # Do not set up a custom bundle if LSP dependencies are already in the Gemfile
  if @dependencies["ruby-lsp"] &&
      @dependencies["debug"] &&
      (@rails_app ? @dependencies["ruby-lsp-rails"] : true)
    $stderr.puts(
      "Ruby LSP> Skipping custom bundle setup since LSP dependencies are already in #{@gemfile}",
    )

    # If the user decided to add `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) to their Gemfile after
    # having already run the Ruby LSP, then we need to remove the `.ruby-lsp` folder, otherwise we will run `bundle
    # install` for the top level and try to execute the Ruby LSP using the custom bundle, which will fail since the
    # gems are not installed there
    @custom_dir.rmtree if @custom_dir.exist?
    return run_bundle_install
  end

  # Automatically create and ignore the .ruby-lsp folder for users
  @custom_dir.mkpath unless @custom_dir.exist?
  ignore_file = @custom_dir + ".gitignore"
  ignore_file.write("*") unless ignore_file.exist?

  write_custom_gemfile

  unless @gemfile&.exist? && @lockfile&.exist?
    $stderr.puts("Ruby LSP> Skipping lockfile copies because there's no top level bundle")
    return run_bundle_install(@custom_gemfile)
  end

  lockfile_contents = @lockfile.read
  current_lockfile_hash = Digest::SHA256.hexdigest(lockfile_contents)

  if @custom_lockfile.exist? && @lockfile_hash_path.exist? && @lockfile_hash_path.read == current_lockfile_hash
    $stderr.puts(
      "Ruby LSP> Skipping custom bundle setup since #{@custom_lockfile} already exists and is up to date",
    )
    return run_bundle_install(@custom_gemfile)
  end

  FileUtils.cp(@lockfile.to_s, @custom_lockfile.to_s)
  correct_relative_remote_paths
  @lockfile_hash_path.write(current_lockfile_hash)
  run_bundle_install(@custom_gemfile)
end