diff options
30 files changed, 522 insertions, 100 deletions
diff --git a/.gitignore b/.gitignore index bd5d29dc7b..88730f82cd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ # output from ronn /lib/bundler/man/ +man/* +!man/*.ronn # rspec failure tracking .rspec_status @@ -27,6 +27,11 @@ See [bundler.io](http://bundler.io) for the full documentation. For help with common problems, see [ISSUES](https://github.com/bundler/bundler/blob/master/ISSUES.md). +### Supporting + +<a href="https://rubytogether.org/"><img src="https://rubytogether.org/images/rubies.svg" width=200></a><br/> +Bundler is maintained by <a href="https://rubytogether.org/">Ruby Together</a>, a grassroots initiative committed to supporting the critical Ruby infrastructure you rely on. Contribute today <a href="https://rubytogether.org/developers">as an individual</a> or even better, <a href="https://rubytogether.org/companies">as a company</a>, and ensure that Bundler, RubyGems, and other shared tooling is around for years to come. + ### Other questions To see what has changed in recent versions of Bundler, see the [CHANGELOG](https://github.com/bundler/bundler/blob/master/CHANGELOG.md). @@ -74,7 +74,7 @@ namespace :spec do $LOAD_PATH.unshift("./spec") require "support/rubygems_ext" - Spec::Rubygems::DEPS["codeclimate-test-reporter"] = nil if RUBY_VERSION >= "2.2.0" + Spec::Rubygems::DEPS["codeclimate-test-reporter"] = "~> 0.6.0" if RUBY_VERSION >= "2.2.0" # Install the other gem deps, etc Rake::Task["spec:deps"].invoke @@ -238,14 +238,15 @@ begin require "ronn" namespace :man do - directory "lib/bundler/man" + directory "man" sources = Dir["man/*.ronn"].map {|f| File.basename(f, ".ronn") } sources.map do |basename| ronn = "man/#{basename}.ronn" - roff = "lib/bundler/man/#{basename}" + manual_section = ".1" unless basename =~ /.*(\d+)\Z/ + roff = "man/#{basename}#{manual_section}" - file roff => ["lib/bundler/man", ronn] do + file roff => ["man", ronn] do sh "#{Gem.ruby} -S ronn --roff --pipe #{ronn} > #{roff}" end @@ -257,9 +258,8 @@ begin end task :clean do - leftovers = Dir["lib/bundler/man/*"].reject do |f| - basename = File.basename(f).sub(/\.(txt|ronn)/, "") - sources.include?(basename) + leftovers = Dir["man/*"].reject do |f| + File.extname(f) == ".ronn" || f == "man/index.txt" end rm leftovers if leftovers.any? end diff --git a/bundler.gemspec b/bundler.gemspec index f67c538fd6..3e71b6b336 100644 --- a/bundler.gemspec +++ b/bundler.gemspec @@ -7,7 +7,7 @@ require "bundler/version" Gem::Specification.new do |s| s.name = "bundler" s.version = Bundler::VERSION - s.licenses = ["MIT"] + s.license = "MIT" s.authors = ["André Arko", "Samuel Giddins"] s.email = ["team@bundler.io"] s.homepage = "http://bundler.io" @@ -27,7 +27,7 @@ Gem::Specification.new do |s| s.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) } # we don't check in man pages, but we need to ship them because # we use them to generate the long-form help for each command. - s.files += Dir.glob("lib/bundler/man/**/*") + s.files += Dir.glob("man/**/*") s.bindir = "exe" s.executables = %w(bundle bundler) diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index 37556f4926..ba6a58db1d 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -61,30 +61,21 @@ module Bundler def help(cli = nil) case cli - when "gemfile" then command = "gemfile.5" + when "gemfile" then command = "gemfile" when nil then command = "bundle" else command = "bundle-#{cli}" end - manpages = %w( - bundle - bundle-config - bundle-exec - bundle-gem - bundle-install - bundle-package - bundle-update - bundle-platform - gemfile.5 - ) - - if manpages.include?(command) - root = File.expand_path("../man", __FILE__) - - if Bundler.which("man") && root !~ %r{^file:/.+!/META-INF/jruby.home/.+} - Kernel.exec "man #{root}/#{command}" + man_path = File.expand_path("../../../man", __FILE__) + man_pages = Hash[Dir.glob(File.join(man_path, "*")).grep(/.*\.\d*\Z/).collect do |f| + [File.basename(f, ".*"), f] + end] + + if man_pages.include?(command) + if Bundler.which("man") && man_path !~ %r{^file:/.+!/META-INF/jruby.home/.+} + Kernel.exec "man #{man_pages[command]}" else - puts File.read("#{root}/#{command}.txt") + puts File.read("#{man_path}/#{File.basename(man_pages[command])}.txt") end elsif command_path = Bundler.which("bundler-#{cli}") Kernel.exec(command_path, "--help") @@ -222,9 +213,9 @@ module Bundler method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "strict", :type => :boolean, :banner => - "Do not allow any gem to be updated past latest --patch/--minor/--major" + "Do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => - "Use bundle install conservative update behavior and do not allowed shared dependencies to be updated." + "Use bundle install conservative update behavior and do not allow shared dependencies to be updated." def update(*gems) require "bundler/cli/update" Update.new(options, gems).run @@ -271,8 +262,8 @@ module Bundler versions of the given gems. Prerelease gems are ignored by default. If your gems are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. - For more information on conservative resolution options (--major, --minor, - --patch, --strict) see documentation on the same options on the update command. + For more information on patch level options (--major, --minor, --patch, + --update-strict) see documentation on the same options on the update command. D method_option "group", :aliases => "--group", :type => :string, :banner => "List gems from a specific group" method_option "groups", :aliases => "--groups", :type => :boolean, :banner => "List gems organized by groups" @@ -283,7 +274,7 @@ module Bundler method_option "strict", :type => :boolean, :banner => "Only list newer versions allowed by your Gemfile requirements" method_option "update-strict", :type => :boolean, :banner => - "Strict conservative resolution, do not allow any gem to be updated past latest --patch/--minor/--major" + "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" method_option "patch", :type => :boolean, :banner => "Prefer updating only to next patch version" @@ -466,9 +457,9 @@ module Bundler method_option "full-index", :type => :boolean, :default => false, :banner => "Fall back to using the single-file index of all gems" method_option "add-platform", :type => :array, :default => [], :banner => - "add a new platform to the lockfile" + "Add a new platform to the lockfile" method_option "remove-platform", :type => :array, :default => [], :banner => - "remove a platform from the lockfile" + "Remove a platform from the lockfile" method_option "patch", :type => :boolean, :banner => "If updating, prefer updating only to next patch version" method_option "minor", :type => :boolean, :banner => @@ -478,7 +469,7 @@ module Bundler method_option "strict", :type => :boolean, :banner => "If updating, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "conservative", :type => :boolean, :banner => - "If updating, use bundle install conservative update behavior and do not allowed shared dependencies to be updated." + "If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated" def lock require "bundler/cli/lock" Lock.new(options).run diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb index 4f238bbb59..62f7bc26cb 100644 --- a/lib/bundler/cli/exec.rb +++ b/lib/bundler/cli/exec.rb @@ -91,6 +91,12 @@ module Bundler "#!/usr/bin/env jruby\n", "#!#{Gem.ruby}\n", ] + + if File.zero?(file) + Bundler.ui.warn "#{file} is empty" + return false + end + first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) } possibilities.any? {|shebang| first_line.start_with?(shebang) } end diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 66162d741a..133c722228 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -17,6 +17,7 @@ module Bundler :ruby_21 => Gem::Platform::RUBY, :ruby_22 => Gem::Platform::RUBY, :ruby_23 => Gem::Platform::RUBY, + :ruby_24 => Gem::Platform::RUBY, :mri => Gem::Platform::RUBY, :mri_18 => Gem::Platform::RUBY, :mri_19 => Gem::Platform::RUBY, @@ -24,6 +25,7 @@ module Bundler :mri_21 => Gem::Platform::RUBY, :mri_22 => Gem::Platform::RUBY, :mri_23 => Gem::Platform::RUBY, + :mri_24 => Gem::Platform::RUBY, :rbx => Gem::Platform::RUBY, :jruby => Gem::Platform::JAVA, :jruby_18 => Gem::Platform::JAVA, @@ -35,12 +37,14 @@ module Bundler :mswin_21 => Gem::Platform::MSWIN, :mswin_22 => Gem::Platform::MSWIN, :mswin_23 => Gem::Platform::MSWIN, + :mswin_24 => Gem::Platform::MSWIN, :mswin64 => Gem::Platform::MSWIN64, :mswin64_19 => Gem::Platform::MSWIN64, :mswin64_20 => Gem::Platform::MSWIN64, :mswin64_21 => Gem::Platform::MSWIN64, :mswin64_22 => Gem::Platform::MSWIN64, :mswin64_23 => Gem::Platform::MSWIN64, + :mswin64_24 => Gem::Platform::MSWIN64, :mingw => Gem::Platform::MINGW, :mingw_18 => Gem::Platform::MINGW, :mingw_19 => Gem::Platform::MINGW, @@ -48,11 +52,13 @@ module Bundler :mingw_21 => Gem::Platform::MINGW, :mingw_22 => Gem::Platform::MINGW, :mingw_23 => Gem::Platform::MINGW, + :mingw_24 => Gem::Platform::MINGW, :x64_mingw => Gem::Platform::X64_MINGW, :x64_mingw_20 => Gem::Platform::X64_MINGW, :x64_mingw_21 => Gem::Platform::X64_MINGW, :x64_mingw_22 => Gem::Platform::X64_MINGW, :x64_mingw_23 => Gem::Platform::X64_MINGW, + :x64_mingw_24 => Gem::Platform::X64_MINGW }.freeze REVERSE_PLATFORM_MAP = {}.tap do |reverse_platform_map| diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index 51148ab614..d885c049d2 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require "strscan" # Some versions of the Bundler 1.1 RC series introduced corrupted # lockfiles. There were two major problems: diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb index ce5c5efa46..28d237482d 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb @@ -182,6 +182,13 @@ module Bundler::Molinillo add_edge_no_circular(origin, destination, requirement) end + # Deletes an {Edge} from the dependency graph + # @param [Edge] edge + # @return [Void] + def delete_edge(edge) + log.delete_edge(self, edge.origin.name, edge.destination.name, edge.requirement) + end + # Sets the payload of the vertex with the given name # @param [String] name the name of the vertex # @param [Object] payload the payload diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb index c8eacbe08f..e0dfe6cbbd 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb @@ -7,7 +7,7 @@ module Bundler::Molinillo # rubocop:disable Lint/UnusedMethodArgument # @return [Symbol] The name of the action. - def self.name + def self.action_name raise 'Abstract' end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb index a7e703a8f9..a030c03f5f 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb @@ -7,8 +7,8 @@ module Bundler::Molinillo class AddEdgeNoCircular < Action # @!group Action - # (see Action.name) - def self.name + # (see Action.action_name) + def self.action_name :add_vertex end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb index 14cd027804..eda4251801 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb @@ -7,8 +7,8 @@ module Bundler::Molinillo class AddVertex < Action # :nodoc: # @!group Action - # (see Action.name) - def self.name + # (see Action.action_name) + def self.action_name :add_vertex end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb new file mode 100644 index 0000000000..e9125a59c6 --- /dev/null +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true +require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/action' +module Bundler::Molinillo + class DependencyGraph + # @!visibility private + # (see DependencyGraph#delete_edge) + class DeleteEdge < Action + # @!group Action + + # (see Action.action_name) + def self.action_name + :delete_edge + end + + # (see Action#up) + def up(graph) + edge = make_edge(graph) + edge.origin.outgoing_edges.delete(edge) + edge.destination.incoming_edges.delete(edge) + end + + # (see Action#down) + def down(graph) + edge = make_edge(graph) + edge.origin.outgoing_edges << edge + edge.destination.incoming_edges << edge + edge + end + + # @!group DeleteEdge + + # @return [String] the name of the origin of the edge + attr_reader :origin_name + + # @return [String] the name of the destination of the edge + attr_reader :destination_name + + # @return [Object] the requirement that the edge represents + attr_reader :requirement + + # @param [DependencyGraph] graph the graph to find vertices from + # @return [Edge] The edge this action adds + def make_edge(graph) + Edge.new( + graph.vertex_named(origin_name), + graph.vertex_named(destination_name), + requirement + ) + end + + # Initialize an action to add an edge to a dependency graph + # @param [String] origin_name the name of the origin of the edge + # @param [String] destination_name the name of the destination of the edge + # @param [Object] requirement the requirement that the edge represents + def initialize(origin_name, destination_name, requirement) + @origin_name = origin_name + @destination_name = destination_name + @requirement = requirement + end + end + end +end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb index 78c0da67ef..fdb6f102b3 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb @@ -8,7 +8,7 @@ module Bundler::Molinillo # @!group Action # (see Action#name) - def self.name + def self.action_name :add_vertex end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb index 863b4912be..72a705e023 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular' require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex' +require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge' require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named' require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload' require 'bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag' @@ -40,6 +41,16 @@ module Bundler::Molinillo push_action(graph, AddEdgeNoCircular.new(origin, destination, requirement)) end + # {include:DependencyGraph#delete_edge} + # @param [Graph] graph the graph to perform the action on + # @param [String] origin_name + # @param [String] destination_name + # @param [Object] requirement + # @return (see DependencyGraph#delete_edge) + def delete_edge(graph, origin_name, destination_name, requirement) + push_action(graph, DeleteEdge.new(origin_name, destination_name, requirement)) + end + # @macro action def set_payload(graph, name, payload) push_action(graph, SetPayload.new(name, payload)) @@ -92,7 +103,7 @@ module Bundler::Molinillo loop do action = pop!(graph) raise "No tag #{tag.inspect} found" unless action - break if action.class.name == :tag && action.tag == tag + break if action.class.action_name == :tag && action.tag == tag end end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb index f2fe4b0289..8d8e10fedf 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb @@ -7,8 +7,8 @@ module Bundler::Molinillo class SetPayload < Action # :nodoc: # @!group Action - # (see Action.name) - def self.name + # (see Action.action_name) + def self.action_name :set_payload end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb index cb0e626e6a..53524d36ad 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb @@ -7,8 +7,8 @@ module Bundler::Molinillo class Tag < Action # @!group Action - # (see Action.name) - def self.name + # (see Action.action_name) + def self.action_name :tag end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb index f840e7ea30..7b3065236b 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Bundler::Molinillo # The version of Bundler::Molinillo. - VERSION = '0.5.1'.freeze + VERSION = '0.5.4'.freeze end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb index 1890d95a56..da1ac5aef0 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb @@ -194,18 +194,20 @@ module Bundler::Molinillo def state_index_for_unwind current_requirement = requirement existing_requirement = requirement_for_existing_name(name) - until current_requirement.nil? - current_state = find_state_for(current_requirement) - return states.index(current_state) if state_any?(current_state) - current_requirement = parent_of(current_requirement) + index = -1 + [current_requirement, existing_requirement].each do |r| + until r.nil? + current_state = find_state_for(r) + if state_any?(current_state) + current_index = states.index(current_state) + index = current_index if current_index > index + break + end + r = parent_of(r) + end end - until existing_requirement.nil? - existing_state = find_state_for(existing_requirement) - return states.index(existing_state) if state_any?(existing_state) - existing_requirement = parent_of(existing_requirement) - end - -1 + index end # @return [Object] the requirement that led to `requirement` being added @@ -356,10 +358,14 @@ module Bundler::Molinillo # @return [void] def fixup_swapped_children(vertex) payload = vertex.payload - dep_names = dependencies_for(payload).map(&method(:name_for)) - vertex.successors.each do |succ| - if !dep_names.include?(succ.name) && !succ.root? && succ.predecessors.to_a == [vertex] + deps = dependencies_for(payload).group_by(&method(:name_for)) + vertex.outgoing_edges.each do |outgoing_edge| + @parent_of[outgoing_edge.requirement] = states.size - 1 + succ = outgoing_edge.destination + matching_deps = Array(deps[succ.name]) + if matching_deps.empty? && !succ.root? && succ.predecessors.to_a == [vertex] debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" } + succ.requirements.each { |r| @parent_of.delete(r) } activated.detach_vertex_named(succ.name) all_successor_names = succ.recursive_successors.map(&:name) @@ -368,6 +374,9 @@ module Bundler::Molinillo requirement_name = name_for(requirement) (requirement_name == succ.name) || all_successor_names.include?(requirement_name) end + elsif !matching_deps.include?(outgoing_edge.requirement) + activated.delete_edge(outgoing_edge) + requirements.delete(outgoing_edge.requirement) end end end diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn index dc701c584f..5f10aaa658 100644 --- a/man/bundle-config.ronn +++ b/man/bundle-config.ronn @@ -223,3 +223,17 @@ For example, to save the credentials of user `claudette` for the gem source at Or you can set the credentials as an environment variable like this: export BUNDLE_GEMS__LONGEROUS__COM="claudette:s00pers3krit" + +For gems with a git source with HTTP(S) URL you can specify credentials like so: + + bundle config https://github.com/bundler/bundler.git username:password + +Or you can set the credentials as an environment variable like so: + + export BUNDLE_GITHUB__COM=username:password + +This is especially useful for private repositories on hosts such as Github, +where you can use personal OAuth tokens: + + export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic + diff --git a/man/bundle-lock.ronn b/man/bundle-lock.ronn index 8afc50af8a..b18d819c21 100644 --- a/man/bundle-lock.ronn +++ b/man/bundle-lock.ronn @@ -7,6 +7,14 @@ bundle-lock(1) -- Creates / Updates a lockfile without installing [--local] [--print] [--lockfile=PATH] + [--full-index] + [--add-platform] + [--remove-platform] + [--patch] + [--minor] + [--major] + [--strict] + [--conservative] ## DESCRIPTION @@ -30,6 +38,30 @@ Lock the gems specified in Gemfile. * `--lockfile=<path>`: The path where the lockfile should be written to. +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--add-platform`: + Add a new platform to the lockfile. + +* `--remove-platform`: + Remove a platform from the lockfile. + +* `--patch`: + If updating, prefer updating only to next patch version. + +* `--minor`: + If updating, prefer updating only to next minor version. + +* `--major`: + If updating, prefer updating to next major version (default). + +* `--strict`: + If updating, do not allow any gem to be updated past latest --patch | --minor | --major. + +* `--conservative`: + If updating, use bundle install conservative update behavior and do not allow shared dependencies to be updated. + ## UPDATING ALL GEMS If you run `bundle lock` with `--update` option without list of gems, bundler will @@ -45,3 +77,7 @@ For instance, you only want to update `nokogiri`, run `bundle lock --update noko Bundler will update `nokogiri` and any of its dependencies, but leave the rest of the gems that you specified locked to the versions in the `Gemfile.lock`. + +## PATCH LEVEL OPTIONS + +See [bundle update(1)][bundle-update] for details. diff --git a/man/bundle-outdated.ronn b/man/bundle-outdated.ronn new file mode 100644 index 0000000000..47792e61b2 --- /dev/null +++ b/man/bundle-outdated.ronn @@ -0,0 +1,107 @@ +bundle-outdated(1) -- List installed gems with newer versions available +======================================================================= + +## SYNOPSIS + +`bundle outdated` [GEM] [--local] + [--pre] + [--source] + [--strict] + [--parseable | --porcelain] + [--group=GROUP] + [--groups] + [--update-strict] + [--patch|--minor|--major] + [--filter-major] + [--filter-minor] + [--filter-patch] + +## DESCRIPTION + +Outdated lists the names and versions of gems that have a newer version available +in the given source. Calling outdated with [GEM [GEM]] will only check for newer +versions of the given gems. Prerelease gems are ignored by default. If your gems +are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1. + +## OPTIONS + +* `--local`: + Do not attempt to fetch gems remotely and use the gem cache instead. + +* `--pre`: + Check for newer pre-release gems. + +* `--source`: + Check against a specific source. + +* `--strict`: + Only list newer versions allowed by your Gemfile requirements. + +* `--parseable`: + Use minimal formatting for more parseable output. + +* `--group`: + List gems from a specific group. + +* `--groups`: + List gems organized by groups. + +* `--update-strict`: + Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor| --major. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--patch`: + Prefer updating only to next patch version. + +* `--filter-major`: + Only list major newer versions. + +* `--filter-minor`: + Only list minor newer versions. + +* `--filter-patch`: + Only list patch newer versions. + +## PATCH LEVEL OPTIONS + +See [bundle update(1)][bundle-update] for details. + +One difference between the patch level options in `bundle update` and here is the `--strict` option. +`--strict` was already an option on outdated before the patch level options were added. `--strict` +wasn't altered, and the `--update-strict` option on `outdated` reflects what `--strict` does on +`bundle update`. + +## FILTERING OUTPUT + +The 3 filtering options do not affect the resolution of versions, merely what versions are shown +in the output. + +If the regular output shows the following: + + * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" + * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" + * headless (newest 2.3.1, installed 2.2.3) in groups "test" + +`--filter-major` would only show: + + * hashie (newest 3.4.6, installed 1.2.0, requested = 1.2.0) in groups "default" + +`--filter-minor` would only show: + + * headless (newest 2.3.1, installed 2.2.3) in groups "test" + +`--filter-patch` would only show: + + * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" + +Filter options can be combined. `--filter-minor` and `--filter-patch` would show: + + * faker (newest 1.6.6, installed 1.6.5, requested ~> 1.4) in groups "development, test" + * headless (newest 2.3.1, installed 2.2.3) in groups "test" + +Combining all three `filter` options would be the same result as providing none of them. diff --git a/man/bundle-update.ronn b/man/bundle-update.ronn index 47d70f661c..7986a17bdc 100644 --- a/man/bundle-update.ronn +++ b/man/bundle-update.ronn @@ -3,7 +3,18 @@ bundle-update(1) -- Update your gems to the latest available versions ## SYNOPSIS -`bundle update` <*gems> [--group=NAME] [--source=NAME] [--local] [--ruby] +`bundle update` <*gems> [--group=NAME] + [--source=NAME] + [--local] + [--ruby] + [--bundler[=VERSION]] + [--full-index] + [--jobs=JOBS] + [--quiet] + [--force] + [--patch|--minor|--major] + [--strict] + [--conservative] ## DESCRIPTION @@ -37,6 +48,33 @@ gem. * `--bundler`: Update the locked version of bundler to the invoked bundler version. +* `--full-index`: + Fall back to using the single-file index of all gems. + +* `--jobs`: + Specify the number of jobs to run in parallel. + +* `--quiet`: + Only output warnings and errors. + +* `--force`: + Force downloading every gem. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +* `--conservative`: + Use bundle install conservative update behavior and do not allow shared dependencies to be updated. + ## UPDATING ALL GEMS If you run `bundle update` with no parameters, bundler will ignore @@ -146,14 +184,125 @@ In this case, the two gems have their own set of dependencies, but they share `bundle update thin` will update `rack` even though it's _also_ a dependency of `rack-perftools_profiler`. -`In short`, when you update a gem using `bundle update`, bundler will update all -dependencies of that gem, including those that are also dependencies of another gem. +In short, by default, when you update a gem using `bundle update`, bundler will +update all dependencies of that gem, including those that are also dependencies +of another gem. + +To prevent updating shared dependencies, prior to version 1.14 the only option +was the `CONSERVATIVE UPDATING` behavior in [bundle install(1)][bundle-install]: In this scenario, updating the `thin` version manually in the Gemfile(5), and then running [bundle install(1)][bundle-install] will only update `daemons` and `eventmachine`, but not `rack`. For more information, see the `CONSERVATIVE UPDATING` section of [bundle install(1)][bundle-install]. +Starting with 1.14, specifying the `--conservative` option will also prevent shared +dependencies from being updated. + +## PATCH LEVEL OPTIONS + +Version 1.14 introduced 4 patch-level options that will influence how gem +versions are resolved. One of the following options can be used: `--patch`, +`--minor` or `--major`. `--strict` can be added to further influence resolution. + +* `--patch`: + Prefer updating only to next patch version. + +* `--minor`: + Prefer updating only to next minor version. + +* `--major`: + Prefer updating to next major version (default). + +* `--strict`: + Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`. + +When Bundler is resolving what versions to use to satisfy declared +requirements in the Gemfile or in parent gems, it looks up all +available versions, filters out any versions that don't satisfy +the requirement, and then, by default, sorts them from newest to +oldest, considering them in that order. + +Providing one of the patch level options (e.g. `--patch`) changes the +sort order of the satisfying versions, causing Bundler to consider the +latest `--patch` or `--minor` version available before other versions. +Note that versions outside the stated patch level could still be +resolved to if necessary to find a suitable dependency graph. + +For example, if gem 'foo' is locked at 1.0.2, with no gem requirement +defined in the Gemfile, and versions 1.0.3, 1.0.4, 1.1.0, 1.1.1, 2.0.0 +all exist, the default order of preference by default (`--major`) will +be "2.0.0, 1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +If the `--patch` option is used, the order of preference will change to +"1.0.4, 1.0.3, 1.0.2, 1.1.1, 1.1.0, 2.0.0". + +If the `--minor` option is used, the order of preference will change to +"1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2, 2.0.0". + +Combining the `--strict` option with any of the patch level options +will remove any versions beyond the scope of the patch level option, +to ensure that no gem is updated that far. + +To continue the previous example, if both `--patch` and `--strict` +options are used, the available versions for resolution would be +"1.0.4, 1.0.3, 1.0.2". If `--minor` and `--strict` are used, it would +be "1.1.1, 1.1.0, 1.0.4, 1.0.3, 1.0.2". + +Gem requirements as defined in the Gemfile will still be the first +determining factor for what versions are available. If the gem +requirement for `foo` in the Gemfile is '~> 1.0', that will accomplish +the same thing as providing the `--minor` and `--strict` options. + +## PATCH LEVEL EXAMPLES + +Given the following gem specifications: + + foo 1.4.3, requires: ~> bar 2.0 + foo 1.4.4, requires: ~> bar 2.0 + foo 1.4.5, requires: ~> bar 2.1 + foo 1.5.0, requires: ~> bar 2.1 + foo 1.5.1, requires: ~> bar 3.0 + bar with versions 2.0.3, 2.0.4, 2.1.0, 2.1.1, 3.0.0 + +Gemfile: + + gem 'foo' + +Gemfile.lock: + + foo (1.4.3) + bar (~> 2.0) + bar (2.0.3) + +Cases: + + # Command Line Result + ------------------------------------------------------------ + 1 bundle update --patch 'foo 1.4.5', 'bar 2.1.1' + 2 bundle update --patch foo 'foo 1.4.5', 'bar 2.1.1' + 3 bundle update --minor 'foo 1.5.1', 'bar 3.0.0' + 4 bundle update --minor --strict 'foo 1.5.0', 'bar 2.1.1' + 5 bundle update --patch --strict 'foo 1.4.4', 'bar 2.0.4' + +In case 1, bar is upgraded to 2.1.1, a minor version increase, because +the dependency from foo 1.4.5 required it. + +In case 2, only foo is requested to be unlocked, but bar is also +allowed to move because it's not a declared dependency in the Gemfile. + +In case 3, bar goes up a whole major release, because a minor increase +is preferred now for foo, and when it goes to 1.5.1, it requires 3.0.0 +of bar. + +In case 4, foo is preferred up to a minor version, but 1.5.1 won't work +because the --strict flag removes bar 3.0.0 from consideration since +it's a major increment. + +In case 5, both foo and bar have any minor or major increments removed +from consideration because of the --strict flag, so the most they can +move is up to 1.4.4 and 2.0.4. + ## RECOMMENDED WORKFLOW In general, when working with an application managed with bundler, you should diff --git a/man/gemfile.5.ronn b/man/gemfile.5.ronn index da2157e971..e06e14fafc 100644 --- a/man/gemfile.5.ronn +++ b/man/gemfile.5.ronn @@ -185,6 +185,8 @@ There are a number of `Gemfile` platforms: _ruby_ `AND` version 2.2 * `ruby_23`: _ruby_ `AND` version 2.3 + * `ruby_24`: + _ruby_ `AND` version 2.4 * `mri`: Same as _ruby_, but not Rubinius * `mri_18`: @@ -199,6 +201,8 @@ There are a number of `Gemfile` platforms: _mri_ `AND` version 2.2 * `mri_23`: _mri_ `AND` version 2.3 + * `mri_24`: + _mri_ `AND` version 2.4 * `rbx`: Same as _ruby_, but only Rubinius (not MRI) * `jruby`: @@ -219,6 +223,8 @@ There are a number of `Gemfile` platforms: _mingw_ `AND` version 2.2 * `mingw_23`: _mingw_ `AND` version 2.3 + * `mingw_24`: + _mingw_ `AND` version 2.4 * `x64_mingw`: Windows 64 bit 'mingw32' platform (aka RubyInstaller x64) * `x64_mingw_20`: @@ -229,6 +235,8 @@ There are a number of `Gemfile` platforms: _x64_mingw_ `AND` version 2.2 * `x64_mingw_23`: _x64_mingw_ `AND` version 2.3 + * `x65_mingw_23`: + _x64_mingw_ `AND` version 2.4 As with groups, you can specify one or more platforms: diff --git a/spec/bundler/dsl_spec.rb b/spec/bundler/dsl_spec.rb index 00d36dd55f..e7df91c06f 100644 --- a/spec/bundler/dsl_spec.rb +++ b/spec/bundler/dsl_spec.rb @@ -93,8 +93,8 @@ describe Bundler::Dsl do end describe "#gem" do - [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :mri, :mri_18, :mri_19, - :mri_20, :mri_21, :mri_22, :mri_23, :jruby, :rbx].each do |platform| + [:ruby, :ruby_18, :ruby_19, :ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24, :mri, :mri_18, :mri_19, + :mri_20, :mri_21, :mri_22, :mri_23, :mri_24, :jruby, :rbx].each do |platform| it "allows #{platform} as a valid platform" do subject.gem("foo", :platform => platform) end diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb index 4dc47919de..5d1a63e680 100644 --- a/spec/commands/exec_spec.rb +++ b/spec/commands/exec_spec.rb @@ -272,35 +272,35 @@ describe "bundle exec" do with_fake_man do bundle "#{exec} --help cat" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when --help is before exec" do with_fake_man do bundle "--help #{exec}" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when -h is before exec" do with_fake_man do bundle "-h #{exec}" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when --help is after exec" do with_fake_man do bundle "#{exec} --help" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end it "shows bundle-exec's man page when -h is after exec" do with_fake_man do bundle "#{exec} -h" end - expect(out).to include(%(["#{root}/lib/bundler/man/bundle-exec"])) + expect(out).to include(%(["#{root}/man/bundle-exec.1"])) end end end @@ -514,6 +514,21 @@ describe "bundle exec" do end end + context "the executable is empty" do + let(:executable) { "" } + + let(:exit_code) { 0 } + let(:expected) { "#{path} is empty" } + let(:expected_err) { "" } + if LessThanProc.with(RUBY_VERSION).call("1.9") + # Kernel#exec in ruby < 1.9 will raise Errno::ENOEXEC if the command content is empty, + # even if the command is set as an executable. + pending "Kernel#exec is different" + else + it_behaves_like "it runs" + end + end + context "the executable raises" do let(:executable) { super() << "\nraise 'ERROR'" } let(:exit_code) { 1 } diff --git a/spec/commands/help_spec.rb b/spec/commands/help_spec.rb index d59346f615..380e3be15e 100644 --- a/spec/commands/help_spec.rb +++ b/spec/commands/help_spec.rb @@ -16,14 +16,14 @@ describe "bundle help" do with_fake_man do bundle "help gemfile" end - expect(out).to eq(%(["#{root}/lib/bundler/man/gemfile.5"])) + expect(out).to eq(%(["#{root}/man/gemfile.5"])) end it "prefixes bundle commands with bundle- when finding the groff files" do with_fake_man do bundle "help install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "simply outputs the txt file when there is no man on the path" do @@ -55,28 +55,28 @@ describe "bundle help" do with_fake_man do bundle "install --help" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the --help flag is used before the command" do with_fake_man do bundle "--help install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the -h flag is used before the command" do with_fake_man do bundle "-h install" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "is called when the -h flag is used after the command" do with_fake_man do bundle "install -h" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle-install"])) + expect(out).to eq(%(["#{root}/man/bundle-install.1"])) end it "has helpful output when using --help flag for a non-existent command" do @@ -90,11 +90,11 @@ describe "bundle help" do with_fake_man do bundle "--help" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle"])) + expect(out).to eq(%(["#{root}/man/bundle.1"])) with_fake_man do bundle "-h" end - expect(out).to eq(%(["#{root}/lib/bundler/man/bundle"])) + expect(out).to eq(%(["#{root}/man/bundle.1"])) end end diff --git a/spec/commands/update_spec.rb b/spec/commands/update_spec.rb index f5c155e73a..63fe951c43 100644 --- a/spec/commands/update_spec.rb +++ b/spec/commands/update_spec.rb @@ -526,8 +526,6 @@ describe "bundle update conservative" do expect(the_bundle).to include_gems "foo 1.4.5", "bar 2.1.1", "qux 1.0.1" end - - it "warns on minor or major increment elsewhere" ## include in prior test end context "minor preferred" do @@ -536,10 +534,6 @@ describe "bundle update conservative" do expect(the_bundle).to include_gems "foo 1.5.1", "bar 3.0.0", "qux 1.0.0" end - - it "warns on major increment elsewhere" ## include in prior test - - it "warns when something unlocked doesn't update at all" end context "strict" do @@ -652,10 +646,4 @@ describe "bundle update conservative" do expect(out).to eq "Provide only one of the following options: minor, patch" end end - - context "other commands" do - it "Installer could support --dry-run flag for install and update" - - it "outdated should conform its flags to the resolver flags" - end end diff --git a/spec/resolver/basic_spec.rb b/spec/resolver/basic_spec.rb index 3e8883d1d4..e3187726fd 100644 --- a/spec/resolver/basic_spec.rb +++ b/spec/resolver/basic_spec.rb @@ -214,18 +214,22 @@ describe "Resolving" do should_conservative_resolve_and_include :patch, [], %w(foo-1.4.4 bar-2.1.1) end - it "will not revert to a previous version in strict mode level patch" do - pending "possible issue with molinillo - needs further research" - should_conservative_resolve_and_include [:patch, :strict], [], %w(foo-1.4.3 bar-2.1.1) + it "cannot revert to a previous version in strict mode level patch" do + # the strict option removes the version required to match, so a version conflict results + expect do + should_conservative_resolve_and_include [:patch, :strict], [], %w(foo-1.4.3 bar-2.1.1) + end.to raise_error Bundler::VersionConflict, /#{Regexp.escape("Could not find gem 'bar (~> 2.1.0)'")}/ end it "could revert to a previous version level minor" do should_conservative_resolve_and_include :minor, [], %w(foo-1.5.0 bar-2.0.5) end - it "will not revert to a previous version in strict mode level minor" do - pending "possible issue with molinillo - needs further research" - should_conservative_resolve_and_include [:minor, :strict], [], %w(foo-1.4.3 bar-2.1.1) + it "cannot revert to a previous version in strict mode level minor" do + # the strict option removes the version required to match, so a version conflict results + expect do + should_conservative_resolve_and_include [:minor, :strict], [], %w(foo-1.4.3 bar-2.1.1) + end.to raise_error Bundler::VersionConflict, /#{Regexp.escape("Could not find gem 'bar (~> 2.0.0)'")}/ end end end diff --git a/spec/support/hax.rb b/spec/support/hax.rb index 2cca22c6ab..d00bf619a9 100644 --- a/spec/support/hax.rb +++ b/spec/support/hax.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true require "rubygems" -class Gem::Platform - @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) if ENV["BUNDLER_SPEC_PLATFORM"] +module Gem + class Platform + @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) if ENV["BUNDLER_SPEC_PLATFORM"] + end + @platforms = [Gem::Platform::RUBY, Gem::Platform.local] end if ENV["BUNDLER_SPEC_VERSION"] |