lib/kpm/plugins_manager.rb



require 'pathname'

module KPM
  class PluginsManager

    def initialize(plugins_dir, logger)
      @plugins_dir = Pathname.new(plugins_dir)
      @logger = logger
    end

    def set_active(plugin_name_or_path, plugin_version=nil)
      if plugin_name_or_path.nil?
        @logger.warn('Unable to mark a plugin as active: no name or path specified')
        return
      end

      if plugin_version.nil?
        # Full path specified, with version
        link = Pathname.new(plugin_name_or_path).join('../ACTIVE')
        FileUtils.rm_f(link)
        FileUtils.ln_s(plugin_name_or_path, link, :force => true)
      else
        # Plugin name (fs directory) specified
        plugin_dir_glob = @plugins_dir.join('*').join(plugin_name_or_path)
        # Only one should match (java or ruby plugin)
        Dir.glob(plugin_dir_glob).each do |plugin_dir_path|
          plugin_dir = Pathname.new(plugin_dir_path)
          link = plugin_dir.join('ACTIVE')
          FileUtils.rm_f(link)
          FileUtils.ln_s(plugin_dir.join(plugin_version), link, :force => true)
        end
      end

      update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
        FileUtils.rm_f(tmp_dir.join('stop.txt'))
        FileUtils.rm_f(tmp_dir.join('restart.txt'))
      end
    end

    def uninstall(plugin_name_or_path, plugin_version=nil)
      update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
        FileUtils.rm_f(tmp_dir.join('restart.txt'))
        # Be safe, keep the code, just never start it
        FileUtils.touch(tmp_dir.join('stop.txt'))
      end
    end

    def restart(plugin_name_or_path, plugin_version=nil)
      update_fs(plugin_name_or_path, plugin_version) do |tmp_dir|
        # Remove stop.txt so that the plugin is started if it was stopped
        FileUtils.rm_f(tmp_dir.join('stop.txt'))
        FileUtils.touch(tmp_dir.join('restart.txt'))
      end
    end

    def guess_plugin_name(artifact_id)
      return nil if artifact_id.nil?
      captures = artifact_id.scan(/(.*)-plugin/)
      if captures.empty? || captures.first.nil? || captures.first.first.nil?
        short_name = artifact_id
      else
        # 'analytics-plugin' or 'stripe-plugin' passed
        short_name = captures.first.first
      end
      Dir.glob(@plugins_dir.join('*').join('*')).each do |plugin_path|
        plugin_name = File.basename(plugin_path)
        if plugin_name == short_name ||
            plugin_name == artifact_id ||
            !plugin_name.scan(/-#{short_name}/).empty? ||
            !plugin_name.scan(/#{short_name}-/).empty?
          return plugin_name
        end
      end
      nil
    end

    private

    # Note: the plugin name here is the directory name on the filesystem
    def update_fs(plugin_name_or_path, plugin_version=nil, &block)
      if plugin_name_or_path.nil?
        @logger.warn('Unable to update the filesystem: no name or path specified')
        return
      end

      p = plugin_version.nil? ? plugin_name_or_path : @plugins_dir.join('*').join(plugin_name_or_path).join(plugin_version == :all ? '*' : plugin_version)

      modified = []
      Dir.glob(p).each do |plugin_dir_path|
        plugin_dir = Pathname.new(plugin_dir_path)
        tmp_dir = plugin_dir.join('tmp')
        FileUtils.mkdir_p(tmp_dir)

        yield(tmp_dir) if block_given?

        modified << plugin_dir
      end

      if modified.empty?
        if plugin_version.nil?
          @logger.warn("No plugin found with name #{plugin_name_or_path}. Installed plugins: #{Dir.glob(@plugins_dir.join('*').join('*'))}")
        else
          @logger.warn("No plugin found with name #{plugin_name_or_path} and version #{plugin_version}. Installed plugins: #{Dir.glob(@plugins_dir.join('*').join('*').join('*'))}")
        end
      end

      modified
    end
  end
end