bundler 1.13.0.rc.1 → 1.13.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +1 -0
  3. data/.rubocop.yml +8 -0
  4. data/.rubocop_todo.yml +21 -21
  5. data/.travis.yml +5 -1
  6. data/CHANGELOG.md +33 -1
  7. data/DEVELOPMENT.md +1 -1
  8. data/Rakefile +21 -12
  9. data/bin/rake +1 -1
  10. data/bin/rspec +1 -1
  11. data/bin/rubocop +2 -2
  12. data/bundler.gemspec +2 -2
  13. data/exe/bundler +1 -19
  14. data/lib/bundler.rb +43 -34
  15. data/lib/bundler/cli.rb +54 -5
  16. data/lib/bundler/cli/binstubs.rb +3 -2
  17. data/lib/bundler/cli/console.rb +3 -0
  18. data/lib/bundler/cli/doctor.rb +95 -0
  19. data/lib/bundler/cli/exec.rb +18 -2
  20. data/lib/bundler/cli/gem.rb +1 -1
  21. data/lib/bundler/cli/inject.rb +25 -7
  22. data/lib/bundler/cli/install.rb +23 -2
  23. data/lib/bundler/cli/lock.rb +14 -2
  24. data/lib/bundler/cli/update.rb +9 -0
  25. data/lib/bundler/definition.rb +86 -17
  26. data/lib/bundler/deployment.rb +6 -0
  27. data/lib/bundler/dsl.rb +67 -22
  28. data/lib/bundler/env.rb +1 -1
  29. data/lib/bundler/environment_preserver.rb +1 -1
  30. data/lib/bundler/errors.rb +11 -1
  31. data/lib/bundler/fetcher.rb +3 -2
  32. data/lib/bundler/fetcher/base.rb +10 -0
  33. data/lib/bundler/fetcher/compact_index.rb +27 -9
  34. data/lib/bundler/fetcher/dependency.rb +1 -12
  35. data/lib/bundler/fetcher/downloader.rb +1 -1
  36. data/lib/bundler/friendly_errors.rb +4 -2
  37. data/lib/bundler/gem_helper.rb +2 -2
  38. data/lib/bundler/gem_version_promoter.rb +175 -0
  39. data/lib/bundler/graph.rb +4 -25
  40. data/lib/bundler/index.rb +9 -1
  41. data/lib/bundler/injector.rb +12 -5
  42. data/lib/bundler/inline.rb +2 -2
  43. data/lib/bundler/installer.rb +23 -8
  44. data/lib/bundler/installer/gem_installer.rb +13 -15
  45. data/lib/bundler/installer/parallel_installer.rb +121 -99
  46. data/lib/bundler/lazy_specification.rb +8 -2
  47. data/lib/bundler/lockfile_parser.rb +20 -12
  48. data/lib/bundler/mirror.rb +2 -2
  49. data/lib/bundler/plugin.rb +153 -31
  50. data/lib/bundler/plugin/api.rb +29 -5
  51. data/lib/bundler/plugin/api/source.rb +293 -0
  52. data/lib/bundler/plugin/dsl.rb +25 -1
  53. data/lib/bundler/plugin/index.rb +80 -13
  54. data/lib/bundler/plugin/installer.rb +6 -10
  55. data/lib/bundler/plugin/source_list.rb +4 -0
  56. data/lib/bundler/postit_trampoline.rb +57 -40
  57. data/lib/bundler/resolver.rb +24 -12
  58. data/lib/bundler/retry.rb +2 -1
  59. data/lib/bundler/ruby_version.rb +4 -2
  60. data/lib/bundler/rubygems_ext.rb +10 -3
  61. data/lib/bundler/rubygems_gem_installer.rb +6 -0
  62. data/lib/bundler/rubygems_integration.rb +101 -66
  63. data/lib/bundler/runtime.rb +25 -2
  64. data/lib/bundler/settings.rb +30 -11
  65. data/lib/bundler/setup.rb +6 -3
  66. data/lib/bundler/shared_helpers.rb +11 -5
  67. data/lib/bundler/source/gemspec.rb +4 -0
  68. data/lib/bundler/source/git.rb +9 -6
  69. data/lib/bundler/source/git/git_proxy.rb +27 -3
  70. data/lib/bundler/source/path.rb +4 -26
  71. data/lib/bundler/source/path/installer.rb +39 -11
  72. data/lib/bundler/source/rubygems.rb +1 -1
  73. data/lib/bundler/source_list.rb +28 -8
  74. data/lib/bundler/spec_set.rb +1 -1
  75. data/lib/bundler/templates/Executable.standalone +4 -2
  76. data/lib/bundler/templates/Gemfile +0 -1
  77. data/lib/bundler/ui/shell.rb +11 -3
  78. data/lib/bundler/ui/silent.rb +1 -3
  79. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +1 -2
  80. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +16 -2
  81. data/lib/bundler/version.rb +1 -1
  82. data/lib/bundler/yaml_serializer.rb +34 -11
  83. data/man/bundle-binstubs.ronn +29 -0
  84. data/man/bundle-config.ronn +32 -0
  85. data/man/bundle-install.ronn +6 -41
  86. data/man/bundle-package.ronn +1 -1
  87. data/man/bundle.ronn +4 -3
  88. data/man/gemfile.5.ronn +1 -1
  89. metadata +13 -9
  90. data/lib/bundler/environment.rb +0 -42
@@ -16,6 +16,10 @@ module Bundler
16
16
  Bundler::SharedHelpers.print_major_deprecations!
17
17
  end
18
18
 
19
+ def self.dispatch(*)
20
+ super {|i| i.send(:print_command) }
21
+ end
22
+
19
23
  def initialize(*args)
20
24
  super
21
25
  Bundler.reset!
@@ -31,6 +35,7 @@ module Bundler
31
35
  raise InvalidOption, e.message
32
36
  ensure
33
37
  self.options ||= {}
38
+ Bundler.settings.cli_flags_given = !options.empty?
34
39
  Bundler.ui = UI::Shell.new(options)
35
40
  Bundler.ui.level = "debug" if options["verbose"]
36
41
 
@@ -38,7 +43,8 @@ module Bundler
38
43
  Bundler.ui.warn(
39
44
  "The RUBYGEMS_GEMDEPS environment variable is set. This enables RubyGems' " \
40
45
  "experimental Gemfile mode, which may conflict with Bundler and cause unexpected errors. " \
41
- "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true)
46
+ "To remove this warning, unset RUBYGEMS_GEMDEPS.", :wrap => true
47
+ )
42
48
  end
43
49
  end
44
50
 
@@ -67,7 +73,8 @@ module Bundler
67
73
  bundle-package
68
74
  bundle-update
69
75
  bundle-platform
70
- gemfile.5)
76
+ gemfile.5
77
+ )
71
78
 
72
79
  if manpages.include?(command)
73
80
  root = File.expand_path("../man", __FILE__)
@@ -208,6 +215,14 @@ module Bundler
208
215
  "Update ruby specified in Gemfile.lock"
209
216
  method_option "bundler", :type => :string, :lazy_default => "> 0.a", :banner =>
210
217
  "Update the locked version of bundler"
218
+ method_option "patch", :type => :boolean, :hide => true, :banner =>
219
+ "Prefer updating only to next patch version"
220
+ method_option "minor", :type => :boolean, :hide => true, :banner =>
221
+ "Prefer updating only to next minor version"
222
+ method_option "major", :type => :boolean, :hide => true, :banner =>
223
+ "Prefer updating to next major version (default)"
224
+ method_option "strict", :type => :boolean, :hide => true, :banner =>
225
+ "Do not allow any gem to be updated past latest --patch/--minor/--major"
211
226
  def update(*gems)
212
227
  require "bundler/cli/update"
213
228
  Update.new(options, gems).run
@@ -223,9 +238,11 @@ module Bundler
223
238
  method_option "outdated", :type => :boolean,
224
239
  :banner => "Show verbose output including whether gems are outdated."
225
240
  def show(gem_name = nil)
241
+ Bundler::SharedHelpers.major_deprecation("use `bundle show` instead of `bundle list`") if ARGV[0] == "list"
226
242
  require "bundler/cli/show"
227
243
  Show.new(options, gem_name).run
228
244
  end
245
+ # TODO: 2.0 remove `bundle list`
229
246
  map %w(list) => "show"
230
247
 
231
248
  desc "binstubs GEM [OPTIONS]", "Install the binstubs of the listed gem"
@@ -340,6 +357,7 @@ module Bundler
340
357
 
341
358
  desc "console [GROUP]", "Opens an IRB session with the bundle pre-loaded"
342
359
  def console(group = nil)
360
+ # TODO: Remove for 2.0
343
361
  require "bundler/cli/console"
344
362
  Console.new(options, group).run
345
363
  end
@@ -419,6 +437,7 @@ module Bundler
419
437
 
420
438
  desc "inject GEM VERSION ...", "Add the named gem(s), with version requirements, to the resolved Gemfile"
421
439
  def inject(name, version, *gems)
440
+ SharedHelpers.major_deprecation "The `inject` command has been replaced by the `add` command"
422
441
  require "bundler/cli/inject"
423
442
  Inject.new(options, name, version, gems).run
424
443
  end
@@ -436,6 +455,8 @@ module Bundler
436
455
  "Fall back to using the single-file index of all gems"
437
456
  method_option "add-platform", :type => :array, :default => [], :banner =>
438
457
  "add a new platform to the lockfile"
458
+ method_option "remove-platform", :type => :array, :default => [], :banner =>
459
+ "remove a platform from the lockfile"
439
460
  def lock
440
461
  require "bundler/cli/lock"
441
462
  Lock.new(options).run
@@ -446,6 +467,21 @@ module Bundler
446
467
  Env.new.write($stdout)
447
468
  end
448
469
 
470
+ desc "doctor [OPTIONS]", "Checks the bundle for common problems"
471
+ long_desc <<-D
472
+ Doctor scans the OS dependencies of each of the gems requested in the Gemfile. If
473
+ missing dependencies are detected, Bundler prints them and exits status 1.
474
+ Otherwise, Bundler prints a success message and exits with a status of 0.
475
+ D
476
+ method_option "gemfile", :type => :string, :banner =>
477
+ "Use the specified gemfile instead of Gemfile"
478
+ method_option "quiet", :type => :boolean, :banner =>
479
+ "Only output warnings and errors."
480
+ def doctor
481
+ require "bundler/cli/doctor"
482
+ Doctor.new(options).run
483
+ end
484
+
449
485
  if Bundler.settings[:plugins]
450
486
  require "bundler/cli/plugin"
451
487
  desc "plugin SUBCOMMAND ...ARGS", "manage the bundler plugins"
@@ -467,10 +503,12 @@ module Bundler
467
503
  else
468
504
  args
469
505
  end
470
- elsif command.nil?
471
- abort("Could not find command \"#{args.join(" ")}\".")
472
- else
506
+ elsif help_used
507
+ args = args.dup
508
+ args.delete_at(help_used)
473
509
  ["help", command || args].flatten.compact
510
+ else
511
+ args
474
512
  end
475
513
  end
476
514
 
@@ -495,5 +533,16 @@ module Bundler
495
533
  Bundler.reset!
496
534
  end
497
535
  end
536
+
537
+ def print_command
538
+ return unless ENV["BUNDLE_POSTIT_TRAMPOLINING_VERSION"] || Bundler.ui.debug?
539
+ _, _, config = @_initializer
540
+ current_command = config[:current_command].name
541
+ return if %w(exec version check platform show help).include?(current_command)
542
+ command = ["bundle", current_command] + args
543
+ command << Thor::Options.to_switches(options)
544
+ command.reject!(&:empty?)
545
+ Bundler.ui.info "Running `#{command * " "}` with bundler #{Bundler::VERSION}"
546
+ end
498
547
  end
499
548
  end
@@ -21,10 +21,11 @@ module Bundler
21
21
  end
22
22
 
23
23
  gems.each do |gem_name|
24
- spec = installer.specs.find {|s| s.name == gem_name }
24
+ spec = Bundler.definition.specs.find {|s| s.name == gem_name }
25
25
  unless spec
26
26
  raise GemNotFound, Bundler::CLI::Common.gem_not_found_message(
27
- gem_name, Bundler.definition.specs)
27
+ gem_name, Bundler.definition.specs
28
+ )
28
29
  end
29
30
 
30
31
  if spec.name == "bundler"
@@ -8,6 +8,9 @@ module Bundler
8
8
  end
9
9
 
10
10
  def run
11
+ Bundler::SharedHelpers.major_deprecation "bundle console will be replaced " \
12
+ "by `bin/console` generated by `bundle gem <name>`"
13
+
11
14
  group ? Bundler.require(:default, *(group.split.map!(&:to_sym))) : Bundler.require
12
15
  ARGV.clear
13
16
 
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+
5
+ module Bundler
6
+ class CLI::Doctor
7
+ DARWIN_REGEX = /\s+(.+) \(compatibility /
8
+ LDD_REGEX = /\t\S+ => (\S+) \(\S+\)/
9
+
10
+ attr_reader :options
11
+
12
+ def initialize(options)
13
+ @options = options
14
+ end
15
+
16
+ def otool_available?
17
+ system("otool --version 2>&1 >#{Bundler::NULL}")
18
+ end
19
+
20
+ def ldd_available?
21
+ !system("ldd --help 2>&1 >#{Bundler::NULL}").nil?
22
+ end
23
+
24
+ def dylibs_darwin(path)
25
+ output = `/usr/bin/otool -L "#{path}"`.chomp
26
+ dylibs = output.split("\n")[1..-1].map {|l| l.match(DARWIN_REGEX).captures[0] }.uniq
27
+ # ignore @rpath and friends
28
+ dylibs.reject {|dylib| dylib.start_with? "@" }
29
+ end
30
+
31
+ def dylibs_ldd(path)
32
+ output = `/usr/bin/ldd "#{path}"`.chomp
33
+ output.split("\n").map do |l|
34
+ match = l.match(LDD_REGEX)
35
+ next if match.nil?
36
+ match.captures[0]
37
+ end.compact
38
+ end
39
+
40
+ def dylibs(path)
41
+ case RbConfig::CONFIG["host_os"]
42
+ when /darwin/
43
+ return [] unless otool_available?
44
+ dylibs_darwin(path)
45
+ when /(linux|solaris|bsd)/
46
+ return [] unless ldd_available?
47
+ dylibs_ldd(path)
48
+ else # Windows, etc.
49
+ Bundler.ui.warn("Dynamic library check not supported on this platform.")
50
+ []
51
+ end
52
+ end
53
+
54
+ def bundles_for_gem(spec)
55
+ Dir.glob("#{spec.full_gem_path}/**/*.bundle")
56
+ end
57
+
58
+ def run
59
+ Bundler.ui.level = "error" if options[:quiet]
60
+
61
+ broken_links = {}
62
+
63
+ begin
64
+ definition = Bundler.definition
65
+ definition.validate_ruby!
66
+ not_installed = definition.missing_specs
67
+ raise GemNotFound if not_installed.any?
68
+ rescue GemNotFound
69
+ Bundler.ui.warn "This bundle's gems must be installed to run this command."
70
+ Bundler.ui.warn "Install missing gems with `bundle install`."
71
+ exit 0
72
+ end
73
+
74
+ definition.specs.each do |spec|
75
+ bundles_for_gem(spec).each do |bundle|
76
+ bad_paths = dylibs(bundle).select {|f| !File.exist?(f) }
77
+ if bad_paths.any?
78
+ broken_links[spec] ||= []
79
+ broken_links[spec].concat(bad_paths)
80
+ end
81
+ end
82
+ end
83
+
84
+ if broken_links.any?
85
+ Bundler.ui.error "The following gems are missing OS dependencies"
86
+ broken_links.each do |spec, paths|
87
+ paths.uniq.each do |path|
88
+ Bundler.ui.error " * #{spec.name}: #{path}"
89
+ end
90
+ end
91
+ exit 1
92
+ end
93
+ end
94
+ end
95
+ end
@@ -5,6 +5,8 @@ module Bundler
5
5
  class CLI::Exec
6
6
  attr_reader :options, :args, :cmd
7
7
 
8
+ RESERVED_SIGNALS = %w(SEGV BUS ILL FPE VTALRM KILL STOP).freeze
9
+
8
10
  def initialize(options, args)
9
11
  @options = options
10
12
  @cmd = args.shift
@@ -21,9 +23,15 @@ module Bundler
21
23
  validate_cmd!
22
24
  SharedHelpers.set_bundle_environment
23
25
  if bin_path = Bundler.which(cmd)
24
- return kernel_load(bin_path, *args) if ruby_shebang?(bin_path)
26
+ if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path)
27
+ return kernel_load(bin_path, *args)
28
+ end
25
29
  # First, try to exec directly to something in PATH
26
- kernel_exec([bin_path, cmd], *args)
30
+ if Bundler.current_ruby.jruby_18?
31
+ kernel_exec(bin_path, *args)
32
+ else
33
+ kernel_exec([bin_path, cmd], *args)
34
+ end
27
35
  else
28
36
  # exec using the given command
29
37
  kernel_exec(cmd, *args)
@@ -57,9 +65,12 @@ module Bundler
57
65
  args.pop if args.last.is_a?(Hash)
58
66
  ARGV.replace(args)
59
67
  $0 = file
68
+ Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle)
60
69
  ui = Bundler.ui
61
70
  Bundler.ui = nil
62
71
  require "bundler/setup"
72
+ signals = Signal.list.keys - RESERVED_SIGNALS
73
+ signals.each {|s| trap(s, "DEFAULT") }
63
74
  Kernel.load(file)
64
75
  rescue SystemExit
65
76
  raise
@@ -70,9 +81,14 @@ module Bundler
70
81
  abort "#{e.class}: #{e.message}\n #{backtrace.join("\n ")}"
71
82
  end
72
83
 
84
+ def process_title(file, args)
85
+ "#{file} #{args.join(" ")}".strip
86
+ end
87
+
73
88
  def ruby_shebang?(file)
74
89
  possibilities = [
75
90
  "#!/usr/bin/env ruby\n",
91
+ "#!/usr/bin/env jruby\n",
76
92
  "#!#{Gem.ruby}\n",
77
93
  ]
78
94
  first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) }
@@ -126,7 +126,7 @@ module Bundler
126
126
 
127
127
  executables.each do |file|
128
128
  path = target.join(file)
129
- executable = (path.stat.mode | 0111)
129
+ executable = (path.stat.mode | 0o111)
130
130
  path.chmod(executable)
131
131
  end
132
132
 
@@ -1,33 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
  module Bundler
3
3
  class CLI::Inject
4
- attr_reader :options, :name, :version, :gems
4
+ attr_reader :options, :name, :version, :group, :source, :gems
5
5
  def initialize(options, name, version, gems)
6
6
  @options = options
7
7
  @name = name
8
- @version = version
8
+ @version = version || last_version_number
9
+ @group = options[:group]
10
+ @source = options[:source]
9
11
  @gems = gems
10
12
  end
11
13
 
12
14
  def run
13
15
  # The required arguments allow Thor to give useful feedback when the arguments
14
16
  # are incorrect. This adds those first two arguments onto the list as a whole.
15
- gems.unshift(version).unshift(name)
17
+ gems.unshift(source).unshift(group).unshift(version).unshift(name)
16
18
 
17
19
  # Build an array of Dependency objects out of the arguments
18
20
  deps = []
19
- gems.each_slice(2) do |gem_name, gem_version|
20
- deps << Bundler::Dependency.new(gem_name, gem_version)
21
+ gems.each_slice(4) do |gem_name, gem_version, gem_group, gem_source|
22
+ ops = Gem::Requirement::OPS.map {|key, _val| key }
23
+ has_op = ops.any? {|op| gem_version.start_with? op }
24
+ gem_version = "~> #{gem_version}" unless has_op
25
+ deps << Bundler::Dependency.new(gem_name, gem_version, "group" => gem_group, "source" => gem_source)
21
26
  end
22
27
 
23
- added = Injector.inject(deps)
28
+ added = Injector.inject(deps, options)
24
29
 
25
30
  if added.any?
26
31
  Bundler.ui.confirm "Added to Gemfile:"
27
32
  Bundler.ui.confirm added.map {|g| " #{g}" }.join("\n")
28
33
  else
29
- Bundler.ui.confirm "All injected gems were already present in the Gemfile"
34
+ Bundler.ui.confirm "All gems were already present in the Gemfile"
30
35
  end
31
36
  end
37
+
38
+ private
39
+
40
+ def last_version_number
41
+ definition = Bundler.definition(true)
42
+ definition.resolve_remotely!
43
+ specs = definition.index[name].sort_by(&:version)
44
+ unless options[:pre]
45
+ specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
46
+ end
47
+ spec = specs.last
48
+ spec.version.to_s
49
+ end
32
50
  end
33
51
  end
@@ -11,6 +11,8 @@ module Bundler
11
11
 
12
12
  warn_if_root
13
13
 
14
+ warn_if_outdated
15
+
14
16
  [:with, :without].each do |option|
15
17
  if options[option]
16
18
  options[option] = options[option].join(":").tr(" ", ":").split(":")
@@ -53,6 +55,11 @@ module Bundler
53
55
 
54
56
  Bundler::Fetcher.disable_endpoint = options["full-index"]
55
57
 
58
+ if options["binstubs"]
59
+ Bundler::SharedHelpers.major_deprecation \
60
+ "the --binstubs option will be removed in favor of `bundle binstubs`"
61
+ end
62
+
56
63
  # rubygems plugins sometimes hook into the gem install process
57
64
  Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
58
65
 
@@ -61,7 +68,7 @@ module Bundler
61
68
  definition = Bundler.definition
62
69
  definition.validate_ruby!
63
70
 
64
- Installer.install(Bundler.root, definition, options)
71
+ installer = Installer.install(Bundler.root, definition, options)
65
72
  Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.settings[:frozen]
66
73
 
67
74
  Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}."
@@ -76,7 +83,7 @@ module Bundler
76
83
  end
77
84
 
78
85
  unless Bundler.settings["ignore_messages"]
79
- Installer.post_install_messages.to_a.each do |name, msg|
86
+ installer.post_install_messages.to_a.each do |name, msg|
80
87
  print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"]
81
88
  end
82
89
  end
@@ -114,6 +121,20 @@ module Bundler
114
121
  "application for all non-root users on this machine.", :wrap => true
115
122
  end
116
123
 
124
+ def warn_if_outdated
125
+ return if ENV["BUNDLE_POSTIT_TRAMPOLINING_VERSION"].nil?
126
+ installed_version = Gem::Version.new(ENV["BUNDLE_POSTIT_TRAMPOLINING_VERSION"].dup)
127
+ running_version = Gem::Version.new(Bundler::VERSION)
128
+ return if Gem::Requirement.new(installed_version).satisfied_by?(running_version)
129
+ if Bundler.settings[:warned_version].nil? || running_version > Gem::Version.new(Bundler.settings[:warned_version])
130
+ Bundler.settings[:warned_version] = running_version
131
+ Bundler.ui.warn "You're running Bundler #{installed_version} but this " \
132
+ "project uses #{running_version}. To update, run `bundle update " \
133
+ "--bundler`. You won't see this message again unless you upgrade " \
134
+ "to a newer version of Bundler.", :wrap => true
135
+ end
136
+ end
137
+
117
138
  def confirm_without_groups
118
139
  return unless Bundler.settings.without.any?
119
140
  require "bundler/cli/common"
@@ -26,11 +26,23 @@ module Bundler
26
26
  definition = Bundler.definition(true)
27
27
  end
28
28
 
29
- options["add-platform"].each do |platform|
30
- platform = Gem::Platform.new(platform)
29
+ options["remove-platform"].each do |platform|
30
+ definition.remove_platform(platform)
31
+ end
32
+
33
+ options["add-platform"].each do |platform_string|
34
+ platform = Gem::Platform.new(platform_string)
35
+ if platform.to_a.compact == %w(unknown)
36
+ Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \
37
+ "and adding it will likely lead to resolution errors"
38
+ end
31
39
  definition.add_platform(platform)
32
40
  end
33
41
 
42
+ if definition.platforms.empty?
43
+ raise InvalidOption, "Removing all platforms from the bundle is not allowed"
44
+ end
45
+
34
46
  definition.resolve_remotely! unless options[:local]
35
47
 
36
48
  if print