class ArduinoCI::ArduinoBackend
Wrap the Arduino executable. This requires, in some cases, a faked display.
Constants
- CONFIG_FILE_NAME
We never even use this in code, it's just here for reference because the backend is picky about it. Used for testing @return [String] the only allowable name for the arduino-cli config file.
Attributes
@return [Array<String>] Additional URLs for the boards manager
the actual path to the executable on this platform @return [Pathname]
If a custom config is deired (i.e. for testing), specify it here. Note github.com/arduino/arduino-cli/issues/753 : the –config-file option is really the director that contains the file @return [Pathname]
@return [String] STDERR of the most recently-run command
@return [String] the most recently-run command
@return [String] STDOUT of the most recently-run command
Public Class Methods
# File lib/arduino_ci/arduino_backend.rb, line 42 def initialize(binary_path) @binary_path = binary_path @config_dir = nil @additional_urls = [] @last_out = "" @last_err = "" @last_msg = "" end
Public Instance Methods
# File lib/arduino_ci/arduino_backend.rb, line 51 def _wrap_run(work_fn, *args, **kwargs) # do some work to extract & merge environment variables if they exist has_env = !args.empty? && args[0].instance_of?(Hash) env_vars = has_env ? args[0] : {} actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args custom_config = @config_dir.nil? ? [] : ["--config-file", @config_dir.to_s] full_args = [binary_path.to_s, "--format", "json"] + custom_config + actual_args full_cmd = env_vars.empty? ? full_args : [env_vars] + full_args shell_vars = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ") @last_msg = " $ #{shell_vars} #{full_args.join(' ')}" work_fn.call(*full_cmd, **kwargs) end
check whether a board is installed we do this by just selecting a board.
the arduino binary will error if unrecognized and do a successful no-op if it's installed
@param boardname [String] The board to test @return [bool] Whether the board is installed
# File lib/arduino_ci/arduino_backend.rb, line 115 def board_installed?(boardname) run_and_capture("board", "details", "--fqbn", boardname)[:success] end
Board manager URLs @return [Array<String>] The additional URLs used by the board manager
# File lib/arduino_ci/arduino_backend.rb, line 98 def board_manager_urls config_dump["board_manager"]["additional_urls"] + @additional_urls end
Set board manager URLs @return [Array<String>] The additional URLs used by the board manager
# File lib/arduino_ci/arduino_backend.rb, line 104 def board_manager_urls=(all_urls) raise ArgumentError("all_urls should be an array, got #{all_urls.class}") unless all_urls.is_a? Array @additional_urls = all_urls end
check whether a board family is installed (e.g. arduino:avr)
@param boardfamily_name [String] The board family to test @return [bool] Whether the board is installed
# File lib/arduino_ci/arduino_backend.rb, line 123 def boards_installed?(boardfamily_name) capture_json("core", "list")[:json].any? { |b| b["ID"] == boardfamily_name } end
# File lib/arduino_ci/arduino_backend.rb, line 79 def capture_json(*args, **kwargs) ret = run_and_capture(*args, **kwargs) ret[:json] = JSON.parse(ret[:out]) ret end
@param path [String] The sketch to compile @param boardname [String] The board to use @return [bool] whether the command succeeded
# File lib/arduino_ci/arduino_backend.rb, line 156 def compile_sketch(path, boardname) ext = File.extname path unless ext.casecmp(".ino").zero? @last_msg = "Refusing to compile sketch with '#{ext}' extension -- rename it to '.ino'!" return false end unless File.exist? path @last_msg = "Can't compile Sketch at nonexistent path '#{path}'!" return false end ret = run_and_capture("compile", "--fqbn", boardname, "--warnings", "all", "--dry-run", path.to_s) ret[:success] end
Get a dump of the entire config @return [Hash] The configuration
# File lib/arduino_ci/arduino_backend.rb, line 87 def config_dump capture_json("config", "dump")[:json] end
install a board by name @param name [String] the board name @return [bool] whether the command succeeded
# File lib/arduino_ci/arduino_backend.rb, line 130 def install_boards(boardfamily) result = if @additional_urls.empty? run_and_capture("core", "install", boardfamily) else run_and_capture("core", "install", boardfamily, "--additional-urls", @additional_urls.join(",")) end result[:success] end
install a library from a path on the local machine (not via library manager), by symlink or no-op as appropriate @param path [Pathname] library to use @return [CppLibrary] the installed library, or nil
# File lib/arduino_ci/arduino_backend.rb, line 205 def install_local_library(path) src_path = path.realpath library_name = name_of_library(path) cpp_library = library_of_name(library_name) destination_path = cpp_library.path # things get weird if the sketchbook contains the library. # check that first if cpp_library.installed? # maybe the project has always lived in the libraries directory, no need to symlink return cpp_library if destination_path == src_path uhoh = "There is already a library '#{library_name}' in the library directory (#{destination_path})" # maybe it's a symlink? that would be OK if Host.symlink?(destination_path) current_destination_target = Host.readlink(destination_path) return cpp_library if current_destination_target == src_path @last_msg = "#{uhoh} and it's symlinked to #{current_destination_target} (expected #{src_path})" return nil end @last_msg = "#{uhoh}. It may need to be removed manually." return nil end # install the library libraries_dir = destination_path.parent libraries_dir.mkpath unless libraries_dir.exist? Host.symlink(src_path, destination_path) cpp_library end
@return [Hash] information about installed libraries via the CLI
# File lib/arduino_ci/arduino_backend.rb, line 149 def installed_libraries capture_json("lib", "list")[:json] end
@return [String] the path to the Arduino libraries directory
# File lib/arduino_ci/arduino_backend.rb, line 92 def lib_dir Pathname.new(config_dump["directories"]["user"]) + "libraries" end
Find out if a library is available
@param name [String] the library name @return [bool] whether the library can be installed via the library manager
# File lib/arduino_ci/arduino_backend.rb, line 143 def library_available?(name) # the --names flag limits the size of the response to just the name field capture_json("lib", "search", "--names", name)[:json]["libraries"].any? { |l| l["name"] == name } end
Create a handle to an Arduino library by name @param name [String] The library “real name” @return [CppLibrary] The library object
# File lib/arduino_ci/arduino_backend.rb, line 185 def library_of_name(name) raise ArgumentError, "name is not a String (got #{name.class})" unless name.is_a? String CppLibrary.new(name, self) end
Create a handle to an Arduino library by path @param path [Pathname] The path to the library @return [CppLibrary] The library object
# File lib/arduino_ci/arduino_backend.rb, line 194 def library_of_path(path) # the path must exist... and if it does, brute-force search the installed libs for it realpath = path.realpath # should produce error if the path doesn't exist to begin with entry = installed_libraries.find { |l| Pathname.new(l["library"]["install_dir"]).realpath == realpath } probable_name = entry["real_name"].nil? ? realpath.basename.to_s : entry["real_name"] CppLibrary.new(probable_name, self) end
Guess the name of a library @param path [Pathname] The path to the library (installed or not) @return [String] the probable library name
# File lib/arduino_ci/arduino_backend.rb, line 173 def name_of_library(path) src_path = path.realpath properties_file = src_path + CppLibrary::LIBRARY_PROPERTIES_FILE return src_path.basename.to_s unless properties_file.exist? return src_path.basename.to_s if LibraryProperties.new(properties_file).name.nil? LibraryProperties.new(properties_file).name end
run a command and capture its output @return [Hash] {:out => String, :err => String, :success => bool}
# File lib/arduino_ci/arduino_backend.rb, line 72 def run_and_capture(*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 end
build and run the arduino command
# File lib/arduino_ci/arduino_backend.rb, line 66 def run_and_output(*args, **kwargs) _wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs) end