rakelib/support.rb
author Jan Vrany <jan.vrany@fit.cvut.cz>
Wed, 25 May 2016 17:19:27 +0100
changeset 11 f7dc950d8df8
parent 10 cb3e0e3ca28f
child 23 7dad21b22558
permissions -rw-r--r--
Automatically download pre-built librun and stc when sources are not available. ...from SWING Jenkins job. A courstesy to those unlucky ones who want to recompile Smalltalk/X but have no access to stc and librun sources.

require 'net/http'
require 'net/https'
require 'json'
require 'rakelib/extensions.rb'
require 'rakelib/rbspec.rb'
require 'rakelib/vcs.rb'

# Following hack is required to allow passing variable
# values in `make` style, i.e., to allow for
#
#  rake PROJECT=stx:jv-branch compile
#
ARGV.each do | arg |
  name_and_value = /^([A-Za-z_]+)\w*=(.*)/.match(arg)
  if name_and_value
     self.class.const_set(name_and_value[1], name_and_value[2])  
  end
end

# Update PATH for build so build scripts may access 
# scripts in `bin` directory. This is required especially
# on Windows as Windows do not ship with some basic tools
# (e.g. zip) by default. As a courtesy to the user, provide
# our own
ENV['PATH'] = "#{ENV['PATH']}#{File::PATH_SEPARATOR}#{File.expand_path('bin')}"

# Return true if running under Jenkins, false otherwise
def jenkins?
  return (ENV.has_key? 'WORKSPACE'   and 
          ENV.has_key? 'JOB_NAME'    and 
          ENV.has_key? 'BUILD_ID')
end

# Returns true if and only if this is machine of one of the core developers
# (currently only JV). 
# Indeed this is a feeble check and can be easily bypassed by chaning the
# code or by setting a proper environment variable. But this should not hurt 
# much as in that case, unauthorized person wouldn't be able to connect to 
# stc and librun repository so the build will fail. 
def core_developer?
  # JV's box: jv@..., vranyj1@...
  if (ENV['USER'] == 'jv') or (ENV['USER'] == 'vranyj1')
    return true
  end
  if (ENV['USERNAME'] == 'jv') or (ENV['USERNAME'] == 'vranyj1')
    return true
  end 
  return false
end

# A super simple API for Jenkins used to download pre-built stc and librun.
module Jenkins
  # Return an a Jenkins build with pre-built stc and librun. 
  # Used to download pre-build stc and librun
  def self.smalltalkx_jv_branch_build()
    plat = nil
    if win32? then        
        plat = 'Windows'
    elsif linux?        
      plat = 'Linux'
    else        
      error_unsupported_platform()
    end
    return Jenkins::Build.new(%Q{https://swing.fit.cvut.cz/jenkins/job/stx_jv_new/ARCH=#{ARCH},PLATFORM=#{plat}N/lastSuccessfulBuild})
  end

  class Artifact
    attr_reader :name
    attr_reader :uri

    def initialize(name, uri)
      @name = name
      @uri = uri
    end

    def download_to(destination)       
      if not File.exist? destination
        if not File.directory? File.dirname(destination)
          raise Exception.new("Invalid destination for download: #{destination}")
        end
      else
        if not File.directory? destination
          raise Exception.new("Invalid destination for download: #{destination}")
        else
          destination = File.join(destination, @name)
        end
      end
      Jenkins::get(@uri) do | response |
        File.open(destination, "wb") do | file |
          response.read_body do | part |
            file.write part
          end
        end
      end
    end
  end

  class Build
    attr_reader :data
    attr_reader :uri

    def initialize(uri)
      @uri = uri
      @data = JSON.parse(Jenkins::get(URI(uri.to_s + '/api/json')))
    end

    # Return a list of artifacts (as instances of `Jenkins::Artifact`) 
    # associated with this build. 
    def artifacts()
      if not @artifacts then
        @artifacts = @data["artifacts"].collect do | each | 
          Artifact.new(each['fileName'], URI(@uri.to_s + '/artifact/' + each['relativePath']))
        end
      end
      return @artifacts      
    end
  end

  # A private method to GET data over HTTP(S)  
  def self.get(uri, &block) 
    # http parameters       
    http_host = Net::HTTP.new(uri.host, uri.port)
    http_host.use_ssl = (uri.scheme == 'https') # simple true enough

    if false # host verification not used (yet)
      http_host.verify_mode = OpenSSL::SSL::VERIFY_PEER
      http_host.cert_store = OpenSSL::X509::Store.new
      http_host.cert_store.set_default_paths
      http_host.cert_store.add_file('cacert.pem') # file downloaded from curl.haxx.se/ca/cacert.pem
    else
      http_host.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end

    # actual download
    body = nil
    http_host.start do | http |        
      http.request_get(uri) do | response |
        if block then
          yield response
        else
          body = response.body
        end
      end
    end
    return body
  end
end