aboutsummaryrefslogtreecommitdiffstats
path: root/lib/bundler/plugin/index.rb
blob: a10b023f4b6cbf4c891dc3770f786ef10c216f57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# frozen_string_literal: true

module Bundler
  # Manages which plugins are installed and their sources. This also is supposed to map
  # which plugin does what (currently the features are not implemented so this class is
  # now a stub class).
  module Plugin
    class Index
      class CommandConflict < PluginError
        def initialize(plugin, commands)
          msg = "Command(s) `#{commands.join("`, `")}` declared by #{plugin} are already registered."
          super msg
        end
      end

      def initialize
        @plugin_paths = {}
        @commands = {}

        load_index
      end

      # This function is to be called when a new plugin is installed. This function shall add
      # the functions of the plugin to existing maps and also the name to source location.
      #
      # @param [String] name of the plugin to be registered
      # @param [String] path where the plugin is installed
      # @param [Array<String>] commands that are handled by the plugin
      def register_plugin(name, path, commands)
        @plugin_paths[name] = path

        common = commands & @commands.keys
        raise CommandConflict.new(name, common) unless common.empty?
        commands.each {|c| @commands[c] = name }

        save_index
      end

      # Path where the index file is stored
      def index_file
        Plugin.root.join("index")
      end

      def plugin_path(name)
        Pathname.new @plugin_paths[name]
      end

      # Fetch the name of plugin handling the command
      def command_plugin(command)
        @commands[command]
      end

    private

      # Reads the index file from the directory and initializes the instance variables.
      def load_index
        SharedHelpers.filesystem_access(index_file, :read) do |index_f|
          valid_file = index_f && index_f.exist? && !index_f.size.zero?
          break unless valid_file
          data = index_f.read
          require "bundler/yaml_serializer"
          index = YAMLSerializer.load(data)
          @plugin_paths = index["plugin_paths"] || {}
          @commands = index["commands"] || {}
        end
      end

      # Should be called when any of the instance variables change. Stores the instance
      # variables in YAML format. (The instance variables are supposed to be only String key value pairs)
      def save_index
        index = {
          "plugin_paths" => @plugin_paths,
          "commands" => @commands,
        }

        require "bundler/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
    end
  end
end