bundler 2.5.16 → 2.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +194 -0
  3. data/bundler.gemspec +2 -2
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/cli/add.rb +3 -1
  6. data/lib/bundler/cli/check.rb +3 -3
  7. data/lib/bundler/cli/console.rb +0 -4
  8. data/lib/bundler/cli/doctor.rb +4 -4
  9. data/lib/bundler/cli/exec.rb +1 -0
  10. data/lib/bundler/cli/gem.rb +6 -3
  11. data/lib/bundler/cli/info.rb +2 -2
  12. data/lib/bundler/cli/inject.rb +1 -1
  13. data/lib/bundler/cli/install.rb +13 -4
  14. data/lib/bundler/cli/lock.rb +25 -6
  15. data/lib/bundler/cli/outdated.rb +16 -18
  16. data/lib/bundler/cli/pristine.rb +1 -1
  17. data/lib/bundler/cli/show.rb +2 -2
  18. data/lib/bundler/cli.rb +38 -68
  19. data/lib/bundler/compact_index_client/cache_file.rb +0 -5
  20. data/lib/bundler/compact_index_client/updater.rb +0 -11
  21. data/lib/bundler/definition.rb +186 -119
  22. data/lib/bundler/dependency.rb +1 -1
  23. data/lib/bundler/dsl.rb +67 -52
  24. data/lib/bundler/endpoint_specification.rb +10 -1
  25. data/lib/bundler/errors.rb +17 -5
  26. data/lib/bundler/feature_flag.rb +1 -0
  27. data/lib/bundler/fetcher/compact_index.rb +1 -1
  28. data/lib/bundler/fetcher.rb +12 -5
  29. data/lib/bundler/force_platform.rb +0 -2
  30. data/lib/bundler/gem_helpers.rb +21 -5
  31. data/lib/bundler/injector.rb +2 -2
  32. data/lib/bundler/inline.rb +42 -17
  33. data/lib/bundler/installer/gem_installer.rb +4 -2
  34. data/lib/bundler/installer/parallel_installer.rb +3 -2
  35. data/lib/bundler/installer/standalone.rb +2 -2
  36. data/lib/bundler/installer.rb +11 -47
  37. data/lib/bundler/lazy_specification.rb +74 -26
  38. data/lib/bundler/lockfile_generator.rb +1 -1
  39. data/lib/bundler/lockfile_parser.rb +10 -2
  40. data/lib/bundler/man/bundle-add.1 +42 -25
  41. data/lib/bundler/man/bundle-add.1.ronn +52 -23
  42. data/lib/bundler/man/bundle-binstubs.1 +7 -4
  43. data/lib/bundler/man/bundle-binstubs.1.ronn +6 -3
  44. data/lib/bundler/man/bundle-cache.1 +30 -2
  45. data/lib/bundler/man/bundle-cache.1.ronn +31 -2
  46. data/lib/bundler/man/bundle-check.1 +3 -3
  47. data/lib/bundler/man/bundle-check.1.ronn +4 -2
  48. data/lib/bundler/man/bundle-clean.1 +1 -1
  49. data/lib/bundler/man/bundle-config.1 +3 -5
  50. data/lib/bundler/man/bundle-config.1.ronn +2 -7
  51. data/lib/bundler/man/bundle-console.1 +2 -4
  52. data/lib/bundler/man/bundle-console.1.ronn +2 -7
  53. data/lib/bundler/man/bundle-doctor.1 +2 -2
  54. data/lib/bundler/man/bundle-doctor.1.ronn +1 -1
  55. data/lib/bundler/man/bundle-env.1 +9 -0
  56. data/lib/bundler/man/bundle-env.1.ronn +10 -0
  57. data/lib/bundler/man/bundle-exec.1 +5 -2
  58. data/lib/bundler/man/bundle-exec.1.ronn +4 -1
  59. data/lib/bundler/man/bundle-fund.1 +22 -0
  60. data/lib/bundler/man/bundle-fund.1.ronn +25 -0
  61. data/lib/bundler/man/bundle-gem.1 +17 -5
  62. data/lib/bundler/man/bundle-gem.1.ronn +27 -6
  63. data/lib/bundler/man/bundle-help.1 +1 -1
  64. data/lib/bundler/man/bundle-info.1 +5 -2
  65. data/lib/bundler/man/bundle-info.1.ronn +6 -2
  66. data/lib/bundler/man/bundle-init.1 +3 -3
  67. data/lib/bundler/man/bundle-init.1.ronn +3 -2
  68. data/lib/bundler/man/bundle-inject.1 +10 -2
  69. data/lib/bundler/man/bundle-inject.1.ronn +9 -1
  70. data/lib/bundler/man/bundle-install.1 +15 -12
  71. data/lib/bundler/man/bundle-install.1.ronn +22 -18
  72. data/lib/bundler/man/bundle-issue.1 +45 -0
  73. data/lib/bundler/man/bundle-issue.1.ronn +37 -0
  74. data/lib/bundler/man/bundle-licenses.1 +9 -0
  75. data/lib/bundler/man/bundle-licenses.1.ronn +10 -0
  76. data/lib/bundler/man/bundle-list.1 +1 -1
  77. data/lib/bundler/man/bundle-list.1.ronn +4 -1
  78. data/lib/bundler/man/bundle-lock.1 +21 -6
  79. data/lib/bundler/man/bundle-lock.1.ronn +25 -4
  80. data/lib/bundler/man/bundle-open.1 +2 -2
  81. data/lib/bundler/man/bundle-open.1.ronn +2 -1
  82. data/lib/bundler/man/bundle-outdated.1 +8 -5
  83. data/lib/bundler/man/bundle-outdated.1.ronn +8 -4
  84. data/lib/bundler/man/bundle-platform.1 +1 -1
  85. data/lib/bundler/man/bundle-plugin.1 +1 -1
  86. data/lib/bundler/man/bundle-pristine.1 +1 -1
  87. data/lib/bundler/man/bundle-pristine.1.ronn +1 -1
  88. data/lib/bundler/man/bundle-remove.1 +1 -1
  89. data/lib/bundler/man/bundle-remove.1.ronn +1 -1
  90. data/lib/bundler/man/bundle-show.1 +5 -2
  91. data/lib/bundler/man/bundle-show.1.ronn +4 -0
  92. data/lib/bundler/man/bundle-update.1 +13 -7
  93. data/lib/bundler/man/bundle-update.1.ronn +14 -6
  94. data/lib/bundler/man/bundle-version.1 +1 -1
  95. data/lib/bundler/man/bundle-viz.1 +4 -4
  96. data/lib/bundler/man/bundle-viz.1.ronn +7 -3
  97. data/lib/bundler/man/bundle.1 +1 -1
  98. data/lib/bundler/man/gemfile.5 +3 -1
  99. data/lib/bundler/man/gemfile.5.ronn +6 -0
  100. data/lib/bundler/man/index.txt +4 -0
  101. data/lib/bundler/materialization.rb +59 -0
  102. data/lib/bundler/plugin/api/source.rb +2 -1
  103. data/lib/bundler/plugin/events.rb +24 -0
  104. data/lib/bundler/plugin/installer.rb +1 -1
  105. data/lib/bundler/plugin.rb +20 -1
  106. data/lib/bundler/process_lock.rb +10 -14
  107. data/lib/bundler/remote_specification.rb +6 -1
  108. data/lib/bundler/resolver/base.rb +12 -6
  109. data/lib/bundler/resolver/candidate.rb +2 -2
  110. data/lib/bundler/resolver/package.rb +10 -1
  111. data/lib/bundler/resolver/spec_group.rb +4 -3
  112. data/lib/bundler/resolver.rb +36 -14
  113. data/lib/bundler/retry.rb +1 -1
  114. data/lib/bundler/ruby_version.rb +7 -1
  115. data/lib/bundler/rubygems_ext.rb +104 -51
  116. data/lib/bundler/rubygems_gem_installer.rb +7 -5
  117. data/lib/bundler/rubygems_integration.rb +23 -62
  118. data/lib/bundler/runtime.rb +22 -7
  119. data/lib/bundler/self_manager.rb +7 -7
  120. data/lib/bundler/settings.rb +6 -1
  121. data/lib/bundler/shared_helpers.rb +29 -17
  122. data/lib/bundler/source/git/git_proxy.rb +0 -2
  123. data/lib/bundler/source/git.rb +93 -40
  124. data/lib/bundler/source/metadata.rb +2 -3
  125. data/lib/bundler/source/path.rb +5 -3
  126. data/lib/bundler/source/rubygems.rb +6 -16
  127. data/lib/bundler/source_list.rb +1 -1
  128. data/lib/bundler/spec_set.rb +82 -57
  129. data/lib/bundler/stub_specification.rb +21 -2
  130. data/lib/bundler/templates/newgem/Gemfile.tt +0 -3
  131. data/lib/bundler/templates/newgem/README.md.tt +7 -3
  132. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +15 -15
  133. data/lib/bundler/templates/newgem/newgem.gemspec.tt +4 -4
  134. data/lib/bundler/ui/shell.rb +24 -2
  135. data/lib/bundler/ui/silent.rb +12 -1
  136. data/lib/bundler/uri_credentials_filter.rb +1 -1
  137. data/lib/bundler/vendor/fileutils/COPYING +56 -0
  138. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +15 -13
  139. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +46 -8
  140. data/lib/bundler/vendor/securerandom/.document +1 -0
  141. data/lib/bundler/vendor/securerandom/COPYING +56 -0
  142. data/lib/bundler/vendor/securerandom/lib/securerandom.rb +102 -0
  143. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +3 -5
  144. data/lib/bundler/vendor/thor/lib/thor/group.rb +11 -0
  145. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +1 -4
  146. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +2 -2
  147. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +2 -1
  148. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +9 -9
  149. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +1 -1
  150. data/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +5 -21
  151. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  152. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  153. data/lib/bundler/vendor/thor/lib/thor.rb +11 -0
  154. data/lib/bundler/vendor/uri/COPYING +56 -0
  155. data/lib/bundler/vendor/uri/lib/uri/common.rb +37 -14
  156. data/lib/bundler/vendor/uri/lib/uri/file.rb +3 -3
  157. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +1 -1
  158. data/lib/bundler/vendor/uri/lib/uri/generic.rb +16 -26
  159. data/lib/bundler/vendor/uri/lib/uri/http.rb +2 -2
  160. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +10 -3
  161. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +26 -3
  162. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  163. data/lib/bundler/vendor/uri/lib/uri.rb +9 -9
  164. data/lib/bundler/vendored_securerandom.rb +12 -0
  165. data/lib/bundler/version.rb +1 -1
  166. data/lib/bundler/yaml_serializer.rb +1 -1
  167. data/lib/bundler.rb +68 -36
  168. metadata +20 -10
  169. data/lib/bundler/vendor/fileutils/LICENSE.txt +0 -22
  170. data/lib/bundler/vendor/uri/LICENSE.txt +0 -22
data/lib/bundler/dsl.rb CHANGED
@@ -42,20 +42,20 @@ module Bundler
42
42
  end
43
43
 
44
44
  def eval_gemfile(gemfile, contents = nil)
45
- expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
46
- original_gemfile = @gemfile
47
- @gemfile = expanded_gemfile_path
48
- @gemfiles << expanded_gemfile_path
49
- contents ||= Bundler.read_file(@gemfile.to_s)
50
- instance_eval(contents, @gemfile.to_s, 1)
51
- rescue Exception => e # rubocop:disable Lint/RescueException
52
- message = "There was an error " \
53
- "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \
54
- "`#{File.basename gemfile.to_s}`: #{e.message}"
55
-
56
- raise DSLError.new(message, gemfile, e.backtrace, contents)
57
- ensure
58
- @gemfile = original_gemfile
45
+ with_gemfile(gemfile) do |current_gemfile|
46
+ contents ||= Bundler.read_file(current_gemfile)
47
+ instance_eval(contents, current_gemfile, 1)
48
+ rescue GemfileEvalError => e
49
+ message = "There was an error evaluating `#{File.basename current_gemfile}`: #{e.message}"
50
+ raise DSLError.new(message, current_gemfile, e.backtrace, contents)
51
+ rescue GemfileError, InvalidArgumentError, InvalidOption, DeprecatedError, ScriptError => e
52
+ message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
53
+ raise DSLError.new(message, current_gemfile, e.backtrace, contents)
54
+ rescue StandardError => e
55
+ raise unless e.backtrace_locations.first.path == current_gemfile
56
+ message = "There was an error parsing `#{File.basename current_gemfile}`: #{e.message}"
57
+ raise DSLError.new(message, current_gemfile, e.backtrace, contents)
58
+ end
59
59
  end
60
60
 
61
61
  def gemspec(opts = nil)
@@ -66,7 +66,7 @@ module Bundler
66
66
  development_group = opts[:development_group] || :development
67
67
  expanded_path = gemfile_root.join(path)
68
68
 
69
- gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact
69
+ gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
70
70
  gemspecs.reject! {|s| s.name != name } if name
71
71
  specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] }
72
72
 
@@ -110,9 +110,23 @@ module Bundler
110
110
  if gemspec_dep
111
111
  gemfile_dep = [dep, current].find(&:runtime?)
112
112
 
113
- unless current_requirement_open
113
+ if gemfile_dep && !current_requirement_open
114
114
  Bundler.ui.warn "A gemspec development dependency (#{gemspec_dep.name}, #{gemspec_dep.requirement}) is being overridden by a Gemfile dependency (#{gemfile_dep.name}, #{gemfile_dep.requirement}).\n" \
115
115
  "This behaviour may change in the future. Please remove either of them, or make sure they both have the same requirement\n"
116
+ elsif gemfile_dep.nil?
117
+ require_relative "vendor/pub_grub/lib/pub_grub/version_range"
118
+ require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
119
+ require_relative "vendor/pub_grub/lib/pub_grub/version_union"
120
+ require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
121
+
122
+ current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
123
+ next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
124
+
125
+ if current_gemspec_range.intersects?(next_gemspec_range)
126
+ dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options)
127
+ else
128
+ raise GemfileError, "Two gemspecs have conflicting requirements on the same gem: #{dep} and #{current}"
129
+ end
116
130
  end
117
131
  else
118
132
  update_prompt = ""
@@ -133,20 +147,22 @@ module Bundler
133
147
  end
134
148
  end
135
149
 
136
- # Always prefer the dependency from the Gemfile
137
- if current.gemspec_dev_dep?
138
- @dependencies.delete(current)
139
- elsif dep.gemspec_dev_dep?
140
- return
141
- elsif current.source != dep.source
142
- raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
143
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
144
- "#{current.source || "an unspecified source"} and #{dep.source}\n"
145
- else
146
- Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
147
- "You should probably keep only one of them.\n" \
148
- "Remove any duplicate entries and specify the gem only once.\n" \
149
- "While it's not a problem now, it could cause errors if you change the version of one of them later."
150
+ unless current.gemspec_dev_dep? && dep.gemspec_dev_dep?
151
+ # Always prefer the dependency from the Gemfile
152
+ if current.gemspec_dev_dep?
153
+ @dependencies.delete(current)
154
+ elsif dep.gemspec_dev_dep?
155
+ return
156
+ elsif current.source != dep.source
157
+ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
158
+ "You specified that #{dep.name} (#{dep.requirement}) should come from " \
159
+ "#{current.source || "an unspecified source"} and #{dep.source}\n"
160
+ else
161
+ Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
162
+ "You should probably keep only one of them.\n" \
163
+ "Remove any duplicate entries and specify the gem only once.\n" \
164
+ "While it's not a problem now, it could cause errors if you change the version of one of them later."
165
+ end
150
166
  end
151
167
  end
152
168
 
@@ -219,7 +235,7 @@ module Bundler
219
235
  end
220
236
 
221
237
  def github(repo, options = {})
222
- raise ArgumentError, "GitHub sources require a block" unless block_given?
238
+ raise InvalidArgumentError, "GitHub sources require a block" unless block_given?
223
239
  github_uri = @git_sources["github"].call(repo)
224
240
  git_options = normalize_hash(options).merge("uri" => github_uri)
225
241
  git_source = @sources.add_git_source(git_options)
@@ -285,6 +301,16 @@ module Bundler
285
301
 
286
302
  private
287
303
 
304
+ def with_gemfile(gemfile)
305
+ expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
306
+ original_gemfile = @gemfile
307
+ @gemfile = expanded_gemfile_path
308
+ @gemfiles << expanded_gemfile_path
309
+ yield @gemfile.to_s
310
+ ensure
311
+ @gemfile = original_gemfile
312
+ end
313
+
288
314
  def add_git_sources
289
315
  git_source(:github) do |repo_name|
290
316
  if repo_name =~ GITHUB_PULL_REQUEST_URL
@@ -477,18 +503,7 @@ module Bundler
477
503
  end
478
504
 
479
505
  def check_rubygems_source_safety
480
- if @sources.implicit_global_source?
481
- implicit_global_source_warning
482
- elsif @sources.aggregate_global_source?
483
- multiple_global_source_warning
484
- end
485
- end
486
-
487
- def implicit_global_source_warning
488
- Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \
489
- "Not using an explicit global source may result in a different lockfile being generated depending on " \
490
- "the gems you have installed locally before bundler is run. " \
491
- "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"."
506
+ multiple_global_source_warning if @sources.aggregate_global_source?
492
507
  end
493
508
 
494
509
  def multiple_global_source_warning
@@ -577,23 +592,23 @@ module Bundler
577
592
 
578
593
  return m unless backtrace && dsl_path && contents
579
594
 
580
- trace_line = backtrace.find {|l| l.include?(dsl_path.to_s) } || trace_line
595
+ trace_line = backtrace.find {|l| l.include?(dsl_path) } || trace_line
581
596
  return m unless trace_line
582
- line_numer = trace_line.split(":")[1].to_i - 1
583
- return m unless line_numer
597
+ line_number = trace_line.split(":")[1].to_i - 1
598
+ return m unless line_number
584
599
 
585
600
  lines = contents.lines.to_a
586
601
  indent = " # "
587
602
  indicator = indent.tr("#", ">")
588
- first_line = line_numer.zero?
589
- last_line = (line_numer == (lines.count - 1))
603
+ first_line = line_number.zero?
604
+ last_line = (line_number == (lines.count - 1))
590
605
 
591
606
  m << "\n"
592
607
  m << "#{indent}from #{trace_line.gsub(/:in.*$/, "")}\n"
593
608
  m << "#{indent}-------------------------------------------\n"
594
- m << "#{indent}#{lines[line_numer - 1]}" unless first_line
595
- m << "#{indicator}#{lines[line_numer]}"
596
- m << "#{indent}#{lines[line_numer + 1]}" unless last_line
609
+ m << "#{indent}#{lines[line_number - 1]}" unless first_line
610
+ m << "#{indicator}#{lines[line_number]}"
611
+ m << "#{indent}#{lines[line_number + 1]}" unless last_line
597
612
  m << "\n" unless m.end_with?("\n")
598
613
  m << "#{indent}-------------------------------------------\n"
599
614
  end
@@ -603,7 +618,7 @@ module Bundler
603
618
 
604
619
  def parse_line_number_from_description
605
620
  description = self.description
606
- if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path.to_s}):\d+)/
621
+ if dsl_path && description =~ /((#{Regexp.quote File.expand_path(dsl_path)}|#{Regexp.quote dsl_path}):\d+)/
607
622
  trace_line = Regexp.last_match[1]
608
623
  description = description.sub(/\n.*\n(\.\.\.)? *\^~+$/, "").sub(/#{Regexp.quote trace_line}:\s*/, "").sub("\n", " - ")
609
624
  end
@@ -6,7 +6,7 @@ module Bundler
6
6
  include MatchRemoteMetadata
7
7
 
8
8
  attr_reader :name, :version, :platform, :checksum
9
- attr_accessor :source, :remote, :dependencies
9
+ attr_accessor :remote, :dependencies, :locked_platform
10
10
 
11
11
  def initialize(name, version, platform, spec_fetcher, dependencies, metadata = nil)
12
12
  super()
@@ -18,10 +18,15 @@ module Bundler
18
18
 
19
19
  @loaded_from = nil
20
20
  @remote_specification = nil
21
+ @locked_platform = nil
21
22
 
22
23
  parse_metadata(metadata)
23
24
  end
24
25
 
26
+ def insecurely_materialized?
27
+ @locked_platform.to_s != @platform.to_s
28
+ end
29
+
25
30
  def fetch_platform
26
31
  @platform
27
32
  end
@@ -115,6 +120,10 @@ module Bundler
115
120
  @remote_specification = spec
116
121
  end
117
122
 
123
+ def inspect
124
+ "#<#{self.class} @name=\"#{name}\" (#{full_name.delete_prefix("#{name}-")})>"
125
+ end
126
+
118
127
  private
119
128
 
120
129
  def _remote_specification
@@ -217,15 +217,15 @@ module Bundler
217
217
  end
218
218
 
219
219
  class InsecureInstallPathError < BundlerError
220
- def initialize(path)
220
+ def initialize(name, path)
221
+ @name = name
221
222
  @path = path
222
223
  end
223
224
 
224
225
  def message
225
- "The installation path is insecure. Bundler cannot continue.\n" \
226
- "#{@path} is world-writable (without sticky bit).\n" \
227
- "Bundler cannot safely replace gems in world-writeable directories due to potential vulnerabilities.\n" \
228
- "Please change the permissions of this directory or choose a different install path."
226
+ "Bundler cannot reinstall #{@name} because there's a previous installation of it at #{@path} that is unsafe to remove.\n" \
227
+ "The parent of #{@path} is world-writable and does not have the sticky bit set, making it insecure to remove due to potential vulnerabilities.\n" \
228
+ "Please change the permissions of #{File.dirname(@path)} or choose a different install path."
229
229
  end
230
230
 
231
231
  status_code(38)
@@ -244,4 +244,16 @@ module Bundler
244
244
 
245
245
  status_code(39)
246
246
  end
247
+
248
+ class InvalidArgumentError < BundlerError; status_code(40); end
249
+
250
+ class IncorrectLockfileDependencies < BundlerError
251
+ attr_reader :spec
252
+
253
+ def initialize(spec)
254
+ @spec = spec
255
+ end
256
+
257
+ status_code(41)
258
+ end
247
259
  end
@@ -33,6 +33,7 @@ module Bundler
33
33
  settings_flag(:default_install_uses_path) { bundler_3_mode? }
34
34
  settings_flag(:forget_cli_options) { bundler_3_mode? }
35
35
  settings_flag(:global_gem_cache) { bundler_3_mode? }
36
+ settings_flag(:lockfile_checksums) { bundler_3_mode? }
36
37
  settings_flag(:path_relative_to_cwd) { bundler_3_mode? }
37
38
  settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
38
39
  settings_flag(:print_only_version_number) { bundler_3_mode? }
@@ -10,7 +10,7 @@ module Bundler
10
10
  method = instance_method(method_name)
11
11
  undef_method(method_name)
12
12
  define_method(method_name) do |*args, &blk|
13
- method.bind(self).call(*args, &blk)
13
+ method.bind_call(self, *args, &blk)
14
14
  rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e
15
15
  raise HTTPError, e.message
16
16
  rescue AuthenticationRequiredError, BadAuthenticationError
@@ -3,7 +3,7 @@
3
3
  require_relative "vendored_persistent"
4
4
  require_relative "vendored_timeout"
5
5
  require "cgi"
6
- require "securerandom"
6
+ require_relative "vendored_securerandom"
7
7
  require "zlib"
8
8
 
9
9
  module Bundler
@@ -37,8 +37,9 @@ module Bundler
37
37
  # This is the error raised when a source is HTTPS and OpenSSL didn't load
38
38
  class SSLError < HTTPError
39
39
  def initialize(msg = nil)
40
- super msg || "Could not load OpenSSL.\n" \
41
- "You must recompile Ruby with OpenSSL support."
40
+ super "Could not load OpenSSL.\n" \
41
+ "You must recompile Ruby with OpenSSL support.\n" \
42
+ "original error: #{msg}\n"
42
43
  end
43
44
  end
44
45
 
@@ -182,7 +183,7 @@ module Bundler
182
183
  agent << " ci/#{cis.join(",")}" if cis.any?
183
184
 
184
185
  # add a random ID so we can consolidate runs server-side
185
- agent << " " << SecureRandom.hex(8)
186
+ agent << " " << Gem::SecureRandom.hex(8)
186
187
 
187
188
  # add any user agent strings set in the config
188
189
  extra_ua = Bundler.settings[:user_agent]
@@ -251,7 +252,13 @@ module Bundler
251
252
  needs_ssl = remote_uri.scheme == "https" ||
252
253
  Bundler.settings[:ssl_verify_mode] ||
253
254
  Bundler.settings[:ssl_client_cert]
254
- raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
255
+ if needs_ssl
256
+ begin
257
+ require "openssl"
258
+ rescue StandardError, LoadError => e
259
+ raise SSLError.new(e.message)
260
+ end
261
+ end
255
262
 
256
263
  con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV
257
264
  if gem_proxy = Gem.configuration[:http_proxy]
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module ForcePlatform
5
- private
6
-
7
5
  # The `:force_ruby_platform` value used by dependencies for resolution, and
8
6
  # by locked specifications for materialization is `false` by default, except
9
7
  # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
@@ -46,7 +46,7 @@ module Bundler
46
46
  end
47
47
  module_function :platform_specificity_match
48
48
 
49
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
49
+ def select_all_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
50
50
  matching = if force_ruby
51
51
  specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
52
52
  else
@@ -58,24 +58,40 @@ module Bundler
58
58
  return locked_originally if locked_originally.any?
59
59
  end
60
60
 
61
- sort_best_platform_match(matching, platform)
61
+ matching
62
+ end
63
+ module_function :select_all_platform_match
64
+
65
+ def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
66
+ matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
67
+
68
+ sort_and_filter_best_platform_match(matching, platform)
62
69
  end
63
70
  module_function :select_best_platform_match
64
71
 
65
72
  def select_best_local_platform_match(specs, force_ruby: false)
66
- select_best_platform_match(specs, local_platform, force_ruby: force_ruby).map(&:materialize_for_installation).compact
73
+ matching = select_all_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
74
+
75
+ sort_best_platform_match(matching, local_platform)
67
76
  end
68
77
  module_function :select_best_local_platform_match
69
78
 
70
- def sort_best_platform_match(matching, platform)
79
+ def sort_and_filter_best_platform_match(matching, platform)
80
+ return matching if matching.one?
81
+
71
82
  exact = matching.select {|spec| spec.platform == platform }
72
83
  return exact if exact.any?
73
84
 
74
- sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
85
+ sorted_matching = sort_best_platform_match(matching, platform)
75
86
  exemplary_spec = sorted_matching.first
76
87
 
77
88
  sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) }
78
89
  end
90
+ module_function :sort_and_filter_best_platform_match
91
+
92
+ def sort_best_platform_match(matching, platform)
93
+ matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
94
+ end
79
95
  module_function :sort_best_platform_match
80
96
 
81
97
  class PlatformMatch
@@ -41,7 +41,7 @@ module Bundler
41
41
 
42
42
  # resolve to see if the new deps broke anything
43
43
  @definition = builder.to_definition(lockfile_path, {})
44
- @definition.resolve_remotely!
44
+ @definition.remotely!
45
45
 
46
46
  # since nothing broke, we can add those gems to the gemfile
47
47
  append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any?
@@ -184,7 +184,7 @@ module Bundler
184
184
  # @param [Array] gems Array of names of gems to be removed.
185
185
  # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies.
186
186
  def remove_gems_from_gemfile(gems, gemfile_path)
187
- patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/
187
+ patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2.*\)/
188
188
  new_gemfile = []
189
189
  multiline_removal = false
190
190
  File.readlines(gemfile_path).each do |line|
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Allows for declaring a Gemfile inline in a ruby script, optionally installing
4
- # any gems that aren't already installed on the user's system.
3
+ # Allows for declaring a Gemfile inline in a ruby script, installing any gems
4
+ # that aren't already installed on the user's system.
5
5
  #
6
6
  # @note Every gem that is specified in this 'Gemfile' will be `require`d, as if
7
7
  # the user had manually called `Bundler.require`. To avoid a requested gem
8
8
  # being automatically required, add the `:require => false` option to the
9
9
  # `gem` dependency declaration.
10
10
  #
11
- # @param install [Boolean] whether gems that aren't already installed on the
12
- # user's system should be installed.
13
- # Defaults to `false`.
11
+ # @param force_latest_compatible [Boolean] Force installing the *latest*
12
+ # compatible versions of the gems,
13
+ # even if compatible versions are
14
+ # already installed locally.
15
+ # This also logs output if the
16
+ # `:quiet` option is not set.
17
+ # Defaults to `false`.
14
18
  #
15
19
  # @param gemfile [Proc] a block that is evaluated as a `Gemfile`.
16
20
  #
@@ -29,31 +33,33 @@
29
33
  #
30
34
  # puts Pod::VERSION # => "0.34.4"
31
35
  #
32
- def gemfile(install = false, options = {}, &gemfile)
36
+ def gemfile(force_latest_compatible = false, options = {}, &gemfile)
33
37
  require_relative "../bundler"
34
38
  Bundler.reset!
35
39
 
36
40
  opts = options.dup
37
41
  ui = opts.delete(:ui) { Bundler::UI::Shell.new }
38
- ui.level = "silent" if opts.delete(:quiet) || !install
42
+ ui.level = "silent" if opts.delete(:quiet) || !force_latest_compatible
39
43
  Bundler.ui = ui
40
44
  raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty?
41
45
 
42
- Bundler.with_unbundled_env do
46
+ old_gemfile = ENV["BUNDLE_GEMFILE"]
47
+
48
+ Bundler.unbundle_env!
49
+
50
+ begin
43
51
  Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir))
44
52
  Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile"
45
53
 
46
54
  Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
47
55
  builder = Bundler::Dsl.new
48
56
  builder.instance_eval(&gemfile)
49
- builder.check_primary_source_safety
50
57
 
51
58
  Bundler.settings.temporary(deployment: false, frozen: false) do
52
59
  definition = builder.to_definition(nil, true)
53
- def definition.lock(*); end
54
60
  definition.validate_runtime!
55
61
 
56
- if install || definition.missing_specs?
62
+ if force_latest_compatible || definition.missing_specs?
57
63
  Bundler.settings.temporary(inline: true, no_install: false) do
58
64
  installer = Bundler::Installer.install(Bundler.root, definition, system: true)
59
65
  installer.post_install_messages.each do |name, message|
@@ -62,12 +68,31 @@ def gemfile(install = false, options = {}, &gemfile)
62
68
  end
63
69
  end
64
70
 
65
- runtime = Bundler::Runtime.new(nil, definition)
66
- runtime.setup.require
67
- end
68
- end
71
+ begin
72
+ runtime = Bundler::Runtime.new(nil, definition).setup
73
+ rescue Gem::LoadError => e
74
+ name = e.name
75
+ version = e.requirement.requirements.first[1]
76
+ activated_version = Gem.loaded_specs[name].version
77
+
78
+ Bundler.ui.info \
79
+ "The #{name} gem was resolved to #{version}, but #{activated_version} was activated by Bundler while installing it, causing a conflict. " \
80
+ "Bundler will now retry resolving with #{activated_version} instead."
69
81
 
70
- if ENV["BUNDLE_GEMFILE"].nil?
71
- ENV["BUNDLE_GEMFILE"] = ""
82
+ builder.dependencies.delete_if {|d| d.name == name }
83
+ builder.instance_eval { gem name, activated_version }
84
+ definition = builder.to_definition(nil, true)
85
+
86
+ retry
87
+ end
88
+
89
+ runtime.require
90
+ end
91
+ ensure
92
+ if old_gemfile
93
+ ENV["BUNDLE_GEMFILE"] = old_gemfile
94
+ else
95
+ ENV["BUNDLE_GEMFILE"] = ""
96
+ end
72
97
  end
73
98
  end
@@ -2,14 +2,15 @@
2
2
 
3
3
  module Bundler
4
4
  class GemInstaller
5
- attr_reader :spec, :standalone, :worker, :force, :installer
5
+ attr_reader :spec, :standalone, :worker, :force, :local, :installer
6
6
 
7
- def initialize(spec, installer, standalone = false, worker = 0, force = false)
7
+ def initialize(spec, installer, standalone = false, worker = 0, force = false, local = false)
8
8
  @spec = spec
9
9
  @installer = installer
10
10
  @standalone = standalone
11
11
  @worker = worker
12
12
  @force = force
13
+ @local = local
13
14
  end
14
15
 
15
16
  def install_from_spec
@@ -54,6 +55,7 @@ module Bundler
54
55
  spec.source.install(
55
56
  spec,
56
57
  force: force,
58
+ local: local,
57
59
  build_args: Array(spec_settings),
58
60
  previous_spec: previous_spec,
59
61
  )
@@ -68,11 +68,12 @@ module Bundler
68
68
 
69
69
  attr_reader :size
70
70
 
71
- def initialize(installer, all_specs, size, standalone, force, skip: nil)
71
+ def initialize(installer, all_specs, size, standalone, force, local: false, skip: nil)
72
72
  @installer = installer
73
73
  @size = size
74
74
  @standalone = standalone
75
75
  @force = force
76
+ @local = local
76
77
  @specs = all_specs.map {|s| SpecInstallation.new(s) }
77
78
  @specs.each do |spec_install|
78
79
  spec_install.state = :installed if skip.include?(spec_install.name)
@@ -127,7 +128,7 @@ module Bundler
127
128
  def do_install(spec_install, worker_num)
128
129
  Plugin.hook(Plugin::Events::GEM_BEFORE_INSTALL, spec_install)
129
130
  gem_installer = Bundler::GemInstaller.new(
130
- spec_install.spec, @installer, @standalone, worker_num, @force
131
+ spec_install.spec, @installer, @standalone, worker_num, @force, @local
131
132
  )
132
133
  success, message = gem_installer.install_from_spec
133
134
  if success
@@ -28,7 +28,7 @@ module Bundler
28
28
  private
29
29
 
30
30
  def paths
31
- @specs.map do |spec|
31
+ @specs.flat_map do |spec|
32
32
  next if spec.name == "bundler"
33
33
  Array(spec.require_paths).map do |path|
34
34
  gem_path(path, spec).
@@ -36,7 +36,7 @@ module Bundler
36
36
  sub(extensions_dir, 'extensions/\k<platform>/#{Gem.extension_api_version}')
37
37
  # This is a static string intentionally. It's interpolated at a later time.
38
38
  end
39
- end.flatten.compact
39
+ end.compact
40
40
  end
41
41
 
42
42
  def version_dir