arduino_ci 0.1.5 → 0.1.6
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/cpp/arduino/Arduino.h +0 -77
- data/cpp/arduino/ArduinoDefines.h +2 -0
- data/cpp/arduino/PinHistory.h +1 -1
- data/cpp/arduino/Print.h +23 -22
- data/cpp/arduino/SoftwareSerial.h +5 -2
- data/cpp/arduino/WString.h +117 -121
- data/cpp/arduino/WString.h.orig +172 -0
- data/cpp/arduino/avr/pgmspace.h +45 -45
- data/cpp/arduino/avr/pgmspace.h.orig +95 -0
- data/cpp/arduino/ci/Queue.h +2 -2
- data/cpp/unittest/ArduinoUnitTests.h +2 -2
- data/cpp/unittest/Compare.h +557 -78
- data/exe/arduino_ci_remote.rb +27 -7
- data/lib/arduino_ci/arduino_cmd.rb +19 -18
- data/lib/arduino_ci/arduino_cmd_linux.rb +9 -2
- data/lib/arduino_ci/arduino_cmd_linux_builder.rb +9 -4
- data/lib/arduino_ci/arduino_cmd_osx.rb +9 -2
- data/lib/arduino_ci/ci_config.rb +2 -0
- data/lib/arduino_ci/cpp_library.rb +12 -15
- data/lib/arduino_ci/cpp_library.rb.orig +215 -0
- data/lib/arduino_ci/display_manager.rb +12 -8
- data/lib/arduino_ci/host.rb +7 -2
- data/lib/arduino_ci/version.rb +1 -1
- metadata +5 -2
data/exe/arduino_ci_remote.rb
CHANGED
@@ -21,11 +21,18 @@ def terminate(final = nil)
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# make a nice status line for an action and react to the action
|
24
|
-
def perform_action(message, on_fail_msg, abort_on_fail)
|
25
|
-
line = "#{message}..."
|
26
|
-
|
24
|
+
def perform_action(message, multiline, on_fail_msg, abort_on_fail)
|
25
|
+
line = "#{message}... "
|
26
|
+
endline = "...#{message} "
|
27
|
+
if multiline
|
28
|
+
puts line
|
29
|
+
else
|
30
|
+
print line
|
31
|
+
end
|
27
32
|
result = yield
|
28
33
|
mark = result ? "✓" : "✗"
|
34
|
+
# if multline, put checkmark at full width
|
35
|
+
print endline if multiline
|
29
36
|
puts mark.rjust(WIDTH - line.length, " ")
|
30
37
|
unless result
|
31
38
|
puts on_fail_msg unless on_fail_msg.nil?
|
@@ -38,12 +45,17 @@ end
|
|
38
45
|
|
39
46
|
# Make a nice status for something that defers any failure code until script exit
|
40
47
|
def attempt(message, &block)
|
41
|
-
perform_action(message, nil, false, &block)
|
48
|
+
perform_action(message, false, nil, false, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Make a nice status for something that defers any failure code until script exit
|
52
|
+
def attempt_multiline(message, &block)
|
53
|
+
perform_action(message, true, nil, false, &block)
|
42
54
|
end
|
43
55
|
|
44
56
|
# Make a nice status for something that kills the script immediately on failure
|
45
57
|
def assure(message, &block)
|
46
|
-
perform_action(message, "This may indicate a problem with ArduinoCI!", true, &block)
|
58
|
+
perform_action(message, false, "This may indicate a problem with ArduinoCI!", true, &block)
|
47
59
|
end
|
48
60
|
|
49
61
|
# initialize command and config
|
@@ -56,6 +68,14 @@ library_examples = @arduino_cmd.library_examples(installed_library_path)
|
|
56
68
|
cpp_library = ArduinoCI::CppLibrary.new(installed_library_path)
|
57
69
|
attempt("Library installed at #{installed_library_path}") { true }
|
58
70
|
|
71
|
+
# check GCC
|
72
|
+
attempt_multiline("Checking GCC version") do
|
73
|
+
version = cpp_library.gcc_version
|
74
|
+
next nil unless version
|
75
|
+
puts version.split("\n").map { |l| " #{l}" }.join("\n")
|
76
|
+
version
|
77
|
+
end
|
78
|
+
|
59
79
|
# gather up all required boards so we can install them up front.
|
60
80
|
# start with the "platforms to unittest" and add the examples
|
61
81
|
# while we're doing that, get the aux libraries as well
|
@@ -97,11 +117,11 @@ elsif config.platforms_to_unittest.empty?
|
|
97
117
|
else
|
98
118
|
config.platforms_to_unittest.each do |p|
|
99
119
|
board = all_platforms[p][:board]
|
100
|
-
|
120
|
+
assure("Switching to board for #{p} (#{board})") { @arduino_cmd.use_board(board) } unless last_board == board
|
101
121
|
last_board = board
|
102
122
|
cpp_library.test_files.each do |unittest_path|
|
103
123
|
unittest_name = File.basename(unittest_path)
|
104
|
-
|
124
|
+
attempt_multiline("Unit testing #{unittest_name}") do
|
105
125
|
exe = cpp_library.build_for_test_with_configuration(
|
106
126
|
unittest_path,
|
107
127
|
config.aux_libraries_for_unittest,
|
@@ -114,12 +114,18 @@ module ArduinoCI
|
|
114
114
|
end
|
115
115
|
|
116
116
|
# run the arduino command
|
117
|
-
|
117
|
+
# @return [bool] whether the command succeeded
|
118
|
+
def _run_and_output(*args, **kwargs)
|
118
119
|
raise "Ian needs to implement this in a subclass #{args} #{kwargs}"
|
119
120
|
end
|
120
121
|
|
121
|
-
#
|
122
|
-
|
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
|
+
def _wrap_run(work_fn, *args, **kwargs)
|
123
129
|
# do some work to extract & merge environment variables if they exist
|
124
130
|
has_env = !args.empty? && args[0].class == Hash
|
125
131
|
env_vars = has_env ? args[0] : {}
|
@@ -129,26 +135,21 @@ module ArduinoCI
|
|
129
135
|
|
130
136
|
shell_vars = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ")
|
131
137
|
@last_msg = " $ #{shell_vars} #{full_args.join(' ')}"
|
132
|
-
|
138
|
+
work_fn.call(*full_cmd, **kwargs)
|
139
|
+
end
|
140
|
+
|
141
|
+
# build and run the arduino command
|
142
|
+
def run_and_output(*args, **kwargs)
|
143
|
+
_wrap_run((proc { |*a, **k| _run_and_output(*a, **k) }), *args, **kwargs)
|
133
144
|
end
|
134
145
|
|
135
146
|
# run a command and capture its output
|
136
147
|
# @return [Hash] {:out => String, :err => String, :success => bool}
|
137
148
|
def run_and_capture(*args, **kwargs)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
success = run(*args, **eventual_kwargs)
|
143
|
-
pipe_out_wr.close
|
144
|
-
pipe_err_wr.close
|
145
|
-
str_out = pipe_out.read
|
146
|
-
str_err = pipe_err.read
|
147
|
-
pipe_out.close
|
148
|
-
pipe_err.close
|
149
|
-
@last_err = str_err
|
150
|
-
@last_out = str_out
|
151
|
-
{ out: str_out, err: str_err, success: success }
|
149
|
+
ret = _wrap_run((proc { |*a, **k| _run_and_capture(*a, **k) }), *args, **kwargs)
|
150
|
+
@last_err = ret[:err]
|
151
|
+
@last_out = ret[:out]
|
152
|
+
ret
|
152
153
|
end
|
153
154
|
|
154
155
|
# run a command and don't capture its output, but use the same signature
|
@@ -39,8 +39,15 @@ module ArduinoCI
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# run the arduino command
|
42
|
-
|
43
|
-
|
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)
|
44
51
|
end
|
45
52
|
|
46
53
|
def run_with_gui_guess(message, *args, **kwargs)
|
@@ -21,10 +21,15 @@ module ArduinoCI
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# run the arduino command
|
24
|
-
# @
|
25
|
-
|
26
|
-
|
27
|
-
|
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)
|
28
33
|
end
|
29
34
|
|
30
35
|
end
|
@@ -14,8 +14,15 @@ module ArduinoCI
|
|
14
14
|
flag :verify, "--verify"
|
15
15
|
|
16
16
|
# run the arduino command
|
17
|
-
|
18
|
-
|
17
|
+
# @return [bool] whether the command succeeded
|
18
|
+
def _run_and_output(*args, **kwargs)
|
19
|
+
Host.run_and_output(*args, **kwargs)
|
20
|
+
end
|
21
|
+
|
22
|
+
# run the arduino command
|
23
|
+
# @return [Hash] keys for :success, :out, and :err
|
24
|
+
def _run_and_capture(*args, **kwargs)
|
25
|
+
Host.run_and_capture(*args, **kwargs)
|
19
26
|
end
|
20
27
|
|
21
28
|
def _lib_dir
|
data/lib/arduino_ci/ci_config.rb
CHANGED
@@ -200,12 +200,14 @@ module ArduinoCI
|
|
200
200
|
# platforms to build [the examples on]
|
201
201
|
# @return [Array<String>] The platforms to build
|
202
202
|
def platforms_to_build
|
203
|
+
return [] if @compile_info[:platforms].nil?
|
203
204
|
@compile_info[:platforms]
|
204
205
|
end
|
205
206
|
|
206
207
|
# platforms to unit test [the tests on]
|
207
208
|
# @return [Array<String>] The platforms to unit test on
|
208
209
|
def platforms_to_unittest
|
210
|
+
return [] if @unittest_info[:platforms].nil?
|
209
211
|
@unittest_info[:platforms]
|
210
212
|
end
|
211
213
|
|
@@ -108,23 +108,20 @@ module ArduinoCI
|
|
108
108
|
|
109
109
|
# wrapper for the GCC command
|
110
110
|
def run_gcc(*args, **kwargs)
|
111
|
-
pipe_out, pipe_out_wr = IO.pipe
|
112
|
-
pipe_err, pipe_err_wr = IO.pipe
|
113
111
|
full_args = ["g++"] + args
|
114
112
|
@last_cmd = " $ #{full_args.join(' ')}"
|
115
|
-
our_kwargs = { out: pipe_out_wr, err: pipe_err_wr }
|
116
|
-
eventual_kwargs = our_kwargs.merge(kwargs)
|
117
|
-
success = Host.run(*full_args, **eventual_kwargs)
|
118
113
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
114
|
+
ret = Host.run_and_capture(*full_args, **kwargs)
|
115
|
+
@last_err = ret[:err]
|
116
|
+
@last_out = ret[:out]
|
117
|
+
ret[:success]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return the GCC version
|
121
|
+
# @return [String] the version reported by `gcc -v`
|
122
|
+
def gcc_version
|
123
|
+
return nil unless run_gcc("-v")
|
124
|
+
@last_err
|
128
125
|
end
|
129
126
|
|
130
127
|
# GCC command line arguments for including aux libraries
|
@@ -207,7 +204,7 @@ module ArduinoCI
|
|
207
204
|
@last_cmd = executable
|
208
205
|
@last_out = ""
|
209
206
|
@last_err = ""
|
210
|
-
Host.
|
207
|
+
Host.run_and_output(executable)
|
211
208
|
end
|
212
209
|
|
213
210
|
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'find'
|
2
|
+
require "arduino_ci/host"
|
3
|
+
|
4
|
+
HPP_EXTENSIONS = [".hpp", ".hh", ".h", ".hxx", ".h++"].freeze
|
5
|
+
CPP_EXTENSIONS = [".cpp", ".cc", ".c", ".cxx", ".c++"].freeze
|
6
|
+
ARDUINO_HEADER_DIR = File.expand_path("../../../cpp/arduino", __FILE__)
|
7
|
+
UNITTEST_HEADER_DIR = File.expand_path("../../../cpp/unittest", __FILE__)
|
8
|
+
|
9
|
+
module ArduinoCI
|
10
|
+
|
11
|
+
# Information about an Arduino CPP library, specifically for compilation purposes
|
12
|
+
class CppLibrary
|
13
|
+
|
14
|
+
# @return [String] The path to the library being tested
|
15
|
+
attr_reader :base_dir
|
16
|
+
|
17
|
+
# @return [Array<String>] The set of artifacts created by this class (note: incomplete!)
|
18
|
+
attr_reader :artifacts
|
19
|
+
|
20
|
+
# @return [String] STDERR from the last command
|
21
|
+
attr_reader :last_err
|
22
|
+
|
23
|
+
# @return [String] STDOUT from the last command
|
24
|
+
attr_reader :last_out
|
25
|
+
|
26
|
+
# @return [String] the last command
|
27
|
+
attr_reader :last_cmd
|
28
|
+
|
29
|
+
# @param base_dir [String] The path to the library being tested
|
30
|
+
def initialize(base_dir)
|
31
|
+
@base_dir = File.expand_path(base_dir)
|
32
|
+
@artifacts = []
|
33
|
+
@last_err = ""
|
34
|
+
@last_out = ""
|
35
|
+
@last_msg = ""
|
36
|
+
end
|
37
|
+
|
38
|
+
# Guess whether a file is part of the vendor bundle (indicating we should ignore it).
|
39
|
+
#
|
40
|
+
# This assumes the vendor bundle will be at `vendor/bundle` and not some other location
|
41
|
+
# @param path [String] The path to check
|
42
|
+
# @return [Array<String>] The paths of the found files
|
43
|
+
def vendor_bundle?(path)
|
44
|
+
# TODO: look for Gemfile, look for .bundle/config and get BUNDLE_PATH from there?
|
45
|
+
base = File.join(@base_dir, "vendor")
|
46
|
+
real = File.join(File.realpath(@base_dir), "vendor")
|
47
|
+
return true if path.start_with?(base)
|
48
|
+
return true if path.start_with?(real)
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get a list of all CPP source files in a directory and its subdirectories
|
53
|
+
# @param some_dir [String] The directory in which to begin the search
|
54
|
+
# @return [Array<String>] The paths of the found files
|
55
|
+
def cpp_files_in(some_dir)
|
56
|
+
return [] unless File.exist?(some_dir)
|
57
|
+
real = File.realpath(some_dir)
|
58
|
+
files = Find.find(real).reject { |path| File.directory?(path) }
|
59
|
+
ret = files.select { |path| CPP_EXTENSIONS.include?(File.extname(path)) }
|
60
|
+
ret
|
61
|
+
end
|
62
|
+
|
63
|
+
# CPP files that are part of the project library under test
|
64
|
+
# @return [Array<String>]
|
65
|
+
def cpp_files
|
66
|
+
real_tests_dir = File.realpath(tests_dir)
|
67
|
+
cpp_files_in(@base_dir).reject do |p|
|
68
|
+
next true if File.dirname(p).include?(tests_dir)
|
69
|
+
next true if File.dirname(p).include?(real_tests_dir)
|
70
|
+
next true if vendor_bundle?(p)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# CPP files that are part of the arduino mock library we're providing
|
75
|
+
# @return [Array<String>]
|
76
|
+
def cpp_files_arduino
|
77
|
+
cpp_files_in(ARDUINO_HEADER_DIR)
|
78
|
+
end
|
79
|
+
|
80
|
+
# CPP files that are part of the unit test library we're providing
|
81
|
+
# @return [Array<String>]
|
82
|
+
def cpp_files_unittest
|
83
|
+
cpp_files_in(UNITTEST_HEADER_DIR)
|
84
|
+
end
|
85
|
+
|
86
|
+
# The directory where we expect to find unit test defintions provided by the user
|
87
|
+
# @return [String]
|
88
|
+
def tests_dir
|
89
|
+
File.join(@base_dir, "test")
|
90
|
+
end
|
91
|
+
|
92
|
+
# The files provided by the user that contain unit tests
|
93
|
+
# @return [Array<String>]
|
94
|
+
def test_files
|
95
|
+
cpp_files_in(tests_dir)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Find all directories in the project library that include C++ header files
|
99
|
+
# @return [Array<String>]
|
100
|
+
def header_dirs
|
101
|
+
real = File.realpath(@base_dir)
|
102
|
+
all_files = Find.find(real).reject { |path| File.directory?(path) }
|
103
|
+
unbundled = all_files.reject { |path| vendor_bundle?(path) }
|
104
|
+
files = unbundled.select { |path| HPP_EXTENSIONS.include?(File.extname(path)) }
|
105
|
+
ret = files.map { |path| File.dirname(path) }.uniq
|
106
|
+
ret
|
107
|
+
end
|
108
|
+
|
109
|
+
# wrapper for the GCC command
|
110
|
+
def run_gcc(*args, **kwargs)
|
111
|
+
full_args = ["g++-4.9"] + args
|
112
|
+
@last_cmd = " $ #{full_args.join(' ')}"
|
113
|
+
<<<<<<< Updated upstream
|
114
|
+
|
115
|
+
=======
|
116
|
+
>>>>>>> Stashed changes
|
117
|
+
ret = Host.run_and_capture(*full_args, **kwargs)
|
118
|
+
@last_err = ret[:err]
|
119
|
+
@last_out = ret[:out]
|
120
|
+
ret[:success]
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return the GCC version
|
124
|
+
# @return [String] the version reported by `gcc -v`
|
125
|
+
def gcc_version
|
126
|
+
return nil unless run_gcc("-v")
|
127
|
+
@last_err
|
128
|
+
end
|
129
|
+
|
130
|
+
# GCC command line arguments for including aux libraries
|
131
|
+
# @param aux_libraries [String] The external Arduino libraries required by this project
|
132
|
+
# @return [Array<String>] The GCC command-line flags necessary to include those libraries
|
133
|
+
def include_args(aux_libraries)
|
134
|
+
places = [ARDUINO_HEADER_DIR, UNITTEST_HEADER_DIR] + header_dirs + aux_libraries
|
135
|
+
places.map { |d| "-I#{d}" }
|
136
|
+
end
|
137
|
+
|
138
|
+
# GCC command line arguments for features (e.g. -fno-weak)
|
139
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
140
|
+
# @return [Array<String>] GCC command-line flags
|
141
|
+
def feature_args(ci_gcc_config)
|
142
|
+
return [] if ci_gcc_config[:features].nil?
|
143
|
+
ci_gcc_config[:features].map { |f| "-f#{f}" }
|
144
|
+
end
|
145
|
+
|
146
|
+
# GCC command line arguments for warning (e.g. -Wall)
|
147
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
148
|
+
# @return [Array<String>] GCC command-line flags
|
149
|
+
def warning_args(ci_gcc_config)
|
150
|
+
return [] if ci_gcc_config[:warnings].nil?
|
151
|
+
ci_gcc_config[:features].map { |w| "-W#{w}" }
|
152
|
+
end
|
153
|
+
|
154
|
+
# GCC command line arguments for defines (e.g. -Dhave_something)
|
155
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
156
|
+
# @return [Array<String>] GCC command-line flags
|
157
|
+
def define_args(ci_gcc_config)
|
158
|
+
return [] if ci_gcc_config[:defines].nil?
|
159
|
+
ci_gcc_config[:defines].map { |d| "-D#{d}" }
|
160
|
+
end
|
161
|
+
|
162
|
+
# GCC command line arguments as-is
|
163
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
164
|
+
# @return [Array<String>] GCC command-line flags
|
165
|
+
def flag_args(ci_gcc_config)
|
166
|
+
return [] if ci_gcc_config[:flags].nil?
|
167
|
+
ci_gcc_config[:flags]
|
168
|
+
end
|
169
|
+
|
170
|
+
# All GCC command line args for building any unit test
|
171
|
+
# @param aux_libraries [String] The external Arduino libraries required by this project
|
172
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
173
|
+
# @return [Array<String>] GCC command-line flags
|
174
|
+
def test_args(aux_libraries, ci_gcc_config)
|
175
|
+
# TODO: something with libraries?
|
176
|
+
ret = include_args(aux_libraries) + cpp_files_arduino + cpp_files_unittest + cpp_files
|
177
|
+
unless ci_gcc_config.nil?
|
178
|
+
cgc = ci_gcc_config
|
179
|
+
ret = feature_args(cgc) + warning_args(cgc) + define_args(cgc) + flag_args(cgc) + ret
|
180
|
+
end
|
181
|
+
ret
|
182
|
+
end
|
183
|
+
|
184
|
+
# build a file for running a test of the given unit test file
|
185
|
+
# @param test_file [String] The path to the file containing the unit tests
|
186
|
+
# @param aux_libraries [String] The external Arduino libraries required by this project
|
187
|
+
# @param ci_gcc_config [Hash] The GCC config object
|
188
|
+
# @return [String] path to the compiled test executable
|
189
|
+
def build_for_test_with_configuration(test_file, aux_libraries, ci_gcc_config)
|
190
|
+
base = File.basename(test_file)
|
191
|
+
executable = File.expand_path("unittest_#{base}.bin")
|
192
|
+
File.delete(executable) if File.exist?(executable)
|
193
|
+
args = [
|
194
|
+
["-std=c++0x", "-o", executable, "-DARDUINO=100"],
|
195
|
+
test_args(aux_libraries, ci_gcc_config),
|
196
|
+
[test_file],
|
197
|
+
].flatten(1)
|
198
|
+
return nil unless run_gcc(*args)
|
199
|
+
artifacts << executable
|
200
|
+
executable
|
201
|
+
end
|
202
|
+
|
203
|
+
# run a test file
|
204
|
+
# @param [String] the path to the test file
|
205
|
+
# @return [bool] whether all tests were successful
|
206
|
+
def run_test_file(executable)
|
207
|
+
@last_cmd = executable
|
208
|
+
@last_out = ""
|
209
|
+
@last_err = ""
|
210
|
+
Host.run_and_output(executable)
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|