Skip to content

Commit 6183778

Browse files
committed
base CppLibrary on ArduinoBackend
1 parent 1972a63 commit 6183778

13 files changed

+506
-308
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1313
### Changed
1414
- Arduino backend is now `arduino-cli` version `0.13.0`
1515
- `ArduinoCmd` is now `ArduinoBackend`
16+
- `CppLibrary` now relies largely on `ArduinoBackend` instead of making its own judgements about libraries (metadata, includes, and examples)
17+
- `ArduinoBackend` functionality related to `CppLibrary` now lives in `CppLibrary`
18+
- `CppLibrary` now works in an installation-first manner for exposure to `arduino-cli`'s logic -- without installation, there is no ability to reason about libraries
19+
- `CppLibrary` forces just-in-time recursive dependency installation in order to work sensibly
20+
- `ArduinoBackend` maintains the central "best guess" logic on what a library (on disk) might be named
1621

1722
### Deprecated
1823
- `arduino_ci_remote.rb` CLI switch `--skip-compilation`

exe/arduino_ci.rb

+63-70
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
@failure_count = 0
1111
@passfail = proc { |result| result ? "✓" : "✗" }
12+
@backend = nil
1213

1314
# Use some basic parsing to allow command-line overrides of config
1415
class Parser
@@ -29,11 +30,6 @@ def self.parse(options)
2930
output_options[:skip_unittests] = p
3031
end
3132

32-
opts.on("--skip-compilation", "Don't compile example sketches (deprecated)") do |p|
33-
puts "The option --skip-compilation has been deprecated in favor of --skip-examples-compilation"
34-
output_options[:skip_compilation] = p
35-
end
36-
3733
opts.on("--skip-examples-compilation", "Don't compile example sketches") do |p|
3834
output_options[:skip_compilation] = p
3935
end
@@ -68,11 +64,11 @@ def self.parse(options)
6864
def terminate(final = nil)
6965
puts "Failures: #{@failure_count}"
7066
unless @failure_count.zero? || final
71-
puts "Last message: #{@arduino_backend.last_msg}"
67+
puts "Last message: #{@backend.last_msg}"
7268
puts "========== Stdout:"
73-
puts @arduino_backend.last_out
69+
puts @backend.last_out
7470
puts "========== Stderr:"
75-
puts @arduino_backend.last_err
71+
puts @backend.last_err
7672
end
7773
retcode = @failure_count.zero? ? 0 : 1
7874
exit(retcode)
@@ -172,25 +168,33 @@ def display_files(pathname)
172168
non_hidden.each { |p| puts "#{margin}#{p}" }
173169
end
174170

175-
def install_arduino_library_dependencies(aux_libraries)
176-
aux_libraries.each do |l|
177-
if @arduino_backend.library_present?(l)
178-
inform("Using pre-existing library") { l.to_s }
171+
# @return [Array<String>] The list of installed libraries
172+
def install_arduino_library_dependencies(library_names, on_behalf_of, already_installed = [])
173+
installed = already_installed.clone
174+
library_names.map { |n| @backend.library_of_name(n) }.each do |l|
175+
if installed.include?(l)
176+
# do nothing
177+
elsif l.installed?
178+
inform("Using pre-existing dependency of #{on_behalf_of}") { l.name }
179179
else
180-
assure("Installing aux library '#{l}'") { @arduino_backend.install_library(l) }
180+
assure("Installing dependency of #{on_behalf_of}: '#{l.name}'") do
181+
next nil unless l.install
182+
183+
l.name
184+
end
181185
end
186+
installed << l.name
187+
installed += install_arduino_library_dependencies(l.arduino_library_dependencies, l.name, installed)
182188
end
189+
installed
183190
end
184191

185-
def perform_unit_tests(file_config)
192+
def perform_unit_tests(cpp_library, file_config)
186193
if @cli_options[:skip_unittests]
187194
inform("Skipping unit tests") { "as requested via command line" }
188195
return
189196
end
190197
config = file_config.with_override_config(@cli_options[:ci_config])
191-
cpp_library = ArduinoCI::CppLibrary.new(Pathname.new("."),
192-
@arduino_backend.lib_dir,
193-
config.exclude_dirs.map(&Pathname.method(:new)))
194198

195199
# check GCC
196200
compilers = config.compilers_to_use
@@ -216,7 +220,7 @@ def perform_unit_tests(file_config)
216220
if !cpp_library.tests_dir.exist?
217221
# alert future me about running the script from the wrong directory, instead of doing the huge file dump
218222
# otherwise, assume that the user might be running the script on a library with no actual unit tests
219-
if (Pathname.new(__dir__).parent == Pathname.new(Dir.pwd))
223+
if Pathname.new(__dir__).parent == Pathname.new(Dir.pwd)
220224
inform_multiline("arduino_ci seems to be trying to test itself") do
221225
[
222226
"arduino_ci (the ruby gem) isn't an arduino project itself, so running the CI test script against",
@@ -243,7 +247,7 @@ def perform_unit_tests(file_config)
243247
elsif config.platforms_to_unittest.empty?
244248
inform("Skipping unit tests") { "no platforms were requested" }
245249
else
246-
install_arduino_library_dependencies(config.aux_libraries_for_unittest)
250+
install_arduino_library_dependencies(config.aux_libraries_for_unittest, "<unittest/libraries>")
247251

248252
config.platforms_to_unittest.each do |p|
249253
config.allowable_unittest_files(cpp_library.test_files).each do |unittest_path|
@@ -271,36 +275,12 @@ def perform_unit_tests(file_config)
271275
end
272276
end
273277

274-
def perform_compilation_tests(config)
278+
def perform_example_compilation_tests(cpp_library, config)
275279
if @cli_options[:skip_compilation]
276280
inform("Skipping compilation of examples") { "as requested via command line" }
277281
return
278282
end
279283

280-
# initialize library under test
281-
installed_library_path = attempt("Installing library under test") do
282-
@arduino_backend.install_local_library(Pathname.new("."))
283-
end
284-
285-
if !installed_library_path.nil? && installed_library_path.exist?
286-
inform("Library installed at") { installed_library_path.to_s }
287-
else
288-
assure_multiline("Library installed successfully") do
289-
if installed_library_path.nil?
290-
puts @arduino_backend.last_msg
291-
else
292-
# print out the contents of the deepest directory we actually find
293-
@arduino_backend.lib_dir.ascend do |path_part|
294-
next unless path_part.exist?
295-
296-
break display_files(path_part)
297-
end
298-
false
299-
end
300-
end
301-
end
302-
library_examples = @arduino_backend.library_examples(installed_library_path)
303-
304284
# gather up all required boards for compilation so we can install them up front.
305285
# start with the "platforms to unittest" and add the examples
306286
# while we're doing that, get the aux libraries as well
@@ -309,6 +289,7 @@ def perform_compilation_tests(config)
309289
aux_libraries = Set.new(config.aux_libraries_for_build)
310290
# while collecting the platforms, ensure they're defined
311291

292+
library_examples = cpp_library.example_sketches
312293
library_examples.each do |path|
313294
ovr_config = config.from_example(path)
314295
ovr_config.platforms_to_build.each do |platform|
@@ -329,33 +310,35 @@ def perform_compilation_tests(config)
329310
# do that, set the URLs, and download the packages
330311
all_packages = example_platform_info.values.map { |v| v[:package] }.uniq.reject(&:nil?)
331312

313+
builtin_packages, external_packages = all_packages.partition { |p| config.package_builtin?(p) }
314+
332315
# inform about builtin packages
333-
all_packages.select { |p| config.package_builtin?(p) }.each do |p|
316+
builtin_packages.each do |p|
334317
inform("Using built-in board package") { p }
335318
end
336319

337320
# make sure any non-builtin package has a URL defined
338-
all_packages.reject { |p| config.package_builtin?(p) }.each do |p|
321+
external_packages.each do |p|
339322
assure("Board package #{p} has a defined URL") { board_package_url[p] }
340323
end
341324

342325
# set up all the board manager URLs.
343326
# we can safely reject nils now, they would be for the builtins
344-
all_urls = all_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
327+
all_urls = external_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
345328

346329
unless all_urls.empty?
347330
assure("Setting board manager URLs") do
348-
@arduino_backend.board_manager_urls = all_urls
331+
@backend.board_manager_urls = all_urls
349332
end
350333
end
351334

352-
all_packages.each do |p|
335+
external_packages.each do |p|
353336
assure("Installing board package #{p}") do
354-
@arduino_backend.install_boards(p)
337+
@backend.install_boards(p)
355338
end
356339
end
357340

358-
install_arduino_library_dependencies(aux_libraries)
341+
install_arduino_library_dependencies(aux_libraries, "<compile/libraries>")
359342

360343
if config.platforms_to_build.empty?
361344
inform("Skipping builds") { "no platforms were requested" }
@@ -367,41 +350,51 @@ def perform_compilation_tests(config)
367350
return
368351
end
369352

370-
# switching boards takes time, so iterate board first
371-
# _then_ whichever examples match it
372-
examples_by_platform = library_examples.each_with_object({}) do |example_path, acc|
353+
library_examples.each do |example_path|
373354
ovr_config = config.from_example(example_path)
374355
ovr_config.platforms_to_build.each do |p|
375-
acc[p] = [] unless acc.key?(p)
376-
acc[p] << example_path
377-
end
378-
end
379-
380-
examples_by_platform.each do |platform, example_paths|
381-
board = example_platform_info[platform][:board]
382-
example_paths.each do |example_path|
356+
board = example_platform_info[p][:board]
383357
example_name = File.basename(example_path)
384358
attempt("Compiling #{example_name} for #{board}") do
385-
ret = @arduino_backend.compile_sketch(example_path, board)
359+
ret = @backend.compile_sketch(example_path, board)
386360
unless ret
387361
puts
388-
puts "Last command: #{@arduino_backend.last_msg}"
389-
puts @arduino_backend.last_err
362+
puts "Last command: #{@backend.last_msg}"
363+
puts @backend.last_err
390364
end
391365
ret
392366
end
393367
end
394368
end
395-
396369
end
397370

398371
# initialize command and config
399372
config = ArduinoCI::CIConfig.default.from_project_library
400373

401-
@arduino_backend = ArduinoCI::ArduinoInstallation.autolocate!
402-
inform("Located arduino-cli binary") { @arduino_backend.binary_path.to_s }
374+
@backend = ArduinoCI::ArduinoInstallation.autolocate!
375+
inform("Located arduino-cli binary") { @backend.binary_path.to_s }
376+
377+
# initialize library under test
378+
cpp_library = assure("Installing library under test") do
379+
@backend.install_local_library(Pathname.new("."))
380+
end
381+
382+
if !cpp_library.nil?
383+
inform("Library installed at") { cpp_library.path.to_s }
384+
else
385+
# this is a longwinded way of failing, we aren't really "assuring" anything at this point
386+
assure_multiline("Library installed successfully") do
387+
puts @backend.last_msg
388+
false
389+
end
390+
end
391+
392+
install_arduino_library_dependencies(
393+
cpp_library.arduino_library_dependencies,
394+
"<#{ArduinoCI::CppLibrary::LIBRARY_PROPERTIES_FILE}>"
395+
)
403396

404-
perform_unit_tests(config)
405-
perform_compilation_tests(config)
397+
perform_unit_tests(cpp_library, config)
398+
perform_example_compilation_tests(cpp_library, config)
406399

407400
terminate(true)

exe/arduino_library_location.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
require 'arduino_ci'
33

44
# locate and/or forcibly install Arduino, keep stdout clean
5-
@arduino_backend = ArduinoCI::ArduinoInstallation.autolocate!($stderr)
5+
@backend = ArduinoCI::ArduinoInstallation.autolocate!($stderr)
66

7-
puts @arduino_backend.lib_dir
7+
puts @backend.lib_dir

0 commit comments

Comments
 (0)