class MiniPortile

Constants

DEFAULT_TIMEOUT
KEYRING_NAME
TAR_EXECUTABLES
VERSION

Attributes

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

Public Class Methods

darwin?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 54
def self.darwin?
  target_os =~ /darwin/
end
freebsd?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 58
def self.freebsd?
  target_os =~ /freebsd/
end
linux?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 66
def self.linux?
  target_os =~ /linux/
end
mingw?() click to toggle source

GNU MinGW compiled Ruby?

# File lib/mini_portile2/mini_portile.rb, line 45
def self.mingw?
  target_os =~ /mingw/
end
mswin?() click to toggle source

MS Visual-C compiled Ruby?

# File lib/mini_portile2/mini_portile.rb, line 50
def self.mswin?
  target_os =~ /mswin/
end
native_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 82
def self.native_path(path)
  path = File.expand_path(path)
  if File::ALT_SEPARATOR
    path.tr(File::SEPARATOR, File::ALT_SEPARATOR)
  else
    path
  end
end
new(name, version, **kwargs) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 100
def initialize(name, version, **kwargs)
  @name = name
  @version = version
  @target = 'ports'
  @files = []
  @patch_files = []
  @log_files = {}
  @logger = kwargs[:logger] || STDOUT
  @source_directory = nil

  @cc_command = kwargs[:cc_command] || kwargs[:gcc_command]
  @cxx_command = kwargs[:cxx_command]
  @make_command = kwargs[:make_command]
  @open_timeout = kwargs[:open_timeout] || DEFAULT_TIMEOUT
  @read_timeout = kwargs[:read_timeout] || DEFAULT_TIMEOUT

  @original_host = @host = detect_host
end
openbsd?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 62
def self.openbsd?
  target_os =~ /openbsd/
end
posix_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 91
def self.posix_path(path)
  path = File.expand_path(path)
  if File::ALT_SEPARATOR
    "/" + path.tr(File::ALT_SEPARATOR, File::SEPARATOR).tr(":", File::SEPARATOR)
  else
    path
  end
end
solaris?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 70
def self.solaris?
  target_os =~ /solaris/
end
target_cpu() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 78
def self.target_cpu
  RbConfig::CONFIG['target_cpu']
end
target_os() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 74
def self.target_os
  RbConfig::CONFIG['target_os']
end
windows?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 40
def self.windows?
  target_os =~ /mswin|mingw/
end

Public Instance Methods

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

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

    # 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 = native_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
apply_patch(patch_file) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 144
def apply_patch(patch_file)
  (
    # Not a class variable because closures will capture self.
    @apply_patch ||=
    case
    when which('git')
      lambda { |file|
        message "Running git apply with #{file}... "
        Dir.mktmpdir do |tmp_git_dir|
          execute('patch', ["git", "--git-dir=#{tmp_git_dir}", "--work-tree=.", "apply", "--whitespace=warn", file], :initial_message => false)
        end
      }
    when which('patch')
      lambda { |file|
        message "Running patch with #{file}... "
        execute('patch', ["patch", "-p1", "-i", file], :initial_message => false)
      }
    else
      raise "Failed to complete patch task; patch(1) or git(1) is required."
    end
  ).call(patch_file)
end
cc_cmd() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 375
def cc_cmd
  (ENV["CC"] || @cc_command || RbConfig::CONFIG["CC"] || "gcc").dup
end
Also aliased as: gcc_cmd
compile() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 193
def compile
  execute('compile', make_cmd)
end
configure() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 178
def configure
  return if configured?

  FileUtils.mkdir_p(tmp_path)
  cache_file = File.join(tmp_path, 'configure.options_cache')
  File.open(cache_file, "w") { |f| f.write computed_options.to_s }

  command = Array(File.join((source_directory || "."), "configure"))
  if RUBY_PLATFORM=~/mingw|mswin/
    # Windows doesn't recognize the shebang.
    command.unshift("sh")
  end
  execute('configure', command + computed_options, altlog: "config.log")
end
configure_options() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 174
def configure_options
  @configure_options ||= configure_defaults
end
configured?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 210
def configured?
  configure = File.join((source_directory || work_path), 'configure')
  makefile  = File.join(work_path, 'Makefile')
  cache_file  = File.join(tmp_path, 'configure.options_cache')

  stored_options  = File.exist?(cache_file) ? File.read(cache_file) : ""
  current_options = computed_options.to_s

  (current_options == stored_options) && newer?(makefile, configure)
end
cook() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 228
def cook
  if source_directory
    prepare_build_directory
  else
    download unless downloaded?
    extract
    patch
  end
  configure unless configured?
  compile
  install unless installed?

  return true
end
cxx_cmd() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 380
def cxx_cmd
  (ENV["CXX"] || @cxx_command || RbConfig::CONFIG["CXX"] || "g++").dup
end
download() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 130
def download
  files_hashs.each do |file|
    download_file(file[:url], file[:local_path])
    verify_file(file)
  end
end
downloaded?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 202
def downloaded?
  missing = files_hashs.detect do |file|
    !File.exist?(file[:local_path])
  end

  missing ? false : true
end
extract() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 137
def extract
  files_hashs.each do |file|
    verify_file(file)
    extract_file(file[:local_path], tmp_path)
  end
end
gcc_cmd()
Alias for: cc_cmd
include_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 367
def include_path
  File.join(path, "include")
end
install() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 197
def install
  return if installed?
  execute('install', %Q(#{make_cmd} install))
end
installed?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 221
def installed?
  makefile  = File.join(work_path, 'Makefile')
  target_dir = Dir.glob("#{port_path}/*").find { |d| File.directory?(d) }

  newer?(target_dir, makefile)
end
lib_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 371
def lib_path
  File.join(path, "lib")
end
make_cmd() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 384
def make_cmd
  (ENV["MAKE"] || @make_command || ENV["make"] || "make").dup
end
mkmf_config(pkg: nil, dir: nil, static: nil) click to toggle source

pkg: the pkg-config file name (without the .pc extension) dir: inject the directory path for the pkg-config file (probably only useful for tests) static: the name of the static library archive (without the “lib” prefix or the file extension), or nil for dynamic linking

we might be able to be terribly clever and infer the name of the static archive file, but unfortunately projects have so much freedom in what they can report (for name, for libs, etc.) that it feels unreliable to try to do so, so I’m preferring to just have the developer make it explicit.

# File lib/mini_portile2/mini_portile.rb, line 282
def mkmf_config(pkg: nil, dir: nil, static: nil)
  require "mkmf"

  if pkg
    dir ||= File.join(lib_path, "pkgconfig")
    pcfile = File.join(dir, "#{pkg}.pc")
    unless File.exist?(pcfile)
      raise ArgumentError, "pkg-config file '#{pcfile}' does not exist"
    end

    output "Configuring MakeMakefile for #{File.basename(pcfile)} (in #{File.dirname(pcfile)})\n"

    # on macos, pkg-config will not return --cflags without this
    ENV["PKG_CONFIG_ALLOW_SYSTEM_CFLAGS"] = "t"

    # append to PKG_CONFIG_PATH as we go, so later pkg-config files can depend on earlier ones
    ENV["PKG_CONFIG_PATH"] = [ENV["PKG_CONFIG_PATH"], dir].compact.join(File::PATH_SEPARATOR)

    incflags = minimal_pkg_config(pcfile, "cflags-only-I")
    cflags = minimal_pkg_config(pcfile, "cflags-only-other")
    if static
      ldflags = minimal_pkg_config(pcfile, "libs-only-L", "static")
      libflags = minimal_pkg_config(pcfile, "libs-only-l", "static")
    else
      ldflags = minimal_pkg_config(pcfile, "libs-only-L")
      libflags = minimal_pkg_config(pcfile, "libs-only-l")
    end
  else
    output "Configuring MakeMakefile for #{@name} #{@version} (from #{path})\n"

    lib_name = name.sub(/\Alib/, "") # TODO: use delete_prefix when we no longer support ruby 2.4

    incflags = Dir.exist?(include_path) ? "-I#{include_path}" : ""
    cflags = ""
    ldflags = Dir.exist?(lib_path) ? "-L#{lib_path}" : ""
    libflags = Dir.exist?(lib_path) ? "-l#{lib_name}" : ""
  end

  if static
    libdir = lib_path
    if pcfile
      pcfile_libdir = minimal_pkg_config(pcfile, "variable=libdir").strip
      libdir = pcfile_libdir unless pcfile_libdir.empty?
    end

    #
    # keep track of the libraries we're statically linking against, and fix up ldflags and
    # libflags to make sure we link statically against the recipe's libaries.
    #
    # this avoids the unintentionally dynamically linking against system libraries, and makes sure
    # that if multiple pkg-config files reference each other that we are able to intercept flags
    # from dependent packages that reference the static archive.
    #
    $MINI_PORTILE_STATIC_LIBS[static] = libdir
    static_ldflags = $MINI_PORTILE_STATIC_LIBS.values.map { |v| "-L#{v}" }
    static_libflags = $MINI_PORTILE_STATIC_LIBS.keys.map { |v| "-l#{v}" }

    # remove `-L#{libdir}` and `-lfoo`. we don't need them since we link against the static
    # archive using the full path.
    ldflags = ldflags.shellsplit.reject { |f| static_ldflags.include?(f) }.shelljoin
    libflags = libflags.shellsplit.reject { |f| static_libflags.include?(f) }.shelljoin

    # prepend the full path to the static archive to the linker flags
    static_archive = File.join(libdir, "lib#{static}.#{$LIBEXT}")
    libflags = [static_archive, libflags].join(" ").strip
  end

  # prefer this package by prepending to search paths and library flags
  #
  # convert the ldflags into a list of directories and append to $LIBPATH (instead of just using
  # $LDFLAGS) to ensure we get the `-Wl,-rpath` linker flag for re-finding shared libraries.
  $INCFLAGS = [incflags, $INCFLAGS].join(" ").strip
  libpaths = ldflags.shellsplit.map { |f| f.sub(/\A-L/, "") }
  $LIBPATH = libpaths | $LIBPATH
  $libs = [libflags, $libs].join(" ").strip

  # prefer this package's compiler flags by appending them to the command line
  $CFLAGS = [$CFLAGS, cflags].join(" ").strip
  $CXXFLAGS = [$CXXFLAGS, cflags].join(" ").strip
end
patch() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 167
def patch
  @patch_files.each do |full_path|
    next unless File.exist?(full_path)
    apply_patch(full_path)
  end
end
path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 363
def path
  File.expand_path(port_path)
end
prepare_build_directory() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 123
def prepare_build_directory
  raise "source_directory is not set" if source_directory.nil?
  output "Building #{@name} from source at '#{source_directory}'"
  FileUtils.mkdir_p(File.join(tmp_path, [name, version].join("-")))
  FileUtils.rm_rf(port_path) # make sure we always re-install
end
source_directory=(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 119
def source_directory=(path)
  @source_directory = posix_path(path)
end

Private Instance Methods

archives_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 406
def archives_path
  "#{@target}/archives"
end
computed_options() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 426
def computed_options
  [
    configure_options,     # customized or default options
    configure_prefix,      # installation target
  ].flatten
end
configure_defaults() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 414
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_portile2/mini_portile.rb, line 422
def configure_prefix
  "--prefix=#{File.expand_path(port_path)}"
end
detect_host() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 528
def detect_host
  return @detect_host if defined?(@detect_host)

  begin
    ENV["LC_ALL"], old_lc_all = "C", ENV["LC_ALL"]

    output = `#{gcc_cmd} -v 2>&1`
    if m = output.match(/^Target\: (.*)$/)
      @detect_host = m[1]
    else
      @detect_host = nil
    end

    @detect_host
  ensure
    ENV["LC_ALL"] = old_lc_all
  end
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_portile2/mini_portile.rb, line 650
def download_file(url, full_path, count = 3)
  return if File.exist?(full_path)
  uri = URI.parse(url)

  case uri.scheme.downcase
  when /ftp/
    download_file_ftp(uri, full_path)
  when /http|https/
    download_file_http(url, full_path, count)
  when /file/
    download_file_file(uri, full_path)
  else
    raise ArgumentError.new("Unsupported protocol for #{url}")
  end
rescue Exception => e
  File.unlink full_path if File.exist?(full_path)
  raise e
end
download_file_file(uri, full_path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 723
def download_file_file(uri, full_path)
  FileUtils.mkdir_p File.dirname(full_path)
  FileUtils.cp uri.path, full_path
end
download_file_ftp(uri, full_path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 728
def download_file_ftp(uri, full_path)
  require "net/ftp"
  filename = File.basename(uri.path)
  with_tempfile(filename, full_path) do |temp_file|
    total = 0
    params = {
      :content_length_proc => lambda{|length| total = length },
      :progress_proc => lambda{|bytes|
        new_progress = (bytes * 100) / total
        message "\rDownloading %s (%3d%%) " % [filename, new_progress]
      },
      :open_timeout => @open_timeout,
      :read_timeout => @read_timeout,
    }
    if ENV["ftp_proxy"]
      _, userinfo, _p_host, _p_port = URI.split(ENV['ftp_proxy'])
      if userinfo
        proxy_user, proxy_pass = userinfo.split(/:/).map{|s| CGI.unescape(s) }
        params[:proxy_http_basic_authentication] =
          [ENV['ftp_proxy'], proxy_user, proxy_pass]
      end
    end
    OpenURI.open_uri(uri, 'rb', params) do |io|
      temp_file << io.read
    end
    output
  end
rescue LoadError
  raise LoadError, "Ruby #{RUBY_VERSION} does not provide the net-ftp gem, please add it as a dependency if you need to use FTP"
rescue Net::FTPError
  return false
end
download_file_http(url, full_path, count = 3) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 669
def download_file_http(url, full_path, count = 3)
  filename = File.basename(full_path)
  with_tempfile(filename, full_path) do |temp_file|
    total = 0
    params = {
      "Accept-Encoding" => 'identity',
      :content_length_proc => lambda{|length| total = length },
      :progress_proc => lambda{|bytes|
        if total
          new_progress = (bytes * 100) / total
          message "\rDownloading %s (%3d%%) " % [filename, new_progress]
        else
          # Content-Length is unavailable because Transfer-Encoding is chunked
          message "\rDownloading %s " % [filename]
        end
      },
      :open_timeout => @open_timeout,
      :read_timeout => @read_timeout,
    }
    proxy_uri = URI.parse(url).scheme.downcase == 'https' ?
                ENV["https_proxy"] :
                ENV["http_proxy"]
    if proxy_uri
      _, userinfo, _p_host, _p_port = URI.split(proxy_uri)
      if userinfo
        proxy_user, proxy_pass = userinfo.split(/:/).map{|s| CGI.unescape(s) }
        params[:proxy_http_basic_authentication] =
          [proxy_uri, proxy_user, proxy_pass]
      end
    end

    begin
      OpenURI.open_uri(url, 'rb', params) do |io|
        temp_file << io.read
      end
      output
    rescue OpenURI::HTTPRedirect => redirect
      raise "Too many redirections for the original URL, halting." if count <= 0
      count = count - 1
      return download_file(redirect.url, full_path, count-1)
    rescue => e
      count = count - 1
      @logger.puts "#{count} retrie(s) left for #{filename} (#{e.message})"
      if count > 0
        sleep 1
        return download_file_http(url, full_path, count)
      end

      output e.message
      return false
    end
  end
end
execute(action, command, command_opts={}) click to toggle source

command could be an array of args, or one string containing a command passed to the shell. See Process.spawn for more information.

# File lib/mini_portile2/mini_portile.rb, line 580
def execute(action, command, command_opts={})
  opt_message = command_opts.fetch(:initial_message, true)
  opt_debug =   command_opts.fetch(:debug, false)
  opt_cd =      command_opts.fetch(:cd) { work_path }
  opt_env =     command_opts.fetch(:env) { Hash.new }
  opt_altlog =  command_opts.fetch(:altlog, nil)

  log_out = log_file(action)

  Dir.chdir(opt_cd) do
    output "DEBUG: env is #{opt_env.inspect}" if opt_debug
    output "DEBUG: command is #{command.inspect}" if opt_debug
    message "Running '#{action}' for #{@name} #{@version}... " if opt_message

    if Process.respond_to?(:spawn) && ! RbConfig.respond_to?(:java)
      options = {[:out, :err]=>[log_out, "a"]}
      output "DEBUG: options are #{options.inspect}" if opt_debug
      args = [opt_env, command, options].flatten
      pid = spawn(*args)
      Process.wait(pid)
    else
      env_args = opt_env.map { |k,v| "#{k}=#{v}".shellescape }.join(" ")
      c = if command.kind_of?(Array)
            command.map(&:shellescape).join(" ")
          else
            command
          end
      redirected = %Q{env #{env_args} #{c} > #{log_out.shellescape} 2>&1}
      output "DEBUG: final command is #{redirected.inspect}" if opt_debug
      system redirected
    end

    if $?.success?
      output "OK"
      return true
    else
      output "ERROR. Please review logs to see what happened:\n"
      [log_out, opt_altlog].compact.each do |log|
        next unless File.exist?(log)
        output("----- contents of '#{log}' -----")
        output(File.read(log))
        output("----- end of file -----")
      end
      raise "Failed to complete #{action} task"
    end
  end
end
extract_file(file, target) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 570
def extract_file(file, target)
  filename = File.basename(file)
  FileUtils.mkdir_p target

  message "Extracting #{filename} into #{target}... "
  execute('extract', tar_command(file, target) , {:cd => Dir.pwd, :initial_message => false})
end
files_hashs() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 433
def files_hashs
  @files.map do |file|
    hash = case file
    when String
      { :url => file }
    when Hash
      file.dup
    else
      raise ArgumentError, "files must be an Array of Stings or Hashs"
    end

    url = hash.fetch(:url){ raise ArgumentError, "no url given" }
    filename = File.basename(url)
    hash[:local_path] = File.join(archives_path, filename)
    hash
  end
end
log_file(action) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 504
def log_file(action)
  @log_files[action] ||=
    File.expand_path("#{action}.log", tmp_path).tap { |file|
      File.unlink(file) if File.exist?(file)
    }
end
message(text) click to toggle source

print out a message with the logger

# File lib/mini_portile2/mini_portile.rb, line 637
def message(text)
  @logger.print text
  @logger.flush
end
minimal_pkg_config(pkg, *pcoptions) click to toggle source

this minimal version of pkg_config is based on ruby 29dc9378 (2023-01-09)

specifically with the fix from b90e56e6 to support multiple pkg-config options, and removing code paths that aren’t helpful for mini-portile’s use case of parsing pc files.

# File lib/mini_portile2/mini_portile.rb, line 777
def minimal_pkg_config(pkg, *pcoptions)
  if pcoptions.empty?
    raise ArgumentError, "no pkg-config options are given"
  end

  if ($PKGCONFIG ||=
      (pkgconfig = MakeMakefile.with_config("pkg-config") {MakeMakefile.config_string("PKG_CONFIG") || "pkg-config"}) &&
      MakeMakefile.find_executable0(pkgconfig) && pkgconfig)
    pkgconfig = $PKGCONFIG
  else
    raise RuntimeError, "pkg-config is not found"
  end

  pcoptions = Array(pcoptions).map { |o| "--#{o}" }
  response = IO.popen([pkgconfig, *pcoptions, pkg], err:[:child, :out], &:read)
  raise RuntimeError, response unless $?.success?
  response.strip
end
native_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 390
def native_path(path)
  MiniPortile.native_path(path)
end
newer?(target, checkpoint) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 628
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_portile2/mini_portile.rb, line 643
def output(text = "")
  @logger.puts text
  @logger.flush
end
port_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 402
def port_path
  "#{@target}/#{@host}/#{@name}/#{@version}"
end
posix_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 394
def posix_path(path)
  MiniPortile.posix_path(path)
end
tar_command(file, target) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 556
def tar_command(file, target)
  case File.extname(file)
    when '.gz', '.tgz'
      [tar_exe, 'xzf', file, '-C', target]
    when '.bz2', '.tbz2'
      [tar_exe, 'xjf', file, '-C', target]
    when '.xz'
      # NOTE: OpenBSD's tar command does not support the -J option
      "xzcat #{file.shellescape} | #{tar_exe.shellescape} xf - -C #{target.shellescape}"
    else
      [tar_exe, 'xf', file, '-C', target]
  end
end
tar_exe() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 548
def tar_exe
  @@tar_exe ||= begin
    TAR_EXECUTABLES.find { |c|
      which(c)
    } or raise("tar not found - please make sure that one of the following commands is in the PATH: #{TAR_EXECUTABLES.join(", ")}")
  end
end
tmp_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 398
def tmp_path
  "tmp/#{@host}/ports/#{@name}/#{@version}"
end
verify_file(file) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 453
def verify_file(file)
  if file.has_key?(:gpg)
    gpg = file[:gpg]

    signature_url = gpg[:signature_url] || "#{file[:url]}.asc"
    signature_file = file[:local_path] + ".asc"
    # download the signature file
    download_file(signature_url, signature_file)

    gpg_exe = which('gpg2') || which('gpg') || raise("Neither GPG nor GPG2 is installed")

    # import the key into our own keyring
    gpg_error = nil
    gpg_status = Open3.popen3(gpg_exe, "--status-fd", "1", "--no-default-keyring", "--keyring", KEYRING_NAME, "--import") do |gpg_in, gpg_out, gpg_err, _thread|
      gpg_in.write gpg[:key]
      gpg_in.close
      gpg_error = gpg_err.read
      gpg_out.read
    end
    key_ids = gpg_status.scan(/\[GNUPG:\] IMPORT_OK \d+ (?<key_id>[0-9a-f]+)/i).map(&:first)
    raise "invalid gpg key provided:\n#{gpg_error}" if key_ids.empty?

    begin
      # verify the signature against our keyring
      gpg_status, gpg_error, _status = Open3.capture3(gpg_exe, "--status-fd", "1", "--no-default-keyring", "--keyring", KEYRING_NAME, "--verify", signature_file, file[:local_path])

      raise "signature mismatch:\n#{gpg_error}" unless gpg_status.match(/^\[GNUPG:\] VALIDSIG/)
    ensure
      # remove the key from our keyring
      key_ids.each do |key_id|
        IO.popen([gpg_exe, "--batch", "--yes", "--no-default-keyring", "--keyring", KEYRING_NAME, "--delete-keys", key_id], &:read)
        raise "unable to delete the imported key" unless $?.exitstatus==0
      end
    end


  else
    digest = case
      when exp=file[:sha256] then Digest::SHA256
      when exp=file[:sha1] then Digest::SHA1
      when exp=file[:md5] then Digest::MD5
    end
    if digest
      is = digest.file(file[:local_path]).hexdigest
      unless is == exp.downcase
        raise "Downloaded file '#{file[:local_path]}' has wrong hash: expected: #{exp} is: #{is}"
      end
    end
  end
end
which(cmd) click to toggle source

From: stackoverflow.com/a/5471032/7672 Thanks, Mislav!

Cross-platform way of finding an executable in the $PATH.

which('ruby') #=> /usr/bin/ruby
# File lib/mini_portile2/mini_portile.rb, line 517
def which(cmd)
  exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
  ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
    exts.each { |ext|
      exe = File.join(path, "#{cmd}#{ext}")
      return exe if File.executable? exe
    }
  end
  return nil
end
with_tempfile(filename, full_path) { |temp_file| ... } click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 761
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.exist?(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_portile2/mini_portile.rb, line 410
def work_path
  Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) }
end