From 4c2ec5ef0d0e45bb08576d45bb3d5043f6656cc6 Mon Sep 17 00:00:00 2001 From: Asutosh Palai Date: Wed, 22 Jun 2016 00:39:34 +0530 Subject: Few correction from suggestions --- lib/bundler/lockfile_parser.rb | 4 +- lib/bundler/plugin.rb | 12 +- lib/bundler/plugin/api.rb | 2 +- lib/bundler/plugin/api/source.rb | 45 ++++- lib/bundler/plugin/dsl.rb | 19 +- spec/plugins/command.rb | 81 --------- spec/plugins/command_spec.rb | 81 +++++++++ spec/plugins/install.rb | 159 ---------------- spec/plugins/install_spec.rb | 159 ++++++++++++++++ spec/plugins/source.rb | 87 --------- spec/plugins/source/example.rb | 354 ------------------------------------ spec/plugins/source/example_spec.rb | 354 ++++++++++++++++++++++++++++++++++++ spec/plugins/source_spec.rb | 87 +++++++++ 13 files changed, 740 insertions(+), 704 deletions(-) delete mode 100644 spec/plugins/command.rb create mode 100644 spec/plugins/command_spec.rb delete mode 100644 spec/plugins/install.rb create mode 100644 spec/plugins/install_spec.rb delete mode 100644 spec/plugins/source.rb delete mode 100644 spec/plugins/source/example.rb create mode 100644 spec/plugins/source/example_spec.rb create mode 100644 spec/plugins/source_spec.rb diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index bbbed381..af01976f 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -22,7 +22,7 @@ module Bundler GIT = "GIT".freeze GEM = "GEM".freeze PATH = "PATH".freeze - PLUGIN = "PLUGIN".freeze + PLUGIN = "PLUGIN SOURCE".freeze SPECS = " specs:".freeze OPTIONS = /^ ([a-z]+): (.*)$/i SOURCE = [GIT, GEM, PATH, PLUGIN].freeze @@ -128,7 +128,7 @@ module Bundler def parse_source(line) case line - when GIT, GEM, PATH, PLUGIN + when *SOURCE @current_source = nil @opts = {} @type = line diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index 98a03362..425f6460 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -128,11 +128,11 @@ module Bundler # # @param [Hash] plugins mapped to their installtion path # @param [Array] names of auto added source plugins that can be ignored - def save_plugins(plugins, optionals = []) + def save_plugins(plugins, optional_plugins = []) plugins.each do |name, path| path = Pathname.new path validate_plugin! path - register_plugin name, path, optionals.include?(name) + register_plugin name, path, optional_plugins.include?(name) Bundler.ui.info "Installed plugin #{name}" end end @@ -153,9 +153,9 @@ module Bundler # # @param [String] name the name of the plugin # @param [Pathname] path the path where the plugin is installed at - # @param [Boolean] optional_plugin, removed if there is conflict (used for - # default source plugins) - def register_plugin(name, path, optional = false) + # @param [Boolean] optional_plugin, removed if there is conflict with any + # other plugin (used for default source plugins) + def register_plugin(name, path, optional_plugin = false) commands = @commands sources = @sources @@ -168,7 +168,7 @@ module Bundler raise MalformattedPlugin, "#{e.class}: #{e.message}" end - if optional && @sources.keys.any? {|s| source? s } + if optional_plugin && @sources.keys.any? {|s| source? s } Bundler.rm_rf(path) else index.register_plugin name, path.to_s, @commands.keys, @sources.keys diff --git a/lib/bundler/plugin/api.rb b/lib/bundler/plugin/api.rb index 14ed8d21..35d34b2e 100644 --- a/lib/bundler/plugin/api.rb +++ b/lib/bundler/plugin/api.rb @@ -65,7 +65,7 @@ module Bundler end def respond_to_missing?(name, include_private = false) - Bundler.respond_to?(name) || super + Bundler.respond_to?(name, include_private) || super end end end diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index 701264ef..5401a97e 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -10,9 +10,9 @@ module Bundler # `uri_hash`, `gem_install_dir`; they are helpers). # # Defaults for methods, where ever possible are provided which is - # expected to work. But, all source plugins have to override `fetch_gemfiles` - # and `install`. Defaults are also not provided for `remote!`, `cache!` - # and `unlock!`. + # expected to work. But, all source plugins have to override + # `fetch_gemspec_files` and `install`. Defaults are also not provided for + # `remote!`, `cache!` and `unlock!`. # # The defaults shall work for most situations but nevertheless they can # be (preferably should be) overridden as per the plugins' needs safely @@ -23,7 +23,20 @@ module Bundler # able to match objects representing same sources, but may be created in # different situation (like form gemfile and lockfile). The default ones # checks only for class and uri, but elaborate source plugins may need - # more comparisons (like, git checking on branch or tag). + # more comparisons (e.g. git checking on branch or tag). + # + # @!attribute [r] uri + # @return [String] the remote specified with `source` block in Gemfile + # + # @!attribute [r] options + # @return [String] options passed during initialization (either from + # lockfile or Gemfile) + # + # @!attribute [rw] dependency_names + # @return [Array] Names of dependencies that the source should + # try to resolve. It is not necessary to use this list intenally. This + # is present to be compatible with `Definition` and is used by + # rubygems source. module Source attr_reader :uri, :options attr_accessor :dependency_names @@ -41,8 +54,9 @@ module Bundler # # Note: If the spec method is overridden, this function is not necessary # - # @return [Array] paths of the gemfiles that can be installed - def fetch_gemfiles + # @return [Array] paths of the gemspec files for gems that can + # be installed + def fetch_gemspec_files [] end @@ -78,7 +92,7 @@ module Bundler end end - # Parses the gemfiles to find the specs for the gems that can be + # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: @@ -91,7 +105,7 @@ module Bundler # # @return [Bundler::Index] index containing the specs def specs - files = fetch_gemfiles + files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| @@ -123,18 +137,31 @@ module Bundler # This shall check if two source object represent the same source. # + # The comparison shall take place only on the attribute that can be + # inferred from the options passed from Gemfile and not on attibutes + # that are used to pin down the gem to specific version (e.g. Git + # sources should compare on branch and tag but not on commit hash) + # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. + # + # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end + # When overriding `eql?` please preserve the behaviour as mentioned in + # docstring for `==` method. alias_method :eql?, :== + # When overriding `hash` please preserve the behaviour as mentioned in + # docstring for `==` method, i.e. two methods equal by above comparison + # should have same hash. def hash [self.class, uri].hash end + # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end @@ -148,7 +175,7 @@ module Bundler end def to_lock - out = String.new("PLUGIN\n") + out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" options_to_lock.each do |opt, value| diff --git a/lib/bundler/plugin/dsl.rb b/lib/bundler/plugin/dsl.rb index 296bfdbc..aefa761c 100644 --- a/lib/bundler/plugin/dsl.rb +++ b/lib/bundler/plugin/dsl.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true module Bundler - # Dsl to parse the Gemfile looking for plugins to install module Plugin + # Dsl to parse the Gemfile looking for plugins to install class DSL < Bundler::Dsl class PluginGemfileError < PluginError; end alias_method :_gem, :gem # To use for plugin installation as gem @@ -12,6 +12,14 @@ module Bundler # They will be handled by method_missing [:gemspec, :gem, :path, :install_if, :platforms, :env].each {|m| undef_method m } + # This lists the plugins that was added automatically and not specified by + # the user. + # + # When we encounter :type attribute with a source block, we add a plugin + # by name bundler-source- to list of plugins to be installed. + # + # These plugins are optional and are not installed when there is conflict + # with any other plugin. attr_reader :auto_plugins def initialize @@ -34,10 +42,11 @@ module Bundler return super unless options.key?("type") plugin_name = "bundler-source-#{options["type"]}" - unless @auto_plugins.include? plugin_name - plugin(plugin_name) - @auto_plugins << plugin_name - end + + return if @auto_plugins.include? plugin_name + + plugin(plugin_name) + @auto_plugins << plugin_name end end end diff --git a/spec/plugins/command.rb b/spec/plugins/command.rb deleted file mode 100644 index 71e87a5b..00000000 --- a/spec/plugins/command.rb +++ /dev/null @@ -1,81 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe "command plugins" do - before do - build_repo2 do - build_plugin "command-mah" do |s| - s.write "plugins.rb", <<-RUBY - module Mah - class Plugin < Bundler::Plugin::API - command "mahcommand" # declares the command - - def exec(command, args) - puts "MahHello" - end - end - end - RUBY - end - end - - bundle "plugin install command-mah --source file://#{gem_repo2}" - end - - it "executes without arguments" do - expect(out).to include("Installed plugin command-mah") - - bundle "mahcommand" - expect(out).to eq("MahHello") - end - - it "accepts the arguments" do - build_repo2 do - build_plugin "the-echoer" do |s| - s.write "plugins.rb", <<-RUBY - module Resonance - class Echoer - # Another method to declare the command - Bundler::Plugin::API.command "echo", self - - def exec(command, args) - puts "You gave me \#{args.join(", ")}" - end - end - end - RUBY - end - end - - bundle "plugin install the-echoer --source file://#{gem_repo2}" - expect(out).to include("Installed plugin the-echoer") - - bundle "echo tacos tofu lasange", "no-color" => false - expect(out).to eq("You gave me tacos, tofu, lasange") - end - - it "raises error on redeclaration of command" do - build_repo2 do - build_plugin "copycat" do |s| - s.write "plugins.rb", <<-RUBY - module CopyCat - class Cheater < Bundler::Plugin::API - command "mahcommand", self - - def exec(command, args) - end - end - end - RUBY - end - end - - bundle "plugin install copycat --source file://#{gem_repo2}" - - expect(out).not_to include("Installed plugin copycat") - - expect(out).to include("Failed to install plugin") - - expect(out).to include("Command(s) `mahcommand` declared by copycat are already registered.") - end -end diff --git a/spec/plugins/command_spec.rb b/spec/plugins/command_spec.rb new file mode 100644 index 00000000..71e87a5b --- /dev/null +++ b/spec/plugins/command_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "command plugins" do + before do + build_repo2 do + build_plugin "command-mah" do |s| + s.write "plugins.rb", <<-RUBY + module Mah + class Plugin < Bundler::Plugin::API + command "mahcommand" # declares the command + + def exec(command, args) + puts "MahHello" + end + end + end + RUBY + end + end + + bundle "plugin install command-mah --source file://#{gem_repo2}" + end + + it "executes without arguments" do + expect(out).to include("Installed plugin command-mah") + + bundle "mahcommand" + expect(out).to eq("MahHello") + end + + it "accepts the arguments" do + build_repo2 do + build_plugin "the-echoer" do |s| + s.write "plugins.rb", <<-RUBY + module Resonance + class Echoer + # Another method to declare the command + Bundler::Plugin::API.command "echo", self + + def exec(command, args) + puts "You gave me \#{args.join(", ")}" + end + end + end + RUBY + end + end + + bundle "plugin install the-echoer --source file://#{gem_repo2}" + expect(out).to include("Installed plugin the-echoer") + + bundle "echo tacos tofu lasange", "no-color" => false + expect(out).to eq("You gave me tacos, tofu, lasange") + end + + it "raises error on redeclaration of command" do + build_repo2 do + build_plugin "copycat" do |s| + s.write "plugins.rb", <<-RUBY + module CopyCat + class Cheater < Bundler::Plugin::API + command "mahcommand", self + + def exec(command, args) + end + end + end + RUBY + end + end + + bundle "plugin install copycat --source file://#{gem_repo2}" + + expect(out).not_to include("Installed plugin copycat") + + expect(out).to include("Failed to install plugin") + + expect(out).to include("Command(s) `mahcommand` declared by copycat are already registered.") + end +end diff --git a/spec/plugins/install.rb b/spec/plugins/install.rb deleted file mode 100644 index e0db0afa..00000000 --- a/spec/plugins/install.rb +++ /dev/null @@ -1,159 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe "bundler plugin install" do - before do - build_repo2 do - build_plugin "foo" - build_plugin "kung-foo" - end - end - - it "shows propper message when gem in not found in the source" do - bundle "plugin install no-foo --source file://#{gem_repo1}" - - expect(out).to include("Could not find") - plugin_should_not_be_installed("no-foo") - end - - it "installs from rubygems source" do - bundle "plugin install foo --source file://#{gem_repo2}" - - expect(out).to include("Installed plugin foo") - plugin_should_be_installed("foo") - end - - it "installs multiple plugins" do - bundle "plugin install foo kung-foo --source file://#{gem_repo2}" - - expect(out).to include("Installed plugin foo") - expect(out).to include("Installed plugin kung-foo") - - plugin_should_be_installed("foo", "kung-foo") - end - - it "uses the same version for multiple plugins" do - update_repo2 do - build_plugin "foo", "1.1" - build_plugin "kung-foo", "1.1" - end - - bundle "plugin install foo kung-foo --version '1.0' --source file://#{gem_repo2}" - - expect(out).to include("Installing foo 1.0") - expect(out).to include("Installing kung-foo 1.0") - plugin_should_be_installed("foo", "kung-foo") - end - - context "malformatted plugin" do - it "fails when plugins.rb is missing" do - build_repo2 do - build_gem "charlie" - end - - bundle "plugin install charlie --source file://#{gem_repo2}" - - expect(out).to include("plugins.rb was not found") - - expect(plugin_gems("charlie-1.0")).not_to be_directory - - plugin_should_not_be_installed("charlie") - end - - it "fails when plugins.rb throws exception on load" do - build_repo2 do - build_plugin "chaplin" do |s| - s.write "plugins.rb", <<-RUBY - raise "I got you man" - RUBY - end - end - - bundle "plugin install chaplin --source file://#{gem_repo2}" - - expect(plugin_gems("chaplin-1.0")).not_to be_directory - - plugin_should_not_be_installed("chaplin") - end - end - - context "git plugins" do - it "installs form a git source" do - build_git "foo" do |s| - s.write "plugins.rb" - end - - bundle "plugin install foo --git file://#{lib_path("foo-1.0")}" - - expect(out).to include("Installed plugin foo") - plugin_should_be_installed("foo") - end - end - - context "Gemfile eval" do - it "installs plugins listed in gemfile" do - gemfile <<-G - source 'file://#{gem_repo2}' - plugin 'foo' - gem 'rack', "1.0.0" - G - - bundle "install" - - expect(out).to include("Installed plugin foo") - - expect(out).to include("Bundle complete!") - - should_be_installed("rack 1.0.0") - plugin_should_be_installed("foo") - end - - it "accepts plugin version" do - update_repo2 do - build_plugin "foo", "1.1.0" - end - - install_gemfile <<-G - source 'file://#{gem_repo2}' - plugin 'foo', "1.0" - G - - bundle "install" - - expect(out).to include("Installing foo 1.0") - - plugin_should_be_installed("foo") - - expect(out).to include("Bundle complete!") - end - - it "accepts git sources" do - build_git "ga-plugin" do |s| - s.write "plugins.rb" - end - - install_gemfile <<-G - plugin 'ga-plugin', :git => "#{lib_path("ga-plugin-1.0")}" - G - - expect(out).to include("Installed plugin ga-plugin") - plugin_should_be_installed("ga-plugin") - end - end - - context "inline gemfiles" do - it "installs the listed plugins" do - code = <<-RUBY - require "bundler/inline" - - gemfile do - source 'file://#{gem_repo2}' - plugin 'foo' - end - RUBY - - ruby code - plugin_should_be_installed("foo") - end - end -end diff --git a/spec/plugins/install_spec.rb b/spec/plugins/install_spec.rb new file mode 100644 index 00000000..e0db0afa --- /dev/null +++ b/spec/plugins/install_spec.rb @@ -0,0 +1,159 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "bundler plugin install" do + before do + build_repo2 do + build_plugin "foo" + build_plugin "kung-foo" + end + end + + it "shows propper message when gem in not found in the source" do + bundle "plugin install no-foo --source file://#{gem_repo1}" + + expect(out).to include("Could not find") + plugin_should_not_be_installed("no-foo") + end + + it "installs from rubygems source" do + bundle "plugin install foo --source file://#{gem_repo2}" + + expect(out).to include("Installed plugin foo") + plugin_should_be_installed("foo") + end + + it "installs multiple plugins" do + bundle "plugin install foo kung-foo --source file://#{gem_repo2}" + + expect(out).to include("Installed plugin foo") + expect(out).to include("Installed plugin kung-foo") + + plugin_should_be_installed("foo", "kung-foo") + end + + it "uses the same version for multiple plugins" do + update_repo2 do + build_plugin "foo", "1.1" + build_plugin "kung-foo", "1.1" + end + + bundle "plugin install foo kung-foo --version '1.0' --source file://#{gem_repo2}" + + expect(out).to include("Installing foo 1.0") + expect(out).to include("Installing kung-foo 1.0") + plugin_should_be_installed("foo", "kung-foo") + end + + context "malformatted plugin" do + it "fails when plugins.rb is missing" do + build_repo2 do + build_gem "charlie" + end + + bundle "plugin install charlie --source file://#{gem_repo2}" + + expect(out).to include("plugins.rb was not found") + + expect(plugin_gems("charlie-1.0")).not_to be_directory + + plugin_should_not_be_installed("charlie") + end + + it "fails when plugins.rb throws exception on load" do + build_repo2 do + build_plugin "chaplin" do |s| + s.write "plugins.rb", <<-RUBY + raise "I got you man" + RUBY + end + end + + bundle "plugin install chaplin --source file://#{gem_repo2}" + + expect(plugin_gems("chaplin-1.0")).not_to be_directory + + plugin_should_not_be_installed("chaplin") + end + end + + context "git plugins" do + it "installs form a git source" do + build_git "foo" do |s| + s.write "plugins.rb" + end + + bundle "plugin install foo --git file://#{lib_path("foo-1.0")}" + + expect(out).to include("Installed plugin foo") + plugin_should_be_installed("foo") + end + end + + context "Gemfile eval" do + it "installs plugins listed in gemfile" do + gemfile <<-G + source 'file://#{gem_repo2}' + plugin 'foo' + gem 'rack', "1.0.0" + G + + bundle "install" + + expect(out).to include("Installed plugin foo") + + expect(out).to include("Bundle complete!") + + should_be_installed("rack 1.0.0") + plugin_should_be_installed("foo") + end + + it "accepts plugin version" do + update_repo2 do + build_plugin "foo", "1.1.0" + end + + install_gemfile <<-G + source 'file://#{gem_repo2}' + plugin 'foo', "1.0" + G + + bundle "install" + + expect(out).to include("Installing foo 1.0") + + plugin_should_be_installed("foo") + + expect(out).to include("Bundle complete!") + end + + it "accepts git sources" do + build_git "ga-plugin" do |s| + s.write "plugins.rb" + end + + install_gemfile <<-G + plugin 'ga-plugin', :git => "#{lib_path("ga-plugin-1.0")}" + G + + expect(out).to include("Installed plugin ga-plugin") + plugin_should_be_installed("ga-plugin") + end + end + + context "inline gemfiles" do + it "installs the listed plugins" do + code = <<-RUBY + require "bundler/inline" + + gemfile do + source 'file://#{gem_repo2}' + plugin 'foo' + end + RUBY + + ruby code + plugin_should_be_installed("foo") + end + end +end diff --git a/spec/plugins/source.rb b/spec/plugins/source.rb deleted file mode 100644 index a5217086..00000000 --- a/spec/plugins/source.rb +++ /dev/null @@ -1,87 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe "bundler source plugin" do - describe "plugins dsl eval for #source with :type option" do - before do - update_repo2 do - build_plugin "bundler-source-psource" do |s| - s.write "plugins.rb", <<-RUBY - class OPSource < Bundler::Plugin::API - source "psource" - end - RUBY - end - end - end - - it "installs bundler-source-* gem when no handler for source is present" do - install_gemfile <<-G - source "file://#{gem_repo2}" - source "file://#{lib_path("gitp")}", :type => :psource do - end - G - - plugin_should_be_installed("bundler-source-psource") - end - - context "with an explicit handler" do - before do - update_repo2 do - build_plugin "another-psource" do |s| - s.write "plugins.rb", <<-RUBY - class Cheater < Bundler::Plugin::API - source "psource" - end - RUBY - end - end - end - - context "installed though cli" do - before do - bundle "plugin install another-psource --source file://#{gem_repo2}" - - install_gemfile <<-G - source "file://#{gem_repo2}" - source "file://#{lib_path("gitp")}", :type => :psource do - end - G - end - - it "completes successfully" do - expect(out).to include("Bundle complete!") - end - - it "doesn't install the default one" do - plugin_should_not_be_installed("bundler-source-psource") - end - end - - context "explicit presence in gemfile" do - before do - install_gemfile <<-G - source "file://#{gem_repo2}" - - plugin "another-psource" - - source "file://#{lib_path("gitp")}", :type => :psource do - end - G - end - - it "completes successfully" do - expect(out).to include("Bundle complete!") - end - - it "installs the explicit one" do - plugin_should_be_installed("another-psource") - end - - it "doesn't install the default one" do - plugin_should_not_be_installed("bundler-source-psource") - end - end - end - end -end diff --git a/spec/plugins/source/example.rb b/spec/plugins/source/example.rb deleted file mode 100644 index 7817d8cc..00000000 --- a/spec/plugins/source/example.rb +++ /dev/null @@ -1,354 +0,0 @@ -# frozen_string_literal: true -require "spec_helper" - -describe "read source plugins" do - context "with a minimal source plugin" do - before do - build_repo2 do - build_plugin "bundler-source-mpath" do |s| - s.write "plugins.rb", <<-RUBY - require "fileutils" - - class MPath < Bundler::Plugin::API - source "mpath" - - attr_reader :path - - def initialize(opts) - super - - @path = Pathname.new options["uri"] - end - - def fetch_gemfiles - @gemfiles ||= begin - glob = "{,*,*/*}.gemspec" - if installed? - search_path = install_path - else - search_path = path - end - Dir["\#{search_path.to_s}/\#{glob}"] - end - end - - def install(spec, opts) - mkdir_p(install_path.parent) - FileUtils.cp_r(path, install_path) - - nil - end - end - RUBY - end # build_plugin - end - - build_lib "a-path-gem" - - gemfile <<-G - source "file://#{gem_repo2}" # plugin source - source "#{lib_path("a-path-gem-1.0")}", :type => :mpath do - gem "a-path-gem" - end - G - end - - it "installs" do - bundle "install" - - should_be_installed("a-path-gem 1.0") - end - - it "writes to lock file" do - bundle "install" - - lockfile_should_be <<-G - PLUGIN - remote: #{lib_path("a-path-gem-1.0")} - type: mpath - specs: - a-path-gem (1.0) - - GEM - remote: file:#{gem_repo2}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - a-path-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - context "with lockfile" do - before do - lockfile <<-G - PLUGIN - remote: #{lib_path("a-path-gem-1.0")} - type: mpath - specs: - a-path-gem (1.0) - - GEM - remote: file:#{gem_repo2}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - a-path-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "installs" do - bundle "install" - - should_be_installed("a-path-gem 1.0") - end - end - end - - context "with a more elaborate source plugin" do - before do - build_repo2 do - build_plugin "bundler-source-gitp" do |s| - s.write "plugins.rb", <<-RUBY - class SPlugin < Bundler::Plugin::API - source "gitp" - - attr_reader :ref - - def initialize(opts) - super - - @ref = options["ref"] || options["branch"] || options["tag"] || "master" - @unlocked = false - end - - def eql?(other) - other.is_a?(self.class) && uri == other.uri && ref == other.ref - end - - alias_method :==, :eql? - - def fetch_gemfiles - @gemfiles ||= begin - glob = "{,*,*/*}.gemspec" - if !cached? - cache_repo - end - - if installed? && !@unlocked - path = install_path - else - path = cache_path - end - - Dir["\#{path}/\#{glob}"] - end - end - - def install(spec, opts) - mkdir_p(install_path.dirname) - rm_rf(install_path) - `git clone --no-checkout --quiet "\#{cache_path}" "\#{install_path}"` - Dir.chdir install_path do - `git reset --hard \#{revision}` - end - - nil - end - - def options_to_lock - opts = {"revision" => revision} - opts["ref"] = ref if ref != "master" - opts - end - - def unlock! - @unlocked = true - @revision = latest_revision - end - - private - - def cache_path - @cache_path ||= cache.join("gitp", base_name) - end - - def cache_repo - `git clone --quiet \#{@options["uri"]} \#{cache_path}` - end - - def cached? - File.directory?(cache_path) - end - - def locked_revision - options["revision"] - end - - def revision - @revision ||= locked_revision || latest_revision - end - - def latest_revision - if !cached? || @unlocked - rm_rf(cache_path) - cache_repo - end - - Dir.chdir cache_path do - `git rev-parse --verify \#{@ref}`.strip - end - end - - def base_name - File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") - end - - def shortref_for_path(ref) - ref[0..12] - end - - def install_path - @install_path ||= begin - git_scope = "\#{base_name}-\#{shortref_for_path(revision)}" - - path = super.join(git_scope) - - if !path.exist? && requires_sudo? - user_bundle_path.join(ruby_scope).join(git_scope) - else - path - end - end - end - - def installed? - File.directory?(install_path) - end - end - RUBY - end - end - - build_git "ma-gitp-gem" - - gemfile <<-G - source "file://#{gem_repo2}" # plugin source - source "file://#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do - gem "ma-gitp-gem" - end - G - end - - it "handles the source option" do - bundle "install" - expect(out).to include("Bundle complete!") - should_be_installed("ma-gitp-gem 1.0") - end - - it "writes to lock file" do - revision = revision_for(lib_path("ma-gitp-gem-1.0")) - bundle "install" - - lockfile_should_be <<-G - PLUGIN - remote: file://#{lib_path("ma-gitp-gem-1.0")} - type: gitp - revision: #{revision} - specs: - ma-gitp-gem (1.0) - - GEM - remote: file:#{gem_repo2}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - ma-gitp-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - context "with lockfile" do - before do - revision = revision_for(lib_path("ma-gitp-gem-1.0")) - lockfile <<-G - PLUGIN - remote: file://#{lib_path("ma-gitp-gem-1.0")} - type: gitp - revision: #{revision} - specs: - ma-gitp-gem (1.0) - - GEM - remote: file:#{gem_repo2}/ - specs: - - PLATFORMS - #{generic_local_platform} - - DEPENDENCIES - ma-gitp-gem! - - BUNDLED WITH - #{Bundler::VERSION} - G - end - - it "installs" do - bundle "install" - should_be_installed("ma-gitp-gem 1.0") - end - - it "uses the locked ref" do - update_git "ma-gitp-gem" - bundle "install" - - run <<-RUBY - require 'ma-gitp-gem' - puts "WIN" unless defined?(MAGITPGEM_PREV_REF) - RUBY - expect(out).to eq("WIN") - end - - it "updates the deps on bundler update" do - update_git "ma-gitp-gem" - bundle "update ma-gitp-gem" - - run <<-RUBY - require 'ma-gitp-gem' - puts "WIN" if defined?(MAGITPGEM_PREV_REF) - RUBY - expect(out).to eq("WIN") - end - - it "updates the deps on change in gemfile" do - update_git "ma-gitp-gem", "1.1", :path => lib_path("ma-gitp-gem-1.0"), :gemspec => true - gemfile <<-G - source "file://#{gem_repo2}" # plugin source - source "file://#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do - gem "ma-gitp-gem", "1.1" - end - G - bundle "install" - - should_be_installed("ma-gitp-gem 1.1") - end - end - end -end diff --git a/spec/plugins/source/example_spec.rb b/spec/plugins/source/example_spec.rb new file mode 100644 index 00000000..15671f67 --- /dev/null +++ b/spec/plugins/source/example_spec.rb @@ -0,0 +1,354 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "real source plugins" do + context "with a minimal source plugin" do + before do + build_repo2 do + build_plugin "bundler-source-mpath" do |s| + s.write "plugins.rb", <<-RUBY + require "fileutils" + + class MPath < Bundler::Plugin::API + source "mpath" + + attr_reader :path + + def initialize(opts) + super + + @path = Pathname.new options["uri"] + end + + def fetch_gemspec_files + @spec_files ||= begin + glob = "{,*,*/*}.gemspec" + if installed? + search_path = install_path + else + search_path = path + end + Dir["\#{search_path.to_s}/\#{glob}"] + end + end + + def install(spec, opts) + mkdir_p(install_path.parent) + FileUtils.cp_r(path, install_path) + + nil + end + end + RUBY + end # build_plugin + end + + build_lib "a-path-gem" + + gemfile <<-G + source "file://#{gem_repo2}" # plugin source + source "#{lib_path("a-path-gem-1.0")}", :type => :mpath do + gem "a-path-gem" + end + G + end + + it "installs" do + bundle "install" + + should_be_installed("a-path-gem 1.0") + end + + it "writes to lock file" do + bundle "install" + + lockfile_should_be <<-G + PLUGIN SOURCE + remote: #{lib_path("a-path-gem-1.0")} + type: mpath + specs: + a-path-gem (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + a-path-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + context "with lockfile" do + before do + lockfile <<-G + PLUGIN SOURCE + remote: #{lib_path("a-path-gem-1.0")} + type: mpath + specs: + a-path-gem (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + a-path-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "installs" do + bundle "install" + + should_be_installed("a-path-gem 1.0") + end + end + end + + context "with a more elaborate source plugin" do + before do + build_repo2 do + build_plugin "bundler-source-gitp" do |s| + s.write "plugins.rb", <<-RUBY + class SPlugin < Bundler::Plugin::API + source "gitp" + + attr_reader :ref + + def initialize(opts) + super + + @ref = options["ref"] || options["branch"] || options["tag"] || "master" + @unlocked = false + end + + def eql?(other) + other.is_a?(self.class) && uri == other.uri && ref == other.ref + end + + alias_method :==, :eql? + + def fetch_gemspec_files + @spec_files ||= begin + glob = "{,*,*/*}.gemspec" + if !cached? + cache_repo + end + + if installed? && !@unlocked + path = install_path + else + path = cache_path + end + + Dir["\#{path}/\#{glob}"] + end + end + + def install(spec, opts) + mkdir_p(install_path.dirname) + rm_rf(install_path) + `git clone --no-checkout --quiet "\#{cache_path}" "\#{install_path}"` + Dir.chdir install_path do + `git reset --hard \#{revision}` + end + + nil + end + + def options_to_lock + opts = {"revision" => revision} + opts["ref"] = ref if ref != "master" + opts + end + + def unlock! + @unlocked = true + @revision = latest_revision + end + + private + + def cache_path + @cache_path ||= cache.join("gitp", base_name) + end + + def cache_repo + `git clone --quiet \#{@options["uri"]} \#{cache_path}` + end + + def cached? + File.directory?(cache_path) + end + + def locked_revision + options["revision"] + end + + def revision + @revision ||= locked_revision || latest_revision + end + + def latest_revision + if !cached? || @unlocked + rm_rf(cache_path) + cache_repo + end + + Dir.chdir cache_path do + `git rev-parse --verify \#{@ref}`.strip + end + end + + def base_name + File.basename(uri.sub(%r{^(\w+://)?([^/:]+:)?(//\w*/)?(\w*/)*}, ""), ".git") + end + + def shortref_for_path(ref) + ref[0..12] + end + + def install_path + @install_path ||= begin + git_scope = "\#{base_name}-\#{shortref_for_path(revision)}" + + path = super.join(git_scope) + + if !path.exist? && requires_sudo? + user_bundle_path.join(ruby_scope).join(git_scope) + else + path + end + end + end + + def installed? + File.directory?(install_path) + end + end + RUBY + end + end + + build_git "ma-gitp-gem" + + gemfile <<-G + source "file://#{gem_repo2}" # plugin source + source "file://#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do + gem "ma-gitp-gem" + end + G + end + + it "handles the source option" do + bundle "install" + expect(out).to include("Bundle complete!") + should_be_installed("ma-gitp-gem 1.0") + end + + it "writes to lock file" do + revision = revision_for(lib_path("ma-gitp-gem-1.0")) + bundle "install" + + lockfile_should_be <<-G + PLUGIN SOURCE + remote: file://#{lib_path("ma-gitp-gem-1.0")} + type: gitp + revision: #{revision} + specs: + ma-gitp-gem (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + ma-gitp-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + context "with lockfile" do + before do + revision = revision_for(lib_path("ma-gitp-gem-1.0")) + lockfile <<-G + PLUGIN SOURCE + remote: file://#{lib_path("ma-gitp-gem-1.0")} + type: gitp + revision: #{revision} + specs: + ma-gitp-gem (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + ma-gitp-gem! + + BUNDLED WITH + #{Bundler::VERSION} + G + end + + it "installs" do + bundle "install" + should_be_installed("ma-gitp-gem 1.0") + end + + it "uses the locked ref" do + update_git "ma-gitp-gem" + bundle "install" + + run <<-RUBY + require 'ma-gitp-gem' + puts "WIN" unless defined?(MAGITPGEM_PREV_REF) + RUBY + expect(out).to eq("WIN") + end + + it "updates the deps on bundler update" do + update_git "ma-gitp-gem" + bundle "update ma-gitp-gem" + + run <<-RUBY + require 'ma-gitp-gem' + puts "WIN" if defined?(MAGITPGEM_PREV_REF) + RUBY + expect(out).to eq("WIN") + end + + it "updates the deps on change in gemfile" do + update_git "ma-gitp-gem", "1.1", :path => lib_path("ma-gitp-gem-1.0"), :gemspec => true + gemfile <<-G + source "file://#{gem_repo2}" # plugin source + source "file://#{lib_path("ma-gitp-gem-1.0")}", :type => :gitp do + gem "ma-gitp-gem", "1.1" + end + G + bundle "install" + + should_be_installed("ma-gitp-gem 1.1") + end + end + end +end diff --git a/spec/plugins/source_spec.rb b/spec/plugins/source_spec.rb new file mode 100644 index 00000000..a5217086 --- /dev/null +++ b/spec/plugins/source_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true +require "spec_helper" + +describe "bundler source plugin" do + describe "plugins dsl eval for #source with :type option" do + before do + update_repo2 do + build_plugin "bundler-source-psource" do |s| + s.write "plugins.rb", <<-RUBY + class OPSource < Bundler::Plugin::API + source "psource" + end + RUBY + end + end + end + + it "installs bundler-source-* gem when no handler for source is present" do + install_gemfile <<-G + source "file://#{gem_repo2}" + source "file://#{lib_path("gitp")}", :type => :psource do + end + G + + plugin_should_be_installed("bundler-source-psource") + end + + context "with an explicit handler" do + before do + update_repo2 do + build_plugin "another-psource" do |s| + s.write "plugins.rb", <<-RUBY + class Cheater < Bundler::Plugin::API + source "psource" + end + RUBY + end + end + end + + context "installed though cli" do + before do + bundle "plugin install another-psource --source file://#{gem_repo2}" + + install_gemfile <<-G + source "file://#{gem_repo2}" + source "file://#{lib_path("gitp")}", :type => :psource do + end + G + end + + it "completes successfully" do + expect(out).to include("Bundle complete!") + end + + it "doesn't install the default one" do + plugin_should_not_be_installed("bundler-source-psource") + end + end + + context "explicit presence in gemfile" do + before do + install_gemfile <<-G + source "file://#{gem_repo2}" + + plugin "another-psource" + + source "file://#{lib_path("gitp")}", :type => :psource do + end + G + end + + it "completes successfully" do + expect(out).to include("Bundle complete!") + end + + it "installs the explicit one" do + plugin_should_be_installed("another-psource") + end + + it "doesn't install the default one" do + plugin_should_not_be_installed("bundler-source-psource") + end + end + end + end +end -- cgit v1.2.3