diff options
Diffstat (limited to 'lib/bundler/plugin/index.rb')
| -rw-r--r-- | lib/bundler/plugin/index.rb | 112 |
1 files changed, 98 insertions, 14 deletions
diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb index 8dde072f16..1dfb061304 100644 --- a/lib/bundler/plugin/index.rb +++ b/lib/bundler/plugin/index.rb @@ -29,7 +29,16 @@ module Bundler @hooks = {} @load_paths = {} - load_index(global_index_file, true) + begin + load_index(global_index_file, true) + rescue PermissionError + # no need to fail when on a read-only FS, for example + nil + rescue ArgumentError => e + # ruby 3.4 checks writability in Dir.tmpdir + raise unless e.message&.include?("could not find a temporary directory") + nil + end load_index(local_index_file) if SharedHelpers.in_bundle? end @@ -53,16 +62,31 @@ module Bundler raise SourceConflict.new(name, common) unless common.empty? sources.each {|k| @sources[k] = name } - hooks.each {|e| (@hooks[e] ||= []) << name } + hooks.each do |event| + event_hooks = (@hooks[event] ||= []) << name + event_hooks.uniq! + end @plugin_paths[name] = path @load_paths[name] = load_paths save_index - rescue + rescue StandardError @commands = old_commands raise end + def unregister_plugin(name) + @commands.delete_if {|_, v| v == name } + @sources.delete_if {|_, v| v == name } + @hooks.each do |hook, names| + names.delete(name) + @hooks.delete(hook) if names.empty? + end + @plugin_paths.delete(name) + @load_paths.delete(name) + save_index + end + # Path of default index file def index_file Plugin.root.join("index") @@ -95,6 +119,20 @@ module Bundler @plugin_paths[name] end + def up_to_date?(spec) + path = installed?(spec.name) + + path == spec.full_gem_path + end + + def installed_plugins + @plugin_paths.keys + end + + def plugin_commands(plugin) + @commands.find_all {|_, n| n == plugin }.map(&:first) + end + def source?(source) @sources.key? source end @@ -108,7 +146,15 @@ module Bundler @hooks[event] || [] end - private + # This plugin is installed inside the .bundle/plugin directory, + # and thus is managed solely by Bundler + def installed_in_plugin_root?(name) + return false unless (path = installed?(name)) + + path.start_with?("#{Plugin.root}/") + end + + private # Reads the index file from the directory and initializes the instance # variables. @@ -117,19 +163,21 @@ module Bundler # @param [Pathname] index file path # @param [Boolean] is the index file global index def load_index(index_file, global = false) + base = base_for_index(global) + SharedHelpers.filesystem_access(index_file, :read) do |index_f| - valid_file = index_f && index_f.exist? && !index_f.size.zero? + valid_file = index_f&.exist? && !index_f.size.zero? break unless valid_file data = index_f.read - require "bundler/yaml_serializer" + require_relative "../yaml_serializer" index = YAMLSerializer.load(data) @commands.merge!(index["commands"]) @hooks.merge!(index["hooks"]) - @load_paths.merge!(index["load_paths"]) - @plugin_paths.merge!(index["plugin_paths"]) + @load_paths.merge!(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) }) + @plugin_paths.merge!(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) }) @sources.merge!(index["sources"]) unless global end end @@ -138,20 +186,56 @@ module Bundler # instance variables in YAML format. (The instance variables are supposed # to be only String key value pairs) def save_index + base = base_for_index(false) + index = { - "commands" => @commands, - "hooks" => @hooks, - "load_paths" => @load_paths, - "plugin_paths" => @plugin_paths, - "sources" => @sources, + "commands" => @commands, + "hooks" => @hooks, + "load_paths" => transform_index_paths(@load_paths) {|p| relativize_path(p, base) }, + "plugin_paths" => transform_index_paths(@plugin_paths) {|p| relativize_path(p, base) }, + "sources" => @sources, } - require "bundler/yaml_serializer" + require_relative "../yaml_serializer" SharedHelpers.filesystem_access(index_file) do |index_f| FileUtils.mkdir_p(index_f.dirname) File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) } end end + + def base_for_index(global) + global ? Plugin.global_root : Plugin.root + end + + def transform_index_paths(paths) + return {} unless paths + + paths.transform_values do |value| + if value.is_a?(Array) + value.map {|path| yield path } + else + yield value + end + end + end + + def relativize_path(path, base) + pathname = Pathname.new(path) + return path unless pathname.absolute? + + base_path = Pathname.new(base) + if pathname == base_path || pathname.to_s.start_with?(base_path.to_s + File::SEPARATOR) + pathname.relative_path_from(base_path).to_s + else + path + end + end + + def absolutize_path(path, base) + pathname = Pathname.new(path) + pathname = Pathname.new(base).join(pathname) unless pathname.absolute? + pathname.to_s + end end end end |
