Skip to content

Enable redirection of installation output, add arduino_library_location.rb #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
- `ArduinoInstallation` and `ArduinoDownloader` now allow console output to optionally be set to an `IO` object of choice during `force_install`
- `ArduinoInstallation::force_install` now optionally accepts a version string
- `arduino_library_location.rb` script to print Arduino library location to stdout

### Changed
- Unit tests and examples are now executed alphabetically by filename
Expand Down
12 changes: 9 additions & 3 deletions REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ However, more flexible usage is available:

Sometimes you need a fork of an Arduino library instead of the version that will be installed via their GUI. `arduino_ci_remote.rb` won't overwrite existing downloaded libraries with fresh downloads, but it won't fetch the custom versions for you either.

If this is the behavior you need, `ensure_arduino_installation.rb` is for you.
If this is the behavior you need, `ensure_arduino_installation.rb` is for you. It ensures that an Arduino binary is available on the system.

```shell
# Example build script
Expand All @@ -147,14 +147,20 @@ bundle install
# ensure the Arduino installation -- creates the Library directory
bundle exec ensure_arduino_installation.rb

# manually install the custom version you need
# manually install a custom library from a zip file
wget https://hosting.com/custom_library.zip
unzip -o custom_library.zip
mv custom_library $(bundle exec arduino_library_location.rb)

# manually install a custom library from a git repository
git clone https://repository.com/custom_library_repo.git
mv custom_library_repo /path/to/Arduino/libraries
mv custom_library_repo $(bundle exec arduino_library_location.rb)

# now run CI
bundle exec arduino_ci_remote.rb
```

Note the use of subshell to execute `bundle exec arduino_library_location.rb`. This command simply returns the directory in which Arduino Libraries are (or should be) installed.



Expand Down
7 changes: 7 additions & 0 deletions exe/arduino_library_location.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env ruby
require 'arduino_ci'

# locate and/or forcibly install Arduino, keep stdout clean
@arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!($stderr)

puts @arduino_cmd.lib_dir
36 changes: 20 additions & 16 deletions lib/arduino_ci/arduino_downloader.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "fileutils"
require 'fileutils'
require 'net/http'
require 'open-uri'
require 'zip'

Expand All @@ -9,8 +10,11 @@ module ArduinoCI
# Manage the OS-specific download & install of Arduino
class ArduinoDownloader

def initialize(desired_ide_version)
# @param desired_ide_version [string] Version string e.g. 1.8.7
# @param output [IO] $stdout, $stderr, File.new(/dev/null, 'w'), etc. where console output will be sent
def initialize(desired_ide_version, output = $stdout)
@desired_ide_version = desired_ide_version
@output = output
end

# Provide guidelines to the implementer of this class
Expand Down Expand Up @@ -115,15 +119,15 @@ def download
total_size += size
needed_dots = (total_size / chunk_size).to_i
unprinted_dots = needed_dots - dots
print("." * unprinted_dots) if unprinted_dots > 0
@output.print("." * unprinted_dots) if unprinted_dots > 0
dots = needed_dots
end

open(package_url, ssl_verify_mode: 0, progress_proc: dot_printer) do |url|
File.open(package_file, 'wb') { |file| file.write(url.read) }
end
rescue Net::OpenTimeout, Net::ReadTimeout => e
puts "\nArduino force-install failed downloading #{package_url}: #{e}"
rescue Net::OpenTimeout, Net::ReadTimeout, OpenURI::HTTPError, URI::InvalidURIError => e
@output.puts "\nArduino force-install failed downloading #{package_url}: #{e}"
end

# Extract the package_file to extracted_file
Expand All @@ -133,7 +137,7 @@ def extract
batch_size = [1, (zip.size / 100).to_i].max
dots = 0
zip.each do |file|
print "." if (dots % batch_size).zero?
@output.print "." if (dots % batch_size).zero?
file.restore_permissions = true
file.extract { accept_all }
dots += 1
Expand All @@ -153,40 +157,40 @@ def install
def execute
error_preparing = prepare
unless error_preparing.nil?
puts "Arduino force-install failed preparation: #{error_preparing}"
@output.puts "Arduino force-install failed preparation: #{error_preparing}"
return false
end

attempts = 0

loop do
if File.exist? package_file
puts "Arduino package seems to have been downloaded already" if attempts.zero?
@output.puts "Arduino package seems to have been downloaded already" if attempts.zero?
break
elsif attempts >= DOWNLOAD_ATTEMPTS
break puts "After #{DOWNLOAD_ATTEMPTS} attempts, failed to download #{package_url}"
break @output.puts "After #{DOWNLOAD_ATTEMPTS} attempts, failed to download #{package_url}"
else
print "Attempting to download Arduino package with #{downloader}"
@output.print "Attempting to download Arduino package with #{downloader}"
download
puts
@output.puts
end
attempts += 1
end

if File.exist? extracted_file
puts "Arduino package seems to have been extracted already"
@output.puts "Arduino package seems to have been extracted already"
elsif File.exist? package_file
print "Extracting archive with #{extracter}"
@output.print "Extracting archive with #{extracter}"
extract
puts
@output.puts
end

if File.exist? self.class.force_install_location
puts "Arduino package seems to have been installed already"
@output.puts "Arduino package seems to have been installed already"
elsif File.exist? extracted_file
install
else
puts "Could not find extracted archive (tried #{extracted_file})"
@output.puts "Could not find extracted archive (tried #{extracted_file})"
end

File.exist? self.class.force_install_location
Expand Down
3 changes: 3 additions & 0 deletions lib/arduino_ci/arduino_downloader_windows.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'shellwords' # fingers crossed this works on win32
require 'win32/registry'
require "arduino_ci/arduino_downloader"
require 'net/http'
require "fileutils"

module ArduinoCI
Expand Down Expand Up @@ -30,6 +31,8 @@ def download
open(URI.parse(package_url), ssl_verify_mode: 0) do |url|
File.open(package_file, 'wb') { |file| file.write(url.read) }
end
rescue Net::OpenTimeout, Net::ReadTimeout, OpenURI::HTTPError, URI::InvalidURIError => e
@output.puts "\nArduino force-install failed downloading #{package_url}: #{e}"
end

# Move the extracted package file from extracted_file to the force_install_location
Expand Down
8 changes: 4 additions & 4 deletions lib/arduino_ci/arduino_installation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,25 @@ def autolocate_osx

# Attempt to find a workable Arduino executable across platforms, and install it if we don't
# @return [ArduinoCI::ArduinoCmd] an instance of a command
def autolocate!
def autolocate!(output = $stdout)
candidate = autolocate
return candidate unless candidate.nil?

# force the install
raise ArduinoInstallationError, "Failed to force-install Arduino" unless force_install
raise ArduinoInstallationError, "Failed to force-install Arduino" unless force_install(output)

autolocate
end

# Forcibly install Arduino from the web
# @return [bool] Whether the command succeeded
def force_install
def force_install(output = $stdout, version = DESIRED_ARDUINO_IDE_VERSION)
worker_class = case Host.os
when :osx then ArduinoDownloaderOSX
when :windows then ArduinoDownloaderWindows
when :linux then ArduinoDownloaderLinux
end
worker = worker_class.new(DESIRED_ARDUINO_IDE_VERSION)
worker = worker_class.new(version, output)
worker.execute
end

Expand Down
12 changes: 12 additions & 0 deletions spec/arduino_installation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,17 @@
end
end

context "force_install" do
it "Can redirect output" do
output = StringIO.new
output.rewind
expect(output.read.empty?).to be true
# install a bogus version to save time downloading
arduino_cmd = ArduinoCI::ArduinoInstallation.force_install(output, "BOGUS VERSION")
output.rewind
expect(output.read.empty?).to be false
end
end

end