diff --git a/CHANGELOG.md b/CHANGELOG.md index c6500ddd..0276e7c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added ### Changed -* Refactored documentation +- Refactored documentation + ### Deprecated ### Removed +- Display Manager became no longer necessary with Arduino 1.8.X ### Fixed diff --git a/lib/arduino_ci/arduino_cmd.rb b/lib/arduino_ci/arduino_cmd.rb index b3b671df..78208fbd 100644 --- a/lib/arduino_ci/arduino_cmd.rb +++ b/lib/arduino_ci/arduino_cmd.rb @@ -113,18 +113,6 @@ def set_pref(key, value) success end - # run the arduino command - # @return [bool] whether the command succeeded - def _run_and_output(*args, **kwargs) - raise "Ian needs to implement this in a subclass #{args} #{kwargs}" - end - - # run the arduino command - # @return [Hash] keys for :success, :out, and :err - def _run_and_capture(*args, **kwargs) - raise "Ian needs to implement this in a subclass #{args} #{kwargs}" - end - def _wrap_run(work_fn, *args, **kwargs) # do some work to extract & merge environment variables if they exist has_env = !args.empty? && args[0].class == Hash @@ -140,13 +128,13 @@ def _wrap_run(work_fn, *args, **kwargs) # build and run the arduino command def run_and_output(*args, **kwargs) - _wrap_run((proc { |*a, **k| _run_and_output(*a, **k) }), *args, **kwargs) + _wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs) end # run a command and capture its output # @return [Hash] {:out => String, :err => String, :success => bool} def run_and_capture(*args, **kwargs) - ret = _wrap_run((proc { |*a, **k| _run_and_capture(*a, **k) }), *args, **kwargs) + ret = _wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs) @last_err = ret[:err] @last_out = ret[:out] ret diff --git a/lib/arduino_ci/arduino_cmd_linux.rb b/lib/arduino_ci/arduino_cmd_linux.rb index 04888077..4485162a 100644 --- a/lib/arduino_ci/arduino_cmd_linux.rb +++ b/lib/arduino_ci/arduino_cmd_linux.rb @@ -1,5 +1,5 @@ require 'arduino_ci/arduino_cmd' -require 'arduino_ci/display_manager' +require 'timeout' module ArduinoCI @@ -19,7 +19,6 @@ class ArduinoCmdLinux < ArduinoCmd def initialize super @prefs_response_time = nil - @display_mgr = DisplayManager::instance end # fetch preferences in their raw form @@ -38,18 +37,6 @@ def _lib_dir File.join(get_pref("sketchbook.path"), "libraries") end - # run the arduino command - # @return [bool] whether the command succeeded - def _run_and_output(*args, **kwargs) - @display_mgr.run_and_output(*args, **kwargs) - end - - # run the arduino command - # @return [Hash] keys for :success, :out, and :err - def _run_and_capture(*args, **kwargs) - @display_mgr.run_and_capture(*args, **kwargs) - end - def run_with_gui_guess(message, *args, **kwargs) # On Travis CI, we get an error message in the GUI instead of on STDERR # so, assume that if we don't get a rapid reply that things are not installed diff --git a/lib/arduino_ci/arduino_cmd_linux_builder.rb b/lib/arduino_ci/arduino_cmd_linux_builder.rb index 486f85f0..b4509b6d 100644 --- a/lib/arduino_ci/arduino_cmd_linux_builder.rb +++ b/lib/arduino_ci/arduino_cmd_linux_builder.rb @@ -20,18 +20,6 @@ def _lib_dir File.join(get_pref("sketchbook.path"), "libraries") end - # run the arduino command - # @return [bool] whether the command succeeded - def _run_and_output(*args, **kwargs) - Host.run_and_output(*args, **kwargs) - end - - # run the arduino command - # @return [Hash] keys for :success, :out, and :err - def _run_and_capture(*args, **kwargs) - Host.run_and_capture(*args, **kwargs) - end - end end diff --git a/lib/arduino_ci/arduino_cmd_osx.rb b/lib/arduino_ci/arduino_cmd_osx.rb index b8d7ad3e..26f8fc82 100644 --- a/lib/arduino_ci/arduino_cmd_osx.rb +++ b/lib/arduino_ci/arduino_cmd_osx.rb @@ -13,18 +13,6 @@ class ArduinoCmdOSX < ArduinoCmd flag :install_library, "--install-library" flag :verify, "--verify" - # run the arduino command - # @return [bool] whether the command succeeded - def _run_and_output(*args, **kwargs) - Host.run_and_output(*args, **kwargs) - end - - # run the arduino command - # @return [Hash] keys for :success, :out, and :err - def _run_and_capture(*args, **kwargs) - Host.run_and_capture(*args, **kwargs) - end - def _lib_dir File.join(ENV['HOME'], "Documents", "Arduino", "libraries") end diff --git a/lib/arduino_ci/arduino_cmd_windows.rb b/lib/arduino_ci/arduino_cmd_windows.rb index 52be6f12..e542dd4d 100644 --- a/lib/arduino_ci/arduino_cmd_windows.rb +++ b/lib/arduino_ci/arduino_cmd_windows.rb @@ -13,18 +13,6 @@ class ArduinoCmdWindows < ArduinoCmd flag :install_library, "--install-library" flag :verify, "--verify" - # run the arduino command - # @return [bool] whether the command succeeded - def _run_and_output(*args, **kwargs) - Host.run_and_output(*args, **kwargs) - end - - # run the arduino command - # @return [Hash] keys for :success, :out, and :err - def _run_and_capture(*args, **kwargs) - Host.run_and_capture(*args, **kwargs) - end - def _lib_dir File.join(ENV['userprofile'], "Documents", "Arduino", "libraries") end diff --git a/lib/arduino_ci/display_manager.rb b/lib/arduino_ci/display_manager.rb deleted file mode 100644 index e215a54d..00000000 --- a/lib/arduino_ci/display_manager.rb +++ /dev/null @@ -1,192 +0,0 @@ -require 'arduino_ci/host' -require 'singleton' -require 'timeout' - -DESIRED_DISPLAY = ":1.0".freeze - -module ArduinoCI - - # When arduino commands run, they need a graphical display. - # This class handles the setup of that display, if needed. - class DisplayManager - include Singleton - - # @return [bool] whether the display manager is currently active - attr_reader :enabled - - # @return [bool] whether to log messages to the terminal - attr_accessor :debug - - def initialize - @existing = existing_display? - @enabled = false - @pid = nil - @debug = false - - # pipes for input and output - @xv_pipe_out_wr = nil - @xv_pipe_err_wr = nil - @xv_pipe_out = nil - @xv_pipe_err = nil - end - - # attempt to determine if the machine is running a graphical display (i.e. not Travis) - # @return [bool] whether there is already a GUI that can accept windows - def existing_display? - return true if RUBY_PLATFORM.include? "darwin" - return true if Host.os == :windows - return false if ENV["DISPLAY"].nil? - return true if ENV["DISPLAY"].include? ":" - false - end - - # check whether a process is alive - # https://stackoverflow.com/a/32513298/2063546 - # @param pid [Int] the process ID - # @return [bool] - def alive?(pid) - Process.kill(0, pid) - true - rescue - false - end - - # check whether an X server is taking connections - # @param display [String] the display variable as it would be specified in the environment - # @return [bool] - def xserver_exist?(display) - system({ "DISPLAY" => display }, "xdpyinfo", out: File::NULL, err: File::NULL) - end - - # wait for the xvfb command to launch - # @param display [String] the value of the DISPLAY env var - # @param pid [Int] the process of Xvfb - # @param timeout [Int] the timeout in seconds - # @return [Bool] whether we detected a launch - def xvfb_launched?(display, pid, timeout) - Timeout.timeout(timeout) do - loop do - unless alive? pid - puts "Xvfb process has died" - return false - end - x = xserver_exist? display - puts "xdpyinfo reports X server status as #{x}" if debug - return true if x - sleep(0.1) - end - end - rescue Timeout::Error - false - end - - # enable a virtual display - def enable - if @existing - puts "DisplayManager enable: no-op for what appears to be an existing display" if debug - @enabled = true - return - end - - return unless @pid.nil? # TODO: disable first? - @xv_pipe_out.close unless @xv_pipe_out.nil? - @xv_pipe_err.close unless @xv_pipe_err.nil? - - # open Xvfb - xvfb_cmd = [ - "Xvfb", - "+extension", "RANDR", - ":1", - "-ac", - "-screen", "0", - "1280x1024x16", - ] - puts "Xvfb launching" if debug - - @xv_pipe_out, @xv_pipe_out_wr = IO.pipe - @xv_pipe_err, @xv_pipe_err_wr = IO.pipe - pipe = IO.popen(xvfb_cmd, stdout: @xv_pipe_out_wr, err: @xv_pipe_err_wr) - @pid = pipe.pid - @enabled = xvfb_launched?(DESIRED_DISPLAY, @pid, 30) - end - - # disable the virtual display - def disable - if @existing - puts "DisplayManager disable: no-op for what appears to be an existing display" if debug - return @enabled = false - end - - return @enabled = false if @pid.nil? - - # https://www.whatastruggle.com/timeout-a-subprocess-in-ruby - begin - Timeout.timeout(30) do - Process.kill("TERM", @pid) - puts "Xvfb TERMed" if debug - end - rescue Timeout::Error - Process.kill(9, @pid) - puts "Xvfb KILLed" if debug - ensure - Process.wait @pid - @enabled = false - @pid = nil - - @xv_pipe_out_wr.close - @xv_pipe_err_wr.close - end - end - - # Enable a virtual display for the duration of the given block - # @yield [environment] The code to execute within the display environment - # @yieldparam [Hash] the environment variables relating to the display - def with_display - was_enabled = @enabled - enable unless was_enabled - begin - yield environment - ensure - disable unless was_enabled - end - end - - def wrap_run(work_fn, *args, **kwargs) - ret = nil - # do some work to extract & merge environment variables if they exist - has_env = !args.empty? && args[0].class == Hash - with_display do |env_vars| - env_vars = {} if env_vars.nil? - env_vars.merge!(args[0]) if has_env - actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args - full_cmd = env_vars.empty? ? actual_args : [env_vars] + actual_args - ret = work_fn.call(*full_cmd, **kwargs) - end - ret - end - - # run a command in a display, outputting to stdout - # @return [bool] - def run_and_output(*args, **kwargs) - wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs) - end - - # run a command in a display, capturing output - # @return [bool] - def run_and_capture(*args, **kwargs) - wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs) - end - - # @return [Hash] the environment variables for the display - def environment - return nil unless @existing || @enabled - return { "EXISTING_DISPLAY" => "YES" } if @existing - { "DISPLAY" => DESIRED_DISPLAY } - end - - # On finalize, ensure child process is ended - def self.finalize - disable - end - end -end diff --git a/spec/display_manager_spec.rb b/spec/display_manager_spec.rb deleted file mode 100644 index 60b25456..00000000 --- a/spec/display_manager_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -require "spec_helper" - -RSpec.describe ArduinoCI::DisplayManager do - context "singleton ::instance" do - it "produces an instance" do - expect(ArduinoCI::DisplayManager::instance).not_to be_nil - end - end - - context "with_display" do - manager = ArduinoCI::DisplayManager::instance - manager.disable - - it "Properly enables and disables when not previously enabled" do - expect(manager.enabled).to be false - manager.with_display do |environment| - expect(manager.enabled).to be true - expect(environment.class).to eq(Hash) - also_manager = ArduinoCI::DisplayManager::instance - expect(also_manager.enabled).to be true - end - expect(manager.enabled).to be false - end - - it "Properly enables and disables when previously enabled" do - manager.enable - expect(manager.enabled).to be true - manager.with_display do |environment| - expect(manager.enabled).to be true - expect(environment.class).to eq(Hash) - also_manager = ArduinoCI::DisplayManager::instance - expect(also_manager.enabled).to be true - end - expect(manager.enabled).to be true - end - end -end