5
5
require 'optparse'
6
6
7
7
WIDTH = 80
8
- FIND_FILES_INDENT = 4
9
8
VAR_EXPECT_EXAMPLES = "EXPECT_EXAMPLES" . freeze
10
9
VAR_EXPECT_UNITTESTS = "EXPECT_UNITTESTS" . freeze
11
10
@@ -99,7 +98,7 @@ def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abor
99
98
else
100
99
print line
101
100
end
102
- STDOUT . flush
101
+ $stdout . flush
103
102
result = yield
104
103
mark = mark_fn . nil? ? "" : mark_fn . call ( result )
105
104
# if multline, put checkmark at full width
@@ -125,7 +124,7 @@ def attempt_multiline(message, &block)
125
124
end
126
125
127
126
# Make a nice status for something that kills the script immediately on failure
128
- FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with ArduinoCI, or your configuration" . freeze
127
+ FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with your configuration; halting here " . freeze
129
128
def assure ( message , &block )
130
129
perform_action ( message , false , @passfail , FAILED_ASSURANCE_MESSAGE , true , true , &block )
131
130
end
@@ -145,9 +144,7 @@ def inform_multiline(message, &block)
145
144
# Assure that a platform exists and return its definition
146
145
def assured_platform ( purpose , name , config )
147
146
platform_definition = config . platform_definition ( name )
148
- assure ( "Requested #{ purpose } platform '#{ name } ' is defined in 'platforms' YML" ) do
149
- !platform_definition . nil?
150
- end
147
+ assure ( "Requested #{ purpose } platform '#{ name } ' is defined in 'platforms' YML" ) { !platform_definition . nil? }
151
148
platform_definition
152
149
end
153
150
@@ -170,17 +167,15 @@ def display_files(pathname)
170
167
non_hidden = all_files . reject { |path | file_is_hidden_somewhere? ( path ) }
171
168
172
169
# print files with an indent
173
- margin = " " * FIND_FILES_INDENT
174
- non_hidden . each { |p | puts "#{ margin } #{ p } " }
170
+ puts " Files (excluding hidden files): #{ non_hidden . size } "
171
+ non_hidden . each { |p | puts " #{ p } " }
175
172
end
176
173
177
174
# @return [Array<String>] The list of installed libraries
178
175
def install_arduino_library_dependencies ( library_names , on_behalf_of , already_installed = [ ] )
179
176
installed = already_installed . clone
180
- library_names . map { |n | @backend . library_of_name ( n ) } . each do |l |
181
- if installed . include? ( l )
182
- # do nothing
183
- elsif l . installed?
177
+ ( library_names . map { |n | @backend . library_of_name ( n ) } - installed ) . each do |l |
178
+ if l . installed?
184
179
inform ( "Using pre-existing dependency of #{ on_behalf_of } " ) { l . name }
185
180
else
186
181
assure ( "Installing dependency of #{ on_behalf_of } : '#{ l . name } '" ) do
@@ -195,30 +190,77 @@ def install_arduino_library_dependencies(library_names, on_behalf_of, already_in
195
190
installed
196
191
end
197
192
198
- def handle_expectation_of_files ( expectation_envvar , operation , filegroup_name , dir_description , dir )
193
+ # @param example_platform_info [Hash] mapping of platform name to package information
194
+ # @param board_package_url [Hash] mapping of package name to URL
195
+ def install_all_packages ( example_platform_info , board_package_url )
196
+ # with all platform info, we can extract unique packages and their urls
197
+ # do that, set the URLs, and download the packages
198
+ all_packages = example_platform_info . values . map { |v | v [ :package ] } . uniq . reject ( &:nil? )
199
+
200
+ # make sure any non-builtin package has a URL defined
201
+ all_packages . each { |p | assure ( "Board package #{ p } has a defined URL" ) { board_package_url [ p ] } }
202
+
203
+ # set up all the board manager URLs.
204
+ # we can safely reject nils now, they would be for the builtins
205
+ all_urls = all_packages . map { |p | board_package_url [ p ] } . uniq . reject ( &:nil? )
206
+ unless all_urls . empty?
207
+ assure_multiline ( "Setting board manager URLs" ) do
208
+ @backend . board_manager_urls = all_urls
209
+ result = @backend . board_manager_urls
210
+ result . each { |u | puts " #{ u } " }
211
+ ( all_urls - result ) . empty? # check that all_urls is completely contained in the result
212
+ end
213
+ end
214
+ all_packages . each { |p | assure ( "Installing board package #{ p } " ) { @backend . install_boards ( p ) } }
215
+ end
216
+
217
+ # @param expectation_envvar [String] the name of the env var to check
218
+ # @param operation [String] a description of what operation we might be skipping
219
+ # @param filegroup_name [String] a description of the set of files without which we effectively skip the operation
220
+ # @param dir_description [String] a description of the directory where we looked for the files
221
+ # @param dir [Pathname] the directory where we looked for the files
222
+ def handle_expectation_of_files ( expectation_envvar , operation , filegroup_name , dir_description , dir_path )
223
+ # alert future me about running the script from the wrong directory, instead of doing the huge file dump
224
+ # otherwise, assume that the user might be running the script on a library with no actual unit tests
225
+ if Pathname . new ( __dir__ ) . parent == Pathname . new ( Dir . pwd )
226
+ inform_multiline ( "arduino_ci seems to be trying to test itself" ) do
227
+ [
228
+ "arduino_ci (the ruby gem) isn't an arduino project itself, so running the CI test script against" ,
229
+ "the core library isn't really a valid thing to do... but it's easy for a developer (including the" ,
230
+ "owner) to mistakenly do just that. Hello future me, you probably meant to run this against one of" ,
231
+ "the sample projects in SampleProjects/ ... if not, please submit a bug report; what a wild case!"
232
+ ] . each { |l | puts " #{ l } " }
233
+ false
234
+ end
235
+ exit ( 1 )
236
+ end
237
+
238
+ # either the directory is empty, or it doesn't exist at all. message accordingly.
239
+ ( problem , dir_desc , dir ) = if dir_path . exist?
240
+ [ "No #{ filegroup_name } were found in" , dir_description , dir_path ]
241
+ else
242
+ [ "No #{ dir_description } at" , "base directory" , dir_path . parent ]
243
+ end
244
+
245
+ inform ( problem ) { dir_path }
246
+ inform ( "Environment variable #{ expectation_envvar } is" ) { "(#{ ENV [ expectation_envvar ] . class } ) #{ ENV [ expectation_envvar ] } " }
199
247
if ENV [ expectation_envvar ] . nil?
200
- inform_multiline ( "Skipping #{ operation } ; no #{ filegroup_name } were found in #{ dir } " ) do
201
- puts " In case that's an error, this is what was found in the #{ dir_description } :"
248
+ inform_multiline ( "Skipping #{ operation } " ) do
249
+ puts " In case that's an error, this is what was found in the #{ dir_desc } :"
202
250
display_files ( dir )
203
- puts "To force an error in this case, set the environment variable #{ expectation_envvar } "
251
+ puts " To force an error in this case, set the environment variable #{ expectation_envvar } "
204
252
true
205
253
end
206
254
else
207
- assure_multiline ( "No #{ filegroup_name } were found in #{ dir } and #{ expectation_envvar } was set" ) do
208
- puts " This is what was found in the #{ dir_description } :"
255
+ assure_multiline ( "Dumping project's #{ dir_desc } before exit" ) do
209
256
display_files ( dir )
210
257
false
211
258
end
212
259
end
213
260
end
214
261
215
- def perform_unit_tests ( cpp_library , file_config )
216
- if @cli_options [ :skip_unittests ]
217
- inform ( "Skipping unit tests" ) { "as requested via command line" }
218
- return
219
- end
220
- config = file_config . with_override_config ( @cli_options [ :ci_config ] )
221
-
262
+ # report and return the set of compilers
263
+ def get_annotated_compilers ( config , cpp_library )
222
264
# check GCC
223
265
compilers = config . compilers_to_use
224
266
assure ( "The set of compilers (#{ compilers . length } ) isn't empty" ) { !compilers . empty? }
@@ -232,62 +274,54 @@ def perform_unit_tests(cpp_library, file_config)
232
274
end
233
275
inform ( "libasan availability for #{ gcc_binary } " ) { cpp_library . libasan? ( gcc_binary ) }
234
276
end
277
+ compilers
278
+ end
235
279
236
- # Ensure platforms exist for unit test, and save their info in all_platform_info keyed by name
237
- all_platform_info = { }
238
- config . platforms_to_unittest . each { |p | all_platform_info [ p ] = assured_platform ( "unittest" , p , config ) }
280
+ def perform_unit_tests ( cpp_library , file_config )
281
+ if @cli_options [ :skip_unittests ]
282
+ inform ( "Skipping unit tests" ) { "as requested via command line" }
283
+ return
284
+ end
285
+
286
+ config = file_config . with_override_config ( @cli_options [ :ci_config ] )
287
+ compilers = get_annotated_compilers ( config , cpp_library )
288
+ config . platforms_to_unittest . each_with_object ( { } ) { |p , acc | acc [ p ] = assured_platform ( "unittest" , p , config ) }
239
289
240
290
inform ( "Library conforms to Arduino library specification" ) { cpp_library . one_point_five? ? "1.5" : "1.0" }
241
291
242
- # iterate boards / tests
243
- if !cpp_library . tests_dir . exist?
244
- # alert future me about running the script from the wrong directory, instead of doing the huge file dump
245
- # otherwise, assume that the user might be running the script on a library with no actual unit tests
246
- if Pathname . new ( __dir__ ) . parent == Pathname . new ( Dir . pwd )
247
- inform_multiline ( "arduino_ci seems to be trying to test itself" ) do
248
- [
249
- "arduino_ci (the ruby gem) isn't an arduino project itself, so running the CI test script against" ,
250
- "the core library isn't really a valid thing to do... but it's easy for a developer (including the" ,
251
- "owner) to mistakenly do just that. Hello future me, you probably meant to run this against one of" ,
252
- "the sample projects in SampleProjects/ ... if not, please submit a bug report; what a wild case!"
253
- ] . each { |l | puts " #{ l } " }
254
- false
255
- end
256
- exit ( 1 )
257
- else
258
- inform_multiline ( "Skipping unit tests; no tests dir at #{ cpp_library . tests_dir } " ) do
259
- puts " In case that's an error, this is what was found in the library:"
260
- display_files ( cpp_library . tests_dir . parent )
261
- true
262
- end
263
- end
264
- elsif cpp_library . test_files . empty?
292
+ # Handle lack of test files
293
+ if cpp_library . test_files . empty?
265
294
handle_expectation_of_files ( VAR_EXPECT_UNITTESTS , "unit tests" , "test files" , "tests directory" , cpp_library . tests_dir )
266
- elsif config . platforms_to_unittest . empty?
295
+ return
296
+ end
297
+
298
+ # Handle lack of platforms
299
+ if config . platforms_to_unittest . empty?
267
300
inform ( "Skipping unit tests" ) { "no platforms were requested" }
268
- else
269
- install_arduino_library_dependencies ( config . aux_libraries_for_unittest , "<unittest/libraries>" )
270
-
271
- config . platforms_to_unittest . each do | p |
272
- config . allowable_unittest_files ( cpp_library . test_files ) . each do | unittest_path |
273
- unittest_name = unittest_path . basename . to_s
274
- compilers . each do |gcc_binary |
275
- attempt_multiline ( "Unit testing #{ unittest_name } with #{ gcc_binary } for #{ p } " ) do
276
- exe = cpp_library . build_for_test_with_configuration (
277
- unittest_path ,
278
- config . aux_libraries_for_unittest ,
279
- gcc_binary ,
280
- config . gcc_config ( p )
281
- )
282
- puts
283
- unless exe
284
- puts "Last command: #{ cpp_library . last_cmd } "
285
- puts cpp_library . last_out
286
- puts cpp_library . last_err
287
- next false
288
- end
289
- cpp_library . run_test_file ( exe )
301
+ return
302
+ end
303
+
304
+ install_arduino_library_dependencies ( config . aux_libraries_for_unittest , "<unittest/libraries>" )
305
+
306
+ config . platforms_to_unittest . each do | p |
307
+ config . allowable_unittest_files ( cpp_library . test_files ) . each do |unittest_path |
308
+ unittest_name = unittest_path . basename . to_s
309
+ compilers . each do | gcc_binary |
310
+ attempt_multiline ( "Unit testing #{ unittest_name } with #{ gcc_binary } for #{ p } " ) do
311
+ exe = cpp_library . build_for_test_with_configuration (
312
+ unittest_path ,
313
+ config . aux_libraries_for_unittest ,
314
+ gcc_binary ,
315
+ config . gcc_config ( p )
316
+ )
317
+ puts
318
+ unless exe
319
+ puts "Last command: #{ cpp_library . last_cmd } "
320
+ puts cpp_library . last_out
321
+ puts cpp_library . last_err
322
+ next false
290
323
end
324
+ cpp_library . run_test_file ( exe )
291
325
end
292
326
end
293
327
end
@@ -325,38 +359,14 @@ def perform_example_compilation_tests(cpp_library, config)
325
359
aux_libraries . merge ( ovr_config . aux_libraries_for_build )
326
360
end
327
361
328
- # with all platform info, we can extract unique packages and their urls
329
- # do that, set the URLs, and download the packages
330
- all_packages = example_platform_info . values . map { |v | v [ :package ] } . uniq . reject ( &:nil? )
331
-
332
- # make sure any non-builtin package has a URL defined
333
- all_packages . each do |p |
334
- assure ( "Board package #{ p } has a defined URL" ) { board_package_url [ p ] }
335
- end
336
-
337
- # set up all the board manager URLs.
338
- # we can safely reject nils now, they would be for the builtins
339
- all_urls = all_packages . map { |p | board_package_url [ p ] } . uniq . reject ( &:nil? )
340
-
341
- unless all_urls . empty?
342
- assure ( "Setting board manager URLs" ) do
343
- @backend . board_manager_urls = all_urls
344
- end
345
- end
346
-
347
- all_packages . each do |p |
348
- assure ( "Installing board package #{ p } " ) do
349
- @backend . install_boards ( p )
350
- end
351
- end
352
-
362
+ install_all_packages ( example_platform_info , board_package_url )
353
363
install_arduino_library_dependencies ( aux_libraries , "<compile/libraries>" )
354
364
355
365
if config . platforms_to_build . empty?
356
366
inform ( "Skipping builds" ) { "no platforms were requested" }
357
367
return
358
368
elsif library_examples . empty?
359
- handle_expectation_of_files ( VAR_EXPECT_EXAMPLES , "builds" , "examples" , "the library directory" , installed_library_path )
369
+ handle_expectation_of_files ( VAR_EXPECT_EXAMPLES , "builds" , "examples" , "the examples directory" , cpp_library . examples_dir )
360
370
return
361
371
end
362
372
0 commit comments