Skip to content

Commit f3ce15d

Browse files
committed
refactor command structure to allow binary-specific flags
1 parent 8500eae commit f3ce15d

8 files changed

+221
-174
lines changed

exe/ci_system_check.rb

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
require 'arduino_ci'
22

3-
puts "Enabling display with display manager"
4-
ArduinoCI::DisplayManager::instance.enable
5-
63
puts "Autlocating Arduino command"
7-
arduino_cmd = ArduinoCI::ArduinoCmd.autolocate!
4+
arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
85

96
board_tests = {
107
"arduino:avr:uno" => true,

lib/arduino_ci.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
require "arduino_ci/version"
2-
require "arduino_ci/arduino_cmd"
2+
require "arduino_ci/arduino_installation"
33

44
# ArduinoCI contains classes for automated testing of Arduino code on the command line
55
# @author Ian Katz <[email protected]>

lib/arduino_ci/arduino_cmd.rb

+56-77
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,43 @@
11
require 'fileutils'
22
require 'arduino_ci/display_manager'
3-
require 'arduino_ci/arduino_installation'
43

54
module ArduinoCI
65

76
# Wrap the Arduino executable. This requires, in some cases, a faked display.
87
class ArduinoCmd
98

10-
class << self
11-
protected :new
12-
13-
# @return [ArduinoCmd] A command object with a best guess (or nil) for the installation
14-
def autolocate
15-
new(ArduinoInstallation.autolocate)
16-
end
17-
18-
# @return [ArduinoCmd] A command object, installing Arduino if necessary
19-
def autolocate!
20-
new(ArduinoInstallation.autolocate!)
21-
end
22-
9+
# Enable a shortcut syntax for command line flags
10+
# @param name [String] What the flag will be called (prefixed with 'flag_')
11+
# @return [void]
12+
# @macro [attach] flag
13+
# @!attribute [r] flag_$1
14+
# @return String $2 the text of the command line flag
15+
def self.flag(name, text = nil)
16+
text = "(flag #{name} not defined)" if text.nil?
17+
self.class_eval("def flag_#{name};\"#{text}\";end")
2318
end
2419

2520
attr_accessor :installation
26-
attr_reader :prefs_response_time
21+
attr_accessor :base_cmd
22+
2723
attr_reader :library_is_indexed
2824

29-
# @param installation [ArduinoInstallation] the location of the Arduino program installation
30-
def initialize(installation)
31-
@display_mgr = DisplayManager::instance
32-
@installation = installation
33-
@prefs_response_time = nil
25+
# set the command line flags (undefined for now).
26+
# These vary between gui/cli
27+
flag :get_pref
28+
flag :set_pref
29+
flag :save_prefs
30+
flag :use_board
31+
flag :install_boards
32+
flag :install_library
33+
flag :verify
34+
35+
def initialize
3436
@prefs_cache = nil
3537
@library_is_indexed = false
3638
end
3739

38-
def _parse_pref_string(arduino_output)
40+
def parse_pref_string(arduino_output)
3941
lines = arduino_output.split("\n").select { |l| l.include? "=" }
4042
ret = lines.each_with_object({}) do |e, acc|
4143
parts = e.split("=", 2)
@@ -45,26 +47,21 @@ def _parse_pref_string(arduino_output)
4547
ret
4648
end
4749

48-
# fetch preferences to a hash
49-
def _prefs
50-
resp = nil
51-
if @installation.requires_x
52-
@display_mgr.with_display do
53-
start = Time.now
54-
resp = run_and_capture("--get-pref")
55-
@prefs_response_time = Time.now - start
56-
end
57-
else
58-
start = Time.now
59-
resp = run_and_capture("--get-pref")
60-
@prefs_response_time = Time.now - start
61-
end
50+
def _lib_dir
51+
"<lib dir not defined>"
52+
end
53+
54+
# fetch preferences to a string
55+
def _prefs_raw
56+
resp = run_and_capture(flag_get_pref)
6257
return nil unless resp[:success]
63-
_parse_pref_string(resp[:out])
58+
resp[:out]
6459
end
6560

6661
def prefs
67-
@prefs_cache = _prefs if @prefs_cache.nil?
62+
prefs_raw = _prefs_raw if @prefs_cache.nil?
63+
return nil if prefs_raw.nil?
64+
@prefs_cache = parse_pref_string(prefs_raw)
6865
@prefs_cache.clone
6966
end
7067

@@ -74,42 +71,25 @@ def get_pref(key)
7471
data[key]
7572
end
7673

77-
# set a preference key/value pair
74+
# underlying preference-setter.
75+
# @return [bool] whether the command succeeded
76+
def _set_pref(key, value)
77+
run_and_capture(flag_set_pref, "#{key}=#{value}", flag_save_prefs)[:success]
78+
end
79+
80+
# set a preference key/value pair, and update the cache.
7881
# @param key [String] the preference key
7982
# @param value [String] the preference value
8083
# @return [bool] whether the command succeeded
8184
def set_pref(key, value)
82-
success = run_with_gui_guess(" about preferences", "--pref", "#{key}=#{value}", "--save-prefs")
85+
success = _set_pref(key, value)
8386
@prefs_cache[key] = value if success
8487
success
8588
end
8689

8790
# run the arduino command
8891
def run(*args, **kwargs)
89-
full_args = @installation.base_cmd + args
90-
if @installation.requires_x
91-
@display_mgr.run(*full_args, **kwargs)
92-
else
93-
Host.run(*full_args, **kwargs)
94-
end
95-
end
96-
97-
def run_with_gui_guess(message, *args, **kwargs)
98-
# On Travis CI, we get an error message in the GUI instead of on STDERR
99-
# so, assume that if we don't get a rapid reply that things are not installed
100-
101-
# if we don't need X, we can skip this whole thing
102-
return run_and_capture(*args, **kwargs)[:success] unless @installation.requires_x
103-
104-
prefs if @prefs_response_time.nil?
105-
x3 = @prefs_response_time * 3
106-
Timeout.timeout(x3) do
107-
result = run_and_capture(*args, **kwargs)
108-
result[:success]
109-
end
110-
rescue Timeout::Error
111-
puts "No response in #{x3} seconds. Assuming graphical modal error message#{message}."
112-
false
92+
raise "Ian needs to implement this in a subclass #{args} #{kwargs}"
11393
end
11494

11595
# run a command and capture its output
@@ -140,30 +120,29 @@ def run_wrap(*args, **kwargs)
140120
# we do this by just selecting a board.
141121
# the arduino binary will error if unrecognized and do a successful no-op if it's installed
142122
def board_installed?(boardname)
143-
run_with_gui_guess(" about board not installed", "--board", boardname)
123+
run_and_capture(flag_use_board, boardname)[:success]
144124
end
145125

146126
# install a board by name
147127
# @param name [String] the board name
148128
# @return [bool] whether the command succeeded
149129
def install_board(boardname)
150130
# TODO: find out why IO.pipe fails but File::NULL succeeds :(
151-
run_and_capture("--install-boards", boardname, out: File::NULL)[:success]
131+
run_and_capture(flag_install_boards, boardname, out: File::NULL)[:success]
152132
end
153133

154134
# install a library by name
155135
# @param name [String] the library name
156136
# @return [bool] whether the command succeeded
157137
def install_library(library_name)
158-
result = run_and_capture("--install-library", library_name)
138+
result = run_and_capture(flag_install_library, library_name)
159139
@library_is_indexed = true if result[:success]
160140
result[:success]
161141
end
162142

163143
# generate the (very likely) path of a library given its name
164144
def library_path(library_name)
165-
sketchbook = get_pref("sketchbook.path")
166-
File.join(sketchbook, library_name)
145+
File.join(@lib_dir, library_name)
167146
end
168147

169148
# update the library index
@@ -175,7 +154,7 @@ def update_library_index
175154

176155
# use a particular board for compilation
177156
def use_board(boardname)
178-
run_with_gui_guess(" about board not installed", "--board", boardname, "--save-prefs")
157+
run_and_capture(flag_use_board, boardname, flag_save_prefs)[:success]
179158
end
180159

181160
# use a particular board for compilation, installing it if necessary
@@ -197,25 +176,25 @@ def verify_sketch(path)
197176
puts "Can't verify nonexistent Sketch at '#{path}'!"
198177
return false
199178
end
200-
run("--verify", path, err: :out)
179+
run(flag_verify, path, err: :out)
201180
end
202181

203182
# ensure that the given library is installed, or symlinked as appropriate
204183
# return the path of the prepared library, or nil
205-
def install_local_library(library_path)
206-
library_name = File.basename(library_path)
207-
destination_path = File.join(@installation.lib_dir, library_name)
184+
def install_local_library(path)
185+
library_name = File.basename(path)
186+
destination_path = library_path(library_name)
208187

209188
# things get weird if the sketchbook contains the library.
210189
# check that first
211190
if File.exist? destination_path
212191
uhoh = "There is already a library '#{library_name}' in the library directory"
213-
return destination_path if destination_path == library_path
192+
return destination_path if destination_path == path
214193

215194
# maybe it's a symlink? that would be OK
216195
if File.symlink?(destination_path)
217-
return destination_path if File.readlink(destination_path) == library_path
218-
puts "#{uhoh} and it's not symlinked to #{library_path}"
196+
return destination_path if File.readlink(destination_path) == path
197+
puts "#{uhoh} and it's not symlinked to #{path}"
219198
return nil
220199
end
221200

@@ -224,7 +203,7 @@ def install_local_library(library_path)
224203
end
225204

226205
# install the library
227-
FileUtils.ln_s(library_path, destination_path)
206+
FileUtils.ln_s(path, destination_path)
228207
destination_path
229208
end
230209

lib/arduino_ci/arduino_cmd_linux.rb

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
require 'arduino_ci/arduino_cmd'
2+
3+
module ArduinoCI
4+
5+
# Implementation of Arduino linux IDE commands
6+
class ArduinoCmdLinux < ArduinoCmd
7+
8+
attr_reader :prefs_response_time
9+
10+
flag :get_pref, "--get-pref"
11+
flag :set_pref, "--pref"
12+
flag :save_prefs, "--save-prefs"
13+
flag :use_board, "--board"
14+
flag :install_boards, "--install-boards"
15+
flag :install_library, "--install-library"
16+
flag :verify, "--verify"
17+
18+
def initialize
19+
super
20+
@prefs_response_time = nil
21+
@display_mgr = DisplayManager::instance
22+
end
23+
24+
# fetch preferences to a hash
25+
def _prefs_raw
26+
start = Time.now
27+
resp = run_and_capture(flag_get_pref)
28+
@prefs_response_time = Time.now - start
29+
return nil unless resp[:success]
30+
resp[:out]
31+
end
32+
33+
def _lib_dir
34+
File.join(get_pref("sketchbook.path"), "libraries")
35+
end
36+
37+
# run the arduino command
38+
def run(*args, **kwargs)
39+
full_args = @base_cmd + args
40+
@display_mgr.run(*full_args, **kwargs)
41+
end
42+
43+
def run_with_gui_guess(message, *args, **kwargs)
44+
# On Travis CI, we get an error message in the GUI instead of on STDERR
45+
# so, assume that if we don't get a rapid reply that things are not installed
46+
47+
prefs if @prefs_response_time.nil?
48+
x3 = @prefs_response_time * 3
49+
Timeout.timeout(x3) do
50+
result = run_and_capture(*args, **kwargs)
51+
result[:success]
52+
end
53+
rescue Timeout::Error
54+
puts "No response in #{x3} seconds. Assuming graphical modal error message#{message}."
55+
false
56+
end
57+
58+
# underlying preference-setter.
59+
# @param key [String] the preference key
60+
# @param value [String] the preference value
61+
# @return [bool] whether the command succeeded
62+
def _set_pref(key, value)
63+
run_with_gui_guess(" about preferences", flag_set_pref, "#{key}=#{value}", flag_save_prefs)
64+
end
65+
66+
# check whether a board is installed
67+
# we do this by just selecting a board.
68+
# the arduino binary will error if unrecognized and do a successful no-op if it's installed
69+
def board_installed?(boardname)
70+
run_with_gui_guess(" about board not installed", flag_use_board, boardname)
71+
end
72+
73+
# use a particular board for compilation
74+
def use_board(boardname)
75+
run_with_gui_guess(" about board not installed", flag_use_board, boardname, flag_save_prefs)
76+
end
77+
78+
end
79+
80+
end

lib/arduino_ci/arduino_cmd_osx.rb

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
require 'arduino_ci/arduino_cmd'
2+
3+
module ArduinoCI
4+
5+
# Implementation of OSX commands
6+
class ArduinoCmdOSX < ArduinoCmd
7+
flag :get_pref, "--get-pref"
8+
flag :set_pref, "--pref"
9+
flag :save_prefs, "--save-prefs"
10+
flag :use_board, "--board"
11+
flag :install_boards, "--install-boards"
12+
flag :install_library, "--install-library"
13+
flag :verify, "--verify"
14+
15+
# run the arduino command
16+
def run(*args, **kwargs)
17+
full_args = @base_cmd + args
18+
Host.run(*full_args, **kwargs)
19+
end
20+
21+
def _lib_dir
22+
File.join(ENV['HOME'], "Documents", "Arduino", "libraries")
23+
end
24+
25+
end
26+
27+
end

0 commit comments

Comments
 (0)