diff --git a/exe/fusuma b/exe/fusuma index f52391e..9665288 100755 --- a/exe/fusuma +++ b/exe/fusuma @@ -27,6 +27,10 @@ opt.on('--log=path/to/file', option[:log_filepath] = v end +opt.on('--show-config', 'Show config as YAML format which is loaded internally') do |v| + option[:show_config] = v +end + opt.on('--device="Device name"', 'Open the given device only (DEPRECATED)') do |v| option[:device] = v diff --git a/lib/fusuma.rb b/lib/fusuma.rb index da3f281..31d5ff9 100644 --- a/lib/fusuma.rb +++ b/lib/fusuma.rb @@ -27,13 +27,18 @@ def read_options(option) MultiLogger.filepath = option[:log_filepath] MultiLogger.instance.debug_mode = option[:verbose] - load_custom_config(option[:config_path]) - Plugin::Manager.require_base_plugins + load_custom_config(option[:config_path]) + Environment.dump_information Kernel.exit(0) if option[:version] + if option[:show_config] + Environment.print_config + Kernel.exit(0) + end + if option[:list] Environment.print_device_list Kernel.exit(0) diff --git a/lib/fusuma/config.rb b/lib/fusuma/config.rb index 5057b7f..8c6bdb0 100644 --- a/lib/fusuma/config.rb +++ b/lib/fusuma/config.rb @@ -46,16 +46,46 @@ def custom_path=(new_path) end def reload + plugin_defaults = { + context: :plugin_defaults, + plugin: {} + } + + plugin_defaults_paths.each do |default_yml| + plugin_defaults.deep_merge!(validate(default_yml)[0]) + end + + find_config_filepath.tap do |path| + MultiLogger.info "reload config: #{path}" + + @keymap = validate(path).tap do |yamls| + yamls << plugin_defaults + end + end + + # reset searcher cache @searcher = Searcher.new - path = find_filepath - MultiLogger.info "reload config: #{path}" - @keymap = validate(path) + self rescue InvalidFileError => e MultiLogger.error e.message exit 1 end + # @param key [Symbol] + # @param base [Config::Index] + # @return [Hash] + def fetch_config_params(key, base) + [{}, :plugin_defaults].find do |context| + ret = Config::Searcher.with_context(context) do + Config.search(base) + end + if ret&.key?(key) + return ret + end + end || {} + end + # @return [Hash] If check passes # @raise [InvalidFileError] If check does not pass def validate(path) @@ -75,7 +105,6 @@ def validate(path) end # @param index [Index] - # @param context [Hash] def search(index) @searcher.search_with_cache(index, location: keymap) end @@ -95,7 +124,7 @@ def find_execute_key(index) private - def find_filepath + def find_config_filepath filename = "fusuma/config.yml" if custom_path return expand_custom_path if File.exist?(expand_custom_path) @@ -120,5 +149,12 @@ def expand_config_path(filename) def expand_default_path(filename) File.expand_path "../../#{filename}", __FILE__ end + + def plugin_defaults_paths + Plugin::Manager.load_paths.map do |plugin_path| + yml = plugin_path.gsub(/\.rb$/, ".yml") + yml if File.exist?(yml) + end.compact + end end end diff --git a/lib/fusuma/config/searcher.rb b/lib/fusuma/config/searcher.rb index 5e6da64..1b2fd5f 100644 --- a/lib/fusuma/config/searcher.rb +++ b/lib/fusuma/config/searcher.rb @@ -111,7 +111,6 @@ def find_context(request_context, &block) end attr_reader :context - end end end diff --git a/lib/fusuma/environment.rb b/lib/fusuma/environment.rb index 9957e76..94127a1 100644 --- a/lib/fusuma/environment.rb +++ b/lib/fusuma/environment.rb @@ -39,6 +39,12 @@ def print_device_list puts device.name end end + + def print_config + Config.instance.keymap.each do |conf| + puts conf.deep_stringify_keys.to_yaml + end + end end end end diff --git a/lib/fusuma/hash_support.rb b/lib/fusuma/hash_support.rb index 0a7c49f..ae3edca 100644 --- a/lib/fusuma/hash_support.rb +++ b/lib/fusuma/hash_support.rb @@ -2,6 +2,28 @@ # Patch to hash class Hash + # activesupport-5.2.0/lib/active_support/core_ext/hash/deep_merge.rb + def deep_merge(other_hash, &block) + dup.deep_merge!(other_hash, &block) + end + + # Same as +deep_merge+, but modifies +self+. + def deep_merge!(other_hash, &block) + merge!(other_hash) do |key, this_val, other_val| + if this_val.is_a?(Hash) && other_val.is_a?(Hash) + this_val.deep_merge(other_val, &block) + elsif block + block.call(key, this_val, other_val) + else + other_val + end + end + end + + def deep_stringify_keys + deep_transform_keys(&:to_s) + end + # activesupport-4.1.1/lib/active_support/core_ext/hash/keys.rb def deep_symbolize_keys deep_transform_keys do |key| diff --git a/lib/fusuma/plugin/base.rb b/lib/fusuma/plugin/base.rb index 1fcb819..b041404 100644 --- a/lib/fusuma/plugin/base.rb +++ b/lib/fusuma/plugin/base.rb @@ -31,14 +31,20 @@ def config_param_types raise NotImplementedError, "override #{self.class.name}##{__method__}" end + # @param key [Symbol] + # @param base [Config::Index] # @return [Object] - def config_params(key = nil, base: config_index) - params = Config.search(base) || {} + def config_params(key = nil) + @config_params ||= {} + if @config_params["#{config_index.cache_key},#{key}"] + return @config_params["#{config_index.cache_key},#{key}"] + end + + params = Config.instance.fetch_config_params(key, config_index) return params unless key - @config_params ||= {} - @config_params["#{base.cache_key},#{key}"] ||= + @config_params["#{config_index.cache_key},#{key}"] = params.fetch(key, nil).tap do |val| next if val.nil? @@ -55,7 +61,7 @@ def config_params(key = nil, base: config_index) end def config_index - Config::Index.new(self.class.name.gsub("Fusuma::", "").underscore.split("/")) + @config_index ||= Config::Index.new(self.class.name.gsub("Fusuma::", "").underscore.split("/")) end end end diff --git a/lib/fusuma/plugin/inputs/libinput_command_input.yml b/lib/fusuma/plugin/inputs/libinput_command_input.yml new file mode 100644 index 0000000..87da0fa --- /dev/null +++ b/lib/fusuma/plugin/inputs/libinput_command_input.yml @@ -0,0 +1,3 @@ +plugin: + inputs: + libinput_command_input: diff --git a/lib/fusuma/plugin/manager.rb b/lib/fusuma/plugin/manager.rb index d6388a3..6f8d505 100644 --- a/lib/fusuma/plugin/manager.rb +++ b/lib/fusuma/plugin/manager.rb @@ -115,6 +115,12 @@ def plugins @plugins ||= {} end + # @return [Array] + # @example + # Manager.load_paths + # => ["/path/to/fusuma/lib/fusuma/plugin/inputs/input.rb", + # "/path/to/fusuma/lib/fusuma/plugin/inputs/libinput_command_input.rb", + # "/path/to/fusuma/lib/fusuma/plugin/inputs/timer_input.rb"] def load_paths @load_paths ||= [] end diff --git a/spec/fusuma/config/searcher_spec.rb b/spec/fusuma/config/searcher_spec.rb index 741e355..20f3aff 100644 --- a/spec/fusuma/config/searcher_spec.rb +++ b/spec/fusuma/config/searcher_spec.rb @@ -57,7 +57,7 @@ module Fusuma ] end it "detects ctrl+minus with skip" do - value = Config::Searcher.new.search(index, location: location) + value = Config::Searcher.new.search(index, location: location) expect(value).to eq("ctrl+minus") end end diff --git a/spec/fusuma/plugin/buffers/buffer_spec.rb b/spec/fusuma/plugin/buffers/buffer_spec.rb index 1d16868..1656759 100644 --- a/spec/fusuma/plugin/buffers/buffer_spec.rb +++ b/spec/fusuma/plugin/buffers/buffer_spec.rb @@ -71,8 +71,8 @@ module Buffers Config.custom_path = nil end - subject { @buffer.config_params } - it { is_expected.to eq(dummy: "dummy") } + subject { @buffer.config_params(:dummy) } + it { is_expected.to eq("dummy") } end end end diff --git a/spec/fusuma/plugin/buffers/gesture_buffer_spec.rb b/spec/fusuma/plugin/buffers/gesture_buffer_spec.rb index c59af52..8176076 100644 --- a/spec/fusuma/plugin/buffers/gesture_buffer_spec.rb +++ b/spec/fusuma/plugin/buffers/gesture_buffer_spec.rb @@ -102,7 +102,7 @@ module Buffers end it "should keep only events generated within 0.3 seconds" do - expect(@buffer.config_params).to eq(seconds_to_keep: 0.3) + expect(@buffer.config_params(:seconds_to_keep)).to eq(0.3) time = Time.now event1 = @event_generator.call(time) @buffer.buffer(event1) diff --git a/spec/fusuma/plugin/detectors/detector_spec.rb b/spec/fusuma/plugin/detectors/detector_spec.rb index a81d160..d35cc8d 100644 --- a/spec/fusuma/plugin/detectors/detector_spec.rb +++ b/spec/fusuma/plugin/detectors/detector_spec.rb @@ -35,7 +35,7 @@ module Detectors end describe "#config_params" do - it { expect(@detector.config_params).to eq(dummy: "dummy") } + it { expect(@detector.config_params(:dummy)).to eq("dummy") } end end end diff --git a/spec/fusuma/plugin/detectors/dummy_detector.rb b/spec/fusuma/plugin/detectors/dummy_detector.rb index 87b675e..81ed638 100644 --- a/spec/fusuma/plugin/detectors/dummy_detector.rb +++ b/spec/fusuma/plugin/detectors/dummy_detector.rb @@ -18,6 +18,12 @@ def detect(buffers) return create_event(record: record) end end + + def config_param_types + { + dummy: String + } + end end end end diff --git a/spec/fusuma/plugin/executors/executor_spec.rb b/spec/fusuma/plugin/executors/executor_spec.rb index 94e2298..8373182 100644 --- a/spec/fusuma/plugin/executors/executor_spec.rb +++ b/spec/fusuma/plugin/executors/executor_spec.rb @@ -27,6 +27,12 @@ module Executors end class DummyExecutor < Executor + def config_param_types + { + dummy: String + } + end + def execute_keys [:dummy] end @@ -171,7 +177,7 @@ def executable?(event) end describe "#config_params" do - it { expect(@executor.config_params).to eq(dummy: "dummy") } + it { expect(@executor.config_params(:dummy)).to eq("dummy") } end end end diff --git a/spec/fusuma/plugin/filters/filter_spec.rb b/spec/fusuma/plugin/filters/filter_spec.rb index d645c50..eb8431f 100644 --- a/spec/fusuma/plugin/filters/filter_spec.rb +++ b/spec/fusuma/plugin/filters/filter_spec.rb @@ -15,7 +15,8 @@ class DummyFilter < Filter def config_param_types { - source: String + source: String, + dummy: String, } end end @@ -83,8 +84,8 @@ def config_param_types Config.custom_path = nil end - subject { filter.config_params } - it { is_expected.to eq(dummy: "dummy") } + subject { filter.config_params(:dummy) } + it { is_expected.to eq("dummy") } end end end diff --git a/spec/fusuma/plugin/inputs/input_spec.rb b/spec/fusuma/plugin/inputs/input_spec.rb index b569c1c..1ae758a 100644 --- a/spec/fusuma/plugin/inputs/input_spec.rb +++ b/spec/fusuma/plugin/inputs/input_spec.rb @@ -29,6 +29,12 @@ module Inputs end class DummyInput < Input + def config_param_types + { + dummy: String + } + end + def io @io ||= begin r, w = IO.pipe @@ -61,8 +67,8 @@ def io end describe "#config_params" do - subject { dummy_input.config_params } - it { is_expected.to eq(dummy: "dummy") } + subject { dummy_input.config_params(:dummy) } + it { is_expected.to eq("dummy") } end end end