module U3d::Utils

Several different utility methods rubocop:disable ModuleLength

Constants

CSIDL_LOCAL_APPDATA

Regex to capture each part of a version string (0.0.0x0)

UNITY_VERSION_REGEX

Public Class Methods

download_file(path, url, size: nil) click to toggle source

size a hint of the expected size

# File lib/u3d/utils.rb, line 90
def download_file(path, url, size: nil)
  File.open(path, 'wb') do |f|
    uri = URI(url)
    current = 0
    last_print_update = 0
    print_progress = UI.interactive? || U3dCore::Globals.verbose?
    Net::HTTP.start(uri.host, uri.port, http_opts(use_ssl: uri.scheme == 'https')) do |http|
      request = Net::HTTP::Get.new uri
      http.request request do |response|
        begin
          # override with actual results, this should help with
          # innacurrate declared sizes, especially on Windows platform
          size = Integer(response['Content-Length'])
        rescue ArgumentError
          UI.verbose 'Unable to get length of file in download'
        end
        started_at = Time.now.to_i - 1
        response.read_body do |segment|
          f.write(segment)
          current += segment.length
          # wait for Net::HTTP buffer on slow networks
          # FIXME revisits, this slows down download on fast network
          # sleep 0.08 # adjust to reduce CPU
          next unless print_progress
          print_progress_now = Time.now.to_f - last_print_update > 0.5
          # force printing when done downloading
          print_progress_now = true if !print_progress_now && size && current >= size
          next unless print_progress_now
          last_print_update = Time.now.to_f
          Utils.print_progress(current, size, started_at)
          print "\n" unless UI.interactive?
        end
      end
    end
    print "\n" if print_progress
  end
end
ensure_dir(dir) click to toggle source
# File lib/u3d/utils.rb, line 150
def ensure_dir(dir)
  FileUtils.mkpath(dir) unless File.directory?(dir)
end
final_url(url, redirect_limit: 10) click to toggle source
# File lib/u3d/utils.rb, line 37
def final_url(url, redirect_limit: 10)
  follow_redirects(url, redirect_limit: redirect_limit, http_method: :head) do |request, _response|
    request.uri.to_s
  end
end
follow_redirects(url, redirect_limit: 10, http_method: :get, request_headers: {}) { |request, response| ... } click to toggle source
# File lib/u3d/utils.rb, line 54
def follow_redirects(url, redirect_limit: 10, http_method: :get, request_headers: {}, &block)
  raise 'Too many redirections' if redirect_limit.zero?
  response = nil
  request = nil
  uri = URI(url)
  begin
    use_ssl = /^https/.match(url)
    Net::HTTP.start(uri.host, uri.port, http_opts(use_ssl: use_ssl)) do |http|
      request = http_request_class http_method, uri
      request_headers.each do |k, v|
        request[k] = v
      end
      response = http.request request
    end
  rescue OpenSSL::OpenSSLError => ssl_error
    UI.error 'SSL has faced an error, you may want to check our README to fix it'
    raise ssl_error
  end

  case response
  when Net::HTTPSuccess then
    yield(request, response)
  when Net::HTTPRedirection then
    UI.verbose "Redirected to #{response['location']}"
    follow_redirects(response['location'], redirect_limit: redirect_limit - 1, http_method: http_method, request_headers: request_headers, &block)
  else raise "Request failed with status #{response.code}"
  end
end
get_ssl(url, redirect_limit: 10, request_headers: {}) click to toggle source

FIXME: alias deprecated

# File lib/u3d/utils.rb, line 44
def get_ssl(url, redirect_limit: 10, request_headers: {})
  page_content(url, redirect_limit: redirect_limit, request_headers: request_headers)
end
get_url_content_length(url) click to toggle source
# File lib/u3d/utils.rb, line 128
def get_url_content_length(url)
  UI.verbose "get_url_content_length #{url}"
  uri = URI(url)
  size = nil
  Net::HTTP.start(uri.host, uri.port, http_opts) do |http|
    response = http.request_head url
    size = Integer(response['Content-Length'])
  end
  UI.verbose "get_url_content_length #{url}: #{size}"
  size
end
get_write_access(dir) { || ... } click to toggle source
# File lib/u3d/utils.rb, line 154
def get_write_access(dir)
  if U3dCore::Helper.operating_system == :win
    yield
  else
    stat_command = if U3dCore::Helper.operating_system == :linux
                     "stat -c \"%U,%a\" #{dir}"
                   elsif U3dCore::Helper.operating_system == :mac
                     "stat -f \"%Su,%A\" #{dir}"
                   end
    owner, access = U3dCore::CommandExecutor.execute(command: stat_command, admin: false).strip.split(',')
    current_user = U3dCore::CommandExecutor.execute(command: 'whoami', admin: false)
    U3dCore::CommandExecutor.execute(command: "chown #{current_user}: #{dir}", admin: true)
    U3dCore::CommandExecutor.execute(command: "chmod u+w #{dir}", admin: true)
    begin
      yield
    ensure
      U3dCore::CommandExecutor.execute(command: "chown #{owner}: #{dir}", admin: true)
      U3dCore::CommandExecutor.execute(command: "chmod #{access} #{dir}", admin: true)
    end
  end
end
hashfile(file_path, blocksize: 65_536) click to toggle source
# File lib/u3d/utils.rb, line 140
def hashfile(file_path, blocksize: 65_536)
  require 'digest'
  raise ArgumentError, 'Not a file' unless File.file?(file_path)
  md5 = Digest::MD5.new
  File.open(file_path, 'r') do |f|
    md5 << f.read(blocksize) until f.eof?
  end
  md5.hexdigest
end
http_request_class(method, uri) click to toggle source
# File lib/u3d/utils.rb, line 83
def http_request_class(method, uri)
  return Net::HTTP::Get.new uri if method == :get
  return Net::HTTP::Head.new uri if method == :head
  raise "Unknown method #{method}"
end
page_content(url, redirect_limit: 10, request_headers: {}) click to toggle source
# File lib/u3d/utils.rb, line 48
def page_content(url, redirect_limit: 10, request_headers: {})
  follow_redirects(url, redirect_limit: redirect_limit, request_headers: request_headers) do |_request, response|
    response.body
  end
end
parse_unity_version(version) click to toggle source
# File lib/u3d/utils.rb, line 198
def parse_unity_version(version)
  ver = UNITY_VERSION_REGEX.match(version)
  if ver.nil?
    raise ArgumentError, "Version (#{version}) does not match the Unity "\
    'version format 0.0.0x0'
  end
  [ver[1], ver[2], ver[3], ver[4], ver[5]]
end
pretty_filesize(filesize) click to toggle source
# File lib/u3d/utils.rb, line 223
def pretty_filesize(filesize)
  Filesize.from(filesize.round.to_s + ' B').pretty
end
print_progress(current, total, started_at) click to toggle source

if total is nil (unknown, falls back to print_progress_nosize)

print_progress_nosize(current, started_at) click to toggle source
strings(path) click to toggle source

Ruby implementation of binutils strings

# File lib/u3d/utils.rb, line 233
def strings(path)
  min = 4
  Enumerator.new do |y|
    File.open(path, "rb") do |f|
      s = ""
      f.each_char do |c|
        if c =~ /[[:print:]]/ # is there a cleaner way to do this check?
          s += c
          next
        else
          y.yield s if s.length >= min
          s = ""
        end
      end
      y.yield s if s.length >= min
    end
  end
end
windows_local_appdata() click to toggle source
# File lib/u3d/utils.rb, line 207
def windows_local_appdata
  require 'win32api'

  windir = ' ' * 261

  getdir = Win32API.new('shell32', 'SHGetFolderPath', 'LLLLP', 'L')
  result = getdir.call(0, CSIDL_LOCAL_APPDATA, 0, 0, windir)
  raise "Unable to get Local Appdata directory, returned with value #{result}" unless result.zero?
  windir.rstrip!
  windir = windir.encode("UTF-8", Encoding.find('filesystem'))
  windir = File.expand_path(windir.rstrip)

  return windir if Dir.exist? windir
  raise "Local Appdata retrieved (#{windir}) is not correct"
end
windows_path(path) click to toggle source
# File lib/u3d/utils.rb, line 227
def windows_path(path)
  UI.deprecated("Use U3dCore::Helper.windows_path")
  U3dCore::Helper.windows_path(path)
end

Private Class Methods

http_max_retries() click to toggle source
# File lib/u3d/utils.rb, line 254
def http_max_retries
  ENV['U3D_HTTP_MAX_RETRIES'].to_i if ENV['U3D_HTTP_MAX_RETRIES']
end
http_opts(opt = {}) click to toggle source
# File lib/u3d/utils.rb, line 263
def http_opts(opt = {})
  # the keys are #ca_file, #ca_path, cert, #cert_store, ciphers, #close_on_empty_response, key, #open_timeout,
  # #read_timeout, #ssl_timeout, #ssl_version, use_ssl, #verify_callback, #verify_depth and verify_mode
  opt[:max_retries] = http_max_retries if http_max_retries
  opt[:read_timeout] = http_read_timeout if http_read_timeout
  UI.verbose "Using http opts: #{opt}"
  opt
end
http_read_timeout() click to toggle source
# File lib/u3d/utils.rb, line 258
def http_read_timeout
  return ENV['U3D_HTTP_READ_TIMEOUT'].to_i if ENV['U3D_HTTP_READ_TIMEOUT']
  300
end