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 55
def self.darwin?
  target_os =~ /darwin/
end
freebsd?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 59
def self.freebsd?
  target_os =~ /freebsd/
end
linux?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 67
def self.linux?
  target_os =~ /linux/
end
mingw?() click to toggle source

GNU MinGW compiled Ruby?

# File lib/mini_portile2/mini_portile.rb, line 46
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 51
def self.mswin?
  target_os =~ /mswin/
end
native_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 83
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 101
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 63
def self.openbsd?
  target_os =~ /openbsd/
end
posix_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 92
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 71
def self.solaris?
  target_os =~ /solaris/
end
target_cpu() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 79
def self.target_cpu
  RbConfig::CONFIG['target_cpu']
end
target_os() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 75
def self.target_os
  RbConfig::CONFIG['target_os']
end
windows?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 41
def self.windows?
  target_os =~ /mswin|mingw/
end

Public Instance Methods

activate() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 244
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 145
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 376
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 194
def compile
  execute('compile', make_cmd)
end
configure() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 179
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 175
def configure_options
  @configure_options ||= configure_defaults
end
configured?() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 211
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 229
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 381
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 131
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 203
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 138
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 368
def include_path
  File.join(path, "include")
end
install() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 198
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 222
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 372
def lib_path
  File.join(path, "lib")
end
make_cmd() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 385
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 283
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 168
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 364
def path
  File.expand_path(port_path)
end
prepare_build_directory() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 124
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 120
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 407
def archives_path
  "#{@target}/archives"
end
computed_options() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 427
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 415
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 423
def configure_prefix
  "--prefix=#{File.expand_path(port_path)}"
end
detect_host() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 529
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 655
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 728
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 733
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 674
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 585
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 575
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 434
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 505
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 642
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 782
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 391
def native_path(path)
  MiniPortile.native_path(path)
end
newer?(target, checkpoint) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 633
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 648
def output(text = "")
  @logger.puts text
  @logger.flush
end
port_path() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 403
def port_path
  "#{@target}/#{@host}/#{@name}/#{@version}"
end
posix_path(path) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 395
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 561
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_exe.shellescape} #{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 549
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 399
def tmp_path
  "tmp/#{@host}/ports/#{@name}/#{@version}"
end
verify_file(file) click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 454
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 518
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 766
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 411
def work_path
  Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) }
end
xzcat_exe() click to toggle source
# File lib/mini_portile2/mini_portile.rb, line 557
def xzcat_exe
  @@xzcat_exe ||= which("xzcat") ? "xzcat" : raise("xzcat not found")
end