class MiniPortile

Attributes

configure_options[W]
files[RW]
host[RW]
logger[RW]
name[R]
original_host[R]
patch_files[RW]
target[RW]
version[R]

Public Class Methods

new(name, version) click to toggle source
# File lib/mini_portile.rb, line 13
def initialize(name, version)
  @name = name
  @version = version
  @target = 'ports'
  @files = []
  @patch_files = []
  @logger = STDOUT

  @original_host = @host = detect_host
end

Public Instance Methods

activate() click to toggle source
# File lib/mini_portile.rb, line 107
def activate
  lib_path = File.join(port_path, "lib")
  vars = {
    'PATH'          => File.join(port_path, 'bin'),
    'CPATH'         => File.join(port_path, 'include'),
    'LIBRARY_PATH'  => lib_path
  }.reject { |env, path| !File.directory?(path) }

  output "Activating #{@name} #{@version} (from #{port_path})..."
  vars.each do |var, path|
    full_path = File.expand_path(path)

    # turn into a valid Windows path (if required)
    full_path.gsub!(File::SEPARATOR, File::ALT_SEPARATOR) if File::ALT_SEPARATOR

    # save current variable value
    old_value = ENV[var] || ''

    unless old_value.include?(full_path)
      ENV[var] = "#{full_path}#{File::PATH_SEPARATOR}#{old_value}"
    end
  end

  # rely on LDFLAGS when cross-compiling
  if File.exist?(lib_path) && (@host != @original_host)
    full_path = File.expand_path(lib_path)

    old_value = ENV.fetch("LDFLAGS", "")

    unless old_value.include?(full_path)
      ENV["LDFLAGS"] = "-L#{full_path} #{old_value}".strip
    end
  end
end
compile() click to toggle source
# File lib/mini_portile.rb, line 60
def compile
  execute('compile', 'make')
end
configure() click to toggle source
# File lib/mini_portile.rb, line 50
def configure
  return if configured?

  md5_file = File.join(tmp_path, 'configure.md5')
  digest   = Digest::MD5.hexdigest(computed_options)
  File.open(md5_file, "w") { |f| f.write digest }

  execute('configure', %Q(sh configure #{computed_options}))
end
configure_options() click to toggle source
# File lib/mini_portile.rb, line 46
def configure_options
  @configure_options ||= configure_defaults
end
configured?() click to toggle source
# File lib/mini_portile.rb, line 78
def configured?
  configure = File.join(work_path, 'configure')
  makefile  = File.join(work_path, 'Makefile')
  md5_file  = File.join(tmp_path, 'configure.md5')

  stored_md5  = File.exist?(md5_file) ? File.read(md5_file) : ""
  current_md5 = Digest::MD5.hexdigest(computed_options)

  (current_md5 == stored_md5) && newer?(makefile, configure)
end
cook() click to toggle source
# File lib/mini_portile.rb, line 96
def cook
  download unless downloaded?
  extract
  patch
  configure unless configured?
  compile
  install unless installed?

  return true
end
download() click to toggle source
# File lib/mini_portile.rb, line 24
def download
  @files.each do |url|
    filename = File.basename(url)
    download_file(url, File.join(archives_path, filename))
  end
end
downloaded?() click to toggle source
# File lib/mini_portile.rb, line 69
def downloaded?
  missing = @files.detect do |url|
    filename = File.basename(url)
    !File.exist?(File.join(archives_path, filename))
  end

  missing ? false : true
end
extract() click to toggle source
# File lib/mini_portile.rb, line 31
def extract
  @files.each do |url|
    filename = File.basename(url)
    extract_file(File.join(archives_path, filename), tmp_path)
  end
end
install() click to toggle source
# File lib/mini_portile.rb, line 64
def install
  return if installed?
  execute('install', %Q(make install))
end
installed?() click to toggle source
# File lib/mini_portile.rb, line 89
def installed?
  makefile  = File.join(work_path, 'Makefile')
  target_dir = Dir.glob("#{port_path}/*").find { |d| File.directory?(d) }

  newer?(target_dir, makefile)
end
patch() click to toggle source
# File lib/mini_portile.rb, line 38
def patch
  @patch_files.each do |full_path|
    next unless File.exists?(full_path)
    output "Running git apply with #{full_path}..."
    execute('patch', %Q(git apply #{full_path}))
  end   
end
path() click to toggle source
# File lib/mini_portile.rb, line 142
def path
  File.expand_path(port_path)
end

Private Instance Methods

archives_path() click to toggle source
# File lib/mini_portile.rb, line 156
def archives_path
  "#{@target}/archives"
end
computed_options() click to toggle source
# File lib/mini_portile.rb, line 176
def computed_options
  [
    configure_options,     # customized or default options
    configure_prefix,      # installation target
  ].flatten.join(' ')
end
configure_defaults() click to toggle source
# File lib/mini_portile.rb, line 164
def configure_defaults
  [
    "--host=#{@host}",    # build for specific target (host)
    "--enable-static",    # build static library
    "--disable-shared"    # disable generation of shared object
  ]
end
configure_prefix() click to toggle source
# File lib/mini_portile.rb, line 172
def configure_prefix
  "--prefix=#{File.expand_path(port_path)}"
end
detect_host() click to toggle source
# File lib/mini_portile.rb, line 196
def detect_host
  return @detect_host if defined?(@detect_host)

  output = %xgcc -v 2>&1`
  if m = output.match(/^Target\: (.*)$/)
    @detect_host = m[1]
  end

  @detect_host
end
download_file(url, full_path, count = 3) click to toggle source

Slighly modified from RubyInstaller uri_ext, Rubinius configure and adaptations of Wayne's RailsInstaller

# File lib/mini_portile.rb, line 262
def download_file(url, full_path, count = 3)
  return if File.exist?(full_path)
  uri = URI.parse(url)
  begin
    case uri.scheme.downcase
    when /ftp/
      download_file_ftp(uri, full_path)
    when /http|https/
      download_file_http(url, full_path, count)
    end
  rescue Exception => e
    File.unlink full_path if File.exists?(full_path)
    output "ERROR: #{e.message}"
    raise "Failed to complete download task"
  end
end
download_file_ftp(uri, full_path) click to toggle source
# File lib/mini_portile.rb, line 326
def download_file_ftp(uri, full_path)
  filename = File.basename(uri.path)
  with_tempfile(filename, full_path) do |temp_file|
    size = 0
    progress = 0
    Net::FTP.open(uri.host, uri.user, uri.password) do |ftp|
      ftp.passive = true
      ftp.login
      remote_dir = File.dirname(uri.path)
      ftp.chdir(remote_dir) unless remote_dir == '.'
      total = ftp.size(filename)
      ftp.getbinaryfile(filename, temp_file.path, 8192) do |chunk|
        # Ruby 1.8.7 already wrote the chunk into the file
        unless RUBY_VERSION < "1.9"
          temp_file << chunk
        end

        size += chunk.size
        new_progress = (size * 100) / total
        unless new_progress == progress
          message "\rDownloading %s (%3d%%) " % [filename, new_progress]
        end
        progress = new_progress
      end
    end
    output
  end
end
download_file_http(url, full_path, count = 3) click to toggle source
# File lib/mini_portile.rb, line 279
def download_file_http(url, full_path, count = 3)
  filename = File.basename(full_path)

  if ENV['http_proxy']
    protocol, userinfo, host, port  = URI::split(ENV['http_proxy'])
    proxy_user, proxy_pass = userinfo.split(/:/) if userinfo
    http = Net::HTTP::Proxy(host, port, proxy_user, proxy_pass)
  else
    http = Net::HTTP
  end

  message "Downloading #{filename} "
  http.get_response(URI.parse(url)) do |response|
    case response
    when Net::HTTPNotFound
      output "404 - Not Found"
      return false

    when Net::HTTPClientError
      output "Error: Client Error: #{response.inspect}"
      return false

    when Net::HTTPRedirection
      raise "Too many redirections for the original URL, halting." if count <= 0
      url = response["location"]
      return download_file(url, full_path, count - 1)

    when Net::HTTPOK
      with_tempfile(filename, full_path) do |temp_file|
        size = 0
        progress = 0
        total = response.header["Content-Length"].to_i
        response.read_body do |chunk|
          temp_file << chunk
          size += chunk.size
          new_progress = (size * 100) / total
          unless new_progress == progress
            message "\rDownloading %s (%3d%%) " % [filename, new_progress]
          end
          progress = new_progress
        end
        output
      end
    end
  end
end
execute(action, command) click to toggle source
# File lib/mini_portile.rb, line 222
def execute(action, command)
  log        = log_file(action)
  log_out    = File.expand_path(log)
  redirected = command << " >#{log_out} 2>&1"

  Dir.chdir work_path do
    message "Running '#{action}' for #{@name} #{@version}... "
    system redirected
    if $?.success?
      output "OK"
      return true
    else
      output "ERROR, review '#{log}' to see what happened."
      raise "Failed to complete #{action} task"
    end
  end
end
extract_file(file, target) click to toggle source
# File lib/mini_portile.rb, line 207
def extract_file(file, target)
  filename = File.basename(file)
  FileUtils.mkdir_p target

  message "Extracting #{filename} into #{target}... "
  result = %x#{tar_exe} xf #{file} -C #{target} 2>&1`
  if $?.success?
    output "OK"
  else
    output "ERROR"
    output result
    raise "Failed to complete extract task"
  end
end
log_file(action) click to toggle source
# File lib/mini_portile.rb, line 183
def log_file(action)
  File.join(tmp_path, "#{action}.log")
end
message(text) click to toggle source

print out a message with the logger

# File lib/mini_portile.rb, line 249
def message(text)
  @logger.print text
  @logger.flush
end
newer?(target, checkpoint) click to toggle source
# File lib/mini_portile.rb, line 240
def newer?(target, checkpoint)
  if (target && File.exist?(target)) && (checkpoint && File.exist?(checkpoint))
    File.mtime(target) > File.mtime(checkpoint)
  else
    false
  end
end
output(text = "") click to toggle source

print out a message using the logger but return to a new line

# File lib/mini_portile.rb, line 255
def output(text = "")
  @logger.puts text
  @logger.flush
end
port_path() click to toggle source
# File lib/mini_portile.rb, line 152
def port_path
  "#{@target}/#{@host}/#{@name}/#{@version}"
end
tar_exe() click to toggle source
# File lib/mini_portile.rb, line 187
def tar_exe
  @@tar_exe ||= begin
    dev_null = RbConfig::CONFIG['host_os'] =~ /mingw|mswin/ ? 'NUL' : '/dev/null'
    %w[tar bsdtar basic-bsdtar].find { |c|
      system("#{c} --version >> #{dev_null} 2>&1")
    }
  end
end
tmp_path() click to toggle source
# File lib/mini_portile.rb, line 148
def tmp_path
  "tmp/#{@host}/ports/#{@name}/#{@version}"
end
with_tempfile(filename, full_path) { |temp_file| ... } click to toggle source
# File lib/mini_portile.rb, line 355
def with_tempfile(filename, full_path)
  temp_file = Tempfile.new("download-#{filename}")
  temp_file.binmode
  yield temp_file
  temp_file.close
  File.unlink full_path if File.exists?(full_path)
  FileUtils.mkdir_p File.dirname(full_path)
  FileUtils.mv temp_file.path, full_path, :force => true
end
work_path() click to toggle source
# File lib/mini_portile.rb, line 160
def work_path
  Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) }
end