diff --git a/.gitignore b/.gitignore index ff0bb19..03296aa 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ /coverage /.DS_Store + +/Gemfile.plugins diff --git a/Gemfile b/Gemfile index eef1be7..6105d88 100644 --- a/Gemfile +++ b/Gemfile @@ -13,3 +13,5 @@ group :development, :test do gem "capybara", "~> 2.2.1" gem "simplecov", "~> 0.7.1", require: false end + +eval File.read "Gemfile.plugins" if File.exist?("Gemfile.plugins") diff --git a/Gemfile.lock b/Gemfile.lock index c8bb041..06aa5fe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -46,6 +46,7 @@ GEM tzinfo (~> 1.1) arel (5.0.1.20140414130214) bcrypt (3.1.7) + bson (1.10.0) builder (3.2.2) capybara (2.2.1) mime-types (>= 1.16) @@ -73,6 +74,9 @@ GEM factory_girl_rails (4.4.1) factory_girl (~> 4.4.0) railties (>= 3.0.0) + fluent-plugin-mongo (0.7.3) + fluentd (~> 0.10.9) + mongo (>= 1.8.0) fluentd (0.10.46) cool.io (>= 1.1.1, < 2.0.0, != 1.2.0) http_parser.rb (>= 0.5.1, < 0.7.0) @@ -118,6 +122,8 @@ GEM mime-types (1.25.1) mini_portile (0.5.3) minitest (5.3.3) + mongo (1.10.0) + bson (~> 1.10.0) msgpack (0.5.8) multi_json (1.10.0) net-http-digest_auth (1.4) @@ -209,6 +215,7 @@ DEPENDENCIES capybara (~> 2.2.1) database_cleaner (~> 1.2.0) factory_girl_rails + fluent-plugin-mongo (= 0.7.3) fluentd-ui! pry rake diff --git a/Gemfile.production b/Gemfile.production index fa75df1..30f7ea5 100644 --- a/Gemfile.production +++ b/Gemfile.production @@ -1,3 +1,5 @@ source 'https://rubygems.org' gemspec + +eval File.read "Gemfile.plugins" if File.exist?("Gemfile.plugins") diff --git a/app/controllers/plugins_controller.rb b/app/controllers/plugins_controller.rb new file mode 100644 index 0000000..53f9b0d --- /dev/null +++ b/app/controllers/plugins_controller.rb @@ -0,0 +1,32 @@ +class PluginsController < ApplicationController + before_action :find_plugin, except: [:index] + + def index + @plugins = plugins + end + + def install + @plugin.install! + redirect_to plugins_path + end + + def uninstall + @plugin.uninstall! + redirect_to plugins_path + end + + private + + def plugins + # TODO + [ + Plugin.new(gem_name: "fluent-plugin-mongo", version: "0.7.3") + ] + end + + def find_plugin + @plugin ||= plugins.find do |plugin| + plugin.to_param == params[:plugin_id] + end + end +end diff --git a/app/helpers/plugins_helper.rb b/app/helpers/plugins_helper.rb new file mode 100644 index 0000000..75f3122 --- /dev/null +++ b/app/helpers/plugins_helper.rb @@ -0,0 +1,2 @@ +module PluginsHelper +end diff --git a/app/models/plugin.rb b/app/models/plugin.rb new file mode 100644 index 0000000..71dc29b --- /dev/null +++ b/app/models/plugin.rb @@ -0,0 +1,80 @@ +require "fileutils" + +class Plugin + class GemError < StandardError; end + + GEMFILE_PLUGIN = Rails.root + "Gemfile.plugins" + unless File.exists?(GEMFILE_PLUGIN) + File.open(GEMFILE_PLUGIN, "w") do |f| + f.write "# USED BY fluentd-ui internally" + end + end + + include ActiveModel::Model + + attr_accessor :gem_name, :version + validates :gem_name, presence: true + validates :version, presence: true + + def to_param + gem_name + end + + def install! + if valid? && !installed? + if fluent_gem("install", gem_name, "-v", version) + File.open(GEMFILE_PLUGIN, "a") do |f| + f.puts format_gemfile + end + self.class.gemfile_updated! + end + end + end + + def uninstall! + if valid? && installed? + # NOTE: do not uninstall gem actually for now. because it is not necessary, and slow job + new_gemfile = "" + File.open(GEMFILE_PLUGIN).each_line do |line| + next if line.strip == format_gemfile + new_gemfile << line + end + File.open(GEMFILE_PLUGIN, "w"){|f| f.write new_gemfile } + self.class.gemfile_updated! + end + end + + def upgrade!(new_version) + if installed? + upgrade = new(gem_name: self.gem_name, version: new_version) + if self.valid? && upgrade.valid? + self.uninstall! + upgrade.install! + end + end + end + + def installed? + File.read(GEMFILE_PLUGIN).lines.map(&:strip).grep(format_gemfile).present? + end + + def format_gemfile + %Q|gem "#{gem_name}", "#{version}"| + end + + def fluent_gem(*commands) + unless system(*%W(bundle exec gem) + commands) # TODO: should grab stdout/stderr + raise GemError, "failed command #{commands}" + end + true + end + + def self.gemfile_changed? + # if true, rails server needs to restart + @gemfile_changed + end + + def self.gemfile_updated! + @gemfile_changed = true + end +end diff --git a/app/views/plugins/index.html.haml b/app/views/plugins/index.html.haml new file mode 100644 index 0000000..a4d6873 --- /dev/null +++ b/app/views/plugins/index.html.haml @@ -0,0 +1,7 @@ +- @plugins.each do |plugin| + / TODO: + = plugin.gem_name + = plugin.version + = "(#{plugin.installed? ? t("terms.installed") : t("terms.not_installed")})" + = link_to t("terms.install"), plugin_install_path(plugin), method: :put + = link_to t("terms.uninstall"), plugin_uninstall_path(plugin), method: :put diff --git a/config/locales/translation_en.yml b/config/locales/translation_en.yml index 0663aae..2cb5523 100644 --- a/config/locales/translation_en.yml +++ b/config/locales/translation_en.yml @@ -2,6 +2,11 @@ en: terms: sign_in: Sign in sign_out: Sign out + install: Install + uninstall: Uninstall + upgrade: Upgrade + installed: Installed + not_installed: Not Installed error: login_failed: Login failed. diff --git a/config/locales/translation_ja.yml b/config/locales/translation_ja.yml index 81cc318..47fd109 100644 --- a/config/locales/translation_ja.yml +++ b/config/locales/translation_ja.yml @@ -2,6 +2,11 @@ ja: terms: sign_in: ログイン sign_out: ログアウト + install: インストール + uninstall: アンインストール + upgrade: アップグレード + installed: インストール済み + not_installed: 未インストール error: login_failed: ログインに失敗しました。 diff --git a/config/routes.rb b/config/routes.rb index a1e7b36..2314209 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,12 @@ Rails.application.routes.draw do resources :users resource :sessions + resources :plugins do + put :install + put :uninstall + end + + resources :misc, only: [] do end # The priority is based upon order of creation: first created -> highest priority. diff --git a/spec/controllers/plugins_controller_spec.rb b/spec/controllers/plugins_controller_spec.rb new file mode 100644 index 0000000..0ec233a --- /dev/null +++ b/spec/controllers/plugins_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe PluginsController do + +end diff --git a/spec/factories/plugins.rb b/spec/factories/plugins.rb new file mode 100644 index 0000000..a0bb630 --- /dev/null +++ b/spec/factories/plugins.rb @@ -0,0 +1,6 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :plugin do + end +end diff --git a/spec/helpers/plugins_helper_spec.rb b/spec/helpers/plugins_helper_spec.rb new file mode 100644 index 0000000..82c1c7c --- /dev/null +++ b/spec/helpers/plugins_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the PluginsHelper. For example: +# +# describe PluginsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +describe PluginsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/plugin_spec.rb b/spec/models/plugin_spec.rb new file mode 100644 index 0000000..546d7fb --- /dev/null +++ b/spec/models/plugin_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Plugin do + pending "add some examples to (or delete) #{__FILE__}" +end