summaryrefslogtreecommitdiff
path: root/lib/rubygems/bundler_version_finder.rb
blob: d792358da70176b51894ed4cce84e54a8c39e105 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
53
54
55
56
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# frozen_string_literal: true

module Gem::BundlerVersionFinder
  def self.bundler_version
    return if bundle_config_version == "system"

    v = ENV["BUNDLER_VERSION"]
    v = nil if v&.empty?

    v ||= bundle_update_bundler_version
    return if v == true

    v ||= bundle_config_version

    v ||= lockfile_version
    return unless v

    Gem::Version.new(v)
  end

  def self.prioritize!(specs)
    exact_match_index = specs.find_index {|spec| spec.version == bundler_version }
    return unless exact_match_index

    specs.unshift(specs.delete_at(exact_match_index))
  end

  def self.bundle_update_bundler_version
    return unless ["bundle", "bundler"].include? File.basename($0)
    return unless "update".start_with?(ARGV.first || " ")
    bundler_version = nil
    update_index = nil
    ARGV.each_with_index do |a, i|
      if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
        bundler_version = a
      end
      next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
      bundler_version = $1 || true
      update_index = i
    end
    bundler_version
  end
  private_class_method :bundle_update_bundler_version

  def self.lockfile_version
    return unless contents = lockfile_contents
    regexp = /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
    return unless contents =~ regexp
    $1
  end
  private_class_method :lockfile_version

  def self.lockfile_contents
    gemfile = gemfile_path

    return unless gemfile

    lockfile = ENV["BUNDLE_LOCKFILE"]
    lockfile = nil if lockfile&.empty?

    lockfile ||= case gemfile
                 when "gems.rb" then "gems.locked"
                 else "#{gemfile}.lock"
    end

    return unless File.file?(lockfile)

    File.read(lockfile)
  end
  private_class_method :lockfile_contents

  def self.bundle_config_version
    version = nil

    [bundler_local_config_file, bundler_global_config_file].each do |config_file|
      next unless config_file && File.file?(config_file)

      contents = File.read(config_file)
      contents =~ /^BUNDLE_VERSION:\s*["']?([^"'\s]+)["']?\s*$/

      version = $1
      break if version
    end

    version
  end
  private_class_method :bundle_config_version

  def self.bundler_global_config_file
    # see Bundler::Settings#global_config_file
    if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty?
      ENV["BUNDLE_CONFIG"]
    elsif ENV["BUNDLE_USER_CONFIG"] && !ENV["BUNDLE_USER_CONFIG"].empty?
      ENV["BUNDLE_USER_CONFIG"]
    elsif ENV["BUNDLE_USER_HOME"] && !ENV["BUNDLE_USER_HOME"].empty?
      ENV["BUNDLE_USER_HOME"] + "config"
    elsif Gem.user_home && !Gem.user_home.empty?
      Gem.user_home + ".bundle/config"
    end
  end
  private_class_method :bundler_global_config_file

  def self.bundler_local_config_file
    gemfile = gemfile_path
    return unless gemfile

    File.join(File.dirname(gemfile), ".bundle", "config")
  end
  private_class_method :bundler_local_config_file

  def self.gemfile_path
    gemfile = ENV["BUNDLE_GEMFILE"]
    gemfile = nil if gemfile&.empty?

    unless gemfile
      begin
        Gem::Util.traverse_parents(Dir.pwd) do |directory|
          next unless gemfile = Gem::GEM_DEP_FILES.find {|f| File.file?(f) }

          gemfile = File.join directory, gemfile
          break
        end
      rescue Errno::ENOENT
        return
      end
    end

    gemfile
  end
  private_class_method :gemfile_path
end