arduino_ci 1.4.0 → 1.6.0
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 +5 -5
- data/REFERENCE.md +5 -0
- data/cpp/arduino/Arduino.h +5 -0
- data/cpp/arduino/ArduinoDefines.h +16 -1
- data/cpp/arduino/Godmode.h +3 -0
- data/cpp/arduino/avr/interrupt.h +7 -0
- data/cpp/arduino/util/atomic.h +313 -0
- data/exe/arduino_ci.rb +267 -244
- data/lib/arduino_ci/arduino_backend.rb +4 -1
- data/lib/arduino_ci/ci_config.rb +29 -18
- data/lib/arduino_ci/host.rb +20 -0
- data/lib/arduino_ci/logger.rb +243 -0
- data/lib/arduino_ci/version.rb +1 -1
- data/lib/arduino_ci.rb +1 -0
- metadata +5 -2
@@ -182,7 +182,10 @@ module ArduinoCI
|
|
182
182
|
result = if @additional_urls.empty?
|
183
183
|
run_and_capture("core", "install", boardfamily)
|
184
184
|
else
|
185
|
-
|
185
|
+
urls = @additional_urls.join(",")
|
186
|
+
# update the index, then install. if the update step fails, return that result
|
187
|
+
updater = run_and_capture("core", "update-index", "--additional-urls", urls)
|
188
|
+
updater[:success] ? run_and_capture("core", "install", boardfamily, "--additional-urls", urls) : updater
|
186
189
|
end
|
187
190
|
result[:success]
|
188
191
|
end
|
data/lib/arduino_ci/ci_config.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
# base config (platforms)
|
4
5
|
# project config - .arduino_ci_platforms.yml
|
@@ -58,7 +59,7 @@ module ArduinoCI
|
|
58
59
|
def default
|
59
60
|
ret = new
|
60
61
|
ret.instance_variable_set("@is_default", true)
|
61
|
-
ret.load_yaml(
|
62
|
+
ret.load_yaml((Pathname.new(__dir__) + "../../misc/default.yml").realpath)
|
62
63
|
ret
|
63
64
|
end
|
64
65
|
end
|
@@ -195,35 +196,45 @@ module ArduinoCI
|
|
195
196
|
overridden_config
|
196
197
|
end
|
197
198
|
|
198
|
-
# Get
|
199
|
-
# Many config files may exist, but only the first match is used
|
199
|
+
# Get available configuration file, if one exists
|
200
200
|
# @param base_dir [String] The directory in which to search for a config file
|
201
|
-
# @
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
201
|
+
# @return [Pathname] the first available config file we could find, or nil
|
202
|
+
def available_override_config_path(base_dir = nil)
|
203
|
+
CONFIG_FILENAMES.map { |f| base_dir.nil? ? Pathname.new(f) : base_dir + f }.find(&:exist?)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Find an available override file from the project directory
|
207
|
+
#
|
208
|
+
# @todo this is currently reliant on launching the arduino_ci.rb test runner from
|
209
|
+
# the correct working directory
|
210
|
+
# @return [Pathname] A file that can override project config, or nil if none was found
|
211
|
+
def override_file_from_project_library
|
212
|
+
available_override_config_path(nil)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Find an available override file from an example sketch
|
216
|
+
#
|
217
|
+
# @param path [Pathname] the path to the example or example directory
|
218
|
+
# @return [Pathname] A file that can override project config, or nil if none was found
|
219
|
+
def override_file_from_example(example_path)
|
220
|
+
base_dir = example_path.directory? ? example_path : example_path.dirname
|
221
|
+
available_override_config_path(base_dir)
|
212
222
|
end
|
213
223
|
|
214
224
|
# Produce a configuration, assuming the CI script runs from the working directory of the base project
|
215
225
|
# @return [ArduinoCI::CIConfig] the new settings object
|
216
226
|
def from_project_library
|
217
|
-
|
227
|
+
ovr = override_file_from_project_library
|
228
|
+
ovr.nil? ? self : with_override(ovr)
|
218
229
|
end
|
219
230
|
|
220
231
|
# Produce a configuration override taken from an Arduino library example path
|
221
232
|
# handle either path to example file or example dir
|
222
|
-
# @param path [
|
233
|
+
# @param path [Pathname] the path to the settings yaml file
|
223
234
|
# @return [ArduinoCI::CIConfig] the new settings object
|
224
235
|
def from_example(example_path)
|
225
|
-
|
226
|
-
|
236
|
+
ovr = override_file_from_example(example_path)
|
237
|
+
ovr.nil? ? self : with_override(ovr)
|
227
238
|
end
|
228
239
|
|
229
240
|
# get information about a given platform: board name, package name, compiler stuff, etc
|
data/lib/arduino_ci/host.rb
CHANGED
@@ -30,11 +30,31 @@ module ArduinoCI
|
|
30
30
|
nil
|
31
31
|
end
|
32
32
|
|
33
|
+
# Execute a shell command and capture stdout, stderr, and status
|
34
|
+
#
|
35
|
+
# @see Process.spawn
|
36
|
+
# @see https://docs.ruby-lang.org/en/2.0.0/Process.html#method-c-spawn
|
37
|
+
# @return [Hash] with keys "stdout" (String), "stderr" (String), and "success" (bool)
|
33
38
|
def self.run_and_capture(*args, **kwargs)
|
34
39
|
stdout, stderr, status = Open3.capture3(*args, **kwargs)
|
35
40
|
{ out: stdout, err: stderr, success: status.exitstatus.zero? }
|
36
41
|
end
|
37
42
|
|
43
|
+
# Merge multiple capture results into one aggregate value
|
44
|
+
#
|
45
|
+
# @param args [Array] Array of hashes from `run_and_capture`
|
46
|
+
# @return [Hash] with keys "stdout" (String), "stderr" (String), and "success" (bool)
|
47
|
+
def self.merge_capture_results(*args)
|
48
|
+
{
|
49
|
+
out: args.map { |a| a[:out] }.join,
|
50
|
+
err: args.map { |a| a[:err] }.join,
|
51
|
+
success: args.all? { |a| a[:success] }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
# Execute a shell command
|
56
|
+
#
|
57
|
+
# @see system
|
38
58
|
def self.run_and_output(*args, **kwargs)
|
39
59
|
system(*args, **kwargs)
|
40
60
|
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'io/console'
|
2
|
+
|
3
|
+
module ArduinoCI
|
4
|
+
|
5
|
+
# Provide all text processing functions to aid readability of the test log
|
6
|
+
class Logger
|
7
|
+
|
8
|
+
TAB_WIDTH = 4
|
9
|
+
INDENT_CHAR = " ".freeze
|
10
|
+
|
11
|
+
# @return [Integer] the cardinal number of indents
|
12
|
+
attr_reader :tab
|
13
|
+
|
14
|
+
# @return [Integer] The number of failures reported through the logging mechanism
|
15
|
+
attr_reader :failure_count
|
16
|
+
|
17
|
+
# @param width [int] The desired console width
|
18
|
+
def initialize(width = nil)
|
19
|
+
@tab = 0
|
20
|
+
@width = width.nil? ? 80 : width
|
21
|
+
@failure_count = 0
|
22
|
+
@passfail = proc { |result| result ? "✓" : "✗" }
|
23
|
+
end
|
24
|
+
|
25
|
+
# create a logger that's automatically sized to the console, between 80 and 132 characters
|
26
|
+
def self.auto_width
|
27
|
+
width = begin
|
28
|
+
[132, [80, IO::console.winsize[1] - 2].max].min
|
29
|
+
rescue NoMethodError
|
30
|
+
80
|
31
|
+
end
|
32
|
+
|
33
|
+
self.new(width)
|
34
|
+
end
|
35
|
+
|
36
|
+
# print a nice banner for this project
|
37
|
+
def banner
|
38
|
+
art = [
|
39
|
+
" . __ ___",
|
40
|
+
" _, ,_ _| , . * ._ _ / ` | ",
|
41
|
+
"(_| [ `(_] (_| | [ ) (_) \\__. _|_ v#{ArduinoCI::VERSION}",
|
42
|
+
]
|
43
|
+
|
44
|
+
pad = " " * ((@width - art[2].length) / 2)
|
45
|
+
art.each { |l| puts "#{pad}#{l}" }
|
46
|
+
puts
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [String] the current line indentation
|
50
|
+
def indentation
|
51
|
+
(INDENT_CHAR * TAB_WIDTH * @tab)
|
52
|
+
end
|
53
|
+
|
54
|
+
# put an indented string
|
55
|
+
#
|
56
|
+
# @param str [String] the string to puts
|
57
|
+
# @return [void]
|
58
|
+
def iputs(str = "")
|
59
|
+
print(indentation)
|
60
|
+
|
61
|
+
# split the lines and interleave with a newline character, then render
|
62
|
+
stream_lines = str.to_s.split("\n")
|
63
|
+
marked_stream_lines = stream_lines.flat_map { |s| [s, :nl] }.tap(&:pop)
|
64
|
+
marked_stream_lines.each { |l| print(l == :nl ? "\n#{indentation}" : l) }
|
65
|
+
puts
|
66
|
+
end
|
67
|
+
|
68
|
+
# print an indented string
|
69
|
+
#
|
70
|
+
# @param str [String] the string to print
|
71
|
+
# @return [void]
|
72
|
+
def iprint(str)
|
73
|
+
print(indentation)
|
74
|
+
print(str)
|
75
|
+
end
|
76
|
+
|
77
|
+
# increment an indentation level for the duration of a block's execution
|
78
|
+
#
|
79
|
+
# @param amount [Integer] the number of tabs to indent
|
80
|
+
# @yield [] The code to execute while indented
|
81
|
+
# @return [void]
|
82
|
+
def indent(amount = 1, &block)
|
83
|
+
@tab += amount
|
84
|
+
block.call
|
85
|
+
ensure
|
86
|
+
@tab -= amount
|
87
|
+
end
|
88
|
+
|
89
|
+
# make a nice status line for an action and react to the action
|
90
|
+
#
|
91
|
+
# TODO / note to self: inform_multiline is tougher to write
|
92
|
+
# without altering the signature because it only leaves space
|
93
|
+
# for the checkmark _after_ the multiline, it doesn't know how
|
94
|
+
# to make that conditionally the body
|
95
|
+
#
|
96
|
+
# @param message String the text of the progress indicator
|
97
|
+
# @param multiline boolean whether multiline output is expected
|
98
|
+
# @param mark_fn block (string) -> string that says how to describe the result
|
99
|
+
# @param on_fail_msg String custom message for failure
|
100
|
+
# @param tally_on_fail boolean whether to increment @failure_count
|
101
|
+
# @param abort_on_fail boolean whether to abort immediately on failure (i.e. if this is a fatal error)
|
102
|
+
# @yield [] The action being performed
|
103
|
+
# @yieldreturn [Object] whether the action was successful, can be any type but it is evaluated as a boolean
|
104
|
+
# @return [Object] The return value of the block
|
105
|
+
def perform_action(message, multiline, mark_fn, on_fail_msg, tally_on_fail, abort_on_fail)
|
106
|
+
line = "#{indentation}#{message}... "
|
107
|
+
endline = "#{indentation}...#{message} "
|
108
|
+
if multiline
|
109
|
+
puts line
|
110
|
+
@tab += 1
|
111
|
+
else
|
112
|
+
print line
|
113
|
+
end
|
114
|
+
$stdout.flush
|
115
|
+
|
116
|
+
# handle the block and any errors it raises
|
117
|
+
caught_error = nil
|
118
|
+
begin
|
119
|
+
result = yield
|
120
|
+
rescue StandardError => e
|
121
|
+
caught_error = e
|
122
|
+
result = false
|
123
|
+
ensure
|
124
|
+
@tab -= 1 if multiline
|
125
|
+
end
|
126
|
+
|
127
|
+
# put the trailing mark
|
128
|
+
mark = mark_fn.nil? ? "" : mark_fn.call(result)
|
129
|
+
# if multiline, put checkmark at full width
|
130
|
+
print endline if multiline
|
131
|
+
puts mark.to_s.rjust(@width - line.length, " ")
|
132
|
+
unless result
|
133
|
+
iputs on_fail_msg unless on_fail_msg.nil?
|
134
|
+
raise caught_error unless caught_error.nil?
|
135
|
+
|
136
|
+
@failure_count += 1 if tally_on_fail
|
137
|
+
terminate if abort_on_fail
|
138
|
+
end
|
139
|
+
result
|
140
|
+
end
|
141
|
+
|
142
|
+
# Make a nice status (with checkmark) for something that defers any failure code until script exit
|
143
|
+
#
|
144
|
+
# @param message the message to print
|
145
|
+
# @yield [] The action being performed
|
146
|
+
# @yieldreturn [boolean] whether the action was successful
|
147
|
+
# @return [Object] The return value of the block
|
148
|
+
def attempt(message, &block)
|
149
|
+
perform_action(message, false, @passfail, nil, true, false, &block)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Make a nice multiline status (with checkmark) for something that defers any failure code until script exit
|
153
|
+
#
|
154
|
+
# @param message the message to print
|
155
|
+
# @yield [] The action being performed
|
156
|
+
# @yieldreturn [boolean] whether the action was successful
|
157
|
+
# @return [Object] The return value of the block
|
158
|
+
def attempt_multiline(message, &block)
|
159
|
+
perform_action(message, true, @passfail, nil, true, false, &block)
|
160
|
+
end
|
161
|
+
|
162
|
+
FAILED_ASSURANCE_MESSAGE = "This may indicate a problem with your configuration; halting here".freeze
|
163
|
+
# Make a nice status (with checkmark) for something that kills the script immediately on failure
|
164
|
+
#
|
165
|
+
# @param message the message to print
|
166
|
+
# @yield [] The action being performed
|
167
|
+
# @yieldreturn [boolean] whether the action was successful
|
168
|
+
# @return [Object] The return value of the block
|
169
|
+
def assure(message, &block)
|
170
|
+
perform_action(message, false, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Make a nice multiline status (with checkmark) for something that kills the script immediately on failure
|
174
|
+
#
|
175
|
+
# @param message the message to print
|
176
|
+
# @yield [] The action being performed
|
177
|
+
# @yieldreturn [boolean] whether the action was successful
|
178
|
+
# @return [Object] The return value of the block
|
179
|
+
def assure_multiline(message, &block)
|
180
|
+
perform_action(message, true, @passfail, FAILED_ASSURANCE_MESSAGE, true, true, &block)
|
181
|
+
end
|
182
|
+
|
183
|
+
# print a failure message (with checkmark) but do not tally a failure
|
184
|
+
# @param message the message to print
|
185
|
+
# @return [Object] The return value of the block
|
186
|
+
def warn(message)
|
187
|
+
inform("WARNING") { message }
|
188
|
+
end
|
189
|
+
|
190
|
+
# print a failure message (with checkmark) but do not exit
|
191
|
+
# @param message the message to print
|
192
|
+
# @return [Object] The return value of the block
|
193
|
+
def fail(message)
|
194
|
+
attempt(message) { false }
|
195
|
+
end
|
196
|
+
|
197
|
+
# print a failure message (with checkmark) and exit immediately afterward
|
198
|
+
# @param message the message to print
|
199
|
+
# @return [Object] The return value of the block
|
200
|
+
def halt(message)
|
201
|
+
assure(message) { false }
|
202
|
+
end
|
203
|
+
|
204
|
+
# Print a value as a status line "message... retval"
|
205
|
+
#
|
206
|
+
# @param message the message to print
|
207
|
+
# @yield [] The action being performed
|
208
|
+
# @yieldreturn [String] The value to print at the end of the line
|
209
|
+
# @return [Object] The return value of the block
|
210
|
+
def inform(message, &block)
|
211
|
+
perform_action(message, false, proc { |x| x }, nil, false, false, &block)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Print section beginning and end
|
215
|
+
#
|
216
|
+
# @param message the message to print
|
217
|
+
# @yield [] The action being performed
|
218
|
+
# @return [Object] The return value of the block
|
219
|
+
def inform_multiline(message, &block)
|
220
|
+
perform_action(message, true, nil, nil, false, false, &block)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Print a horizontal rule across the console
|
224
|
+
# @param char [String] the character to use
|
225
|
+
# @return [void]
|
226
|
+
def rule(char)
|
227
|
+
puts char[0] * @width
|
228
|
+
end
|
229
|
+
|
230
|
+
# Print a section heading to the console to break up the text output
|
231
|
+
#
|
232
|
+
# @param name [String] the section name
|
233
|
+
# @return [void]
|
234
|
+
def phase(name)
|
235
|
+
puts
|
236
|
+
rule("=")
|
237
|
+
puts("| #{name}")
|
238
|
+
puts("====")
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
data/lib/arduino_ci/version.rb
CHANGED
data/lib/arduino_ci.rb
CHANGED
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: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Katz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: os
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- cpp/arduino/avr/README.md
|
79
79
|
- cpp/arduino/avr/common.h
|
80
80
|
- cpp/arduino/avr/fuse.h
|
81
|
+
- cpp/arduino/avr/interrupt.h
|
81
82
|
- cpp/arduino/avr/io.h
|
82
83
|
- cpp/arduino/avr/io1200.h
|
83
84
|
- cpp/arduino/avr/io2313.h
|
@@ -359,6 +360,7 @@ files:
|
|
359
360
|
- cpp/arduino/ci/Table.h
|
360
361
|
- cpp/arduino/stdlib.cpp
|
361
362
|
- cpp/arduino/stdlib.h
|
363
|
+
- cpp/arduino/util/atomic.h
|
362
364
|
- cpp/unittest/ArduinoUnitTests.cpp
|
363
365
|
- cpp/unittest/ArduinoUnitTests.h
|
364
366
|
- cpp/unittest/Assertion.h
|
@@ -379,6 +381,7 @@ files:
|
|
379
381
|
- lib/arduino_ci/cpp_library.rb
|
380
382
|
- lib/arduino_ci/host.rb
|
381
383
|
- lib/arduino_ci/library_properties.rb
|
384
|
+
- lib/arduino_ci/logger.rb
|
382
385
|
- lib/arduino_ci/version.rb
|
383
386
|
- misc/default.yml
|
384
387
|
homepage: http://github.com/Arduino-CI/arduino_ci
|