1
1
require 'fileutils'
2
- require 'arduino_ci/display_manager'
3
- require 'arduino_ci/arduino_installation'
4
2
5
3
module ArduinoCI
6
4
7
5
# Wrap the Arduino executable. This requires, in some cases, a faked display.
8
6
class ArduinoCmd
9
7
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" )
23
17
end
24
18
25
19
attr_accessor :installation
26
- attr_reader :prefs_response_time
20
+ attr_accessor :base_cmd
21
+ attr_accessor :gcc_cmd
22
+
27
23
attr_reader :library_is_indexed
28
24
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
34
36
@prefs_cache = nil
35
37
@library_is_indexed = false
36
38
end
37
39
38
- def _parse_pref_string ( arduino_output )
40
+ def parse_pref_string ( arduino_output )
39
41
lines = arduino_output . split ( "\n " ) . select { |l | l . include? "=" }
40
42
ret = lines . each_with_object ( { } ) do |e , acc |
41
43
parts = e . split ( "=" , 2 )
@@ -45,26 +47,21 @@ def _parse_pref_string(arduino_output)
45
47
ret
46
48
end
47
49
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 )
62
57
return nil unless resp [ :success ]
63
- _parse_pref_string ( resp [ :out ] )
58
+ resp [ :out ]
64
59
end
65
60
66
61
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 )
68
65
@prefs_cache . clone
69
66
end
70
67
@@ -74,42 +71,38 @@ def get_pref(key)
74
71
data [ key ]
75
72
end
76
73
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.
78
81
# @param key [String] the preference key
79
82
# @param value [String] the preference value
80
83
# @return [bool] whether the command succeeded
81
84
def set_pref ( key , value )
82
- success = run_with_gui_guess ( " about preferences" , "--pref" , " #{ key } = #{ value } " , "--save-prefs" )
85
+ success = _set_pref ( key , value )
83
86
@prefs_cache [ key ] = value if success
84
87
success
85
88
end
86
89
87
90
# 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 } "
95
93
end
96
94
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
103
101
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 )
113
106
end
114
107
115
108
# run a command and capture its output
@@ -140,30 +133,29 @@ def run_wrap(*args, **kwargs)
140
133
# we do this by just selecting a board.
141
134
# the arduino binary will error if unrecognized and do a successful no-op if it's installed
142
135
def board_installed? ( boardname )
143
- run_with_gui_guess ( " about board not installed" , "--board" , boardname )
136
+ run_and_capture ( flag_use_board , boardname ) [ :success ]
144
137
end
145
138
146
139
# install a board by name
147
140
# @param name [String] the board name
148
141
# @return [bool] whether the command succeeded
149
142
def install_board ( boardname )
150
143
# 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 ]
152
145
end
153
146
154
147
# install a library by name
155
148
# @param name [String] the library name
156
149
# @return [bool] whether the command succeeded
157
150
def install_library ( library_name )
158
- result = run_and_capture ( "--install-library" , library_name )
151
+ result = run_and_capture ( flag_install_library , library_name )
159
152
@library_is_indexed = true if result [ :success ]
160
153
result [ :success ]
161
154
end
162
155
163
156
# generate the (very likely) path of a library given its name
164
157
def library_path ( library_name )
165
- sketchbook = get_pref ( "sketchbook.path" )
166
- File . join ( sketchbook , library_name )
158
+ File . join ( _lib_dir , library_name )
167
159
end
168
160
169
161
# update the library index
@@ -175,7 +167,7 @@ def update_library_index
175
167
176
168
# use a particular board for compilation
177
169
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 ]
179
171
end
180
172
181
173
# use a particular board for compilation, installing it if necessary
@@ -197,25 +189,25 @@ def verify_sketch(path)
197
189
puts "Can't verify nonexistent Sketch at '#{ path } '!"
198
190
return false
199
191
end
200
- run ( "--verify" , path , err : :out )
192
+ run ( flag_verify , path , err : :out )
201
193
end
202
194
203
195
# ensure that the given library is installed, or symlinked as appropriate
204
196
# 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 )
208
200
209
201
# things get weird if the sketchbook contains the library.
210
202
# check that first
211
203
if File . exist? destination_path
212
204
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
214
206
215
207
# maybe it's a symlink? that would be OK
216
208
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 } "
219
211
return nil
220
212
end
221
213
@@ -224,7 +216,7 @@ def install_local_library(library_path)
224
216
end
225
217
226
218
# install the library
227
- FileUtils . ln_s ( library_path , destination_path )
219
+ FileUtils . ln_s ( path , destination_path )
228
220
destination_path
229
221
end
230
222
0 commit comments