Class: RubyLsp::SetupBundler

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

Defined Under Namespace

Classes: BundleNotLocked

Constant Summary collapse

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

Instance Method Summary collapse

Constructor Details

#initialize(project_path, **options) ⇒ SetupBundler

Returns a new instance of SetupBundler.



26
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
# File 'lib/ruby_lsp/setup_bundler.rb', line 26

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(Dir.pwd), 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])
end

Instance Method Details

#setup!Object

Raises:



57
58
59
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
# File 'lib/ruby_lsp/setup_bundler.rb', line 57

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

  # Do not setup a custom bundle if both `ruby-lsp` and `debug` are already in the Gemfile
  if @dependencies["ruby-lsp"] && @dependencies["debug"]
    warn("Ruby LSP> Skipping custom bundle setup since both `ruby-lsp` and `debug` are already in #{@gemfile}")

    # If the user decided to add the `ruby-lsp` and `debug` 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?
    warn("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
    warn("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)
  @lockfile_hash_path.write(current_lockfile_hash)
  run_bundle_install(@custom_gemfile)
end