11require 'fileutils'
2- require 'arduino_ci/display_manager'
3- require 'arduino_ci/arduino_installation'
42
53module ArduinoCI
64
75 # Wrap the Arduino executable. This requires, in some cases, a faked display.
86 class ArduinoCmd
97
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-
8+ # Enable a shortcut syntax for command line flags
9+ # @param name [String] What the flag will be called (prefixed with 'flag_')
10+ # @return [void]
11+ # @macro [attach] flag
12+ # @!attribute [r] flag_$1
13+ # @return String $2 the text of the command line flag
14+ def self . flag ( name , text = nil )
15+ text = "(flag #{ name } not defined)" if text . nil?
16+ self . class_eval ( "def flag_#{ name } ;\" #{ text } \" ;end" )
2317 end
2418
2519 attr_accessor :installation
26- attr_reader :prefs_response_time
20+ attr_accessor :base_cmd
21+ attr_accessor :gcc_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,38 @@ 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
88- 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
91+ def _run ( *args , **kwargs )
92+ raise "Ian needs to implement this in a subclass #{ args } #{ kwargs } "
9593 end
9694
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
95+ # build and run the arduino command
96+ def run ( * args , ** kwargs )
97+ # TODO: detect env!!
98+ full_args = @base_cmd + args
99+ _run ( * full_args , ** kwargs )
100+ end
103101
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
102+ def run_gcc ( *args , **kwargs )
103+ # TODO: detect env!!
104+ full_args = @gcc_cmd + args
105+ _run ( *full_args , **kwargs )
113106 end
114107
115108 # run a command and capture its output
@@ -140,30 +133,29 @@ def run_wrap(*args, **kwargs)
140133 # we do this by just selecting a board.
141134 # the arduino binary will error if unrecognized and do a successful no-op if it's installed
142135 def board_installed? ( boardname )
143- run_with_gui_guess ( " about board not installed" , "--board" , boardname )
136+ run_and_capture ( flag_use_board , boardname ) [ :success ]
144137 end
145138
146139 # install a board by name
147140 # @param name [String] the board name
148141 # @return [bool] whether the command succeeded
149142 def install_board ( boardname )
150143 # TODO: find out why IO.pipe fails but File::NULL succeeds :(
151- run_and_capture ( "--install-boards" , boardname , out : File ::NULL ) [ :success ]
144+ run_and_capture ( flag_install_boards , boardname , out : File ::NULL ) [ :success ]
152145 end
153146
154147 # install a library by name
155148 # @param name [String] the library name
156149 # @return [bool] whether the command succeeded
157150 def install_library ( library_name )
158- result = run_and_capture ( "--install-library" , library_name )
151+ result = run_and_capture ( flag_install_library , library_name )
159152 @library_is_indexed = true if result [ :success ]
160153 result [ :success ]
161154 end
162155
163156 # generate the (very likely) path of a library given its name
164157 def library_path ( library_name )
165- sketchbook = get_pref ( "sketchbook.path" )
166- File . join ( sketchbook , library_name )
158+ File . join ( _lib_dir , library_name )
167159 end
168160
169161 # update the library index
@@ -175,7 +167,7 @@ def update_library_index
175167
176168 # use a particular board for compilation
177169 def use_board ( boardname )
178- run_with_gui_guess ( " about board not installed" , "--board" , boardname , "--save-prefs" )
170+ run_and_capture ( flag_use_board , boardname , flag_save_prefs ) [ :success ]
179171 end
180172
181173 # use a particular board for compilation, installing it if necessary
@@ -197,25 +189,25 @@ def verify_sketch(path)
197189 puts "Can't verify nonexistent Sketch at '#{ path } '!"
198190 return false
199191 end
200- run ( "--verify" , path , err : :out )
192+ run ( flag_verify , path , err : :out )
201193 end
202194
203195 # ensure that the given library is installed, or symlinked as appropriate
204196 # 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 )
197+ def install_local_library ( path )
198+ library_name = File . basename ( path )
199+ destination_path = library_path ( library_name )
208200
209201 # things get weird if the sketchbook contains the library.
210202 # check that first
211203 if File . exist? destination_path
212204 uhoh = "There is already a library '#{ library_name } ' in the library directory"
213- return destination_path if destination_path == library_path
205+ return destination_path if destination_path == path
214206
215207 # maybe it's a symlink? that would be OK
216208 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 } "
209+ return destination_path if File . readlink ( destination_path ) == path
210+ puts "#{ uhoh } and it's not symlinked to #{ path } "
219211 return nil
220212 end
221213
@@ -224,7 +216,7 @@ def install_local_library(library_path)
224216 end
225217
226218 # install the library
227- FileUtils . ln_s ( library_path , destination_path )
219+ FileUtils . ln_s ( path , destination_path )
228220 destination_path
229221 end
230222
0 commit comments