bundler 1.13.7 → 1.14.0.pre.1

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop_todo.yml +100 -18
  4. data/.travis.yml +32 -18
  5. data/CHANGELOG.md +64 -2
  6. data/DEVELOPMENT.md +5 -3
  7. data/ISSUES.md +17 -0
  8. data/README.md +7 -0
  9. data/Rakefile +34 -23
  10. data/bin/rubocop +1 -1
  11. data/bundler.gemspec +2 -2
  12. data/exe/bundle +4 -6
  13. data/lib/bundler.rb +57 -5
  14. data/lib/bundler/cli.rb +51 -38
  15. data/lib/bundler/cli/binstubs.rb +1 -1
  16. data/lib/bundler/cli/cache.rb +1 -1
  17. data/lib/bundler/cli/check.rb +1 -1
  18. data/lib/bundler/cli/clean.rb +1 -1
  19. data/lib/bundler/cli/common.rb +30 -0
  20. data/lib/bundler/cli/doctor.rb +17 -19
  21. data/lib/bundler/cli/exec.rb +6 -0
  22. data/lib/bundler/cli/gem.rb +18 -4
  23. data/lib/bundler/cli/install.rb +9 -25
  24. data/lib/bundler/cli/lock.rb +8 -7
  25. data/lib/bundler/cli/outdated.rb +163 -56
  26. data/lib/bundler/cli/platform.rb +1 -1
  27. data/lib/bundler/cli/show.rb +1 -1
  28. data/lib/bundler/cli/update.rb +10 -23
  29. data/lib/bundler/compact_index_client.rb +108 -0
  30. data/lib/bundler/compact_index_client/cache.rb +119 -0
  31. data/lib/bundler/compact_index_client/updater.rb +88 -0
  32. data/lib/bundler/current_ruby.rb +4 -3
  33. data/lib/bundler/definition.rb +107 -17
  34. data/lib/bundler/dependency.rb +6 -0
  35. data/lib/bundler/dsl.rb +3 -2
  36. data/lib/bundler/env.rb +27 -18
  37. data/lib/bundler/errors.rb +22 -0
  38. data/lib/bundler/feature_flag.rb +32 -0
  39. data/lib/bundler/fetcher.rb +2 -2
  40. data/lib/bundler/fetcher/compact_index.rb +17 -5
  41. data/lib/bundler/fetcher/dependency.rb +1 -1
  42. data/lib/bundler/fetcher/downloader.rb +11 -0
  43. data/lib/bundler/friendly_errors.rb +28 -7
  44. data/lib/bundler/gem_helper.rb +1 -1
  45. data/lib/bundler/gem_helpers.rb +69 -1
  46. data/lib/bundler/gemdeps.rb +28 -0
  47. data/lib/bundler/index.rb +9 -4
  48. data/lib/bundler/inline.rb +3 -3
  49. data/lib/bundler/installer.rb +3 -2
  50. data/lib/bundler/installer/gem_installer.rb +2 -2
  51. data/lib/bundler/installer/parallel_installer.rb +40 -9
  52. data/lib/bundler/lazy_specification.rb +16 -1
  53. data/lib/bundler/lockfile_parser.rb +1 -2
  54. data/lib/bundler/match_platform.rb +12 -3
  55. data/lib/bundler/plugin.rb +4 -2
  56. data/lib/bundler/plugin/api.rb +2 -1
  57. data/lib/bundler/plugin/api/source.rb +1 -1
  58. data/lib/bundler/postit_trampoline.rb +12 -7
  59. data/lib/bundler/remote_specification.rb +5 -0
  60. data/lib/bundler/resolver.rb +59 -49
  61. data/lib/bundler/retry.rb +4 -1
  62. data/lib/bundler/ruby_version.rb +5 -0
  63. data/lib/bundler/rubygems_ext.rb +5 -0
  64. data/lib/bundler/rubygems_gem_installer.rb +60 -0
  65. data/lib/bundler/rubygems_integration.rb +28 -2
  66. data/lib/bundler/runtime.rb +2 -1
  67. data/lib/bundler/settings.rb +29 -5
  68. data/lib/bundler/setup.rb +1 -1
  69. data/lib/bundler/shared_helpers.rb +26 -15
  70. data/lib/bundler/source.rb +5 -0
  71. data/lib/bundler/source/git.rb +1 -1
  72. data/lib/bundler/source/git/git_proxy.rb +5 -0
  73. data/lib/bundler/source/path.rb +6 -1
  74. data/lib/bundler/source/rubygems.rb +11 -1
  75. data/lib/bundler/spec_set.rb +32 -13
  76. data/lib/bundler/templates/newgem/README.md.tt +1 -1
  77. data/lib/bundler/templates/newgem/bin/console.tt +1 -1
  78. data/lib/bundler/templates/newgem/gitignore.tt +5 -0
  79. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  80. data/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +10 -1
  81. data/lib/bundler/ui/shell.rb +4 -0
  82. data/lib/bundler/ui/silent.rb +9 -0
  83. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +7 -0
  84. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +1 -1
  85. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +2 -2
  86. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +2 -2
  87. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +62 -0
  88. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +1 -1
  89. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +12 -1
  90. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +2 -2
  91. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +2 -2
  92. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  93. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +22 -13
  94. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/faster.rb +1 -0
  95. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent.rb +24 -23
  96. data/lib/bundler/vendor/{net → net-http-persistent/lib/net}/http/persistent/ssl_reuse.rb +2 -1
  97. data/lib/bundler/vendored_persistent.rb +9 -4
  98. data/lib/bundler/version.rb +1 -1
  99. data/lib/bundler/worker.rb +27 -5
  100. data/lib/bundler/yaml_serializer.rb +1 -1
  101. data/man/bundle-config.ronn +29 -2
  102. data/man/bundle-install.ronn +1 -1
  103. data/man/bundle-lock.ronn +47 -0
  104. data/man/bundle-outdated.ronn +107 -0
  105. data/man/bundle-update.ronn +152 -3
  106. data/man/bundle.ronn +27 -9
  107. data/man/gemfile.5.ronn +8 -0
  108. metadata +37 -31
  109. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client.rb +0 -79
  110. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/cache.rb +0 -112
  111. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/updater.rb +0 -80
  112. data/lib/bundler/vendor/compact_index_client/lib/compact_index_client/version.rb +0 -4
@@ -10,7 +10,7 @@ module Bundler
10
10
  end
11
11
 
12
12
  def run
13
- Bundler.definition.validate_ruby!
13
+ Bundler.definition.validate_runtime!
14
14
  Bundler.settings[:bin] = options["path"] if options["path"]
15
15
  Bundler.settings[:bin] = nil if options["path"] && options["path"].empty?
16
16
  installer = Installer.new(Bundler.root, Bundler.definition)
@@ -7,7 +7,7 @@ module Bundler
7
7
  end
8
8
 
9
9
  def run
10
- Bundler.definition.validate_ruby!
10
+ Bundler.definition.validate_runtime!
11
11
  Bundler.definition.resolve_with_cache!
12
12
  setup_cache_all
13
13
  Bundler.settings[:cache_all_platforms] = options["all-platforms"] if options.key?("all-platforms")
@@ -15,7 +15,7 @@ module Bundler
15
15
 
16
16
  begin
17
17
  definition = Bundler.definition
18
- definition.validate_ruby!
18
+ definition.validate_runtime!
19
19
  not_installed = definition.missing_specs
20
20
  rescue GemNotFound, VersionConflict
21
21
  Bundler.ui.error "Bundler can't satisfy your Gemfile's dependencies."
@@ -8,7 +8,7 @@ module Bundler
8
8
  end
9
9
 
10
10
  def run
11
- require_path_or_force
11
+ require_path_or_force unless options[:"dry-run"]
12
12
  Bundler.load.clean(options[:"dry-run"])
13
13
  end
14
14
 
@@ -1,6 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
  module Bundler
3
3
  module CLI::Common
4
+ def self.output_post_install_messages(messages)
5
+ return if Bundler.settings["ignore_messages"]
6
+ messages.to_a.each do |name, msg|
7
+ print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"]
8
+ end
9
+ end
10
+
11
+ def self.print_post_install_message(name, msg)
12
+ Bundler.ui.confirm "Post-install message from #{name}:"
13
+ Bundler.ui.info msg
14
+ end
15
+
16
+ def self.output_without_groups_message
17
+ return unless Bundler.settings.without.any?
18
+ Bundler.ui.confirm without_groups_message
19
+ end
20
+
4
21
  def self.without_groups_message
5
22
  groups = Bundler.settings.without
6
23
  group_list = [groups[0...-1].join(", "), groups[-1..-1]].
@@ -52,5 +69,18 @@ module Bundler
52
69
  message += "\nDid you mean #{suggestions}?" if suggestions
53
70
  message
54
71
  end
72
+
73
+ def self.configure_gem_version_promoter(definition, options)
74
+ patch_level = patch_level_options(options)
75
+ raise InvalidOption, "Provide only one of the following options: #{patch_level.join(", ")}" unless patch_level.length <= 1
76
+ definition.gem_version_promoter.tap do |gvp|
77
+ gvp.level = patch_level.first || :major
78
+ gvp.strict = options[:strict] || options["update-strict"]
79
+ end
80
+ end
81
+
82
+ def self.patch_level_options(options)
83
+ [:major, :minor, :patch].select {|v| options.keys.include?(v.to_s) }
84
+ end
55
85
  end
56
86
  end
@@ -14,11 +14,11 @@ module Bundler
14
14
  end
15
15
 
16
16
  def otool_available?
17
- system("otool --version 2>&1 >#{Bundler::NULL}")
17
+ Bundler.which("otool")
18
18
  end
19
19
 
20
20
  def ldd_available?
21
- !system("ldd --help 2>&1 >#{Bundler::NULL}").nil?
21
+ Bundler.which("ldd")
22
22
  end
23
23
 
24
24
  def dylibs_darwin(path)
@@ -55,22 +55,18 @@ module Bundler
55
55
  Dir.glob("#{spec.full_gem_path}/**/*.bundle")
56
56
  end
57
57
 
58
+ def check!
59
+ require "bundler/cli/check"
60
+ Bundler::CLI::Check.new({}).run
61
+ end
62
+
58
63
  def run
59
64
  Bundler.ui.level = "error" if options[:quiet]
65
+ check!
60
66
 
67
+ definition = Bundler.definition
61
68
  broken_links = {}
62
69
 
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
70
  definition.specs.each do |spec|
75
71
  bundles_for_gem(spec).each do |bundle|
76
72
  bad_paths = dylibs(bundle).select {|f| !File.exist?(f) }
@@ -82,13 +78,15 @@ module Bundler
82
78
  end
83
79
 
84
80
  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}"
81
+ message = "The following gems are missing OS dependencies:"
82
+ broken_links.map do |spec, paths|
83
+ paths.uniq.map do |path|
84
+ "\n * #{spec.name}: #{path}"
89
85
  end
90
- end
91
- exit 1
86
+ end.flatten.sort.each {|m| message += m }
87
+ raise ProductionError, message
88
+ else
89
+ Bundler.ui.info "No issues found with the installed bundle"
92
90
  end
93
91
  end
94
92
  end
@@ -91,6 +91,12 @@ module Bundler
91
91
  "#!/usr/bin/env jruby\n",
92
92
  "#!#{Gem.ruby}\n",
93
93
  ]
94
+
95
+ if File.zero?(file)
96
+ Bundler.ui.warn "#{file} is empty"
97
+ return false
98
+ end
99
+
94
100
  first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) }
95
101
  possibilities.any? {|shebang| first_line.start_with?(shebang) }
96
102
  end
@@ -44,7 +44,8 @@ module Bundler
44
44
  :test => options[:test],
45
45
  :ext => options[:ext],
46
46
  :exe => options[:exe],
47
- :bundler_version => bundler_dependency_version
47
+ :bundler_version => bundler_dependency_version,
48
+ :git_user_name => git_user_name.empty? ? "[USERNAME]" : git_user_name
48
49
  }
49
50
  ensure_safe_gem_name(name, constant_array)
50
51
 
@@ -201,10 +202,23 @@ module Bundler
201
202
  if name =~ /^\d/
202
203
  Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers."
203
204
  exit 1
204
- elsif constant_array.inject(Object) {|c, s| (c.const_defined?(s) && c.const_get(s)) || break }
205
- Bundler.ui.error "Invalid gem name #{name} constant #{constant_array.join("::")} is already in use. Please choose another gem name."
206
- exit 1
207
205
  end
206
+
207
+ constant_name = constant_array.join("::")
208
+
209
+ existing_constant = constant_array.inject(Object) do |c, s|
210
+ defined = begin
211
+ c.const_defined?(s)
212
+ rescue NameError
213
+ Bundler.ui.error "Invalid gem name #{name} -- `#{constant_name}` is an invalid constant name"
214
+ exit 1
215
+ end
216
+ (defined && c.const_get(s)) || break
217
+ end
218
+
219
+ return unless existing_constant
220
+ Bundler.ui.error "Invalid gem name #{name} constant #{constant_name} is already in use. Please choose another gem name."
221
+ exit 1
208
222
  end
209
223
 
210
224
  def open_editor(editor, file)
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+ require "bundler/cli/common"
3
+
2
4
  module Bundler
3
5
  class CLI::Install
4
6
  attr_reader :options
@@ -57,22 +59,19 @@ module Bundler
57
59
 
58
60
  if options["binstubs"]
59
61
  Bundler::SharedHelpers.major_deprecation \
60
- "the --binstubs option will be removed in favor of `bundle binstubs`"
62
+ "The --binstubs option will be removed in favor of `bundle binstubs`"
61
63
  end
62
64
 
63
- # rubygems plugins sometimes hook into the gem install process
64
- Gem.load_env_plugins if Gem.respond_to?(:load_env_plugins)
65
-
66
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
65
+ Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
67
66
 
68
67
  definition = Bundler.definition
69
- definition.validate_ruby!
68
+ definition.validate_runtime!
70
69
 
71
70
  installer = Installer.install(Bundler.root, definition, options)
72
71
  Bundler.load.cache if Bundler.app_cache.exist? && !options["no-cache"] && !Bundler.settings[:frozen]
73
72
 
74
73
  Bundler.ui.confirm "Bundle complete! #{dependencies_count_for(definition)}, #{gems_installed_for(definition)}."
75
- confirm_without_groups
74
+ Bundler::CLI::Common.output_without_groups_message
76
75
 
77
76
  if Bundler.settings[:path]
78
77
  absolute_path = File.expand_path(Bundler.settings[:path])
@@ -82,11 +81,7 @@ module Bundler
82
81
  Bundler.ui.confirm "Use `bundle show [gemname]` to see where a bundled gem is installed."
83
82
  end
84
83
 
85
- unless Bundler.settings["ignore_messages"]
86
- installer.post_install_messages.to_a.each do |name, msg|
87
- print_post_install_message(name, msg) unless Bundler.settings["ignore_messages.#{name}"]
88
- end
89
- end
84
+ Bundler::CLI::Common.output_post_install_messages installer.post_install_messages
90
85
 
91
86
  warn_ambiguous_gems
92
87
 
@@ -135,12 +130,6 @@ module Bundler
135
130
  end
136
131
  end
137
132
 
138
- def confirm_without_groups
139
- return unless Bundler.settings.without.any?
140
- require "bundler/cli/common"
141
- Bundler.ui.confirm Bundler::CLI::Common.without_groups_message
142
- end
143
-
144
133
  def dependencies_count_for(definition)
145
134
  count = definition.dependencies.count
146
135
  "#{count} Gemfile #{count == 1 ? "dependency" : "dependencies"}"
@@ -151,11 +140,6 @@ module Bundler
151
140
  "#{count} #{count == 1 ? "gem" : "gems"} now installed"
152
141
  end
153
142
 
154
- def print_post_install_message(name, msg)
155
- Bundler.ui.confirm "Post-install message from #{name}:"
156
- Bundler.ui.info msg
157
- end
158
-
159
143
  def check_for_group_conflicts
160
144
  if options[:without] && options[:with]
161
145
  conflicting_groups = options[:without] & options[:with]
@@ -170,8 +154,8 @@ module Bundler
170
154
  def check_for_options_conflicts
171
155
  if (options[:path] || options[:deployment]) && options[:system]
172
156
  error_message = String.new
173
- error_message << "You have specified both a path to install your gems to as well as --system. Please choose.\n" if options[:path]
174
- error_message << "You have specified both --deployment as well as --system. Please choose.\n" if options[:deployment]
157
+ error_message << "You have specified both --path as well as --system. Please choose only one option.\n" if options[:path]
158
+ error_message << "You have specified both --deployment as well as --system. Please choose only one option.\n" if options[:deployment]
175
159
  raise InvalidOption.new(error_message)
176
160
  end
177
161
  end
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+ require "bundler/cli/common"
3
+
2
4
  module Bundler
3
5
  class CLI::Lock
4
6
  attr_reader :options
@@ -17,14 +19,13 @@ module Bundler
17
19
  ui = Bundler.ui
18
20
  Bundler.ui = UI::Silent.new if print
19
21
 
20
- gems = options[:update]
21
22
  Bundler::Fetcher.disable_endpoint = options["full-index"]
22
23
 
23
- if gems && !gems.empty?
24
- definition = Bundler.definition(:gems => gems)
25
- else
26
- definition = Bundler.definition(true)
27
- end
24
+ update = options[:update]
25
+ update = { :gems => update, :lock_shared_dependencies => options[:conservative] } if update.is_a?(Array)
26
+ definition = Bundler.definition(update)
27
+
28
+ Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options) if options[:update]
28
29
 
29
30
  options["remove-platform"].each do |platform|
30
31
  definition.remove_platform(platform)
@@ -32,7 +33,7 @@ module Bundler
32
33
 
33
34
  options["add-platform"].each do |platform_string|
34
35
  platform = Gem::Platform.new(platform_string)
35
- if platform.to_a.compact == %w(unknown)
36
+ if platform.to_s == "unknown"
36
37
  Bundler.ui.warn "The platform `#{platform_string}` is unknown to RubyGems " \
37
38
  "and adding it will likely lead to resolution errors"
38
39
  end
@@ -4,6 +4,7 @@ require "bundler/cli/common"
4
4
  module Bundler
5
5
  class CLI::Outdated
6
6
  attr_reader :options, :gems
7
+
7
8
  def initialize(options, gems)
8
9
  @options = options
9
10
  @gems = gems
@@ -18,10 +19,14 @@ module Bundler
18
19
  Bundler::CLI::Common.select_spec(gem_name)
19
20
  end
20
21
 
21
- Bundler.definition.validate_ruby!
22
+ Bundler.definition.validate_runtime!
22
23
  current_specs = Bundler.ui.silence { Bundler.load.specs }
23
24
  current_dependencies = {}
24
- Bundler.ui.silence { Bundler.load.dependencies.each {|dep| current_dependencies[dep.name] = dep } }
25
+ Bundler.ui.silence do
26
+ Bundler.load.dependencies.each do |dep|
27
+ current_dependencies[dep.name] = dep
28
+ end
29
+ end
25
30
 
26
31
  definition = if gems.empty? && sources.empty?
27
32
  # We're doing a full update
@@ -30,7 +35,24 @@ module Bundler
30
35
  Bundler.definition(:gems => gems, :sources => sources)
31
36
  end
32
37
 
33
- definition_resolution = proc { options["local"] ? definition.resolve_with_cache! : definition.resolve_remotely! }
38
+ Bundler::CLI::Common.configure_gem_version_promoter(
39
+ Bundler.definition,
40
+ options
41
+ )
42
+
43
+ # the patch level options imply strict is also true. It wouldn't make
44
+ # sense otherwise.
45
+ strict = options[:strict] ||
46
+ Bundler::CLI::Common.patch_level_options(options).any?
47
+
48
+ filter_options_patch = options.keys &
49
+ %w(filter-major filter-minor filter-patch)
50
+
51
+ definition_resolution = proc do
52
+ return definition.resolve_with_cache! if options[:local]
53
+ definition.resolve_remotely!
54
+ end
55
+
34
56
  if options[:parseable]
35
57
  Bundler.ui.silence(&definition_resolution)
36
58
  else
@@ -38,83 +60,169 @@ module Bundler
38
60
  end
39
61
 
40
62
  Bundler.ui.info ""
63
+ outdated_gems_by_groups = {}
64
+ outdated_gems_list = []
41
65
 
42
- out_count = 0
43
66
  # Loop through the current specs
44
- gemfile_specs, dependency_specs = current_specs.partition {|spec| current_dependencies.key? spec.name }
45
- [gemfile_specs.sort_by(&:name), dependency_specs.sort_by(&:name)].flatten.each do |current_spec|
67
+ gemfile_specs, dependency_specs = current_specs.partition do |spec|
68
+ current_dependencies.key? spec.name
69
+ end
70
+
71
+ (gemfile_specs + dependency_specs).sort_by(&:name).each do |current_spec|
46
72
  next if !gems.empty? && !gems.include?(current_spec.name)
47
73
 
48
74
  dependency = current_dependencies[current_spec.name]
75
+ active_spec = retrieve_active_spec(strict, definition, current_spec)
49
76
 
50
- if options["strict"]
51
- active_spec = definition.specs.detect {|spec| spec.name == current_spec.name && spec.platform == current_spec.platform }
52
- else
53
- active_specs = definition.index[current_spec.name].select {|spec| spec.platform == current_spec.platform }.sort_by(&:version)
54
- if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
55
- active_spec = active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
77
+ next if active_spec.nil?
78
+ if filter_options_patch.any?
79
+ update_present = update_present_via_semver_portions(current_spec, active_spec, options)
80
+ next unless update_present
81
+ end
82
+
83
+ gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version)
84
+ if gem_outdated || (current_spec.git_version != active_spec.git_version)
85
+ groups = nil
86
+ if dependency && !options[:parseable]
87
+ groups = dependency.groups.join(", ")
56
88
  end
57
- active_spec = active_specs.last
58
89
 
59
- if options[:major] || options[:minor] || options[:patch]
60
- update_present = update_present_via_semver_portions(current_spec, active_spec, options)
61
- active_spec = nil unless update_present
90
+ outdated_gems_list << { :active_spec => active_spec,
91
+ :current_spec => current_spec,
92
+ :dependency => dependency,
93
+ :groups => groups }
94
+
95
+ outdated_gems_by_groups[groups] ||= []
96
+ outdated_gems_by_groups[groups] << { :active_spec => active_spec,
97
+ :current_spec => current_spec,
98
+ :dependency => dependency,
99
+ :groups => groups }
100
+ end
101
+
102
+ Bundler.ui.debug "from #{active_spec.loaded_from}"
103
+ end
104
+
105
+ if outdated_gems_list.empty?
106
+ display_nothing_outdated_message(filter_options_patch)
107
+ else
108
+ unless options[:parseable]
109
+ if options[:pre]
110
+ Bundler.ui.info "Outdated gems included in the bundle (including " \
111
+ "pre-releases):"
112
+ else
113
+ Bundler.ui.info "Outdated gems included in the bundle:"
62
114
  end
63
115
  end
64
116
 
65
- next if active_spec.nil?
117
+ options_include_groups = [:group, :groups].select do |v|
118
+ options.keys.include?(v.to_s)
119
+ end
66
120
 
67
- gem_outdated = Gem::Version.new(active_spec.version) > Gem::Version.new(current_spec.version)
68
- git_outdated = current_spec.git_version != active_spec.git_version
69
- if gem_outdated || git_outdated
70
- unless options[:parseable]
71
- if out_count == 0
72
- if options["pre"]
73
- Bundler.ui.info "Outdated gems included in the bundle (including pre-releases):"
121
+ if options_include_groups.any?
122
+ ordered_groups = outdated_gems_by_groups.keys.compact.sort
123
+ [nil, ordered_groups].flatten.each do |groups|
124
+ gems = outdated_gems_by_groups[groups]
125
+ contains_group = if groups
126
+ groups.split(",").include?(options[:group])
127
+ else
128
+ options[:group] == "group"
129
+ end
130
+
131
+ next if (!options[:groups] && !contains_group) || gems.nil?
132
+
133
+ unless options[:parseable]
134
+ if groups
135
+ Bundler.ui.info "===== Group #{groups} ====="
74
136
  else
75
- Bundler.ui.info "Outdated gems included in the bundle:"
137
+ Bundler.ui.info "===== Without group ====="
76
138
  end
77
139
  end
140
+
141
+ gems.each do |gem|
142
+ print_gem(
143
+ gem[:current_spec],
144
+ gem[:active_spec],
145
+ gem[:dependency],
146
+ groups,
147
+ options_include_groups.any?
148
+ )
149
+ end
150
+ end
151
+ else
152
+ outdated_gems_list.each do |gem|
153
+ print_gem(
154
+ gem[:current_spec],
155
+ gem[:active_spec],
156
+ gem[:dependency],
157
+ gem[:groups],
158
+ options_include_groups.any?
159
+ )
78
160
  end
161
+ end
79
162
 
80
- spec_version = "#{active_spec.version}#{active_spec.git_version}"
81
- current_version = "#{current_spec.version}#{current_spec.git_version}"
82
- dependency_version = %(, requested #{dependency.requirement}) if dependency && dependency.specific?
163
+ exit 1
164
+ end
165
+ end
83
166
 
84
- if dependency && !options[:parseable]
85
- groups = dependency.groups.join(", ")
86
- pl = (dependency.groups.length > 1) ? "s" : ""
87
- groups = " in group#{pl} \"#{groups}\""
88
- end
167
+ private
89
168
 
90
- spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, installed #{current_version}#{dependency_version})"
91
- if options[:parseable]
92
- Bundler.ui.info spec_outdated_info.to_s.rstrip
93
- else
94
- Bundler.ui.info " * #{spec_outdated_info}#{groups}".rstrip
95
- end
169
+ def retrieve_active_spec(strict, definition, current_spec)
170
+ if strict
171
+ active_spec = definition.find_resolved_spec(current_spec)
172
+ else
173
+ active_specs = definition.find_indexed_specs(current_spec)
174
+ if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1
175
+ active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? }
176
+ end
177
+ active_spec = active_specs.last
178
+ end
96
179
 
97
- out_count += 1
180
+ active_spec
181
+ end
182
+
183
+ def display_nothing_outdated_message(filter_options_patch)
184
+ unless options[:parseable]
185
+ if filter_options_patch.any?
186
+ display = filter_options_patch.map do |o|
187
+ o.sub("filter-", "")
188
+ end.join(" or ")
189
+
190
+ Bundler.ui.info "No #{display} updates to display.\n"
191
+ else
192
+ Bundler.ui.info "Bundle up to date!\n"
98
193
  end
99
- Bundler.ui.debug "from #{active_spec.loaded_from}"
100
194
  end
195
+ end
101
196
 
102
- if out_count.zero?
103
- Bundler.ui.info "Bundle up to date!\n" unless options[:parseable]
197
+ def print_gem(current_spec, active_spec, dependency, groups, options_include_groups)
198
+ spec_version = "#{active_spec.version}#{active_spec.git_version}"
199
+ current_version = "#{current_spec.version}#{current_spec.git_version}"
200
+
201
+ if dependency && dependency.specific?
202
+ dependency_version = %(, requested #{dependency.requirement})
203
+ end
204
+
205
+ spec_outdated_info = "#{active_spec.name} (newest #{spec_version}, " \
206
+ "installed #{current_version}#{dependency_version})"
207
+
208
+ output_message = if options[:parseable]
209
+ spec_outdated_info.to_s
210
+ elsif options_include_groups || !groups
211
+ " * #{spec_outdated_info}"
104
212
  else
105
- exit 1
213
+ " * #{spec_outdated_info} in groups \"#{groups}\""
106
214
  end
107
- end
108
215
 
109
- private
216
+ Bundler.ui.info output_message.rstrip
217
+ end
110
218
 
111
219
  def check_for_deployment_mode
112
220
  if Bundler.settings[:frozen]
113
- error_message = "You are trying to check outdated gems in deployment mode. " \
114
- "Run `bundle outdated` elsewhere.\n" \
115
- "\nIf this is a development machine, remove the #{Bundler.default_gemfile} freeze" \
116
- "\nby running `bundle install --no-deployment`."
117
- raise ProductionError, error_message
221
+ raise ProductionError, "You are trying to check outdated gems in " \
222
+ "deployment mode. Run `bundle outdated` elsewhere.\n" \
223
+ "\nIf this is a development machine, remove the " \
224
+ "#{Bundler.default_gemfile} freeze" \
225
+ "\nby running `bundle install --no-deployment`."
118
226
  end
119
227
  end
120
228
 
@@ -123,16 +231,15 @@ module Bundler
123
231
  active_major = active_spec.version.segments.first
124
232
 
125
233
  update_present = false
234
+ update_present = active_major > current_major if options["filter-major"]
126
235
 
127
- update_present = active_major > current_major if options[:major]
128
-
129
- if !update_present && (options[:minor] || options[:patch]) && current_major == active_major
236
+ if !update_present && (options["filter-minor"] || options["filter-patch"]) && current_major == active_major
130
237
  current_minor = get_version_semver_portion_value(current_spec, 1)
131
238
  active_minor = get_version_semver_portion_value(active_spec, 1)
132
239
 
133
- update_present = active_minor > current_minor if options[:minor]
240
+ update_present = active_minor > current_minor if options["filter-minor"]
134
241
 
135
- if !update_present && options[:patch] && current_minor == active_minor
242
+ if !update_present && options["filter-patch"] && current_minor == active_minor
136
243
  current_patch = get_version_semver_portion_value(current_spec, 2)
137
244
  active_patch = get_version_semver_portion_value(active_spec, 2)
138
245