arduino_ci 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +48 -336
- data/cpp/arduino/Arduino.h +4 -68
- data/cpp/arduino/Godmode.cpp +14 -0
- data/cpp/arduino/Godmode.h +32 -12
- data/cpp/arduino/SPI.h +150 -0
- data/cpp/arduino/ci/Table.h +8 -0
- data/exe/arduino_ci_remote.rb +88 -33
- data/exe/arduino_ci_remote.rb.orig +216 -0
- data/exe/ensure_arduino_installation.rb +5 -0
- data/lib/arduino_ci/arduino_cmd.rb +40 -32
- data/lib/arduino_ci/arduino_cmd_linux.rb +2 -20
- data/lib/arduino_ci/arduino_cmd_linux_builder.rb +0 -18
- data/lib/arduino_ci/arduino_cmd_osx.rb +0 -17
- data/lib/arduino_ci/arduino_cmd_windows.rb +0 -17
- data/lib/arduino_ci/arduino_downloader.rb +4 -0
- data/lib/arduino_ci/arduino_downloader_linux.rb +2 -0
- data/lib/arduino_ci/arduino_downloader_windows.rb +2 -0
- data/lib/arduino_ci/arduino_installation.rb +6 -3
- data/lib/arduino_ci/ci_config.rb +13 -3
- data/lib/arduino_ci/cpp_library.rb +129 -52
- data/lib/arduino_ci/host.rb +10 -4
- data/lib/arduino_ci/version.rb +1 -1
- metadata +11 -11
- data/lib/arduino_ci/arduino_downloader.rb.orig +0 -219
- data/lib/arduino_ci/arduino_downloader_linux.rb.orig +0 -79
- data/lib/arduino_ci/arduino_downloader_osx.rb.orig +0 -88
- data/lib/arduino_ci/arduino_installation.rb.orig +0 -116
- data/lib/arduino_ci/display_manager.rb +0 -192
@@ -0,0 +1,216 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'arduino_ci'
|
3
|
+
require 'set'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
WIDTH = 80
|
7
|
+
|
8
|
+
@failure_count = 0
|
9
|
+
@passfail = proc { |result| result ? "✓" : "✗" }
|
10
|
+
|
11
|
+
# terminate after printing any debug info. TODO: capture debug info
|
12
|
+
def terminate(final = nil)
|
13
|
+
puts "Failures: #{@failure_count}"
|
14
|
+
unless @failure_count.zero? || final
|
15
|
+
puts "Last message: #{@arduino_cmd.last_msg}"
|
16
|
+
puts "========== Stdout:"
|
17
|
+
puts @arduino_cmd.last_out
|
18
|
+
puts "========== Stderr:"
|
19
|
+
puts @arduino_cmd.last_err
|
20
|
+
end
|
21
|
+
retcode = @failure_count.zero? ? 0 : 1
|
22
|
+
exit(retcode)
|
23
|
+
end
|
24
|
+
|
25
|
+
# make a nice status line for an action and react to the action
|
26
|
+
def perform_action(message, multiline, mark_fn, on_fail_msg, abort_on_fail)
|
27
|
+
line = "#{message}... "
|
28
|
+
endline = "...#{message} "
|
29
|
+
if multiline
|
30
|
+
puts line
|
31
|
+
else
|
32
|
+
print line
|
33
|
+
end
|
34
|
+
result = yield
|
35
|
+
mark = mark_fn.nil? ? "" : mark_fn.call(result)
|
36
|
+
# if multline, put checkmark at full width
|
37
|
+
print endline if multiline
|
38
|
+
puts mark.rjust(WIDTH - line.length, " ")
|
39
|
+
unless result
|
40
|
+
puts on_fail_msg unless on_fail_msg.nil?
|
41
|
+
@failure_count += 1
|
42
|
+
# print out error messaging here if we've captured it
|
43
|
+
terminate if abort_on_fail
|
44
|
+
end
|
45
|
+
result
|
46
|
+
end
|
47
|
+
|
48
|
+
# Make a nice status for something that defers any failure code until script exit
|
49
|
+
def attempt(message, &block)
|
50
|
+
perform_action(message, false, @passfail, nil, false, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Make a nice status for something that defers any failure code until script exit
|
54
|
+
def attempt_multiline(message, &block)
|
55
|
+
perform_action(message, true, @passfail, nil, false, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Make a nice status for something that kills the script immediately on failure
|
59
|
+
def assure(message, &block)
|
60
|
+
perform_action(message, false, @passfail, "This may indicate a problem with ArduinoCI, or your configuration", true, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def inform(message, &block)
|
64
|
+
perform_action(message, false, proc { |x| x }, nil, false, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def inform_multiline(message, &block)
|
68
|
+
<<<<<<< HEAD
|
69
|
+
perform_action(message, true, nil, nil, false, &block)
|
70
|
+
=======
|
71
|
+
perform_action(message, true, proc { }, nil, false, &block)
|
72
|
+
>>>>>>> 30d4a9f... Show file tree when unittests or examples aren't found
|
73
|
+
end
|
74
|
+
|
75
|
+
# Assure that a platform exists and return its definition
|
76
|
+
def assured_platform(purpose, name, config)
|
77
|
+
platform_definition = config.platform_definition(name)
|
78
|
+
assure("Requested #{purpose} platform '#{name}' is defined in 'platforms' YML") do
|
79
|
+
!platform_definition.nil?
|
80
|
+
end
|
81
|
+
platform_definition
|
82
|
+
end
|
83
|
+
|
84
|
+
# initialize command and config
|
85
|
+
config = ArduinoCI::CIConfig.default.from_project_library
|
86
|
+
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
|
87
|
+
|
88
|
+
# initialize library under test
|
89
|
+
installed_library_path = assure("Installing library under test") { @arduino_cmd.install_local_library(".") }
|
90
|
+
library_examples = @arduino_cmd.library_examples(installed_library_path)
|
91
|
+
cpp_library = ArduinoCI::CppLibrary.new(installed_library_path, @arduino_cmd.lib_dir)
|
92
|
+
inform("Library installed at") { installed_library_path.to_s }
|
93
|
+
|
94
|
+
# check GCC
|
95
|
+
compilers = config.compilers_to_use
|
96
|
+
assure("The set of compilers (#{compilers.length}) isn't empty") { !compilers.empty? }
|
97
|
+
compilers.each do |gcc_binary|
|
98
|
+
attempt_multiline("Checking #{gcc_binary} version") do
|
99
|
+
version = cpp_library.gcc_version(gcc_binary)
|
100
|
+
next nil unless version
|
101
|
+
|
102
|
+
puts version.split("\n").map { |l| " #{l}" }.join("\n")
|
103
|
+
version
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# gather up all required boards so we can install them up front.
|
108
|
+
# start with the "platforms to unittest" and add the examples
|
109
|
+
# while we're doing that, get the aux libraries as well
|
110
|
+
all_platforms = {}
|
111
|
+
aux_libraries = Set.new(config.aux_libraries_for_unittest + config.aux_libraries_for_build)
|
112
|
+
# while collecting the platforms, ensure they're defined
|
113
|
+
config.platforms_to_unittest.each { |p| all_platforms[p] = assured_platform("unittest", p, config) }
|
114
|
+
library_examples.each do |path|
|
115
|
+
ovr_config = config.from_example(path)
|
116
|
+
ovr_config.platforms_to_build.each { |p| all_platforms[p] = assured_platform("library example", p, config) }
|
117
|
+
aux_libraries.merge(ovr_config.aux_libraries_for_build)
|
118
|
+
end
|
119
|
+
|
120
|
+
# with all platform info, we can extract unique packages and their urls
|
121
|
+
# do that, set the URLs, and download the packages
|
122
|
+
all_packages = all_platforms.values.map { |v| v[:package] }.uniq.reject(&:nil?)
|
123
|
+
all_urls = all_packages.map { |p| config.package_url(p) }.uniq.reject(&:nil?)
|
124
|
+
unless all_urls.empty?
|
125
|
+
assure("Setting board manager URLs") do
|
126
|
+
@arduino_cmd.set_pref("boardsmanager.additional.urls", all_urls.join(","))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
all_packages.each do |p|
|
131
|
+
assure("Installing board package #{p}") do
|
132
|
+
@arduino_cmd.install_boards(p)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
aux_libraries.each do |l|
|
137
|
+
if @arduino_cmd.library_present?(l)
|
138
|
+
inform("Using pre-existing library") { l.to_s }
|
139
|
+
else
|
140
|
+
assure("Installing aux library '#{l}'") { @arduino_cmd.install_library(l) }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# iterate boards / tests
|
145
|
+
last_board = nil
|
146
|
+
if !cpp_library.tests_dir.exist?
|
147
|
+
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
|
148
|
+
puts cpp_library.tests_dir.find.to_a.to_s
|
149
|
+
true
|
150
|
+
end
|
151
|
+
elsif cpp_library.test_files.empty?
|
152
|
+
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
|
153
|
+
puts cpp_library.tests_dir.find.to_a.to_s
|
154
|
+
true
|
155
|
+
end
|
156
|
+
elsif config.platforms_to_unittest.empty?
|
157
|
+
inform("Skipping unit tests") { "no platforms were requested" }
|
158
|
+
else
|
159
|
+
config.platforms_to_unittest.each do |p|
|
160
|
+
board = all_platforms[p][:board]
|
161
|
+
last_board = "arduino:avr:pro:cpu=16MHzatmega328"
|
162
|
+
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
163
|
+
last_board = board
|
164
|
+
cpp_library.test_files.each do |unittest_path|
|
165
|
+
unittest_name = unittest_path.basename.to_s
|
166
|
+
compilers.each do |gcc_binary|
|
167
|
+
attempt_multiline("Unit testing #{unittest_name} with #{gcc_binary}") do
|
168
|
+
exe = cpp_library.build_for_test_with_configuration(
|
169
|
+
unittest_path,
|
170
|
+
config.aux_libraries_for_unittest,
|
171
|
+
gcc_binary,
|
172
|
+
config.gcc_config(p)
|
173
|
+
)
|
174
|
+
puts
|
175
|
+
unless exe
|
176
|
+
puts "Last command: #{cpp_library.last_cmd}"
|
177
|
+
puts cpp_library.last_out
|
178
|
+
puts cpp_library.last_err
|
179
|
+
next false
|
180
|
+
end
|
181
|
+
cpp_library.run_test_file(exe)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
if library_examples.empty?
|
189
|
+
inform_multiline("Skipping libraries; no examples found in #{installed_library_path}") do
|
190
|
+
puts installed_library_path.find.to_a.to_s
|
191
|
+
end
|
192
|
+
else
|
193
|
+
attempt("Setting compiler warning level") { @arduino_cmd.set_pref("compiler.warning_level", "all") }
|
194
|
+
|
195
|
+
# unlike previous, iterate examples / boards
|
196
|
+
library_examples.each do |example_path|
|
197
|
+
ovr_config = config.from_example(example_path)
|
198
|
+
ovr_config.platforms_to_build.each do |p|
|
199
|
+
board = all_platforms[p][:board]
|
200
|
+
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
201
|
+
last_board = board
|
202
|
+
example_name = File.basename(example_path)
|
203
|
+
attempt("Verifying #{example_name}") do
|
204
|
+
ret = @arduino_cmd.verify_sketch(example_path)
|
205
|
+
unless ret
|
206
|
+
puts
|
207
|
+
puts "Last command: #{@arduino_cmd.last_msg}"
|
208
|
+
puts @arduino_cmd.last_err
|
209
|
+
end
|
210
|
+
ret
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
terminate(true)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
module ArduinoCI
|
4
5
|
|
@@ -14,7 +15,7 @@ module ArduinoCI
|
|
14
15
|
# @return [String] the text of the command line flag (`$2` in this case)
|
15
16
|
def self.flag(name, text = nil)
|
16
17
|
text = "(flag #{name} not defined)" if text.nil?
|
17
|
-
self.class_eval("def flag_#{name};\"#{text}\";end")
|
18
|
+
self.class_eval("def flag_#{name};\"#{text}\";end", __FILE__, __LINE__)
|
18
19
|
end
|
19
20
|
|
20
21
|
# the path to the Arduino executable
|
@@ -66,8 +67,8 @@ module ArduinoCI
|
|
66
67
|
end
|
67
68
|
|
68
69
|
# @return [String] the path to the Arduino libraries directory
|
69
|
-
def
|
70
|
-
"
|
70
|
+
def lib_dir
|
71
|
+
Pathname.new(get_pref("sketchbook.path")) + "libraries"
|
71
72
|
end
|
72
73
|
|
73
74
|
# fetch preferences in their raw form
|
@@ -75,6 +76,8 @@ module ArduinoCI
|
|
75
76
|
def _prefs_raw
|
76
77
|
resp = run_and_capture(flag_get_pref)
|
77
78
|
return nil unless resp[:success]
|
79
|
+
|
80
|
+
@prefs_fetched = true
|
78
81
|
resp[:out]
|
79
82
|
end
|
80
83
|
|
@@ -83,6 +86,7 @@ module ArduinoCI
|
|
83
86
|
def prefs
|
84
87
|
prefs_raw = _prefs_raw unless @prefs_fetched
|
85
88
|
return nil if prefs_raw.nil?
|
89
|
+
|
86
90
|
@prefs_cache = parse_pref_string(prefs_raw)
|
87
91
|
@prefs_cache.clone
|
88
92
|
end
|
@@ -108,23 +112,12 @@ module ArduinoCI
|
|
108
112
|
# @param value [String] the preference value
|
109
113
|
# @return [bool] whether the command succeeded
|
110
114
|
def set_pref(key, value)
|
115
|
+
prefs unless @prefs_fetched # update cache first
|
111
116
|
success = _set_pref(key, value)
|
112
117
|
@prefs_cache[key] = value if success
|
113
118
|
success
|
114
119
|
end
|
115
120
|
|
116
|
-
# run the arduino command
|
117
|
-
# @return [bool] whether the command succeeded
|
118
|
-
def _run_and_output(*args, **kwargs)
|
119
|
-
raise "Ian needs to implement this in a subclass #{args} #{kwargs}"
|
120
|
-
end
|
121
|
-
|
122
|
-
# run the arduino command
|
123
|
-
# @return [Hash] keys for :success, :out, and :err
|
124
|
-
def _run_and_capture(*args, **kwargs)
|
125
|
-
raise "Ian needs to implement this in a subclass #{args} #{kwargs}"
|
126
|
-
end
|
127
|
-
|
128
121
|
def _wrap_run(work_fn, *args, **kwargs)
|
129
122
|
# do some work to extract & merge environment variables if they exist
|
130
123
|
has_env = !args.empty? && args[0].class == Hash
|
@@ -140,13 +133,13 @@ module ArduinoCI
|
|
140
133
|
|
141
134
|
# build and run the arduino command
|
142
135
|
def run_and_output(*args, **kwargs)
|
143
|
-
_wrap_run((proc { |*a, **k|
|
136
|
+
_wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs)
|
144
137
|
end
|
145
138
|
|
146
139
|
# run a command and capture its output
|
147
140
|
# @return [Hash] {:out => String, :err => String, :success => bool}
|
148
141
|
def run_and_capture(*args, **kwargs)
|
149
|
-
ret = _wrap_run((proc { |*a, **k|
|
142
|
+
ret = _wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs)
|
150
143
|
@last_err = ret[:err]
|
151
144
|
@last_out = ret[:out]
|
152
145
|
ret
|
@@ -200,9 +193,20 @@ module ArduinoCI
|
|
200
193
|
|
201
194
|
# generate the (very likely) path of a library given its name
|
202
195
|
# @param library_name [String] The name of the library
|
203
|
-
# @return [
|
196
|
+
# @return [Pathname] The fully qualified library name
|
204
197
|
def library_path(library_name)
|
205
|
-
|
198
|
+
Pathname.new(lib_dir) + library_name
|
199
|
+
end
|
200
|
+
|
201
|
+
# Determine whether a library is present in the lib dir
|
202
|
+
#
|
203
|
+
# Note that `true` doesn't guarantee that the library is valid/installed
|
204
|
+
# and `false` doesn't guarantee that the library isn't built-in
|
205
|
+
#
|
206
|
+
# @param library_name [String] The name of the library
|
207
|
+
# @return [bool]
|
208
|
+
def library_present?(library_name)
|
209
|
+
library_path(library_name).exist?
|
206
210
|
end
|
207
211
|
|
208
212
|
# update the library index
|
@@ -225,9 +229,11 @@ module ArduinoCI
|
|
225
229
|
# @return [bool] whether the command succeeded
|
226
230
|
def use_board!(boardname)
|
227
231
|
return true if use_board(boardname)
|
232
|
+
|
228
233
|
boardfamily = boardname.split(":")[0..1].join(":")
|
229
234
|
puts "Board '#{boardname}' not found; attempting to install '#{boardfamily}'"
|
230
235
|
return false unless install_boards(boardfamily) # guess board family from first 2 :-separated fields
|
236
|
+
|
231
237
|
use_board(boardname)
|
232
238
|
end
|
233
239
|
|
@@ -249,23 +255,24 @@ module ArduinoCI
|
|
249
255
|
|
250
256
|
# ensure that the given library is installed, or symlinked as appropriate
|
251
257
|
# return the path of the prepared library, or nil
|
252
|
-
# @param path [
|
258
|
+
# @param path [Pathname] library to use
|
253
259
|
# @return [String] the path of the installed library
|
254
260
|
def install_local_library(path)
|
255
|
-
|
256
|
-
library_name =
|
261
|
+
src_path = path.realpath
|
262
|
+
library_name = src_path.basename
|
257
263
|
destination_path = library_path(library_name)
|
258
264
|
|
259
265
|
# things get weird if the sketchbook contains the library.
|
260
266
|
# check that first
|
261
|
-
if
|
267
|
+
if destination_path.exist?
|
262
268
|
uhoh = "There is already a library '#{library_name}' in the library directory"
|
263
|
-
return destination_path if destination_path ==
|
269
|
+
return destination_path if destination_path == src_path
|
264
270
|
|
265
271
|
# maybe it's a symlink? that would be OK
|
266
|
-
if
|
267
|
-
return destination_path if
|
268
|
-
|
272
|
+
if destination_path.symlink?
|
273
|
+
return destination_path if destination_path.readlink == src_path
|
274
|
+
|
275
|
+
@last_msg = "#{uhoh} and it's not symlinked to #{src_path}"
|
269
276
|
return nil
|
270
277
|
end
|
271
278
|
|
@@ -274,19 +281,20 @@ module ArduinoCI
|
|
274
281
|
end
|
275
282
|
|
276
283
|
# install the library
|
277
|
-
Host.symlink(
|
284
|
+
Host.symlink(src_path, destination_path)
|
278
285
|
destination_path
|
279
286
|
end
|
280
287
|
|
281
288
|
# @param installed_library_path [String] The library to query
|
282
289
|
# @return [Array<String>] Example sketch files
|
283
290
|
def library_examples(installed_library_path)
|
284
|
-
example_path =
|
291
|
+
example_path = Pathname.new(installed_library_path) + "examples"
|
285
292
|
return [] unless File.exist?(example_path)
|
286
|
-
|
293
|
+
|
294
|
+
examples = example_path.children.select(&:directory?).map(&:to_path).map(&File.method(:basename))
|
287
295
|
files = examples.map do |e|
|
288
|
-
proj_file =
|
289
|
-
|
296
|
+
proj_file = example_path + e + "#{e}.ino"
|
297
|
+
proj_file.exist? ? proj_file.to_s : nil
|
290
298
|
end
|
291
299
|
files.reject(&:nil?)
|
292
300
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'arduino_ci/arduino_cmd'
|
2
|
-
require '
|
2
|
+
require 'timeout'
|
3
3
|
|
4
4
|
module ArduinoCI
|
5
5
|
|
@@ -19,7 +19,6 @@ module ArduinoCI
|
|
19
19
|
def initialize
|
20
20
|
super
|
21
21
|
@prefs_response_time = nil
|
22
|
-
@display_mgr = DisplayManager::instance
|
23
22
|
end
|
24
23
|
|
25
24
|
# fetch preferences in their raw form
|
@@ -29,25 +28,8 @@ module ArduinoCI
|
|
29
28
|
resp = run_and_capture(flag_get_pref)
|
30
29
|
@prefs_response_time = Time.now - start
|
31
30
|
return nil unless resp[:success]
|
32
|
-
resp[:out]
|
33
|
-
end
|
34
|
-
|
35
|
-
# implementation for Arduino library dir location
|
36
|
-
# @return [String] the path to the Arduino libraries directory
|
37
|
-
def _lib_dir
|
38
|
-
File.join(get_pref("sketchbook.path"), "libraries")
|
39
|
-
end
|
40
31
|
|
41
|
-
|
42
|
-
# @return [bool] whether the command succeeded
|
43
|
-
def _run_and_output(*args, **kwargs)
|
44
|
-
@display_mgr.run_and_output(*args, **kwargs)
|
45
|
-
end
|
46
|
-
|
47
|
-
# run the arduino command
|
48
|
-
# @return [Hash] keys for :success, :out, and :err
|
49
|
-
def _run_and_capture(*args, **kwargs)
|
50
|
-
@display_mgr.run_and_capture(*args, **kwargs)
|
32
|
+
resp[:out]
|
51
33
|
end
|
52
34
|
|
53
35
|
def run_with_gui_guess(message, *args, **kwargs)
|
@@ -14,24 +14,6 @@ module ArduinoCI
|
|
14
14
|
flag :install_library, "--install-library" # apparently doesn't exist
|
15
15
|
flag :verify, "-compile"
|
16
16
|
|
17
|
-
# linux-specific implementation
|
18
|
-
# @return [String] The path to the library dir
|
19
|
-
def _lib_dir
|
20
|
-
File.join(get_pref("sketchbook.path"), "libraries")
|
21
|
-
end
|
22
|
-
|
23
|
-
# run the arduino command
|
24
|
-
# @return [bool] whether the command succeeded
|
25
|
-
def _run_and_output(*args, **kwargs)
|
26
|
-
Host.run_and_output(*args, **kwargs)
|
27
|
-
end
|
28
|
-
|
29
|
-
# run the arduino command
|
30
|
-
# @return [Hash] keys for :success, :out, and :err
|
31
|
-
def _run_and_capture(*args, **kwargs)
|
32
|
-
Host.run_and_capture(*args, **kwargs)
|
33
|
-
end
|
34
|
-
|
35
17
|
end
|
36
18
|
|
37
19
|
end
|