diff --git a/.travis.yml b/.travis.yml index 4f51fddf..e93a54e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,25 @@ sudo: false language: ruby -# rvm: -# - "2.0.0" -# - "2.1.0" -# - "2.2.0" -# - rbx -# - "2.5.0" +os: + - linux + - osx + +env: + - BADGE=linux + - BADGE=osx + +# hack to get some OS-specific badges +matrix: + exclude: + - os: linux + env: BADGE=osx + - os: osx + env: BADGE=linux #before_install: gem install bundler -v 1.15.4 script: + - g++ -v - bundle install - bundle exec rubocop --version - bundle exec rubocop -D . diff --git a/README.md b/README.md index 6b01acef..782bf75f 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,18 @@ -[![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) -[![Linux Build Status](https://travis-ci.org/ianfixes/arduino_ci.svg)](https://travis-ci.org/ianfixes/arduino_ci) -[![Windows Build status](https://ci.appveyor.com/api/projects/status/8f6e39dea319m83q?svg=true)](https://ci.appveyor.com/project/ianfixes/arduino-ci) -[![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/0.1.9) -# ArduinoCI Ruby gem (`arduino_ci`) +# 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.9) -[Arduino CI](https://github.com/ianfixes/arduino_ci) is a Ruby gem for executing Continuous Integration (CI) tests on an Arduino library -- both locally and as part of a service like Travis CI. + +[Arduino CI](https://github.com/ianfixes/arduino_ci) is a cross-platform Ruby gem for executing Continuous Integration (CI) tests on an Arduino library -- both locally and as part of a service like Travis CI. + +It doesn't matter whether your contributors are using OSX, Linux, or Windows; everyone can run unit tests locally with `arduino_ci`, and be assured that the CI system used by the GitHub project maintainer will run the same tests and get the same results. + +You don't have to take my word for it; let the build logs speak for themselves: + +Platform | CI Status +---------|:--------- +OSX | [![OSX Build Status](http://badges.herokuapp.com/travis/ianfixes/arduino_ci?env=BADGE=osx&label=build&branch=master)](https://travis-ci.org/ianfixes/arduino_ci) +Linux | [![Linux Build Status](http://badges.herokuapp.com/travis/ianfixes/arduino_ci?env=BADGE=linux&label=build&branch=master)](https://travis-ci.org/ianfixes/arduino_ci) +Windows | [![Windows Build status](https://ci.appveyor.com/api/projects/status/8f6e39dea319m83q?svg=true)](https://ci.appveyor.com/project/ianfixes/arduino-ci) ## Installation In Your GitHub Project And Using Travis CI diff --git a/cpp/arduino/WString.h b/cpp/arduino/WString.h index 498de157..f79f3361 100644 --- a/cpp/arduino/WString.h +++ b/cpp/arduino/WString.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -11,8 +12,8 @@ typedef std::string string; // work around some portability issues #if defined(__clang__) - #define ARDUINOCI_ISNAN ::isnan - #define ARDUINOCI_ISINF ::isinf + #define ARDUINOCI_ISNAN isnan + #define ARDUINOCI_ISINF isinf #elif defined(__GNUC__) || defined(__GNUG__) #define ARDUINOCI_ISNAN std::isnan #define ARDUINOCI_ISINF std::isinf diff --git a/lib/arduino_ci/arduino_downloader.rb b/lib/arduino_ci/arduino_downloader.rb index 87f998c1..9244178d 100644 --- a/lib/arduino_ci/arduino_downloader.rb +++ b/lib/arduino_ci/arduino_downloader.rb @@ -1,3 +1,7 @@ +require "fileutils" +require 'open-uri' +require 'zip' + DOWNLOAD_ATTEMPTS = 3 module ArduinoCI @@ -74,14 +78,14 @@ def self.force_installed_executable # (for logging purposes) # @return [string] def downloader - self.class.must_implement(__method__) + "open-uri" end # The technology that will be used to extract the download # (for logging purposes) # @return [string] def extracter - self.class.must_implement(__method__) + "Zip" end # The URL of the desired IDE package (zip/tar/etc) for this platform @@ -107,22 +111,49 @@ def self.force_install_location File.join(ENV['HOME'], 'arduino_ci_ide') end - # Download the package_url to package_file, and maybe print a line of dots...... + # Download the package_url to package_file # @return [bool] whether successful def download - self.class.must_implement(__method__) + # Turned off ssl verification + # This should be acceptable because it won't happen on a user's machine, just CI + + # define a progress-bar printer + chunk_size = 1024 * 1024 * 1024 + total_size = 0 + dots = 0 + dot_printer = lambda do |size| + total_size += size + needed_dots = (total_size / chunk_size).to_i + unprinted_dots = needed_dots - dots + 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 end # Extract the package_file to extracted_file # @return [bool] whether successful def extract - self.class.must_implement(__method__) + Zip::File.open(package_file) do |zip| + batch_size = [1, (zip.size / 100).to_i].max + dots = 0 + zip.each do |file| + print "." if (dots % batch_size).zero? + file.restore_permissions = true + file.extract { accept_all } + dots += 1 + end + end end # Move the extracted package file from extracted_file to the force_install_location # @return [bool] whether successful def install - self.class.must_implement(__method__) + # Move only the content of the directory + FileUtils.mv extracted_file, self.class.force_install_location end # Forcibly install Arduino on linux from the web @@ -143,8 +174,9 @@ def execute elsif attempts >= DOWNLOAD_ATTEMPTS break puts "After #{DOWNLOAD_ATTEMPTS} attempts, failed to download #{package_url}" else - puts "Attempting to download Arduino package with #{downloader}" + print "Attempting to download Arduino package with #{downloader}" download + puts end attempts += 1 end @@ -152,8 +184,9 @@ def execute if File.exist? extracted_file puts "Arduino package seems to have been extracted already" elsif File.exist? package_file - puts "Extracting archive with #{extracter}" + print "Extracting archive with #{extracter}" extract + puts end if File.exist? self.class.force_install_location diff --git a/lib/arduino_ci/arduino_downloader_linux.rb b/lib/arduino_ci/arduino_downloader_linux.rb index d0fcdb0c..12c7db95 100644 --- a/lib/arduino_ci/arduino_downloader_linux.rb +++ b/lib/arduino_ci/arduino_downloader_linux.rb @@ -1,11 +1,11 @@ -require "arduino_ci/arduino_downloader_posix" +require "arduino_ci/arduino_downloader" USE_BUILDER = false module ArduinoCI # Manage the linux download & install of Arduino - class ArduinoDownloaderLinux < ArduinoDownloaderPosix + class ArduinoDownloaderLinux < ArduinoDownloader # The local filename of the desired IDE package (zip/tar/etc) # @return [string] @@ -13,6 +13,16 @@ def package_file "#{extracted_file}-linux64.tar.xz" end + # Make any preparations or run any checks prior to making changes + # @return [string] Error message, or nil if success + def prepare + reqs = [extracter] + reqs.each do |req| + return "#{req} does not appear to be installed!" unless Host.which(req) + end + nil + end + # The technology that will be used to extract the download # (for logging purposes) # @return [string] diff --git a/lib/arduino_ci/arduino_downloader_osx.rb b/lib/arduino_ci/arduino_downloader_osx.rb index c695c9ee..9ff7588d 100644 --- a/lib/arduino_ci/arduino_downloader_osx.rb +++ b/lib/arduino_ci/arduino_downloader_osx.rb @@ -1,9 +1,9 @@ -require "arduino_ci/arduino_downloader_posix" +require "arduino_ci/arduino_downloader" module ArduinoCI # Manage the OSX download & install of Arduino - class ArduinoDownloaderOSX < ArduinoDownloaderPosix + class ArduinoDownloaderOSX < ArduinoDownloader # The local filename of the desired IDE package (zip/tar/etc) # @return [string] @@ -11,25 +11,18 @@ def package_file "arduino-#{@desired_ide_version}-macosx.zip" end - # The technology that will be used to extract the download - # (for logging purposes) - # @return [string] - def extracter - "unzip" - end - - # Extract the package_file to extracted_file - # @return [bool] whether successful - def extract - system(extracter, package_file) - end - # The local file (dir) name of the extracted IDE package (zip/tar/etc) # @return [string] def extracted_file "Arduino.app" end + # @return [String] The location where a forced install will go + def self.force_install_location + # include the .app extension + File.join(ENV['HOME'], 'Arduino.app') + end + # An existing Arduino directory in one of the given directories, or nil # @param Array a list of places to look # @return [string] @@ -54,19 +47,19 @@ def self.find_existing_arduino_exe(paths) # The path to the directory of an existing installation, or nil # @return [string] def self.existing_installation - self.find_existing_arduino_dir(["/Applications/Arduino.app/Contents"]) + self.find_existing_arduino_dir(["/Applications/Arduino.app"]) end # The executable Arduino file in an existing installation, or nil # @return [string] def self.existing_executable - self.find_existing_arduino_exe(["/Applications/Arduino.app/Contents"]) + self.find_existing_arduino_exe(["/Applications/Arduino.app"]) end # The executable Arduino file in a forced installation, or nil # @return [string] def self.force_installed_executable - self.find_existing_arduino_exe([File.join(self.force_install_location, "Contents")]) + self.find_existing_arduino_exe([self.force_install_location]) end end diff --git a/lib/arduino_ci/arduino_downloader_posix.rb b/lib/arduino_ci/arduino_downloader_posix.rb deleted file mode 100644 index 9b9eeece..00000000 --- a/lib/arduino_ci/arduino_downloader_posix.rb +++ /dev/null @@ -1,38 +0,0 @@ -require "arduino_ci/arduino_downloader" - -module ArduinoCI - - # Manage the POSIX download & install of Arduino - class ArduinoDownloaderPosix < ArduinoDownloader - - # Make any preparations or run any checks prior to making changes - # @return [string] Error message, or nil if success - def prepare - reqs = [downloader, extracter] - reqs.each do |req| - return "#{req} does not appear to be installed!" unless Host.which(req) - end - nil - end - - # The technology that will be used to complete the download - # (for logging purposes) - # @return [string] - def downloader - "wget" - end - - # Download the package_url to package_file - # @return [bool] whether successful - def download - system(downloader, "--quiet", "--progress=dot:giga", package_url) - end - - # Move the extracted package file from extracted_file to the force_install_location - # @return [bool] whether successful - def install - system("mv", extracted_file, self.class.force_install_location) - end - - end -end diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 417ff49f..31dc0b9f 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -2,8 +2,6 @@ require 'shellwords' # fingers crossed this works on win32 require 'win32/registry' require "arduino_ci/arduino_downloader" -require 'open-uri' -require 'zip' require "fileutils" module ArduinoCI @@ -39,8 +37,6 @@ def download def install # Move only the content of the directory FileUtils.mv extracted_file, self.class.force_install_location - # clean up the no longer required root extracted folder - FileUtils.rm_rf extracted_file end # The local filename of the desired IDE package (zip/tar/etc) @@ -64,8 +60,6 @@ def extract file.extract(file.name) end end - # clean up the no longer required zip - FileUtils.rm_rf package_file end # The local file (dir) name of the extracted IDE package (zip/tar/etc) diff --git a/lib/arduino_ci/arduino_installation.rb b/lib/arduino_ci/arduino_installation.rb index 20229467..4d9800cf 100644 --- a/lib/arduino_ci/arduino_installation.rb +++ b/lib/arduino_ci/arduino_installation.rb @@ -60,7 +60,7 @@ def autolocate_osx "processing.app.Base", ], # failsafe way - [File.join(osx_root, "MacOS", "Arduino")] + [File.join(osx_root, "Contents", "MacOS", "Arduino")] ] # create return and find a command launcher that works diff --git a/spec/arduino_downloader_spec.rb b/spec/arduino_downloader_spec.rb index 185cdd2c..693d5816 100644 --- a/spec/arduino_downloader_spec.rb +++ b/spec/arduino_downloader_spec.rb @@ -17,8 +17,6 @@ it "has correct instance properties" do ad = ArduinoCI::ArduinoDownloader.new(DESIRED_VERSION) expect(ad.prepare).to be nil - expect{ad.downloader}.to raise_error(NotImplementedError) - expect{ad.extracter}.to raise_error(NotImplementedError) expect{ad.package_url}.to raise_error(NotImplementedError) expect{ad.package_file}.to raise_error(NotImplementedError) end @@ -42,7 +40,7 @@ it "has correct instance properties" do ad = ArduinoCI::ArduinoDownloaderLinux.new(DESIRED_VERSION) expect(ad.prepare).to be nil - expect(ad.downloader).to eq("wget") + expect(ad.downloader).to eq("open-uri") expect(ad.extracter).to eq("tar") expect(ad.package_url).to eq("https://downloads.arduino.cc/arduino-rhubarb-linux64.tar.xz") expect(ad.package_file).to eq("arduino-rhubarb-linux64.tar.xz") @@ -61,14 +59,14 @@ # expect(ad.existing_executable).to be nil # expect(ad.force_installed_executable).to be nil - expect(ad.force_install_location).to eq(File.join(ENV['HOME'], 'arduino_ci_ide')) + expect(ad.force_install_location).to eq(File.join(ENV['HOME'], 'Arduino.app')) end it "has correct instance properties" do ad = ArduinoCI::ArduinoDownloaderOSX.new(DESIRED_VERSION) expect(ad.prepare).to be nil - expect(ad.downloader).to eq("wget") - expect(ad.extracter).to eq("unzip") + expect(ad.downloader).to eq("open-uri") + expect(ad.extracter).to eq("Zip") expect(ad.package_url).to eq("https://downloads.arduino.cc/arduino-rhubarb-macosx.zip") expect(ad.package_file).to eq("arduino-rhubarb-macosx.zip") end