arduino_ci 0.1.13 → 0.1.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/exe/arduino_ci_remote.rb +76 -13
- data/exe/arduino_ci_remote.rb.orig +76 -24
- data/lib/arduino_ci/arduino_cmd.rb +45 -22
- data/lib/arduino_ci/arduino_cmd_linux.rb +0 -58
- data/lib/arduino_ci/arduino_installation.rb +8 -4
- data/lib/arduino_ci/ci_config.rb +7 -0
- data/lib/arduino_ci/cpp_library.rb +22 -15
- data/lib/arduino_ci/version.rb +1 -1
- data/misc/default.yml +53 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28e1e4179be7a5d17d57b16b02f3eb75a41f6bb9506c8d034c14d2f077d09c48
|
4
|
+
data.tar.gz: b60ab526bb91b353379aa7f3d4a3ab8ec3f8fa18442369e0197c098487ed53a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b9b69ee987e14970104cbf6c6e41f846b714d40536af43d5cc1b21e5811bb75f12172de94a21340277cc830654f97a5a8cb4c5e954f5c2358e515a39ac9c871
|
7
|
+
data.tar.gz: 360e1c2b48e9f706a90275356363802c6534968e0d96c29d5f7a825a1f0c73df2d2526d680bf103909544508506c1e0a7effec59a722f1788b171184d0bbd332
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
# ArduinoCI Ruby gem (`arduino_ci`) [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/0.1.
|
2
|
+
# ArduinoCI Ruby gem (`arduino_ci`) [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/0.1.14)
|
3
3
|
|
4
4
|
You want your Arduino library to be automatically built and tested every time someone contributes code to your project on GitHub, but the Arduino IDE lacks the ability to run unit tests. [Arduino CI](https://github.com/ianfixes/arduino_ci) provides that ability.
|
5
5
|
|
data/exe/arduino_ci_remote.rb
CHANGED
@@ -4,6 +4,7 @@ require 'set'
|
|
4
4
|
require 'pathname'
|
5
5
|
|
6
6
|
WIDTH = 80
|
7
|
+
FIND_FILES_INDENT = 4
|
7
8
|
|
8
9
|
@failure_count = 0
|
9
10
|
@passfail = proc { |result| result ? "✓" : "✗" }
|
@@ -23,6 +24,10 @@ def terminate(final = nil)
|
|
23
24
|
end
|
24
25
|
|
25
26
|
# make a nice status line for an action and react to the action
|
27
|
+
# TODO / note to self: inform_multline is tougher to write
|
28
|
+
# without altering the signature because it only leaves space
|
29
|
+
# for the checkmark _after_ the multiline, it doesn't know how
|
30
|
+
# to make that conditionally the body
|
26
31
|
def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abort_on_fail)
|
27
32
|
line = "#{message}... "
|
28
33
|
endline = "...#{message} "
|
@@ -83,9 +88,36 @@ def assured_platform(purpose, name, config)
|
|
83
88
|
platform_definition
|
84
89
|
end
|
85
90
|
|
91
|
+
# Return true if the file (or one of the dirs containing it) is hidden
|
92
|
+
def file_is_hidden_somewhere?(path)
|
93
|
+
# this is clunkly but pre-2.2-ish ruby doesn't return ascend as an enumerator
|
94
|
+
path.ascend do |part|
|
95
|
+
return true if part.basename.to_s.start_with? "."
|
96
|
+
end
|
97
|
+
false
|
98
|
+
end
|
99
|
+
|
100
|
+
# print out some files
|
101
|
+
def display_files(pathname)
|
102
|
+
# `find` doesn't follow symlinks, so we should instead
|
103
|
+
realpath = pathname.symlink? ? pathname.readlink : pathname
|
104
|
+
|
105
|
+
# suppress directories and dotfile-based things
|
106
|
+
all_files = realpath.find.select(&:file?)
|
107
|
+
non_hidden = all_files.reject { |path| file_is_hidden_somewhere?(path) }
|
108
|
+
|
109
|
+
# print files with an indent
|
110
|
+
margin = " " * FIND_FILES_INDENT
|
111
|
+
non_hidden.each { |p| puts "#{margin}#{p}" }
|
112
|
+
end
|
113
|
+
|
86
114
|
# initialize command and config
|
87
115
|
config = ArduinoCI::CIConfig.default.from_project_library
|
88
116
|
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
|
117
|
+
inform("Located Arduino binary") { @arduino_cmd.binary_path.to_s }
|
118
|
+
|
119
|
+
# index the existing libraries
|
120
|
+
attempt("Indexing libraries") { @arduino_cmd.index_libraries } unless @arduino_cmd.libraries_indexed
|
89
121
|
|
90
122
|
# initialize library under test
|
91
123
|
installed_library_path = attempt("Installing library under test") do
|
@@ -95,10 +127,11 @@ if installed_library_path.exist?
|
|
95
127
|
inform("Library installed at") { installed_library_path.to_s }
|
96
128
|
else
|
97
129
|
assure_multiline("Library installed successfully") do
|
130
|
+
# print out the contents of the deepest directory we actually find
|
98
131
|
@arduino_cmd.lib_dir.ascend do |path_part|
|
99
132
|
next unless path_part.exist?
|
100
133
|
|
101
|
-
break
|
134
|
+
break display_files(path_part)
|
102
135
|
end
|
103
136
|
false
|
104
137
|
end
|
@@ -120,26 +153,54 @@ compilers.each do |gcc_binary|
|
|
120
153
|
inform("libasan availability for #{gcc_binary}") { cpp_library.libasan?(gcc_binary) }
|
121
154
|
end
|
122
155
|
|
123
|
-
#
|
156
|
+
# Ensure platforms exist for unit test, and save their info in all_platform_info keyed by name
|
157
|
+
all_platform_info = {}
|
158
|
+
config.platforms_to_unittest.each { |p| all_platform_info[p] = assured_platform("unittest", p, config) }
|
159
|
+
|
160
|
+
# gather up all required boards for compilation so we can install them up front.
|
124
161
|
# start with the "platforms to unittest" and add the examples
|
125
162
|
# while we're doing that, get the aux libraries as well
|
126
|
-
|
163
|
+
example_platform_info = {}
|
164
|
+
board_package_url = {}
|
127
165
|
aux_libraries = Set.new(config.aux_libraries_for_unittest + config.aux_libraries_for_build)
|
128
166
|
# while collecting the platforms, ensure they're defined
|
129
|
-
config.platforms_to_unittest.each { |p| all_platforms[p] = assured_platform("unittest", p, config) }
|
130
167
|
library_examples.each do |path|
|
131
168
|
ovr_config = config.from_example(path)
|
132
|
-
ovr_config.platforms_to_build.each
|
169
|
+
ovr_config.platforms_to_build.each do |platform|
|
170
|
+
# assure the platform if we haven't already
|
171
|
+
next if example_platform_info.key?(platform)
|
172
|
+
|
173
|
+
platform_info = assured_platform("library example", platform, config)
|
174
|
+
next if platform_info.nil?
|
175
|
+
|
176
|
+
example_platform_info[platform] = all_platform_info[platform] = platform_info
|
177
|
+
package = platform_info[:package]
|
178
|
+
board_package_url[package] = ovr_config.package_url(package)
|
179
|
+
end
|
133
180
|
aux_libraries.merge(ovr_config.aux_libraries_for_build)
|
134
181
|
end
|
135
182
|
|
136
183
|
# with all platform info, we can extract unique packages and their urls
|
137
184
|
# do that, set the URLs, and download the packages
|
138
|
-
all_packages =
|
139
|
-
|
185
|
+
all_packages = all_platform_info.values.map { |v| v[:package] }.uniq.reject(&:nil?)
|
186
|
+
|
187
|
+
# inform about builtin packages
|
188
|
+
all_packages.select { |p| config.package_builtin?(p) }.each do |p|
|
189
|
+
inform("Using built-in board package") { p }
|
190
|
+
end
|
191
|
+
|
192
|
+
# make sure any non-builtin package has a URL defined
|
193
|
+
all_packages.reject { |p| config.package_builtin?(p) }.each do |p|
|
194
|
+
assure("Board package #{p} has a defined URL") { board_package_url[p] }
|
195
|
+
end
|
196
|
+
|
197
|
+
# set up all the board manager URLs.
|
198
|
+
# we can safely reject nils now, they would be for the builtins
|
199
|
+
all_urls = all_packages.map { |p| board_package_url[p] }.uniq.reject(&:nil?)
|
200
|
+
|
140
201
|
unless all_urls.empty?
|
141
202
|
assure("Setting board manager URLs") do
|
142
|
-
@arduino_cmd.
|
203
|
+
@arduino_cmd.board_manager_urls = all_urls
|
143
204
|
end
|
144
205
|
end
|
145
206
|
|
@@ -161,19 +222,21 @@ end
|
|
161
222
|
last_board = nil
|
162
223
|
if !cpp_library.tests_dir.exist?
|
163
224
|
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
|
164
|
-
puts
|
225
|
+
puts " In case that's an error, this is what was found in the library:"
|
226
|
+
display_files(cpp_library.tests_dir.parent)
|
165
227
|
true
|
166
228
|
end
|
167
229
|
elsif cpp_library.test_files.empty?
|
168
230
|
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
|
169
|
-
puts
|
231
|
+
puts " In case that's an error, this is what was found in the tests directory:"
|
232
|
+
display_files(cpp_library.tests_dir)
|
170
233
|
true
|
171
234
|
end
|
172
235
|
elsif config.platforms_to_unittest.empty?
|
173
236
|
inform("Skipping unit tests") { "no platforms were requested" }
|
174
237
|
else
|
175
238
|
config.platforms_to_unittest.each do |p|
|
176
|
-
board =
|
239
|
+
board = all_platform_info[p][:board]
|
177
240
|
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
178
241
|
last_board = board
|
179
242
|
cpp_library.test_files.each do |unittest_path|
|
@@ -202,7 +265,7 @@ end
|
|
202
265
|
|
203
266
|
if library_examples.empty?
|
204
267
|
inform_multiline("Skipping libraries; no examples found in #{installed_library_path}") do
|
205
|
-
|
268
|
+
display_files(installed_library_path)
|
206
269
|
end
|
207
270
|
else
|
208
271
|
attempt("Setting compiler warning level") { @arduino_cmd.set_pref("compiler.warning_level", "all") }
|
@@ -218,7 +281,7 @@ else
|
|
218
281
|
end
|
219
282
|
|
220
283
|
examples_by_platform.each do |platform, example_paths|
|
221
|
-
board =
|
284
|
+
board = all_platform_info[platform][:board]
|
222
285
|
assure("Switching to board for #{platform} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
223
286
|
last_board = board
|
224
287
|
|
@@ -4,6 +4,7 @@ require 'set'
|
|
4
4
|
require 'pathname'
|
5
5
|
|
6
6
|
WIDTH = 80
|
7
|
+
FIND_FILES_INDENT = 4
|
7
8
|
|
8
9
|
@failure_count = 0
|
9
10
|
@passfail = proc { |result| result ? "✓" : "✗" }
|
@@ -23,7 +24,7 @@ def terminate(final = nil)
|
|
23
24
|
end
|
24
25
|
|
25
26
|
# 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
|
+
def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abort_on_fail)
|
27
28
|
line = "#{message}... "
|
28
29
|
endline = "...#{message} "
|
29
30
|
if multiline
|
@@ -31,14 +32,15 @@ def perform_action(message, multiline, mark_fn, on_fail_msg, abort_on_fail)
|
|
31
32
|
else
|
32
33
|
print line
|
33
34
|
end
|
35
|
+
STDOUT.flush
|
34
36
|
result = yield
|
35
37
|
mark = mark_fn.nil? ? "" : mark_fn.call(result)
|
36
38
|
# if multline, put checkmark at full width
|
37
39
|
print endline if multiline
|
38
|
-
puts mark.rjust(WIDTH - line.length, " ")
|
40
|
+
puts mark.to_s.rjust(WIDTH - line.length, " ")
|
39
41
|
unless result
|
40
42
|
puts on_fail_msg unless on_fail_msg.nil?
|
41
|
-
@failure_count += 1
|
43
|
+
@failure_count += 1 if tally_on_fail
|
42
44
|
# print out error messaging here if we've captured it
|
43
45
|
terminate if abort_on_fail
|
44
46
|
end
|
@@ -47,29 +49,30 @@ end
|
|
47
49
|
|
48
50
|
# Make a nice status for something that defers any failure code until script exit
|
49
51
|
def attempt(message, &block)
|
50
|
-
perform_action(message, false, @passfail, nil, false, &block)
|
52
|
+
perform_action(message, false, @passfail, nil, true, false, &block)
|
51
53
|
end
|
52
54
|
|
53
55
|
# Make a nice status for something that defers any failure code until script exit
|
54
56
|
def attempt_multiline(message, &block)
|
55
|
-
perform_action(message, true, @passfail, nil, false, &block)
|
57
|
+
perform_action(message, true, @passfail, nil, true, false, &block)
|
56
58
|
end
|
57
59
|
|
58
60
|
# Make a nice status for something that kills the script immediately on failure
|
61
|
+
FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with ArduinoCI, or your configuration".freeze
|
59
62
|
def assure(message, &block)
|
60
|
-
perform_action(message, false, @passfail,
|
63
|
+
perform_action(message, false, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def assure_multiline(message, &block)
|
67
|
+
perform_action(message, true, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
61
68
|
end
|
62
69
|
|
63
70
|
def inform(message, &block)
|
64
|
-
perform_action(message, false, proc { |x| x }, nil, false, &block)
|
71
|
+
perform_action(message, false, proc { |x| x }, nil, false, false, &block)
|
65
72
|
end
|
66
73
|
|
67
74
|
def inform_multiline(message, &block)
|
68
|
-
|
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
|
75
|
+
perform_action(message, true, nil, nil, false, false, &block)
|
73
76
|
end
|
74
77
|
|
75
78
|
# Assure that a platform exists and return its definition
|
@@ -81,15 +84,51 @@ def assured_platform(purpose, name, config)
|
|
81
84
|
platform_definition
|
82
85
|
end
|
83
86
|
|
87
|
+
# print out some files
|
88
|
+
def display_files(pathname)
|
89
|
+
# `find` doesn't follow symlinks, so we should instead
|
90
|
+
realpath = pathname.symlink? ? pathname.readlink : pathname
|
91
|
+
|
92
|
+
# suppress directories and dotfile-based things
|
93
|
+
all_files = realpath.find.select(&:file?)
|
94
|
+
non_hidden = all_files.reject do |path|
|
95
|
+
<<<<<<< HEAD
|
96
|
+
path.ascend.any? { |part| part.basename.to_s.start_with? "." }
|
97
|
+
=======
|
98
|
+
path.ascend do |path_part|
|
99
|
+
next true if path_part.basename.to_s.start_with? "."
|
100
|
+
end
|
101
|
+
false
|
102
|
+
>>>>>>> 0f4e679... don't redundantly report assured platforms
|
103
|
+
end
|
104
|
+
|
105
|
+
# print files with an indent
|
106
|
+
margin = " " * FIND_FILES_INDENT
|
107
|
+
non_hidden.each { |p| puts "#{margin}#{p}" }
|
108
|
+
end
|
109
|
+
|
84
110
|
# initialize command and config
|
85
111
|
config = ArduinoCI::CIConfig.default.from_project_library
|
86
112
|
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
|
87
113
|
|
88
114
|
# initialize library under test
|
89
|
-
installed_library_path =
|
115
|
+
installed_library_path = attempt("Installing library under test") do
|
116
|
+
@arduino_cmd.install_local_library(Pathname.new("."))
|
117
|
+
end
|
118
|
+
if installed_library_path.exist?
|
119
|
+
inform("Library installed at") { installed_library_path.to_s }
|
120
|
+
else
|
121
|
+
assure_multiline("Library installed successfully") do
|
122
|
+
@arduino_cmd.lib_dir.ascend do |path_part|
|
123
|
+
next unless path_part.exist?
|
124
|
+
|
125
|
+
break display_files(path_part)
|
126
|
+
end
|
127
|
+
false
|
128
|
+
end
|
129
|
+
end
|
90
130
|
library_examples = @arduino_cmd.library_examples(installed_library_path)
|
91
131
|
cpp_library = ArduinoCI::CppLibrary.new(installed_library_path, @arduino_cmd.lib_dir)
|
92
|
-
inform("Library installed at") { installed_library_path.to_s }
|
93
132
|
|
94
133
|
# check GCC
|
95
134
|
compilers = config.compilers_to_use
|
@@ -102,6 +141,7 @@ compilers.each do |gcc_binary|
|
|
102
141
|
puts version.split("\n").map { |l| " #{l}" }.join("\n")
|
103
142
|
version
|
104
143
|
end
|
144
|
+
inform("libasan availability for #{gcc_binary}") { cpp_library.libasan?(gcc_binary) }
|
105
145
|
end
|
106
146
|
|
107
147
|
# gather up all required boards so we can install them up front.
|
@@ -111,9 +151,13 @@ all_platforms = {}
|
|
111
151
|
aux_libraries = Set.new(config.aux_libraries_for_unittest + config.aux_libraries_for_build)
|
112
152
|
# while collecting the platforms, ensure they're defined
|
113
153
|
config.platforms_to_unittest.each { |p| all_platforms[p] = assured_platform("unittest", p, config) }
|
154
|
+
example_platforms = {}
|
114
155
|
library_examples.each do |path|
|
115
156
|
ovr_config = config.from_example(path)
|
116
|
-
ovr_config.platforms_to_build.each
|
157
|
+
ovr_config.platforms_to_build.each do |p|
|
158
|
+
# assure the platform if we haven't already
|
159
|
+
example_platforms[p] = all_platforms[p] = assured_platform("library example", p, config) unless example_platforms.key?(p)
|
160
|
+
end
|
117
161
|
aux_libraries.merge(ovr_config.aux_libraries_for_build)
|
118
162
|
end
|
119
163
|
|
@@ -145,12 +189,12 @@ end
|
|
145
189
|
last_board = nil
|
146
190
|
if !cpp_library.tests_dir.exist?
|
147
191
|
inform_multiline("Skipping unit tests; no tests dir at #{cpp_library.tests_dir}") do
|
148
|
-
|
192
|
+
display_files(cpp_library.tests_dir.parent)
|
149
193
|
true
|
150
194
|
end
|
151
195
|
elsif cpp_library.test_files.empty?
|
152
196
|
inform_multiline("Skipping unit tests; no test files were found in #{cpp_library.tests_dir}") do
|
153
|
-
|
197
|
+
display_files(cpp_library.tests_dir)
|
154
198
|
true
|
155
199
|
end
|
156
200
|
elsif config.platforms_to_unittest.empty?
|
@@ -158,7 +202,6 @@ elsif config.platforms_to_unittest.empty?
|
|
158
202
|
else
|
159
203
|
config.platforms_to_unittest.each do |p|
|
160
204
|
board = all_platforms[p][:board]
|
161
|
-
last_board = "arduino:avr:pro:cpu=16MHzatmega328"
|
162
205
|
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
163
206
|
last_board = board
|
164
207
|
cpp_library.test_files.each do |unittest_path|
|
@@ -187,18 +230,27 @@ end
|
|
187
230
|
|
188
231
|
if library_examples.empty?
|
189
232
|
inform_multiline("Skipping libraries; no examples found in #{installed_library_path}") do
|
190
|
-
|
233
|
+
display_files(installed_library_path)
|
191
234
|
end
|
192
235
|
else
|
193
236
|
attempt("Setting compiler warning level") { @arduino_cmd.set_pref("compiler.warning_level", "all") }
|
194
237
|
|
195
|
-
#
|
196
|
-
|
238
|
+
# switching boards takes time, so iterate board first
|
239
|
+
# _then_ whichever examples match it
|
240
|
+
examples_by_platform = library_examples.each_with_object({}) do |example_path, acc|
|
197
241
|
ovr_config = config.from_example(example_path)
|
198
242
|
ovr_config.platforms_to_build.each do |p|
|
199
|
-
|
200
|
-
|
201
|
-
|
243
|
+
acc[p] = [] unless acc.key?(p)
|
244
|
+
acc[p] << example_path
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
examples_by_platform.each do |platform, example_paths|
|
249
|
+
board = all_platforms[platform][:board]
|
250
|
+
assure("Switching to board for #{platform} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
251
|
+
last_board = board
|
252
|
+
|
253
|
+
example_paths.each do |example_path|
|
202
254
|
example_name = File.basename(example_path)
|
203
255
|
attempt("Verifying #{example_name}") do
|
204
256
|
ret = @arduino_cmd.verify_sketch(example_path)
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
+
# workaround for https://github.com/arduino/Arduino/issues/3535
|
5
|
+
WORKAROUND_LIB = "USBHost".freeze
|
6
|
+
|
4
7
|
module ArduinoCI
|
5
8
|
|
6
9
|
# Wrap the Arduino executable. This requires, in some cases, a faked display.
|
@@ -18,12 +21,16 @@ module ArduinoCI
|
|
18
21
|
self.class_eval("def flag_#{name};\"#{text}\";end", __FILE__, __LINE__)
|
19
22
|
end
|
20
23
|
|
21
|
-
# the
|
22
|
-
# @return [String]
|
24
|
+
# the array of command components to launch the Arduino executable
|
25
|
+
# @return [Array<String>]
|
23
26
|
attr_accessor :base_cmd
|
24
27
|
|
28
|
+
# the actual path to the executable on this platform
|
29
|
+
# @return [Pathname]
|
30
|
+
attr_accessor :binary_path
|
31
|
+
|
25
32
|
# part of a workaround for https://github.com/arduino/Arduino/issues/3535
|
26
|
-
attr_reader :
|
33
|
+
attr_reader :libraries_indexed
|
27
34
|
|
28
35
|
# @return [String] STDOUT of the most recently-run command
|
29
36
|
attr_reader :last_out
|
@@ -47,7 +54,7 @@ module ArduinoCI
|
|
47
54
|
def initialize
|
48
55
|
@prefs_cache = {}
|
49
56
|
@prefs_fetched = false
|
50
|
-
@
|
57
|
+
@libraries_indexed = false
|
51
58
|
@last_out = ""
|
52
59
|
@last_err = ""
|
53
60
|
@last_msg = ""
|
@@ -145,11 +152,19 @@ module ArduinoCI
|
|
145
152
|
ret
|
146
153
|
end
|
147
154
|
|
148
|
-
#
|
149
|
-
# @return [
|
150
|
-
def
|
151
|
-
|
152
|
-
|
155
|
+
# Board manager URLs
|
156
|
+
# @return [Array<String>] The additional URLs used by the board manager
|
157
|
+
def board_manager_urls
|
158
|
+
url_list = get_pref("boardsmanager.additional.urls")
|
159
|
+
return [] if url_list.nil?
|
160
|
+
|
161
|
+
url_list.split(",")
|
162
|
+
end
|
163
|
+
|
164
|
+
# Set board manager URLs
|
165
|
+
# @return [Array<String>] The additional URLs used by the board manager
|
166
|
+
def board_manager_urls=(all_urls)
|
167
|
+
set_pref("boardsmanager.additional.urls", all_urls.join(","))
|
153
168
|
end
|
154
169
|
|
155
170
|
# check whether a board is installed
|
@@ -174,21 +189,29 @@ module ArduinoCI
|
|
174
189
|
# install a library by name
|
175
190
|
# @param name [String] the library name
|
176
191
|
# @return [bool] whether the command succeeded
|
177
|
-
def
|
178
|
-
|
179
|
-
# use a dummy library name but keep open the possiblity that said library
|
180
|
-
# might be selected by choice for installation
|
181
|
-
workaround_lib = "USBHost"
|
182
|
-
unless @library_is_indexed || workaround_lib == library_name
|
183
|
-
@library_is_indexed = run_and_capture(flag_install_library, workaround_lib)
|
184
|
-
end
|
192
|
+
def _install_library(library_name)
|
193
|
+
success = run_and_capture(flag_install_library, library_name)[:success]
|
185
194
|
|
186
|
-
|
187
|
-
|
195
|
+
@libraries_indexed = (@libraries_indexed || success) if library_name == WORKAROUND_LIB
|
196
|
+
success
|
197
|
+
end
|
198
|
+
|
199
|
+
# index the set of libraries by installing a dummy library
|
200
|
+
# related to WORKAROUND_LIB and https://github.com/arduino/Arduino/issues/3535
|
201
|
+
# TODO: unclear if this is still necessary
|
202
|
+
def index_libraries
|
203
|
+
return true if @libraries_indexed
|
204
|
+
|
205
|
+
_install_library(WORKAROUND_LIB)
|
206
|
+
@libraries_indexed
|
207
|
+
end
|
188
208
|
|
189
|
-
|
190
|
-
|
191
|
-
|
209
|
+
# install a library by name
|
210
|
+
# @param name [String] the library name
|
211
|
+
# @return [bool] whether the command succeeded
|
212
|
+
def install_library(library_name)
|
213
|
+
index_libraries
|
214
|
+
_install_library(library_name)
|
192
215
|
end
|
193
216
|
|
194
217
|
# generate the (very likely) path of a library given its name
|
@@ -5,9 +5,6 @@ module ArduinoCI
|
|
5
5
|
|
6
6
|
# Implementation of Arduino linux IDE commands
|
7
7
|
class ArduinoCmdLinux < ArduinoCmd
|
8
|
-
|
9
|
-
attr_reader :prefs_response_time
|
10
|
-
|
11
8
|
flag :get_pref, "--get-pref"
|
12
9
|
flag :set_pref, "--pref"
|
13
10
|
flag :save_prefs, "--save-prefs"
|
@@ -15,61 +12,6 @@ module ArduinoCI
|
|
15
12
|
flag :install_boards, "--install-boards"
|
16
13
|
flag :install_library, "--install-library"
|
17
14
|
flag :verify, "--verify"
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
super
|
21
|
-
@prefs_response_time = nil
|
22
|
-
end
|
23
|
-
|
24
|
-
# fetch preferences in their raw form
|
25
|
-
# @return [String] Preferences as a set of lines
|
26
|
-
def _prefs_raw
|
27
|
-
start = Time.now
|
28
|
-
resp = run_and_capture(flag_get_pref)
|
29
|
-
@prefs_response_time = Time.now - start
|
30
|
-
return nil unless resp[:success]
|
31
|
-
|
32
|
-
resp[:out]
|
33
|
-
end
|
34
|
-
|
35
|
-
def run_with_gui_guess(message, *args, **kwargs)
|
36
|
-
# On Travis CI, we get an error message in the GUI instead of on STDERR
|
37
|
-
# so, assume that if we don't get a rapid reply that things are not installed
|
38
|
-
|
39
|
-
prefs if @prefs_response_time.nil?
|
40
|
-
x3 = @prefs_response_time * 3
|
41
|
-
Timeout.timeout(x3) do
|
42
|
-
result = run_and_capture(*args, **kwargs)
|
43
|
-
result[:success]
|
44
|
-
end
|
45
|
-
rescue Timeout::Error
|
46
|
-
puts "No response in #{x3} seconds. Assuming graphical modal error message#{message}."
|
47
|
-
false
|
48
|
-
end
|
49
|
-
|
50
|
-
# underlying preference-setter.
|
51
|
-
# @param key [String] the preference key
|
52
|
-
# @param value [String] the preference value
|
53
|
-
# @return [bool] whether the command succeeded
|
54
|
-
def _set_pref(key, value)
|
55
|
-
run_with_gui_guess(" about preferences", flag_set_pref, "#{key}=#{value}", flag_save_prefs)
|
56
|
-
end
|
57
|
-
|
58
|
-
# check whether a board is installed
|
59
|
-
# we do this by just selecting a board.
|
60
|
-
# the arduino binary will error if unrecognized and do a successful no-op if it's installed
|
61
|
-
# @param boardname [String] The name of the board
|
62
|
-
# @return [bool]
|
63
|
-
def board_installed?(boardname)
|
64
|
-
run_with_gui_guess(" about board not installed", flag_use_board, boardname)
|
65
|
-
end
|
66
|
-
|
67
|
-
# use a particular board for compilation
|
68
|
-
# @param boardname [String] The name of the board
|
69
|
-
def use_board(boardname)
|
70
|
-
run_with_gui_guess(" about board not installed", flag_use_board, boardname, flag_save_prefs)
|
71
|
-
end
|
72
|
-
|
73
15
|
end
|
74
16
|
|
75
17
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'pathname'
|
1
2
|
require "arduino_ci/host"
|
2
3
|
require "arduino_ci/arduino_cmd_osx"
|
3
4
|
require "arduino_ci/arduino_cmd_linux"
|
@@ -32,12 +33,14 @@ module ArduinoCI
|
|
32
33
|
|
33
34
|
ret = ArduinoCmdLinux.new
|
34
35
|
ret.base_cmd = [loc]
|
36
|
+
ret.binary_path = Pathname.new(loc)
|
35
37
|
when :windows then
|
36
38
|
loc = ArduinoDownloaderWindows.autolocated_executable
|
37
39
|
return nil if loc.nil?
|
38
40
|
|
39
41
|
ret = ArduinoCmdWindows.new
|
40
42
|
ret.base_cmd = [loc]
|
43
|
+
ret.binary_path = Pathname.new(loc)
|
41
44
|
end
|
42
45
|
ret
|
43
46
|
end
|
@@ -75,10 +78,11 @@ module ArduinoCI
|
|
75
78
|
# don't want to see is a java error.
|
76
79
|
args = launcher + ["--bogus-option"]
|
77
80
|
result = Host.run_and_capture(*args)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
next unless result[:err].include? "Error: unknown option: --bogus-option"
|
82
|
+
|
83
|
+
ret.base_cmd = launcher
|
84
|
+
ret.binary_path = Pathname.new(osx_root)
|
85
|
+
return ret
|
82
86
|
end
|
83
87
|
nil
|
84
88
|
end
|
data/lib/arduino_ci/ci_config.rb
CHANGED
@@ -191,6 +191,13 @@ module ArduinoCI
|
|
191
191
|
deep_clone(defn)
|
192
192
|
end
|
193
193
|
|
194
|
+
# Whether a package is built-in to arduino
|
195
|
+
# @param package [String] the package name (e.g. "arduino:avr")
|
196
|
+
# @return [bool]
|
197
|
+
def package_builtin?(package)
|
198
|
+
package.start_with?("arduino:")
|
199
|
+
end
|
200
|
+
|
194
201
|
# the URL that gives the download info for a given package (a JSON file).
|
195
202
|
# this is NOT where the package comes from.
|
196
203
|
# @param package [String] the package name (e.g. "arduino:avr")
|
@@ -50,16 +50,32 @@ module ArduinoCI
|
|
50
50
|
#
|
51
51
|
# This assumes the vendor bundle will be at `vendor/bundle` and not some other location
|
52
52
|
# @param path [Pathname] The path to check
|
53
|
-
# @return [
|
53
|
+
# @return [bool]
|
54
54
|
def vendor_bundle?(path)
|
55
55
|
# TODO: look for Gemfile, look for .bundle/config and get BUNDLE_PATH from there?
|
56
56
|
base = @base_dir + "vendor"
|
57
57
|
return false unless base.exist?
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
vendor_bundle_aliases = [base, base.realpath]
|
60
|
+
|
61
|
+
# we could do this but some rubies don't return an enumerator for ascend
|
62
|
+
# path.ascend.any? { |part| vendor_bundle_aliases.include?(part) }
|
63
|
+
path.ascend do |part|
|
64
|
+
return true if vendor_bundle_aliases.include?(part)
|
65
|
+
end
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Guess whether a file is part of the tests/ dir (indicating library compilation should ignore it).
|
70
|
+
#
|
71
|
+
# @param path [Pathname] The path to check
|
72
|
+
# @return [bool]
|
73
|
+
def in_tests_dir?(path)
|
74
|
+
tests_dir_aliases = [tests_dir, tests_dir.realpath]
|
75
|
+
# we could do this but some rubies don't return an enumerator for ascend
|
76
|
+
# path.ascend.any? { |part| tests_dir_aliases.include?(part) }
|
77
|
+
path.ascend do |part|
|
78
|
+
return true if tests_dir_aliases.include?(part)
|
63
79
|
end
|
64
80
|
false
|
65
81
|
end
|
@@ -98,16 +114,7 @@ module ArduinoCI
|
|
98
114
|
# CPP files that are part of the project library under test
|
99
115
|
# @return [Array<Pathname>]
|
100
116
|
def cpp_files
|
101
|
-
|
102
|
-
cpp_files_in(@base_dir).reject do |p|
|
103
|
-
next true if p.ascend do |path_part|
|
104
|
-
break true if path_part == tests_dir
|
105
|
-
break true if path_part == real_tests_dir
|
106
|
-
break true if vendor_bundle?(p)
|
107
|
-
end
|
108
|
-
|
109
|
-
false
|
110
|
-
end
|
117
|
+
cpp_files_in(@base_dir).reject { |p| vendor_bundle?(p) || in_tests_dir?(p) }
|
111
118
|
end
|
112
119
|
|
113
120
|
# CPP files that are part of the arduino mock library we're providing
|
data/lib/arduino_ci/version.rb
CHANGED
data/misc/default.yml
CHANGED
@@ -3,15 +3,21 @@
|
|
3
3
|
# https://en.wikipedia.org/wiki/List_of_Arduino_boards_and_compatible_systems
|
4
4
|
|
5
5
|
packages:
|
6
|
+
# arduino:xxx are builtin, we don't need to include them here
|
6
7
|
esp8266:esp8266:
|
7
8
|
url: http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
8
9
|
adafruit:avr:
|
9
10
|
url: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
|
11
|
+
adafruit:samd:
|
12
|
+
url: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
|
13
|
+
esp32:esp32:
|
14
|
+
url: https://dl.espressif.com/dl/package_esp32_index.json
|
10
15
|
|
11
16
|
platforms:
|
17
|
+
|
12
18
|
uno:
|
13
19
|
board: arduino:avr:uno
|
14
|
-
package:
|
20
|
+
package: arduino:avr
|
15
21
|
gcc:
|
16
22
|
features:
|
17
23
|
defines:
|
@@ -37,6 +43,14 @@ platforms:
|
|
37
43
|
- ARDUINO_SAMD_ZERO
|
38
44
|
warnings:
|
39
45
|
flags:
|
46
|
+
esp32:
|
47
|
+
board: esp32:esp32:featheresp32:FlashFreq=80
|
48
|
+
package: esp32:esp32
|
49
|
+
gcc:
|
50
|
+
features:
|
51
|
+
defines:
|
52
|
+
warnings:
|
53
|
+
flags:
|
40
54
|
esp8266:
|
41
55
|
board: esp8266:esp8266:huzzah:FlashSize=4M3M,CpuFrequency=80
|
42
56
|
package: esp8266:esp8266
|
@@ -47,7 +61,7 @@ platforms:
|
|
47
61
|
flags:
|
48
62
|
leonardo:
|
49
63
|
board: arduino:avr:leonardo
|
50
|
-
package:
|
64
|
+
package: arduino:avr
|
51
65
|
gcc:
|
52
66
|
features:
|
53
67
|
defines:
|
@@ -70,6 +84,39 @@ platforms:
|
|
70
84
|
defines:
|
71
85
|
warnings:
|
72
86
|
flags:
|
87
|
+
m4:
|
88
|
+
board: adafruit:samd:adafruit_metro_m4
|
89
|
+
package: adafruit:samd
|
90
|
+
gcc:
|
91
|
+
features:
|
92
|
+
defines:
|
93
|
+
warnings:
|
94
|
+
flags:
|
95
|
+
mega2560:
|
96
|
+
board: arduino:avr:mega:cpu=atmega2560
|
97
|
+
package: arduino:avr
|
98
|
+
gcc:
|
99
|
+
features:
|
100
|
+
defines:
|
101
|
+
warnings:
|
102
|
+
flags:
|
103
|
+
cplayClassic:
|
104
|
+
board: arduino:avr:circuitplay32u4cat
|
105
|
+
package: arduino:avr
|
106
|
+
gcc:
|
107
|
+
features:
|
108
|
+
defines:
|
109
|
+
warnings:
|
110
|
+
flags:
|
111
|
+
cplayExpress:
|
112
|
+
board: arduino:samd:adafruit_circuitplayground_m0
|
113
|
+
package: arduino:samd
|
114
|
+
gcc:
|
115
|
+
features:
|
116
|
+
defines:
|
117
|
+
warnings:
|
118
|
+
flags:
|
119
|
+
|
73
120
|
|
74
121
|
compile:
|
75
122
|
libraries: ~
|
@@ -78,6 +125,10 @@ compile:
|
|
78
125
|
- due
|
79
126
|
- zero
|
80
127
|
- leonardo
|
128
|
+
- m4
|
129
|
+
- esp32
|
130
|
+
- esp8266
|
131
|
+
- mega2560
|
81
132
|
|
82
133
|
unittest:
|
83
134
|
compilers:
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arduino_ci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Katz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: os
|