arduino_ci 0.4.0 → 1.0.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 +34 -7
- data/cpp/arduino/Client.h +1 -0
- data/exe/arduino_ci.rb +85 -86
- data/exe/arduino_library_location.rb +2 -2
- data/lib/arduino_ci/arduino_backend.rb +218 -0
- data/lib/arduino_ci/arduino_downloader.rb +42 -73
- data/lib/arduino_ci/arduino_downloader_linux.rb +17 -55
- data/lib/arduino_ci/arduino_downloader_osx.rb +21 -33
- data/lib/arduino_ci/arduino_downloader_windows.rb +11 -53
- data/lib/arduino_ci/arduino_installation.rb +13 -75
- data/lib/arduino_ci/ci_config.rb +0 -7
- data/lib/arduino_ci/cpp_library.rb +166 -79
- data/lib/arduino_ci/host.rb +59 -4
- data/lib/arduino_ci/library_properties.rb +12 -2
- data/lib/arduino_ci/version.rb +1 -1
- data/misc/default.yml +6 -2
- metadata +3 -78
- data/lib/arduino_ci/arduino_cmd.rb +0 -332
- data/lib/arduino_ci/arduino_cmd_linux.rb +0 -17
- data/lib/arduino_ci/arduino_cmd_linux_builder.rb +0 -19
- data/lib/arduino_ci/arduino_cmd_osx.rb +0 -17
- data/lib/arduino_ci/arduino_cmd_windows.rb +0 -17
- data/lib/arduino_ci/installed_cpp_library.rb +0 -0
data/lib/arduino_ci/host.rb
CHANGED
@@ -6,6 +6,13 @@ module ArduinoCI
|
|
6
6
|
|
7
7
|
# Tools for interacting with the host machine
|
8
8
|
class Host
|
9
|
+
# TODO: this came from https://stackoverflow.com/a/22716582/2063546
|
10
|
+
# and I'm not sure if it can be replaced by self.os == :windows
|
11
|
+
WINDOWS_VARIANT_REGEX = /mswin32|cygwin|mingw|bccwin/
|
12
|
+
|
13
|
+
# e.g. 11/27/2020 01:02 AM <SYMLINKD> ExcludeSomething [C:\projects\arduino-ci\SampleProjects\ExcludeSomething]
|
14
|
+
DIR_SYMLINK_REGEX = %r{\d+/\d+/\d+\s+[^<]+<SYMLINKD?>\s+(.*) \[([^\]]+)\]}
|
15
|
+
|
9
16
|
# Cross-platform way of finding an executable in the $PATH.
|
10
17
|
# via https://stackoverflow.com/a/5471032/2063546
|
11
18
|
# which('ruby') #=> /usr/bin/ruby
|
@@ -38,21 +45,69 @@ module ArduinoCI
|
|
38
45
|
return :windows if OS.windows?
|
39
46
|
end
|
40
47
|
|
48
|
+
# Cross-platform symlinking
|
41
49
|
# if on windows, call mklink, else self.symlink
|
42
50
|
# @param [Pathname] old_path
|
43
51
|
# @param [Pathname] new_path
|
44
52
|
def self.symlink(old_path, new_path)
|
45
|
-
|
53
|
+
# we would prefer `new_path.make_symlink(old_path)` but "symlink function is unimplemented on this machine" with windows
|
54
|
+
return new_path.make_symlink(old_path) unless needs_symlink_hack?
|
46
55
|
|
47
|
-
# https://stackoverflow.com/a/22716582/2063546
|
56
|
+
# via https://stackoverflow.com/a/22716582/2063546
|
48
57
|
# windows mklink syntax is reverse of unix ln -s
|
49
58
|
# windows mklink is built into cmd.exe
|
50
59
|
# vulnerable to command injection, but okay because this is a hack to make a cli tool work.
|
51
|
-
orp = old_path.realpath
|
52
|
-
np
|
60
|
+
orp = pathname_to_windows(old_path.realpath)
|
61
|
+
np = pathname_to_windows(new_path)
|
53
62
|
|
54
63
|
_stdout, _stderr, exitstatus = Open3.capture3('cmd.exe', "/C mklink /D #{np} #{orp}")
|
55
64
|
exitstatus.success?
|
56
65
|
end
|
66
|
+
|
67
|
+
# Hack for "realpath" which on windows joins paths with slashes instead of backslashes
|
68
|
+
# @param path [Pathname] the path to render
|
69
|
+
# @return [String] A path that will work on windows
|
70
|
+
def self.pathname_to_windows(path)
|
71
|
+
path.to_s.tr("/", "\\")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Hack for "realpath" which on windows joins paths with slashes instead of backslashes
|
75
|
+
# @param str [String] the windows path
|
76
|
+
# @return [Pathname] A path that will be recognized by pathname
|
77
|
+
def self.windows_to_pathname(str)
|
78
|
+
Pathname.new(str.tr("\\", "/"))
|
79
|
+
end
|
80
|
+
|
81
|
+
# Whether this OS requires a hack for symlinks
|
82
|
+
# @return [bool]
|
83
|
+
def self.needs_symlink_hack?
|
84
|
+
RUBY_PLATFORM =~ WINDOWS_VARIANT_REGEX
|
85
|
+
end
|
86
|
+
|
87
|
+
# Cross-platform is-this-a-symlink function
|
88
|
+
# @param [Pathname] path
|
89
|
+
# @return [bool] Whether the file is a symlink
|
90
|
+
def self.symlink?(path)
|
91
|
+
return path.symlink? unless needs_symlink_hack?
|
92
|
+
|
93
|
+
!readlink(path).nil?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Cross-platform "read link" function
|
97
|
+
# @param [Pathname] path
|
98
|
+
# @return [Pathname] the link target
|
99
|
+
def self.readlink(path)
|
100
|
+
return path.readlink unless needs_symlink_hack?
|
101
|
+
|
102
|
+
the_dir = pathname_to_windows(path.parent)
|
103
|
+
the_file = path.basename.to_s
|
104
|
+
|
105
|
+
stdout, _stderr, _exitstatus = Open3.capture3('cmd.exe', "/c dir /al #{the_dir}")
|
106
|
+
symlinks = stdout.lines.map { |l| DIR_SYMLINK_REGEX.match(l) }.compact
|
107
|
+
our_link = symlinks.find { |m| m[1] == the_file }
|
108
|
+
return nil if our_link.nil?
|
109
|
+
|
110
|
+
windows_to_pathname(our_link[2])
|
111
|
+
end
|
57
112
|
end
|
58
113
|
end
|
@@ -11,12 +11,22 @@ module ArduinoCI
|
|
11
11
|
# @param path [Pathname] The path to the library.properties file
|
12
12
|
def initialize(path)
|
13
13
|
@fields = {}
|
14
|
-
File.foreach(path) do |
|
14
|
+
File.foreach(path) do |line_with_delim|
|
15
|
+
line = line_with_delim.chomp
|
15
16
|
parts = line.split("=", 2)
|
16
|
-
|
17
|
+
next if parts[0].nil?
|
18
|
+
next if parts[0].empty?
|
19
|
+
next if parts[1].nil?
|
20
|
+
|
21
|
+
@fields[parts[0]] = parts[1] unless parts[1].empty?
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
25
|
+
# @return [Hash] the properties as a hash, all strings
|
26
|
+
def to_h
|
27
|
+
@fields.clone
|
28
|
+
end
|
29
|
+
|
20
30
|
# Enable a shortcut syntax for library property accessors, in the style of `attr_accessor` metaprogramming.
|
21
31
|
# This is used to create a named field pointing to a specific property in the file, optionally applying
|
22
32
|
# a specific formatting function.
|
data/lib/arduino_ci/version.rb
CHANGED
data/misc/default.yml
CHANGED
@@ -3,8 +3,12 @@
|
|
3
3
|
# https://en.wikipedia.org/wiki/List_of_Arduino_boards_and_compatible_systems
|
4
4
|
|
5
5
|
packages:
|
6
|
-
|
7
|
-
|
6
|
+
arduino:avr:
|
7
|
+
url: https://downloads.arduino.cc/packages/package_index.json
|
8
|
+
arduino:sam:
|
9
|
+
url: https://downloads.arduino.cc/packages/package_index.json
|
10
|
+
arduino:samd:
|
11
|
+
url: https://downloads.arduino.cc/packages/package_index.json
|
8
12
|
esp8266:esp8266:
|
9
13
|
url: http://arduino.esp8266.com/stable/package_esp8266com_index.json
|
10
14
|
adafruit:avr:
|
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.
|
4
|
+
version: 1.0.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: 2020-11-
|
11
|
+
date: 2020-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: os
|
@@ -38,76 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.2'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.15'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.15'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: keepachangelog_manager
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 0.0.2
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.0.2
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rspec
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '3.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '3.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 0.59.0
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.59.0
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: yard
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - "~>"
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 0.9.11
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - "~>"
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 0.9.11
|
111
41
|
description: ''
|
112
42
|
email:
|
113
43
|
- arduino.continuous.integration@gmail.com
|
@@ -437,11 +367,7 @@ files:
|
|
437
367
|
- exe/arduino_library_location.rb
|
438
368
|
- exe/ensure_arduino_installation.rb
|
439
369
|
- lib/arduino_ci.rb
|
440
|
-
- lib/arduino_ci/
|
441
|
-
- lib/arduino_ci/arduino_cmd_linux.rb
|
442
|
-
- lib/arduino_ci/arduino_cmd_linux_builder.rb
|
443
|
-
- lib/arduino_ci/arduino_cmd_osx.rb
|
444
|
-
- lib/arduino_ci/arduino_cmd_windows.rb
|
370
|
+
- lib/arduino_ci/arduino_backend.rb
|
445
371
|
- lib/arduino_ci/arduino_downloader.rb
|
446
372
|
- lib/arduino_ci/arduino_downloader_linux.rb
|
447
373
|
- lib/arduino_ci/arduino_downloader_osx.rb
|
@@ -450,7 +376,6 @@ files:
|
|
450
376
|
- lib/arduino_ci/ci_config.rb
|
451
377
|
- lib/arduino_ci/cpp_library.rb
|
452
378
|
- lib/arduino_ci/host.rb
|
453
|
-
- lib/arduino_ci/installed_cpp_library.rb
|
454
379
|
- lib/arduino_ci/library_properties.rb
|
455
380
|
- lib/arduino_ci/version.rb
|
456
381
|
- misc/default.yml
|
@@ -1,332 +0,0 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'pathname'
|
3
|
-
|
4
|
-
# workaround for https://github.com/arduino/Arduino/issues/3535
|
5
|
-
WORKAROUND_LIB = "USBHost".freeze
|
6
|
-
|
7
|
-
module ArduinoCI
|
8
|
-
|
9
|
-
# To report errors that we can't resolve or possibly even explain
|
10
|
-
class ArduinoExecutionError < StandardError; end
|
11
|
-
|
12
|
-
# Wrap the Arduino executable. This requires, in some cases, a faked display.
|
13
|
-
class ArduinoCmd
|
14
|
-
|
15
|
-
# Enable a shortcut syntax for command line flags
|
16
|
-
# @param name [String] What the flag will be called (prefixed with 'flag_')
|
17
|
-
# @return [void]
|
18
|
-
# @macro [attach] flag
|
19
|
-
# The text of the command line flag for $1
|
20
|
-
# @!attribute [r] flag_$1
|
21
|
-
# @return [String] the text of the command line flag (`$2` in this case)
|
22
|
-
def self.flag(name, text = nil)
|
23
|
-
text = "(flag #{name} not defined)" if text.nil?
|
24
|
-
self.class_eval("def flag_#{name};\"#{text}\";end", __FILE__, __LINE__)
|
25
|
-
end
|
26
|
-
|
27
|
-
# the array of command components to launch the Arduino executable
|
28
|
-
# @return [Array<String>]
|
29
|
-
attr_accessor :base_cmd
|
30
|
-
|
31
|
-
# the actual path to the executable on this platform
|
32
|
-
# @return [Pathname]
|
33
|
-
attr_accessor :binary_path
|
34
|
-
|
35
|
-
# part of a workaround for https://github.com/arduino/Arduino/issues/3535
|
36
|
-
attr_reader :libraries_indexed
|
37
|
-
|
38
|
-
# @return [String] STDOUT of the most recently-run command
|
39
|
-
attr_reader :last_out
|
40
|
-
|
41
|
-
# @return [String] STDERR of the most recently-run command
|
42
|
-
attr_reader :last_err
|
43
|
-
|
44
|
-
# @return [String] the most recently-run command
|
45
|
-
attr_reader :last_msg
|
46
|
-
|
47
|
-
# set the command line flags (undefined for now).
|
48
|
-
# These vary between gui/cli. Inline comments added for greppability
|
49
|
-
flag :get_pref # flag_get_pref
|
50
|
-
flag :set_pref # flag_set_pref
|
51
|
-
flag :save_prefs # flag_save_prefs
|
52
|
-
flag :use_board # flag_use_board
|
53
|
-
flag :install_boards # flag_install_boards
|
54
|
-
flag :install_library # flag_install_library
|
55
|
-
flag :verify # flag_verify
|
56
|
-
|
57
|
-
def initialize
|
58
|
-
@prefs_cache = {}
|
59
|
-
@prefs_fetched = false
|
60
|
-
@libraries_indexed = false
|
61
|
-
@last_out = ""
|
62
|
-
@last_err = ""
|
63
|
-
@last_msg = ""
|
64
|
-
end
|
65
|
-
|
66
|
-
# Convert a preferences dump into a flat hash
|
67
|
-
# @param arduino_output [String] The raw Arduino executable output
|
68
|
-
# @return [Hash] preferences as a hash
|
69
|
-
def parse_pref_string(arduino_output)
|
70
|
-
lines = arduino_output.split("\n").select { |l| l.include? "=" }
|
71
|
-
ret = lines.each_with_object({}) do |e, acc|
|
72
|
-
parts = e.split("=", 2)
|
73
|
-
acc[parts[0]] = parts[1]
|
74
|
-
acc
|
75
|
-
end
|
76
|
-
ret
|
77
|
-
end
|
78
|
-
|
79
|
-
# @return [String] the path to the Arduino libraries directory
|
80
|
-
def lib_dir
|
81
|
-
Pathname.new(get_pref("sketchbook.path")) + "libraries"
|
82
|
-
end
|
83
|
-
|
84
|
-
# fetch preferences in their raw form
|
85
|
-
# @return [String] Preferences as a set of lines
|
86
|
-
def _prefs_raw
|
87
|
-
resp = run_and_capture(flag_get_pref)
|
88
|
-
fail_msg = "Arduino binary failed to operate as expected; you will have to troubleshoot it manually"
|
89
|
-
raise ArduinoExecutionError, "#{fail_msg}. The command was #{@last_msg}" unless resp[:success]
|
90
|
-
|
91
|
-
@prefs_fetched = true
|
92
|
-
resp[:out]
|
93
|
-
end
|
94
|
-
|
95
|
-
# Get the Arduino preferences, from cache if possible
|
96
|
-
# @return [Hash] The full set of preferences
|
97
|
-
def prefs
|
98
|
-
prefs_raw = _prefs_raw unless @prefs_fetched
|
99
|
-
return nil if prefs_raw.nil?
|
100
|
-
|
101
|
-
@prefs_cache = parse_pref_string(prefs_raw)
|
102
|
-
@prefs_cache.clone
|
103
|
-
end
|
104
|
-
|
105
|
-
# get a preference key
|
106
|
-
# @param key [String] The preferences key to look up
|
107
|
-
# @return [String] The preference value
|
108
|
-
def get_pref(key)
|
109
|
-
data = @prefs_fetched ? @prefs_cache : prefs
|
110
|
-
data[key]
|
111
|
-
end
|
112
|
-
|
113
|
-
# underlying preference-setter.
|
114
|
-
# @param key [String] The preference name
|
115
|
-
# @param value [String] The value to set to
|
116
|
-
# @return [bool] whether the command succeeded
|
117
|
-
def _set_pref(key, value)
|
118
|
-
run_and_capture(flag_set_pref, "#{key}=#{value}", flag_save_prefs)[:success]
|
119
|
-
end
|
120
|
-
|
121
|
-
# set a preference key/value pair, and update the cache.
|
122
|
-
# @param key [String] the preference key
|
123
|
-
# @param value [String] the preference value
|
124
|
-
# @return [bool] whether the command succeeded
|
125
|
-
def set_pref(key, value)
|
126
|
-
prefs unless @prefs_fetched # update cache first
|
127
|
-
success = _set_pref(key, value)
|
128
|
-
@prefs_cache[key] = value if success
|
129
|
-
success
|
130
|
-
end
|
131
|
-
|
132
|
-
def _wrap_run(work_fn, *args, **kwargs)
|
133
|
-
# do some work to extract & merge environment variables if they exist
|
134
|
-
has_env = !args.empty? && args[0].class == Hash
|
135
|
-
env_vars = has_env ? args[0] : {}
|
136
|
-
actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args
|
137
|
-
full_args = @base_cmd + actual_args
|
138
|
-
full_cmd = env_vars.empty? ? full_args : [env_vars] + full_args
|
139
|
-
|
140
|
-
shell_vars = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ")
|
141
|
-
@last_msg = " $ #{shell_vars} #{full_args.join(' ')}"
|
142
|
-
work_fn.call(*full_cmd, **kwargs)
|
143
|
-
end
|
144
|
-
|
145
|
-
# build and run the arduino command
|
146
|
-
def run_and_output(*args, **kwargs)
|
147
|
-
_wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs)
|
148
|
-
end
|
149
|
-
|
150
|
-
# run a command and capture its output
|
151
|
-
# @return [Hash] {:out => String, :err => String, :success => bool}
|
152
|
-
def run_and_capture(*args, **kwargs)
|
153
|
-
ret = _wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs)
|
154
|
-
@last_err = ret[:err]
|
155
|
-
@last_out = ret[:out]
|
156
|
-
ret
|
157
|
-
end
|
158
|
-
|
159
|
-
# Board manager URLs
|
160
|
-
# @return [Array<String>] The additional URLs used by the board manager
|
161
|
-
def board_manager_urls
|
162
|
-
url_list = get_pref("boardsmanager.additional.urls")
|
163
|
-
return [] if url_list.nil?
|
164
|
-
|
165
|
-
url_list.split(",")
|
166
|
-
end
|
167
|
-
|
168
|
-
# Set board manager URLs
|
169
|
-
# @return [Array<String>] The additional URLs used by the board manager
|
170
|
-
def board_manager_urls=(all_urls)
|
171
|
-
set_pref("boardsmanager.additional.urls", all_urls.join(","))
|
172
|
-
end
|
173
|
-
|
174
|
-
# check whether a board is installed
|
175
|
-
# we do this by just selecting a board.
|
176
|
-
# the arduino binary will error if unrecognized and do a successful no-op if it's installed
|
177
|
-
# @param boardname [String] The board to test
|
178
|
-
# @return [bool] Whether the board is installed
|
179
|
-
def board_installed?(boardname)
|
180
|
-
run_and_capture(flag_use_board, boardname)[:success]
|
181
|
-
end
|
182
|
-
|
183
|
-
# install a board by name
|
184
|
-
# @param name [String] the board name
|
185
|
-
# @return [bool] whether the command succeeded
|
186
|
-
def install_boards(boardfamily)
|
187
|
-
# TODO: find out why IO.pipe fails but File::NULL succeeds :(
|
188
|
-
result = run_and_capture(flag_install_boards, boardfamily)
|
189
|
-
already_installed = result[:err].include?("Platform is already installed!")
|
190
|
-
result[:success] || already_installed
|
191
|
-
end
|
192
|
-
|
193
|
-
# install a library by name
|
194
|
-
# @param name [String] the library name
|
195
|
-
# @return [bool] whether the command succeeded
|
196
|
-
def _install_library(library_name)
|
197
|
-
result = run_and_capture(flag_install_library, library_name)
|
198
|
-
|
199
|
-
already_installed = result[:err].include?("Library is already installed: #{library_name}")
|
200
|
-
success = result[:success] || already_installed
|
201
|
-
|
202
|
-
@libraries_indexed = (@libraries_indexed || success) if library_name == WORKAROUND_LIB
|
203
|
-
success
|
204
|
-
end
|
205
|
-
|
206
|
-
# index the set of libraries by installing a dummy library
|
207
|
-
# related to WORKAROUND_LIB and https://github.com/arduino/Arduino/issues/3535
|
208
|
-
# TODO: unclear if this is still necessary
|
209
|
-
def index_libraries
|
210
|
-
return true if @libraries_indexed
|
211
|
-
|
212
|
-
_install_library(WORKAROUND_LIB)
|
213
|
-
@libraries_indexed
|
214
|
-
end
|
215
|
-
|
216
|
-
# install a library by name
|
217
|
-
# @param name [String] the library name
|
218
|
-
# @return [bool] whether the command succeeded
|
219
|
-
def install_library(library_name)
|
220
|
-
index_libraries
|
221
|
-
_install_library(library_name)
|
222
|
-
end
|
223
|
-
|
224
|
-
# generate the (very likely) path of a library given its name
|
225
|
-
# @param library_name [String] The name of the library
|
226
|
-
# @return [Pathname] The fully qualified library name
|
227
|
-
def library_path(library_name)
|
228
|
-
Pathname.new(lib_dir) + library_name
|
229
|
-
end
|
230
|
-
|
231
|
-
# Determine whether a library is present in the lib dir
|
232
|
-
#
|
233
|
-
# Note that `true` doesn't guarantee that the library is valid/installed
|
234
|
-
# and `false` doesn't guarantee that the library isn't built-in
|
235
|
-
#
|
236
|
-
# @param library_name [String] The name of the library
|
237
|
-
# @return [bool]
|
238
|
-
def library_present?(library_name)
|
239
|
-
library_path(library_name).exist?
|
240
|
-
end
|
241
|
-
|
242
|
-
# update the library index
|
243
|
-
# @return [bool] Whether the update succeeded
|
244
|
-
def update_library_index
|
245
|
-
# install random lib so the arduino IDE grabs a new library index
|
246
|
-
# see: https://github.com/arduino/Arduino/issues/3535
|
247
|
-
install_library(WORKAROUND_LIB)
|
248
|
-
end
|
249
|
-
|
250
|
-
# use a particular board for compilation
|
251
|
-
# @param boardname [String] The board to use
|
252
|
-
# @return [bool] whether the command succeeded
|
253
|
-
def use_board(boardname)
|
254
|
-
run_and_capture(flag_use_board, boardname, flag_save_prefs)[:success]
|
255
|
-
end
|
256
|
-
|
257
|
-
# use a particular board for compilation, installing it if necessary
|
258
|
-
# @param boardname [String] The board to use
|
259
|
-
# @return [bool] whether the command succeeded
|
260
|
-
def use_board!(boardname)
|
261
|
-
return true if use_board(boardname)
|
262
|
-
|
263
|
-
boardfamily = boardname.split(":")[0..1].join(":")
|
264
|
-
puts "Board '#{boardname}' not found; attempting to install '#{boardfamily}'"
|
265
|
-
return false unless install_boards(boardfamily) # guess board family from first 2 :-separated fields
|
266
|
-
|
267
|
-
use_board(boardname)
|
268
|
-
end
|
269
|
-
|
270
|
-
# @param path [String] The sketch to verify
|
271
|
-
# @return [bool] whether the command succeeded
|
272
|
-
def verify_sketch(path)
|
273
|
-
ext = File.extname path
|
274
|
-
unless ext.casecmp(".ino").zero?
|
275
|
-
@last_msg = "Refusing to verify sketch with '#{ext}' extension -- rename it to '.ino'!"
|
276
|
-
return false
|
277
|
-
end
|
278
|
-
unless File.exist? path
|
279
|
-
@last_msg = "Can't verify Sketch at nonexistent path '#{path}'!"
|
280
|
-
return false
|
281
|
-
end
|
282
|
-
ret = run_and_capture(flag_verify, path)
|
283
|
-
ret[:success]
|
284
|
-
end
|
285
|
-
|
286
|
-
# ensure that the given library is installed, or symlinked as appropriate
|
287
|
-
# return the path of the prepared library, or nil
|
288
|
-
# @param path [Pathname] library to use
|
289
|
-
# @return [String] the path of the installed library
|
290
|
-
def install_local_library(path)
|
291
|
-
src_path = path.realpath
|
292
|
-
library_name = src_path.basename
|
293
|
-
destination_path = library_path(library_name)
|
294
|
-
|
295
|
-
# things get weird if the sketchbook contains the library.
|
296
|
-
# check that first
|
297
|
-
if destination_path.exist?
|
298
|
-
uhoh = "There is already a library '#{library_name}' in the library directory"
|
299
|
-
return destination_path if destination_path == src_path
|
300
|
-
|
301
|
-
# maybe it's a symlink? that would be OK
|
302
|
-
if destination_path.symlink?
|
303
|
-
return destination_path if destination_path.readlink == src_path
|
304
|
-
|
305
|
-
@last_msg = "#{uhoh} and it's not symlinked to #{src_path}"
|
306
|
-
return nil
|
307
|
-
end
|
308
|
-
|
309
|
-
@last_msg = "#{uhoh}. It may need to be removed manually."
|
310
|
-
return nil
|
311
|
-
end
|
312
|
-
|
313
|
-
# install the library
|
314
|
-
Host.symlink(src_path, destination_path)
|
315
|
-
destination_path
|
316
|
-
end
|
317
|
-
|
318
|
-
# @param installed_library_path [String] The library to query
|
319
|
-
# @return [Array<String>] Example sketch files
|
320
|
-
def library_examples(installed_library_path)
|
321
|
-
example_path = Pathname.new(installed_library_path) + "examples"
|
322
|
-
return [] unless File.exist?(example_path)
|
323
|
-
|
324
|
-
examples = example_path.children.select(&:directory?).map(&:to_path).map(&File.method(:basename))
|
325
|
-
files = examples.map do |e|
|
326
|
-
proj_file = example_path + e + "#{e}.ino"
|
327
|
-
proj_file.exist? ? proj_file.to_s : nil
|
328
|
-
end
|
329
|
-
files.reject(&:nil?).sort_by(&:to_s)
|
330
|
-
end
|
331
|
-
end
|
332
|
-
end
|