From ab604214eb9c7b6d641419b666d79e1c72ae4dbe Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Wed, 25 Apr 2018 10:44:48 -0400 Subject: [PATCH 01/19] Initial and likely very broken windows CI commit --- README.md | 3 +- appveyor.yml | 25 +++++ lib/arduino_ci/arduino_cmd_windows.rb | 34 ++++++ lib/arduino_ci/arduino_downloader_windows.rb | 105 +++++++++++++++++++ lib/arduino_ci/arduino_installation.rb | 15 +-- 5 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 appveyor.yml create mode 100644 lib/arduino_ci/arduino_cmd_windows.rb create mode 100644 lib/arduino_ci/arduino_downloader_windows.rb diff --git a/README.md b/README.md index df7b609d..6b01acef 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci) -[![Build Status](https://travis-ci.org/ianfixes/arduino_ci.svg)](https://travis-ci.org/ianfixes/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`) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..4f13a7af --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,25 @@ +install: + - set PATH=C:\Ruby22\bin;%PATH% + - bundle install + - '%CYG_ROOT%\setup-%CYG_ARCH%.exe -qnNdO -R %CYG_ROOT% -s http://cygwin.mirror.constant.com -l %CYG_ROOT%/var/cache/setup -P autoconf -P automake -P bison -P libgmp-devel -P gcc-core -P gcc-g++ -P mingw-runtime -P mingw-binutils -P mingw-gcc-core -P mingw-gcc-g++ -P mingw-pthreads -P mingw-w32api -P libtool -P make -P gettext-devel -P gettext -P intltool -P libiconv -P pkg-config -P git -P wget -P curl' + +environment: + matrix: + - CYG_ARCH: x86_64 + CYG_ROOT: C:/cygwin64 + +build: off + +before_test: + - ruby -v + - gem -v + - bundle -v + - g++ -v + +test_script: + - bundle exec rubocop --version + - bundle exec rubocop -D . + - bundle exec rspec + - cd SampleProjects\TestSomething + - bundle install + - bundle exec arduino_ci_remote.rb diff --git a/lib/arduino_ci/arduino_cmd_windows.rb b/lib/arduino_ci/arduino_cmd_windows.rb new file mode 100644 index 00000000..52be6f12 --- /dev/null +++ b/lib/arduino_ci/arduino_cmd_windows.rb @@ -0,0 +1,34 @@ +require "arduino_ci/host" +require 'arduino_ci/arduino_cmd' + +module ArduinoCI + + # Implementation of OSX commands + class ArduinoCmdWindows < ArduinoCmd + flag :get_pref, "--get-pref" + flag :set_pref, "--pref" + flag :save_prefs, "--save-prefs" + flag :use_board, "--board" + flag :install_boards, "--install-boards" + flag :install_library, "--install-library" + flag :verify, "--verify" + + # run the arduino command + # @return [bool] whether the command succeeded + def _run_and_output(*args, **kwargs) + Host.run_and_output(*args, **kwargs) + end + + # run the arduino command + # @return [Hash] keys for :success, :out, and :err + def _run_and_capture(*args, **kwargs) + Host.run_and_capture(*args, **kwargs) + end + + def _lib_dir + File.join(ENV['userprofile'], "Documents", "Arduino", "libraries") + end + + end + +end diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb new file mode 100644 index 00000000..995c5d24 --- /dev/null +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -0,0 +1,105 @@ +require 'base64' +require 'shellwords' # fingers crossed this works on win32 +require 'win32' +require "arduino_ci/arduino_downloader" + +module ArduinoCI + + # Manage the POSIX download & install of Arduino + class ArduinoDownloaderWindows < ArduinoDownloader + + def powershell(*args) + encoded_cmd = Base64.strict_encode64(args.shelljoin.encode('utf-16le')) + system("powershell.exe", "-encodedCommand", encoded_cmd) + end + + def cygwin(*args) + system("%CYG_ROOT%/bin/bash", "-lc", args.shelljoin) + end + + # Make any preparations or run any checks prior to making changes + # @return [string] Error message, or nil if success + def prepare + 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 + powershell("(New-Object Net.WebClient).DownloadFile('#{package_url}', '#{package_file}')") + end + + # Move the extracted package file from extracted_file to the force_install_location + # @return [bool] whether successful + def install + powershell("Move-Item", extracted_file, self.class.force_install_location) + end + + # The local filename of the desired IDE package (zip/tar/etc) + # @return [string] + def package_file + "#{extracted_file}-windows.zip" + end + + # The technology that will be used to extract the download + # (for logging purposes) + # @return [string] + def extracter + "Expand-Archive" + end + + # Extract the package_file to extracted_file + # @return [bool] whether successful + def extract + powershell("Expand-Archive", package_file, "-dest", extracted_file) + end + + # The local file (dir) name of the extracted IDE package (zip/tar/etc) + # @return [string] + def extracted_file + "arduino-#{@desired_ide_version}" + end + + # The path to the directory of an existing installation, or nil + # @return [string] + def self.existing_installation + exe = self.existing_executable + return nil if exe.nil? + File.dirname(exe) + end + + # The executable Arduino file in an existing installation, or nil + # @return [string] + def self.existing_executable + arduino_reg = 'Software\SOFTWARE\Classes\Arduino file\shell\open\command' + Win32::Registry::HKEY_LOCAL_MACHINE.open(arduino_reg) do |reg| + reg.each_key do |key| + k = reg.open(key) + puts key + puts k + return k + # puts k["DisplayName"] rescue "?" + # puts k["DisplayVersion"] rescue "?" + # puts + end + end + nil + end + + # The executable Arduino file in a forced installation, or nil + # @return [string] + def self.force_installed_executable + exe = File.join(self.force_install_location, "arduino.exe") + return nil if exe.nil? + exe + end + + end +end diff --git a/lib/arduino_ci/arduino_installation.rb b/lib/arduino_ci/arduino_installation.rb index ad1cef47..5ffaf1b8 100644 --- a/lib/arduino_ci/arduino_installation.rb +++ b/lib/arduino_ci/arduino_installation.rb @@ -1,9 +1,12 @@ require "arduino_ci/host" require "arduino_ci/arduino_cmd_osx" require "arduino_ci/arduino_cmd_linux" +require "arduino_ci/arduino_cmd_windows" require "arduino_ci/arduino_cmd_linux_builder" -require "arduino_ci/arduino_downloader_linux" require "arduino_ci/arduino_downloader_osx" +require "arduino_ci/arduino_downloader_linux" + +require "arduino_ci/arduino_downloader_windows" if ArduinoCI::Host.os == :windows DESIRED_ARDUINO_IDE_VERSION = "1.8.5".freeze @@ -28,11 +31,11 @@ def autolocate return nil if loc.nil? ret = ArduinoCmdLinux.new ret.base_cmd = [loc] - # when :windows then - # ArduinoDownloaderWindows.autolocation - # return nil if loc.nil? - # ret = ArduinoCmdWindows.new - # ret.base_cmd = [loc] + when :windows then + ArduinoDownloaderWindows.autolocation + return nil if loc.nil? + ret = ArduinoCmdWindows.new + ret.base_cmd = [loc] end ret end From 4b5bd8ac52980c7de3727b33b3b54124c56f9e2a Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 26 Apr 2018 07:14:01 -0400 Subject: [PATCH 02/19] attempt to fix cygwin binary path --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4f13a7af..3a39e007 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ install: - - set PATH=C:\Ruby22\bin;%PATH% + - set PATH=C:\Ruby22\bin;C:\cygwin\bin;C:\cygwin64\bin;%PATH% - bundle install - '%CYG_ROOT%\setup-%CYG_ARCH%.exe -qnNdO -R %CYG_ROOT% -s http://cygwin.mirror.constant.com -l %CYG_ROOT%/var/cache/setup -P autoconf -P automake -P bison -P libgmp-devel -P gcc-core -P gcc-g++ -P mingw-runtime -P mingw-binutils -P mingw-gcc-core -P mingw-gcc-g++ -P mingw-pthreads -P mingw-w32api -P libtool -P make -P gettext-devel -P gettext -P intltool -P libiconv -P pkg-config -P git -P wget -P curl' From 15070c486ed06071bdbe5608ec0a63f9b2847e3a Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 26 Apr 2018 07:21:50 -0400 Subject: [PATCH 03/19] Specify platform EOL marker for Rubocop --- .rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 04aadfbc..069524cb 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -21,6 +21,9 @@ Layout/EmptyLinesAroundModuleBody: Layout/ExtraSpacing: Enabled: false +Layout/EndOfLine: + EnforcedStyle: lf + Metrics/LineLength: Description: Limit lines to 80 characters. StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits From e322e977246e5ae3d5d4476295e7d3e2cfbf2763 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 26 Apr 2018 07:26:46 -0400 Subject: [PATCH 04/19] try to fix require win32/registry --- lib/arduino_ci/arduino_downloader_windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 995c5d24..87e0fc85 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -1,6 +1,6 @@ require 'base64' require 'shellwords' # fingers crossed this works on win32 -require 'win32' +require 'win32/registry' require "arduino_ci/arduino_downloader" module ArduinoCI From a7187b0964da252bfc7b2f7da9b6665decc638bb Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Thu, 26 Apr 2018 07:28:54 -0400 Subject: [PATCH 05/19] fixup windows downloader --- lib/arduino_ci/arduino_installation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arduino_ci/arduino_installation.rb b/lib/arduino_ci/arduino_installation.rb index 5ffaf1b8..457c0094 100644 --- a/lib/arduino_ci/arduino_installation.rb +++ b/lib/arduino_ci/arduino_installation.rb @@ -32,7 +32,7 @@ def autolocate ret = ArduinoCmdLinux.new ret.base_cmd = [loc] when :windows then - ArduinoDownloaderWindows.autolocation + loc = ArduinoDownloaderWindows.autolocated_executable return nil if loc.nil? ret = ArduinoCmdWindows.new ret.base_cmd = [loc] From 6656efd291d67f175f3ff53a782a624011d5d5f4 Mon Sep 17 00:00:00 2001 From: Tom Duff Date: Sat, 5 May 2018 15:57:56 +0100 Subject: [PATCH 06/19] Arduino exe now found on windows (#43) Windows compilation support * Updated arduino self.existing_executable function to find arduino_debug.exe * Added compilers to .arduino-ci.yaml so that build runs * Added error handling around the reg lookup so that it does not just bomb out and runs to the force install function. * Corrected the incorrect reg key used to allow testing of force download * Switched to http for downloads to avoid ssl error --- SampleProjects/DoSomething/.arduino-ci.yaml | 2 + SampleProjects/DoSomething/Gemfile.lock | 7 ++-- lib/arduino_ci/arduino_downloader_windows.rb | 41 +++++++++++++------- lib/arduino_ci/arduino_installation.rb | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/SampleProjects/DoSomething/.arduino-ci.yaml b/SampleProjects/DoSomething/.arduino-ci.yaml index f75da570..59c23ed6 100644 --- a/SampleProjects/DoSomething/.arduino-ci.yaml +++ b/SampleProjects/DoSomething/.arduino-ci.yaml @@ -11,3 +11,5 @@ unittest: - uno - due - leonardo + compilers: + - g++ diff --git a/SampleProjects/DoSomething/Gemfile.lock b/SampleProjects/DoSomething/Gemfile.lock index 01228d8d..6707a33d 100644 --- a/SampleProjects/DoSomething/Gemfile.lock +++ b/SampleProjects/DoSomething/Gemfile.lock @@ -1,7 +1,7 @@ PATH - remote: /Users/ikatz/Development/non-wayfair/arduino_ci + remote: ../.. specs: - arduino_ci (0.1.7) + arduino_ci (0.1.9) os (~> 1.0) GEM @@ -11,9 +11,10 @@ GEM PLATFORMS ruby + x64-mingw32 DEPENDENCIES arduino_ci! BUNDLED WITH - 1.16.0 + 1.16.1 diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 87e0fc85..952bd2bc 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -2,6 +2,7 @@ require 'shellwords' # fingers crossed this works on win32 require 'win32/registry' require "arduino_ci/arduino_downloader" +require 'open-uri' module ArduinoCI @@ -27,19 +28,28 @@ def prepare # (for logging purposes) # @return [string] def downloader - "wget" + "open-uri" end # Download the package_url to package_file # @return [bool] whether successful def download - powershell("(New-Object Net.WebClient).DownloadFile('#{package_url}', '#{package_file}')") + puts 'Downloading from ' + package_url + # Turned off ssl verification + open(URI.parse(package_url), ssl_verify_mode: 0) do |url| + File.open(package_file, 'wb') { |file| file.write(url.read) } + end end # Move the extracted package file from extracted_file to the force_install_location # @return [bool] whether successful def install - powershell("Move-Item", extracted_file, self.class.force_install_location) + puts 'Installing to ' + self.class.force_install_location + # Move only the content of the directory + powershell("Move-Item", extracted_file + "\*", self.class.force_install_location) + # clean up the no longer required root extracted folder + puts 'Removing ' + package_file + powershell("Remove-Item", extracted_file) end # The local filename of the desired IDE package (zip/tar/etc) @@ -58,7 +68,11 @@ def extracter # Extract the package_file to extracted_file # @return [bool] whether successful def extract - powershell("Expand-Archive", package_file, "-dest", extracted_file) + puts 'Extracting ' + package_file + " to " + extracted_file + powershell("Expand-Archive", "-Path", package_file, "-DestinationPath", extracted_file) + # clean up the no longer required zip + puts 'Removing ' + package_file + powershell("Remove-Item", package_file) end # The local file (dir) name of the extracted IDE package (zip/tar/etc) @@ -78,25 +92,22 @@ def self.existing_installation # The executable Arduino file in an existing installation, or nil # @return [string] def self.existing_executable - arduino_reg = 'Software\SOFTWARE\Classes\Arduino file\shell\open\command' + arduino_reg = 'SOFTWARE\WOW6432Node\Arduino' Win32::Registry::HKEY_LOCAL_MACHINE.open(arduino_reg) do |reg| - reg.each_key do |key| - k = reg.open(key) - puts key - puts k - return k - # puts k["DisplayName"] rescue "?" - # puts k["DisplayVersion"] rescue "?" - # puts - end + path = reg.read_s('Install_Dir') + exe = File.join(path, "arduino_debug.exe") + puts "Using existing exe located at " + exe + return exe if File.exist? exe end + rescue nil end # The executable Arduino file in a forced installation, or nil # @return [string] def self.force_installed_executable - exe = File.join(self.force_install_location, "arduino.exe") + exe = File.join(self.force_install_location, "arduino_debug.exe") + puts "Using force installed exe located at " + exe return nil if exe.nil? exe end diff --git a/lib/arduino_ci/arduino_installation.rb b/lib/arduino_ci/arduino_installation.rb index 457c0094..20229467 100644 --- a/lib/arduino_ci/arduino_installation.rb +++ b/lib/arduino_ci/arduino_installation.rb @@ -96,7 +96,7 @@ def autolocate! def force_install worker_class = case Host.os when :osx then ArduinoDownloaderOSX - # when :windows then force_install_windows + when :windows then ArduinoDownloaderWindows when :linux then ArduinoDownloaderLinux end worker = worker_class.new(DESIRED_ARDUINO_IDE_VERSION) From 72cff59fad4ab1c84008834f3a72c7324573c629 Mon Sep 17 00:00:00 2001 From: Tom Duff Date: Sat, 5 May 2018 16:25:21 +0100 Subject: [PATCH 07/19] Attempt to supress powershell output It appears that the standard way to do it is pipe to null. The logs are spammed when run locally so I am not sure if this has the desired effect --- lib/arduino_ci/arduino_downloader_windows.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 952bd2bc..37506719 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -10,7 +10,7 @@ module ArduinoCI class ArduinoDownloaderWindows < ArduinoDownloader def powershell(*args) - encoded_cmd = Base64.strict_encode64(args.shelljoin.encode('utf-16le')) + encoded_cmd = Base64.strict_encode64((args.shelljoin + " | Out-Null").encode('utf-16le') ) system("powershell.exe", "-encodedCommand", encoded_cmd) end From 808d3732e9f585f0cc049198241f6824634c05eb Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 5 May 2018 16:22:55 -0400 Subject: [PATCH 08/19] Mark windows hosts as having existing display (no xvfb display mgr) --- lib/arduino_ci/display_manager.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/arduino_ci/display_manager.rb b/lib/arduino_ci/display_manager.rb index 05f8189b..e215a54d 100644 --- a/lib/arduino_ci/display_manager.rb +++ b/lib/arduino_ci/display_manager.rb @@ -34,6 +34,7 @@ def initialize # @return [bool] whether there is already a GUI that can accept windows def existing_display? return true if RUBY_PLATFORM.include? "darwin" + return true if Host.os == :windows return false if ENV["DISPLAY"].nil? return true if ENV["DISPLAY"].include? ":" false From 960c23ff55ff59b0f30c77dd9206cc518b5c845a Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 5 May 2018 16:25:19 -0400 Subject: [PATCH 09/19] clean up comments and debug statements --- lib/arduino_ci/arduino_downloader_windows.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 37506719..455cdf69 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -10,7 +10,7 @@ module ArduinoCI class ArduinoDownloaderWindows < ArduinoDownloader def powershell(*args) - encoded_cmd = Base64.strict_encode64((args.shelljoin + " | Out-Null").encode('utf-16le') ) + encoded_cmd = Base64.strict_encode64((args.shelljoin + " | Out-Null").encode('utf-16le')) system("powershell.exe", "-encodedCommand", encoded_cmd) end @@ -34,8 +34,8 @@ def downloader # Download the package_url to package_file # @return [bool] whether successful def download - puts 'Downloading from ' + package_url # Turned off ssl verification + # This should be acceptable because it won't happen on a user's machine, just CI open(URI.parse(package_url), ssl_verify_mode: 0) do |url| File.open(package_file, 'wb') { |file| file.write(url.read) } end @@ -44,11 +44,9 @@ def download # Move the extracted package file from extracted_file to the force_install_location # @return [bool] whether successful def install - puts 'Installing to ' + self.class.force_install_location # Move only the content of the directory powershell("Move-Item", extracted_file + "\*", self.class.force_install_location) # clean up the no longer required root extracted folder - puts 'Removing ' + package_file powershell("Remove-Item", extracted_file) end @@ -68,10 +66,8 @@ def extracter # Extract the package_file to extracted_file # @return [bool] whether successful def extract - puts 'Extracting ' + package_file + " to " + extracted_file powershell("Expand-Archive", "-Path", package_file, "-DestinationPath", extracted_file) # clean up the no longer required zip - puts 'Removing ' + package_file powershell("Remove-Item", package_file) end @@ -96,7 +92,6 @@ def self.existing_executable Win32::Registry::HKEY_LOCAL_MACHINE.open(arduino_reg) do |reg| path = reg.read_s('Install_Dir') exe = File.join(path, "arduino_debug.exe") - puts "Using existing exe located at " + exe return exe if File.exist? exe end rescue @@ -107,7 +102,6 @@ def self.existing_executable # @return [string] def self.force_installed_executable exe = File.join(self.force_install_location, "arduino_debug.exe") - puts "Using force installed exe located at " + exe return nil if exe.nil? exe end From 0e548ba56af7aea62e470ef5001ffe9b364f00d9 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sat, 5 May 2018 21:20:29 -0400 Subject: [PATCH 10/19] Use -NoProfile in powershell to (hopefully) suppress output --- appveyor.yml | 2 ++ lib/arduino_ci/arduino_downloader_windows.rb | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 3a39e007..b810ba1e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,6 +17,8 @@ before_test: - g++ -v test_script: + # https://help.appveyor.com/discussions/problems/5170-progresspreference-not-works-always-shown-preparing-modules-for-first-use-in-stderr + - ps: $ProgressPreference = "SilentlyContinue" - bundle exec rubocop --version - bundle exec rubocop -D . - bundle exec rspec diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 455cdf69..43145fb2 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -10,8 +10,8 @@ module ArduinoCI class ArduinoDownloaderWindows < ArduinoDownloader def powershell(*args) - encoded_cmd = Base64.strict_encode64((args.shelljoin + " | Out-Null").encode('utf-16le')) - system("powershell.exe", "-encodedCommand", encoded_cmd) + encoded_cmd = Base64.strict_encode64(args.shelljoin.encode('utf-16le')) + system("powershell.exe", "-NoProfile", "-encodedCommand", encoded_cmd) end def cygwin(*args) From 6beaa12a03ebe4a5e1936e11326e213a2cacda99 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 06:18:08 -0400 Subject: [PATCH 11/19] Ignore Gemfile.lock in project directories, fixes #41 --- .gitignore | 2 +- SampleProjects/DoSomething/Gemfile.lock | 20 -------------------- SampleProjects/TestSomething/Gemfile.lock | 19 ------------------- 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 SampleProjects/DoSomething/Gemfile.lock delete mode 100644 SampleProjects/TestSomething/Gemfile.lock diff --git a/.gitignore b/.gitignore index 6e35644c..2b5aa6a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /.bundle/ /.yardoc -/Gemfile.lock +Gemfile.lock /_yardoc/ /coverage/ /doc/ diff --git a/SampleProjects/DoSomething/Gemfile.lock b/SampleProjects/DoSomething/Gemfile.lock deleted file mode 100644 index 6707a33d..00000000 --- a/SampleProjects/DoSomething/Gemfile.lock +++ /dev/null @@ -1,20 +0,0 @@ -PATH - remote: ../.. - specs: - arduino_ci (0.1.9) - os (~> 1.0) - -GEM - remote: https://rubygems.org/ - specs: - os (1.0.0) - -PLATFORMS - ruby - x64-mingw32 - -DEPENDENCIES - arduino_ci! - -BUNDLED WITH - 1.16.1 diff --git a/SampleProjects/TestSomething/Gemfile.lock b/SampleProjects/TestSomething/Gemfile.lock deleted file mode 100644 index e1c89622..00000000 --- a/SampleProjects/TestSomething/Gemfile.lock +++ /dev/null @@ -1,19 +0,0 @@ -PATH - remote: /Users/ikatz/Development/non-wayfair/arduino_ci - specs: - arduino_ci (0.1.8) - os (~> 1.0) - -GEM - remote: https://rubygems.org/ - specs: - os (1.0.0) - -PLATFORMS - ruby - -DEPENDENCIES - arduino_ci! - -BUNDLED WITH - 1.16.0 From 9cdb651f200dd4babe1c86c4cd6821495bfe5fe9 Mon Sep 17 00:00:00 2001 From: Tom Duff Date: Sun, 6 May 2018 09:33:12 +0100 Subject: [PATCH 12/19] Removed use of powershell Switched to ruby methods for file system manipulation Introduced dependency on rubyzip for archive extraction --- arduino_ci.gemspec | 1 + lib/arduino_ci/arduino_downloader_windows.rb | 23 +++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/arduino_ci.gemspec b/arduino_ci.gemspec index 3ba43660..f4a77ace 100644 --- a/arduino_ci.gemspec +++ b/arduino_ci.gemspec @@ -26,6 +26,7 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] spec.add_dependency "os", "~> 1.0" + spec.add_dependency "rubyzip", "~> 1.2.1" spec.add_development_dependency "bundler", "~> 1.15" spec.add_development_dependency "rspec", "~> 3.0" diff --git a/lib/arduino_ci/arduino_downloader_windows.rb b/lib/arduino_ci/arduino_downloader_windows.rb index 43145fb2..417ff49f 100644 --- a/lib/arduino_ci/arduino_downloader_windows.rb +++ b/lib/arduino_ci/arduino_downloader_windows.rb @@ -3,21 +3,14 @@ require 'win32/registry' require "arduino_ci/arduino_downloader" require 'open-uri' +require 'zip' +require "fileutils" module ArduinoCI # Manage the POSIX download & install of Arduino class ArduinoDownloaderWindows < ArduinoDownloader - def powershell(*args) - encoded_cmd = Base64.strict_encode64(args.shelljoin.encode('utf-16le')) - system("powershell.exe", "-NoProfile", "-encodedCommand", encoded_cmd) - end - - def cygwin(*args) - system("%CYG_ROOT%/bin/bash", "-lc", args.shelljoin) - end - # Make any preparations or run any checks prior to making changes # @return [string] Error message, or nil if success def prepare @@ -45,9 +38,9 @@ def download # @return [bool] whether successful def install # Move only the content of the directory - powershell("Move-Item", extracted_file + "\*", self.class.force_install_location) + FileUtils.mv extracted_file, self.class.force_install_location # clean up the no longer required root extracted folder - powershell("Remove-Item", extracted_file) + FileUtils.rm_rf extracted_file end # The local filename of the desired IDE package (zip/tar/etc) @@ -66,9 +59,13 @@ def extracter # Extract the package_file to extracted_file # @return [bool] whether successful def extract - powershell("Expand-Archive", "-Path", package_file, "-DestinationPath", extracted_file) + Zip::File.open(package_file) do |zip| + zip.each do |file| + file.extract(file.name) + end + end # clean up the no longer required zip - powershell("Remove-Item", package_file) + FileUtils.rm_rf package_file end # The local file (dir) name of the extracted IDE package (zip/tar/etc) From e6ab58c63403b3a6ffec69e7769845f1319335fc Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 06:37:06 -0400 Subject: [PATCH 13/19] Put decent .gitignore into sample projects too --- SampleProjects/DoSomething/.gitignore | 17 +++++++++++++++++ SampleProjects/TestSomething/.gitignore | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 SampleProjects/DoSomething/.gitignore create mode 100644 SampleProjects/TestSomething/.gitignore diff --git a/SampleProjects/DoSomething/.gitignore b/SampleProjects/DoSomething/.gitignore new file mode 100644 index 00000000..2b5aa6a7 --- /dev/null +++ b/SampleProjects/DoSomething/.gitignore @@ -0,0 +1,17 @@ +/.bundle/ +/.yardoc +Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +vendor +*.gem + +# rspec failure tracking +.rspec_status + +# C++ stuff +*.bin +*.bin.dSYM diff --git a/SampleProjects/TestSomething/.gitignore b/SampleProjects/TestSomething/.gitignore new file mode 100644 index 00000000..2b5aa6a7 --- /dev/null +++ b/SampleProjects/TestSomething/.gitignore @@ -0,0 +1,17 @@ +/.bundle/ +/.yardoc +Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +vendor +*.gem + +# rspec failure tracking +.rspec_status + +# C++ stuff +*.bin +*.bin.dSYM From a19d127f11b132354adad1a90a2d06f1de737d13 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 07:01:37 -0400 Subject: [PATCH 14/19] Add long long support (hopefully) --- cpp/arduino/WString.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cpp/arduino/WString.h b/cpp/arduino/WString.h index 39474564..1901582c 100644 --- a/cpp/arduino/WString.h +++ b/cpp/arduino/WString.h @@ -73,6 +73,8 @@ class String: public string explicit String(unsigned int val , unsigned char base=10): string(mytoa(val, base)) {} explicit String(long val, unsigned char base=10): string(mytoas(val, base)) {} explicit String(unsigned long val, unsigned char base=10): string(mytoa(val, base)) {} + explicit String(long long val, unsigned char base=10): string(mytoas(val, base)) {} + explicit String(unsigned long long val, unsigned char base=10): string(mytoa(val, base)) {} explicit String(float val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} explicit String(double val, unsigned char decimalPlaces=2): string(dtoas(val, decimalPlaces)) {} @@ -95,6 +97,8 @@ class String: public string unsigned char concat(unsigned int num) { append(String(num)); return 1; } unsigned char concat(long num) { append(String(num)); return 1; } unsigned char concat(unsigned long num) { append(String(num)); return 1; } + unsigned char concat(long long num) { append(String(num)); return 1; } + unsigned char concat(unsigned long long num) { append(String(num)); return 1; } unsigned char concat(float num) { append(String(num)); return 1; } unsigned char concat(double num) { append(String(num)); return 1; } @@ -107,6 +111,8 @@ class String: public string String & operator += (unsigned int num) { concat(num); return *this; } String & operator += (long num) { concat(num); return *this; } String & operator += (unsigned long num) { concat(num); return *this; } + String & operator += (long long num) { concat(num); return *this; } + String & operator += (unsigned long long num) { concat(num); return *this; } String & operator += (float num) { concat(num); return *this; } String & operator += (double num) { concat(num); return *this; } From 84a57bf0c4809d3fa02d9a08a02902fb53fc266c Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 07:11:05 -0400 Subject: [PATCH 15/19] Fall back on std::stoll for std::out_of_range errors --- cpp/arduino/WString.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpp/arduino/WString.h b/cpp/arduino/WString.h index 1901582c..498de157 100644 --- a/cpp/arduino/WString.h +++ b/cpp/arduino/WString.h @@ -175,9 +175,15 @@ class String: public string assign(substr(b, e - b + 1)); } - long toInt(void) const { return std::stol(*this); } float toFloat(void) const { return std::stof(*this); } double toDouble(void) const { return std::stod(*this); } + long toInt(void) const { + try { + return std::stol(*this); + } catch (std::out_of_range) { + return std::stoll(*this); + } + } }; From 722934464fdf50d7ecfbb9b11f8857d082454f39 Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 07:16:59 -0400 Subject: [PATCH 16/19] force random function to wrap at 32 bits --- cpp/arduino/Godmode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/arduino/Godmode.cpp b/cpp/arduino/Godmode.cpp index 2c0c6697..d9e46b52 100644 --- a/cpp/arduino/Godmode.cpp +++ b/cpp/arduino/Godmode.cpp @@ -38,6 +38,7 @@ long random(long vmax) { GodmodeState* godmode = GODMODE(); godmode->seed += 4294967291; // it's a prime that fits in 32 bits + godmode->seed = godmode->seed % 4294967296; // explicitly wrap in case we're on a 64-bit impl return godmode->seed % vmax; } From fffb623926bd2fd7034a079ed0a4551e706b80fc Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 07:31:45 -0400 Subject: [PATCH 17/19] update Random() tests for 32-bit arch --- SampleProjects/TestSomething/test/godmode.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/SampleProjects/TestSomething/test/godmode.cpp b/SampleProjects/TestSomething/test/godmode.cpp index 991b829d..9364a07f 100644 --- a/SampleProjects/TestSomething/test/godmode.cpp +++ b/SampleProjects/TestSomething/test/godmode.cpp @@ -17,14 +17,21 @@ unittest(millis_micros_and_delay) unittest(random) { + GodmodeState* state = GODMODE(); + state->reset(); randomSeed(1); + assertEqual(state->seed, 1); + unsigned long x; x = random(4294967293); assertEqual(4294967292, x); + assertEqual(state->seed, 4294967292); x = random(50, 100); - assertEqual(83, x); + assertEqual(87, x); + assertEqual(state->seed, 4294967287); x = random(100); - assertEqual(74, x); + assertEqual(82, x); + assertEqual(state->seed, 4294967282); } void myInterruptHandler() { From e71164b092d680567aba7e1ba0556bc26e05137a Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 07:37:10 -0400 Subject: [PATCH 18/19] update CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16895a8c..1bc3ce9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,17 +8,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Arduino `force_install` on Linux now attempts downloading 3 times and provides more information on failure - Explicit check for `wget` +- Windows / Appveyor support, enabled largely by contributions from @tomduff +- `long long` support in `String` +- Representative `.gitignore` files in sample projects ### Changed - Author - Splash-screen-skip hack on OSX now falls back on "official" launch method if the hack doesn't work - Refactored download/install code in prepration for windows CI +- Explicitly use 32-bit math for mocked Random() ### Deprecated ### Removed ### Fixed +- `Gemfile.lock` files are properly ignored +- Windows hosts won't try to open a display manager ### Security From 0a8058398d2ac32ddcbd2d40672f743f19a1dbaf Mon Sep 17 00:00:00 2001 From: Ian Katz Date: Sun, 6 May 2018 08:16:11 -0400 Subject: [PATCH 19/19] cross-platform symlinking --- CHANGELOG.md | 1 + lib/arduino_ci/arduino_cmd.rb | 2 +- lib/arduino_ci/host.rb | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bc3ce9b..bf305622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Windows / Appveyor support, enabled largely by contributions from @tomduff - `long long` support in `String` - Representative `.gitignore` files in sample projects +- Cross-platform symlinking ### Changed - Author diff --git a/lib/arduino_ci/arduino_cmd.rb b/lib/arduino_ci/arduino_cmd.rb index d1e16a3a..b3b671df 100644 --- a/lib/arduino_ci/arduino_cmd.rb +++ b/lib/arduino_ci/arduino_cmd.rb @@ -274,7 +274,7 @@ def install_local_library(path) end # install the library - FileUtils.ln_s(realpath, destination_path) + Host.symlink(realpath, destination_path) destination_path end diff --git a/lib/arduino_ci/host.rb b/lib/arduino_ci/host.rb index 7a2983e6..ad7f1293 100644 --- a/lib/arduino_ci/host.rb +++ b/lib/arduino_ci/host.rb @@ -37,5 +37,16 @@ def self.os return :windows if OS.windows? end + # if on windows, call mklink, else self.symlink + # https://stackoverflow.com/a/22716582/2063546 + def self.symlink(old_path, new_path) + return FileUtils.ln_s(old_path, new_path) unless RUBY_PLATFORM =~ /mswin32|cygwin|mingw|bccwin/ + + # windows mklink syntax is reverse of unix ln -s + # windows mklink is built into cmd.exe + # vulnerable to command injection, but okay because this is a hack to make a cli tool work. + _stdin, _stdout, _stderr, wait_thr = Open3.popen3('cmd.exe', "/c mklink #{new_path} #{old_path}") + wait_thr.value.exitstatus + end end end