Class: ArduinoCI::ArduinoDownloader

Inherits:
Object
  • Object
show all
Defined in:
lib/arduino_ci/arduino_downloader.rb

Overview

Manage the OS-specific download & install of Arduino

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(desired_ide_version, output = $stdout) ⇒ ArduinoDownloader

Returns a new instance of ArduinoDownloader.

Parameters:

  • desired_ide_version (string)

    Version string e.g. 1.8.7

  • output (IO) (defaults to: $stdout)

    $stdout, $stderr, File.new(/dev/null, ‘w’), etc. where console output will be sent

 15 16 17 18
# File 'lib/arduino_ci/arduino_downloader.rb', line 15 def initialize(desired_ide_version, output = $stdout) @desired_ide_version = desired_ide_version @output = output end

Class Method Details

.autolocated_executablestring

The autolocated executable of the installation

Returns:

  • (string)

    or nil

 34 35 36 37 38 39 40
# File 'lib/arduino_ci/arduino_downloader.rb', line 34 def self.autolocated_executable # Arbitrarily, I'm going to pick the force installed location first  # if it exists. I'm not sure why we would have both, but if we did  # a force install then let's make sure we actually use it.  locations = [self.force_installed_executable, self.existing_executable] locations.find { |loc| !loc.nil? && File.exist?(loc) } end

.autolocated_installationstring

The autolocated directory of the installation

Returns:

  • (string)

    or nil

 45 46 47 48 49 50 51
# File 'lib/arduino_ci/arduino_downloader.rb', line 45 def self.autolocated_installation # Arbitrarily, I'm going to pick the force installed location first  # if it exists. I'm not sure why we would have both, but if we did  # a force install then let's make sure we actually use it.  locations = [self.force_install_location, self.existing_installation] locations.find { |loc| !loc.nil? && File.exist?(loc) } end

.existing_executablestring

The executable Arduino file in an existing installation, or nil

Returns:

  • (string)
 61 62 63
# File 'lib/arduino_ci/arduino_downloader.rb', line 61 def self.existing_executable self.must_implement(__method__) end

.existing_installationstring

The path to the directory of an existing installation, or nil

Returns:

  • (string)
 55 56 57
# File 'lib/arduino_ci/arduino_downloader.rb', line 55 def self.existing_installation self.must_implement(__method__) end

.force_install_locationString

Returns The location where a forced install will go.

Returns:

  • (String)

    The location where a forced install will go

 104 105 106
# File 'lib/arduino_ci/arduino_downloader.rb', line 104 def self.force_install_location File.join(ENV['HOME'], 'arduino_ci_ide') end

.force_installed_executablestring

The executable Arduino file in a forced installation, or nil

Returns:

  • (string)
 67 68 69
# File 'lib/arduino_ci/arduino_downloader.rb', line 67 def self.force_installed_executable self.must_implement(__method__) end

.must_implement(method) ⇒ Object

Provide guidelines to the implementer of this class

Raises:

  • (NotImplementedError)
 21 22 23
# File 'lib/arduino_ci/arduino_downloader.rb', line 21 def self.must_implement(method) raise NotImplementedError, "#{self.class.name} failed to implement ArduinoDownloader.#{method}" end

Instance Method Details

#downloadbool

Download the package_url to package_file

Returns:

  • (bool)

    whether successful

 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
# File 'lib/arduino_ci/arduino_downloader.rb', line 110 def download # 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 @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, OpenURI::HTTPError, URI::InvalidURIError => e @output.puts "\nArduino force-install failed downloading #{package_url}: #{e}" end

#downloaderstring

The technology that will be used to complete the download (for logging purposes)

Returns:

  • (string)
 74 75 76
# File 'lib/arduino_ci/arduino_downloader.rb', line 74 def downloader "open-uri" end

#executebool

Forcibly install Arduino on linux from the web

Returns:

  • (bool)

    Whether the command succeeded

 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
# File 'lib/arduino_ci/arduino_downloader.rb', line 157 def execute error_preparing = prepare unless error_preparing.nil? @output.puts "Arduino force-install failed preparation: #{error_preparing}" return false end attempts = 0 loop do if File.exist? package_file @output.puts "Arduino package seems to have been downloaded already" if attempts.zero? break elsif attempts >= DOWNLOAD_ATTEMPTS break @output.puts "After #{DOWNLOAD_ATTEMPTS} attempts, failed to download #{package_url}" else @output.print "Attempting to download Arduino package with #{downloader}" download @output.puts end attempts += 1 end if File.exist? extracted_file @output.puts "Arduino package seems to have been extracted already" elsif File.exist? package_file @output.print "Extracting archive with #{extracter}" extract @output.puts end if File.exist? self.class.force_install_location @output.puts "Arduino package seems to have been installed already" elsif File.exist? extracted_file install else @output.puts "Could not find extracted archive (tried #{extracted_file})" end File.exist? self.class.force_install_location end

#extractbool

Extract the package_file to extracted_file

Returns:

  • (bool)

    whether successful

 135 136 137 138 139 140 141 142 143 144 145 146
# File 'lib/arduino_ci/arduino_downloader.rb', line 135 def extract Zip::File.open(package_file) do |zip| batch_size = [1, (zip.size / 100).to_i].max dots = 0 zip.each do |file| @output.print "." if (dots % batch_size).zero? file.restore_permissions = true file.extract { accept_all } dots += 1 end end end

#extracted_filestring

The local filename of the extracted IDE package (zip/tar/etc)

Returns:

  • (string)
 99 100 101
# File 'lib/arduino_ci/arduino_downloader.rb', line 99 def extracted_file self.class.must_implement(__method__) end

#extracterstring

The technology that will be used to extract the download (for logging purposes)

Returns:

  • (string)
 81 82 83
# File 'lib/arduino_ci/arduino_downloader.rb', line 81 def extracter "Zip" end

#installbool

Move the extracted package file from extracted_file to the force_install_location

Returns:

  • (bool)

    whether successful

 150 151 152 153
# File 'lib/arduino_ci/arduino_downloader.rb', line 150 def install # Move only the content of the directory  FileUtils.mv extracted_file, self.class.force_install_location end

#package_filestring

The local file (dir) name of the desired IDE package (zip/tar/etc)

Returns:

  • (string)
 93 94 95
# File 'lib/arduino_ci/arduino_downloader.rb', line 93 def package_file self.class.must_implement(__method__) end

#package_urlstring

The URL of the desired IDE package (zip/tar/etc) for this platform

Returns:

  • (string)
 87 88 89
# File 'lib/arduino_ci/arduino_downloader.rb', line 87 def package_url "https://downloads.arduino.cc/#{package_file}" end

#preparestring

Make any preparations or run any checks prior to making changes

Returns:

  • (string)

    Error message, or nil if success

 27 28 29
# File 'lib/arduino_ci/arduino_downloader.rb', line 27 def prepare nil end