From c399e7a710b1efed5b9a7db66582c91fa5f626e1 Mon Sep 17 00:00:00 2001 From: iberianpig Date: Mon, 11 Jun 2018 23:42:47 +0900 Subject: [PATCH] fix for libinput version 1.8 or later --- lib/fusuma.rb | 36 +++----- lib/fusuma/device.rb | 12 +-- lib/fusuma/libinput_commands.rb | 95 ++++++++++++++++++++ lib/fusuma/version.rb | 2 +- spec/fusuma_spec.rb | 6 +- spec/lib/libinput_commands_spec.rb | 138 +++++++++++++++++++++++++++++ 6 files changed, 252 insertions(+), 37 deletions(-) create mode 100644 lib/fusuma/libinput_commands.rb create mode 100644 spec/lib/libinput_commands_spec.rb diff --git a/lib/fusuma.rb b/lib/fusuma.rb index 9a6c742..8d8a61c 100644 --- a/lib/fusuma.rb +++ b/lib/fusuma.rb @@ -7,6 +7,7 @@ require_relative 'fusuma/multi_logger' require_relative 'fusuma/config.rb' require_relative 'fusuma/device.rb' +require_relative 'fusuma/libinput_commands.rb' require 'logger' require 'open3' require 'yaml' @@ -20,7 +21,7 @@ def run(option = {}) set_trap read_options(option) instance = new - instance.read_libinput + instance.run end private @@ -33,6 +34,7 @@ def set_trap def print_version puts '---------------------------------------------' puts "Fusuma: #{Fusuma::VERSION}" + puts "libinput: #{LibinputCommands.new.version}" puts "OS: #{`uname -rsv`}" puts "Distribution: #{`cat /etc/issue`}" puts "Desktop session: #{`echo $DESKTOP_SESSION`}" @@ -53,31 +55,15 @@ def read_options(option) end end - def read_libinput - Open3.popen3(libinput_command) do |_i, o, _e, _w| - o.each do |line| - gesture_action = GestureAction.initialize_by(line, Device.names) - next if gesture_action.nil? - @action_stack ||= ActionStack.new - @action_stack << gesture_action - event_trigger = @action_stack.generate_event_trigger - event_trigger.send_command unless event_trigger.nil? - end + def run + LibinputCommands.new.debug_events do |line| + gesture_action = GestureAction.initialize_by(line, Device.names) + next if gesture_action.nil? + @action_stack ||= ActionStack.new + @action_stack << gesture_action + event_trigger = @action_stack.generate_event_trigger + event_trigger.send_command unless event_trigger.nil? end end - - private - - def libinput_command - return @libinput_command if @libinput_command - prefix = 'stdbuf -oL --' - command = 'libinput-debug-events' - device_option = if Device.names.size == 1 - "--device /dev/input/#{Device.names.first}" - end - @libinput_command = [prefix, command, device_option].join(' ') - MultiLogger.debug(libinput_command: @libinput_command) - @libinput_command - end end end diff --git a/lib/fusuma/device.rb b/lib/fusuma/device.rb index 055573c..cfe6742 100644 --- a/lib/fusuma/device.rb +++ b/lib/fusuma/device.rb @@ -19,17 +19,13 @@ def names def fetch_device_names current_device = nil - list_devices_logs.map do |line| + devices = [] + LibinputCommands.new.list_devices do |line| current_device = extracted_input_device_from(line) || current_device next unless natural_scroll_is_available?(line) - current_device - end.compact - end - - def list_devices_logs - Open3.popen3('libinput-list-devices') do |_i, o, _e, _w| - return o.to_a + devices << current_device end + devices.compact end def extracted_input_device_from(line) diff --git a/lib/fusuma/libinput_commands.rb b/lib/fusuma/libinput_commands.rb new file mode 100644 index 0000000..1eea8ee --- /dev/null +++ b/lib/fusuma/libinput_commands.rb @@ -0,0 +1,95 @@ +module Fusuma + # libinput commands wrapper + class LibinputCommands + def initialize(*options) + @options = options + end + + # `libinput-list-devices` and `libinput-debug-events` are deprecated, + # use `libinput list-devices` and `libinput debug-events` from 1.8. + NEW_CLI_OPTION_VERSION = 1.8 + + # @return [Boolean] + def new_cli_option_available? + Gem::Version.new(version) >= Gem::Version.new(NEW_CLI_OPTION_VERSION) + end + + # @return [String] + def version + # versiom_command prints "1.6.3\n" + @version ||= `#{version_command}`.strip + end + + # @yield [line] gives a line in libinput list-devices output to the block + def list_devices + cmd = list_devices_command + MultiLogger.debug(debug_events: cmd) + Open3.popen3(cmd) do |_i, o, _e, _w| + o.each { |line| yield(line) } + end + end + + # @yield [line] gives a line in libinput debug-events output to the block + def debug_events + prefix = 'stdbuf -oL --' + options = [*@options, device_option] + cmd = "#{prefix} #{debug_events_command} #{options.join(' ')}".strip + MultiLogger.debug(debug_events: cmd) + Open3.popen3(cmd) do |_i, o, _e, _w| + o.each { |line| yield(line) } + end + end + + # @return [String] command + # @raise [SystemExit] + def version_command + if which('libinput') + 'libinput --version' + elsif which('libinput-list-devices') + 'libinput-list-devices --version' + else + MultiLogger.error 'install libinput-tools' + exit 1 + end + end + + def list_devices_command + if new_cli_option_available? + 'libinput list-devices' + else + 'libinput-list-devices' + end + end + + def debug_events_command + if new_cli_option_available? + 'libinput debug-events' + else + 'libinput-debug-events' + end + end + + private + + def device_option + "--device /dev/input/#{Device.names.first}" if Device.names.size == 1 + end + + # which in ruby: Checking if program exists in $PATH from ruby + # (https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby) + # Cross-platform way of finding an executable in the $PATH. + # + # which('ruby') #=> /usr/bin/ruby + # @return [String, nil] + def which(command) + exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] + ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| + exts.each do |ext| + exe = File.join(path, "#{command}#{ext}") + return exe if File.executable?(exe) && !File.directory?(exe) + end + end + nil + end + end +end diff --git a/lib/fusuma/version.rb b/lib/fusuma/version.rb index 32be9d5..17594e9 100644 --- a/lib/fusuma/version.rb +++ b/lib/fusuma/version.rb @@ -1,3 +1,3 @@ module Fusuma - VERSION = '0.7.1'.freeze + VERSION = '0.7.2'.freeze end diff --git a/spec/fusuma_spec.rb b/spec/fusuma_spec.rb index 78b379e..b99f235 100644 --- a/spec/fusuma_spec.rb +++ b/spec/fusuma_spec.rb @@ -10,7 +10,7 @@ module Fusuma context 'when without option' do it 'should not enable debug mode' do - allow_any_instance_of(Fusuma::Runner).to receive(:read_libinput) + allow_any_instance_of(Fusuma::Runner).to receive(:run) Fusuma::Runner.run expect(Fusuma::MultiLogger.instance).not_to be_debug_mode end @@ -18,7 +18,7 @@ module Fusuma context 'when run with argument "-v"' do it 'should enable debug mode' do - allow_any_instance_of(Fusuma::Runner).to receive(:read_libinput) + allow_any_instance_of(Fusuma::Runner).to receive(:run) Fusuma::MultiLogger.send(:new) Fusuma::Runner.run(verbose: true) expect(Fusuma::MultiLogger.instance).to be_debug_mode @@ -27,7 +27,7 @@ module Fusuma context 'when run with argument "-c path/to/config.yml"' do it 'should assign custom_path' do - allow_any_instance_of(Fusuma::Runner).to receive(:read_libinput) + allow_any_instance_of(Fusuma::Runner).to receive(:run) config = Fusuma::Config.instance expect { Fusuma::Runner.run(config_path: 'path/to/config.yml') } .to change { config.custom_path }.from(nil).to('path/to/config.yml') diff --git a/spec/lib/libinput_commands_spec.rb b/spec/lib/libinput_commands_spec.rb new file mode 100644 index 0000000..9da192e --- /dev/null +++ b/spec/lib/libinput_commands_spec.rb @@ -0,0 +1,138 @@ +require 'spec_helper' +module Fusuma + describe LibinputCommands do + let(:libinput_commands) { described_class.new } + describe '#version' do + subject { libinput_commands.version } + + context 'when libinput-list-device is available' do + before do + allow(libinput_commands).to receive('which') + .with('libinput') { false } + allow(libinput_commands).to receive('which') + .with('libinput-list-devices') { true } + allow_any_instance_of(Kernel).to receive(:`) + .with('libinput-list-devices --version') { "1.6.3\n" } + end + + it { is_expected.to eq '1.6.3' } + it { expect(libinput_commands.new_cli_option_available?).to be false } + end + + context 'when libinput is available' do + before do + allow(libinput_commands).to receive('which') + .with('libinput') { true } + allow(libinput_commands).to receive('which') + .with('libinput-list-devices') { false } + allow_any_instance_of(Kernel).to receive(:`) + .with('libinput --version') { "1.8\n" } + end + + it { is_expected.to eq '1.8' } + it { expect(libinput_commands.new_cli_option_available?).to be true } + end + + context 'when libinput command is not found' do + before do + allow(libinput_commands).to receive('which') + .with('libinput') { false } + allow(libinput_commands).to receive('which') + .with('libinput-list-devices') { false } + end + + it 'shold print error and exit 1' do + expect(MultiLogger).to receive(:error) + expect { subject }.to raise_error(SystemExit) + end + end + end + + describe '#new_cli_option_available?' do + subject { libinput_commands.new_cli_option_available? } + context 'with NEW_CLI_OPTION_VERSION' do + before do + allow(libinput_commands).to receive(:version) + .and_return(LibinputCommands::NEW_CLI_OPTION_VERSION) + end + it { is_expected.to eq true } + end + context 'without NEW_CLI_OPTION_VERSION' do + before do + allow(libinput_commands).to receive(:version) + .and_return(LibinputCommands::NEW_CLI_OPTION_VERSION - 0.1) + end + it { is_expected.to eq false } + end + end + + describe 'list_devices' do + subject { libinput_commands.list_devices } + after { subject } + + context 'with new cli version' do + before do + allow(libinput_commands).to receive(:new_cli_option_available?) + .and_return(true) + end + + it 'call `libinput list-devices`' do + command = 'libinput list-devices' + expect(Open3).to receive(:popen3) + .with("#{command}") + end + end + context 'with old cli version' do + before do + allow(libinput_commands).to receive(:new_cli_option_available?) + .and_return(false) + end + + it 'call `libinput-list-devices`' do + command = 'libinput-list-devices' + expect(Open3).to receive(:popen3) + .with("#{command}") + end + end + end + + describe 'debug_events' do + subject { libinput_commands.debug_events } + + before do + allow(libinput_commands).to receive(:device_option) + .and_return('--device stub_device') + end + + after { subject } + + context 'with new cli version' do + before do + allow(libinput_commands).to receive(:new_cli_option_available?) + .and_return(true) + end + + it 'call `libinput debug-events`' do + command = 'libinput debug-events' + expect(Open3).to receive(:popen3) + .with("stdbuf -oL -- #{command} --device stub_device") + .and_return 'stub message' + end + end + + context 'with old cli version' do + before do + allow(libinput_commands).to receive(:new_cli_option_available?) + .and_return(false) + end + + it 'call `libinput-debug-events`' do + command = 'libinput-debug-events' + expect(Open3).to receive(:popen3) + .with("stdbuf -oL -- #{command} --device stub_device") + .and_return 'stub message' + end + end + end + end +end