mini_portile2-2.7.1/0000755000004100000410000000000014135542067014334 5ustar www-datawww-datamini_portile2-2.7.1/test/0000755000004100000410000000000014135542067015313 5ustar www-datawww-datamini_portile2-2.7.1/test/test_execute.rb0000644000004100000410000000223014135542067020336 0ustar www-datawww-datarequire_relative "helper" class TestExecute < TestCase def setup super @env = {"TEST_ENV_VAR1" => "VAR1_VALUE", "TEST_ENV_VAR2" => "VAR2_VALUE"} @recipe = MiniPortile.new("test_execute", "1.0.0") @log_path = @recipe.send(:tmp_path) FileUtils.mkdir_p File.join(@log_path, "subdir") # normally created by `download` end def test_execute_one_big_string_arg class << @recipe def execute_with_env(env) execute("testenv1", %Q(ruby -e "puts ENV['TEST_ENV_VAR1'].inspect ; exit 0"), {:env => env, :initial_message => false, :debug => true}) end end @recipe.execute_with_env(@env) assert_equal("VAR1_VALUE".inspect, IO.read(File.join(@log_path, "testenv1.log")).chomp) end def test_execute_array_args class << @recipe def execute_with_env(env) execute("testenv2", ["ruby", "-e", "puts ENV['TEST_ENV_VAR2'].inspect"], {:env => env, :initial_message => false, :debug => true}) end end @recipe.execute_with_env(@env) assert_equal("VAR2_VALUE".inspect, IO.read(File.join(@log_path, "testenv2.log")).chomp) end end mini_portile2-2.7.1/test/helper.rb0000644000004100000410000000272414135542067017124 0ustar www-datawww-datarequire 'minitest/autorun' require 'minitest/unit' require 'minitest/spec' require 'minitest/hooks/test' require 'webrick' require 'fileutils' require 'zlib' require 'archive/tar/minitar' require 'fileutils' require 'erb' require 'mini_portile2' class TestCase < Minitest::Test include Minitest::Hooks HTTP_PORT = 23523 attr_accessor :webrick def start_webrick(path) @webrick = WEBrick::HTTPServer.new(:Port => HTTP_PORT, :DocumentRoot => path).tap do |w| Thread.new do w.start end until w.status==:Running sleep 0.1 end end end def stop_webrick if w=@webrick w.shutdown until w.status==:Stop sleep 0.1 end end end def create_tar(tar_path, assets_path, directory) FileUtils.mkdir_p(File.dirname(tar_path)) Zlib::GzipWriter.open(tar_path) do |fdtgz| Dir.chdir(assets_path) do Archive::Tar::Minitar.pack(directory, fdtgz) end end end def work_dir(r=recipe) "tmp/#{r.host}/ports/#{r.name}/#{r.version}/#{r.name}-#{r.version}" end def with_custom_git_dir(dir) old = ENV['GIT_DIR'] ENV['GIT_DIR'] = dir yield ensure ENV['GIT_DIR'] = old end def with_env(env) before = ENV.to_h.dup env.each { |k, v| ENV[k] = v } yield ensure ENV.replace(before) end def without_env(*keys, &blk) before = ENV.to_h.dup keys.flatten.each { |k| ENV.delete(k) } yield ensure ENV.replace(before) end end mini_portile2-2.7.1/test/test_cook.rb0000644000004100000410000001174214135542067017637 0ustar www-datawww-datarequire File.expand_path('../helper', __FILE__) class TestCook < TestCase attr_accessor :assets_path, :tar_path, :recipe def before_all super @assets_path = File.expand_path("../assets", __FILE__) @tar_path = File.expand_path("../../tmp/test mini portile-1.0.0.tar.gz", __FILE__) FileUtils.rm_rf("tmp") # remove any previous test files create_tar(@tar_path, @assets_path, "test mini portile-1.0.0") start_webrick(File.dirname(@tar_path)) @recipe = MiniPortile.new("test mini portile", "1.0.0").tap do |recipe| recipe.files << "http://localhost:#{HTTP_PORT}/#{ERB::Util.url_encode(File.basename(@tar_path))}" recipe.patch_files << File.join(@assets_path, "patch 1.diff") recipe.configure_options << "--option=\"path with 'space'\"" git_dir = File.join(@assets_path, "git") with_custom_git_dir(git_dir) do recipe.cook end end end def after_all super stop_webrick FileUtils.rm_rf("tmp") # remove test files end def test_download download = "ports/archives/test%20mini%20portile-1.0.0.tar.gz" assert File.exist?(download), download end def test_untar configure = File.join(work_dir, "configure") assert File.exist?(configure), configure assert_match( /^#!\/bin\/sh/, IO.read(configure) ) end def test_patch patch1 = File.join(work_dir, "patch 1.txt") assert File.exist?(patch1), patch1 assert_match( /^\tchange 1/, IO.read(patch1) ) end def test_configure txt = File.join(work_dir, "configure.txt") assert File.exist?(txt), txt opts = recipe.configure_options + ["--prefix=#{recipe.path}"] assert_equal( opts.inspect, IO.read(txt).chomp ) end def test_compile txt = File.join(work_dir, "compile.txt") assert File.exist?(txt), txt assert_equal( ["all"].inspect, IO.read(txt).chomp ) end def test_install txt = File.join(work_dir, "install.txt") assert File.exist?(txt), txt assert_equal( ["install"].inspect, IO.read(txt).chomp ) end end class TestCookConfiguration < TestCase def test_make_command_configuration without_env("MAKE") do assert_equal("make", MiniPortile.new("test", "1.0.0").make_cmd) assert_equal("xyzzy", MiniPortile.new("test", "1.0.0", make_command: "xyzzy").make_cmd) end with_env("MAKE"=>"asdf") do assert_equal("asdf", MiniPortile.new("test", "1.0.0").make_cmd) assert_equal("asdf", MiniPortile.new("test", "1.0.0", make_command: "xyzzy").make_cmd) end end def test_gcc_command_configuration without_env("CC") do expected_compiler = RbConfig::CONFIG["CC"] || "gcc" assert_equal(expected_compiler, MiniPortile.new("test", "1.0.0").gcc_cmd) assert_equal("xyzzy", MiniPortile.new("test", "1.0.0", gcc_command: "xyzzy").gcc_cmd) end with_env("CC"=>"asdf") do assert_equal("asdf", MiniPortile.new("test", "1.0.0").gcc_cmd) assert_equal("asdf", MiniPortile.new("test", "1.0.0", gcc_command: "xyzzy").gcc_cmd) end end end class TestCookWithBrokenGitDir < TestCase # # this is a test for #69 # https://github.com/flavorjones/mini_portile/issues/69 # attr_accessor :assets_path, :tar_path, :recipe def before_all super @assets_path = File.expand_path("../assets", __FILE__) @tar_path = File.expand_path("../../tmp/test-mini-portile-1.0.0.tar.gz", __FILE__) @git_dir = File.join(@assets_path, "git-broken") FileUtils.rm_rf @git_dir FileUtils.mkdir_p @git_dir Dir.chdir(@git_dir) do File.open ".git", "w" do |f| f.write "gitdir: /nonexistent" end end create_tar(@tar_path, @assets_path, "test mini portile-1.0.0") @recipe = MiniPortile.new("test mini portile", "1.0.0").tap do |recipe| recipe.files << "file://#{@tar_path}" recipe.patch_files << File.join(@assets_path, "patch 1.diff") recipe.configure_options << "--option=\"path with 'space'\"" end Dir.chdir(@git_dir) do @recipe.cook end end def after_all FileUtils.rm_rf @git_dir end def test_patch Dir.chdir(@git_dir) do patch1 = File.join(work_dir, "patch 1.txt") assert File.exist?(patch1), patch1 assert_match( /^\tchange 1/, IO.read(patch1) ) end end end class TestCookAgainstSourceDirectory < TestCase attr_accessor :recipe def setup super @recipe ||= MiniPortile.new("test mini portile", "1.0.0").tap do |recipe| recipe.source_directory = File.expand_path("../assets/test mini portile-1.0.0", __FILE__) end end def test_source_directory recipe.cook path = File.join(work_dir, "configure.txt") assert(File.exist?(path)) assert_equal((recipe.configure_options + ["--prefix=#{recipe.path}"]).inspect, File.read(path).chomp); path = File.join(work_dir, "compile.txt") assert(File.exist?(path)) assert_equal("[\"all\"]", File.read(path).chomp); path = File.join(work_dir, "install.txt") assert(File.exist?(path)) assert_equal("[\"install\"]", File.read(path).chomp); end end mini_portile2-2.7.1/test/test_digest.rb0000644000004100000410000001643014135542067020162 0ustar www-datawww-datarequire File.expand_path('../helper', __FILE__) class TestDigest < TestCase attr :assets_path, :tar_path, :recipe def before_all super @assets_path = File.expand_path("../assets", __FILE__) @tar_path = File.expand_path("../../tmp/test-digest-1.0.0.tar.gz", __FILE__) # remove any previous test files FileUtils.rm_rf("tmp") create_tar(@tar_path, @assets_path, "test mini portile-1.0.0") start_webrick(File.dirname(@tar_path)) end def after_all super stop_webrick # leave test files for inspection end def setup super FileUtils.rm_rf("ports/archives") @recipe = MiniPortile.new("test-digest", "1.0.0") end def download_with_digest(key, klass) @recipe.files << { :url => "http://localhost:#{webrick.config[:Port]}/#{ERB::Util.url_encode(File.basename(tar_path))}", key => klass.file(tar_path).hexdigest, } @recipe.download end def download_with_wrong_digest(key) @recipe.files << { :url => "http://localhost:#{webrick.config[:Port]}/#{ERB::Util.url_encode(File.basename(tar_path))}", key => "0011223344556677", } assert_raises(RuntimeError){ @recipe.download } end def test_sha256 download_with_digest(:sha256, Digest::SHA256) end def test_wrong_sha256 download_with_wrong_digest(:sha256) end def test_sha1 download_with_digest(:sha1, Digest::SHA1) end def test_wrong_sha1 download_with_wrong_digest(:sha1) end def test_md5 download_with_digest(:md5, Digest::MD5) end def test_wrong_md5 download_with_wrong_digest(:md5) end def public_key <<-KEY -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 mI0EVwUhJQEEAMYxFhgaAdM2Ul5r+XfpqAaI7SOxB14eRjhFjhchy4ylgVxetyLq di3zeANXBIHsLBl7quYTlnmhJr/+GQRkCnXWiUp0tJsBVzGM3puK7c534gakEUH6 AlDtj5p3IeygzSyn8u7KORv+ainXfhwkvTO04mJmxAb2uT8ngKYFdPa1ABEBAAG0 J1Rlc3QgTWluaXBvcnRpbGUgPHRlc3RAbWluaXBvcnRpbGUub3JnPoi4BBMBAgAi BQJXBSElAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBl6D5JZMNwswAK A/90Cdb+PX21weBR2Q6uR06M/alPexuXXyJL8ZcwbQMJ/pBBgcS5/h1+rQkBI/CN qpXdDlw2Xys2k0sNwdjIw3hmYRzBrddXlCSW3Sifq/hS+kfPZ1snQmIjCgy1Xky5 QGCcPUxBUxzmra88LakkDO+euKK3hcrfeFIi611lTum1NLiNBFcFISUBBADoyY6z 2PwH3RWUbqv0VX1s3/JO3v3xMjCRKPlFwsNwLTBtZoWfR6Ao1ajeCuZKfzNKIQ2I rn86Rcqyrq4hTj+7BTWjkIPOBthjiL1YqbEBtX7jcYRkYvdQz/IG2F4zVV6X4AAR Twx7qaXNt67ArzbHCe5gLNRUK6e6OArkahMv7QARAQABiJ8EGAECAAkFAlcFISUC GwwACgkQZeg+SWTDcLNFiwP/TR33ClqWOz0mpjt0xPEoZ0ORmV6fo4sjjzgQoHH/ KTdsabJbGp8oLQGW/mx3OxgbsAkyZymb5H5cjaF4HtSd4cxI5t1C9ZS/ytN8pqfR e29SBje8DAAJn2l57s2OddXLPQ0DUwCcdNEaqgHwSk/Swxc7K+IpfvjLKHKUZZBP 4Ko= =SVWi -----END PGP PUBLIC KEY BLOCK----- KEY end def test_with_valid_gpg_signature data_file = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'gpg-fixtures', 'data')) @recipe.files << { :url => "file://#{data_file}", :gpg => { :key => public_key, :signature_url => "file://#{data_file}.asc" } } @recipe.download end def test_optional_gpg_signature_url data_file = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'gpg-fixtures', 'data')) @recipe.files << { :url => "file://#{data_file}", :gpg => { :key => public_key } } @recipe.download end def test_with_invalid_gpg_signature data_file = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'gpg-fixtures', 'data')) @recipe.files << { :url => "file://#{data_file}", :gpg => { :key => public_key, :signature_url => "file://#{data_file}.invalid.asc" } } exception = assert_raises(RuntimeError){ @recipe.download } assert_equal("signature mismatch", exception.message) end def test_with_invalid_key data_file = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'gpg-fixtures', 'data')) @recipe.files << { :url => "file://#{data_file}", :gpg => { :key => "thisisaninvalidkey", :signature_url => "file://#{data_file}.asc" } } exception = assert_raises(RuntimeError){ @recipe.download } assert_equal("invalid gpg key provided", exception.message) end def test_with_different_key_than_one_used_to_sign puts "################" key = <<-KEY -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 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 =4JAR -----END PGP PUBLIC KEY BLOCK----- KEY data_file = File.expand_path(File.join(File.dirname(__FILE__), 'assets', 'gpg-fixtures', 'data')) @recipe.files << { :url => "file://#{data_file}", :gpg => { :key => key, :signature_url => "file://#{data_file}.asc" } } exception = assert_raises(RuntimeError){ @recipe.download } assert_equal("signature mismatch", exception.message) end end mini_portile2-2.7.1/test/assets/0000755000004100000410000000000014135542067016615 5ustar www-datawww-datamini_portile2-2.7.1/test/assets/gpg-fixtures/0000755000004100000410000000000014135542067021241 5ustar www-datawww-datamini_portile2-2.7.1/test/assets/gpg-fixtures/data0000644000004100000410000000000514135542067022070 0ustar www-datawww-datatest mini_portile2-2.7.1/test/assets/gpg-fixtures/data.asc0000644000004100000410000000045314135542067022644 0ustar www-datawww-data-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iJwEAAECAAYFAlcFOD8ACgkQZeg+SWTDcLNIswP/XvVRoJ+eQ2u2v+WjXdBBKBSW pzM216aJPRBxPl98xNUUKjqga+tjKmIHJn5T4CIxHqis1toPxtE5tKnc6cVO1aqY bCUfkWyt/A3qRHQuniRUWSBKZWdk+j3AopTpd3i/r/s0pDj3bMHJ7bDOTsEskNcM KpgFfNM1ieFRQmIWPWg= =kbKc -----END PGP SIGNATURE----- mini_portile2-2.7.1/test/assets/gpg-fixtures/data.invalid.asc0000644000004100000410000000045314135542067024271 0ustar www-datawww-data-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iJwEAQECAAYFAlcFLEgACgkQZeg+SWTDcLPVwgQAg8KTI91Ryx38YplzgWV9tUPj o7J7IEzb8faE7m2mgtq8m62DvA4h/PJzmbh1EJJ4VkO+A4O2LVh/bTgnyYXv+kMu sEmvK35PnAC8r7pv98VSbMEXyV/rK3+uGhTvnXZYkULvMVYkN/EHIh2bCQJ3R14X MY8El95QST8/dR/yBkw= =qbod -----END PGP SIGNATURE----- mini_portile2-2.7.1/test/assets/git/0000755000004100000410000000000014135542067017400 5ustar www-datawww-datamini_portile2-2.7.1/test/assets/git/config0000644000004100000410000000012014135542067020561 0ustar www-datawww-data[core] whitespace=tab-in-indent,-indent-with-non-tab [apply] whitespace=fix mini_portile2-2.7.1/test/assets/test-cmake-1.0/0000755000004100000410000000000014135542067021146 5ustar www-datawww-datamini_portile2-2.7.1/test/assets/test-cmake-1.0/CMakeLists.txt0000644000004100000410000000047214135542067023711 0ustar www-datawww-data# CMakeLists files in this project can # refer to the root source directory of the project as ${HELLO_SOURCE_DIR} and # to the root binary directory of the project as ${HELLO_BINARY_DIR}. cmake_minimum_required (VERSION 2.8.7) project (HELLO) add_executable (hello hello.c) install (TARGETS hello DESTINATION bin) mini_portile2-2.7.1/test/assets/test-cmake-1.0/hello.c0000644000004100000410000000006114135542067022412 0ustar www-datawww-dataint main(int argc, char** argv) { return 0 ; } mini_portile2-2.7.1/test/assets/test-download-archive.tar.gz0000644000004100000410000000017114135542067024146 0ustar www-datawww-data1 0%'y:A@[[AAp{aaOi3 噹3B.놮%buY90[Or\~Gpe(mini_portile2-2.7.1/test/assets/test mini portile-1.0.0/0000755000004100000410000000000014135542067022602 5ustar www-datawww-datamini_portile2-2.7.1/test/assets/test mini portile-1.0.0/configure0000755000004100000410000000026414135542067024513 0ustar www-datawww-data#!/bin/sh set -e ruby -e "p ARGV" -- "$@" > configure.txt cat <Makefile all: ruby -e "p ARGV" -- "\$@" > compile.txt install: ruby -e "p ARGV" -- "\$@" > install.txt EOT mini_portile2-2.7.1/test/assets/patch 1.diff0000644000004100000410000000022214135542067020663 0ustar www-datawww-datadiff --git "a/patch 1.txt" "b/patch 1.txt" new file mode 100644 index 0000000..70885e4 --- /dev/null +++ "b/patch 1.txt" @@ -0,0 +1 @@ + change 1 mini_portile2-2.7.1/test/test_cmake.rb0000644000004100000410000000525014135542067017761 0ustar www-datawww-datarequire File.expand_path('../helper', __FILE__) class TestCMake < TestCase attr_accessor :assets_path, :tar_path, :recipe def before_all super @assets_path = File.expand_path("../assets", __FILE__) @tar_path = File.expand_path("../../tmp/test-cmake-1.0.tar.gz", __FILE__) # remove any previous test files FileUtils.rm_rf("tmp") create_tar(@tar_path, @assets_path, "test-cmake-1.0") start_webrick(File.dirname(@tar_path)) @recipe = MiniPortileCMake.new("test-cmake", "1.0").tap do |recipe| recipe.files << "http://localhost:#{HTTP_PORT}/#{ERB::Util.url_encode(File.basename(@tar_path))}" recipe.patch_files << File.join(@assets_path, "patch 1.diff") git_dir = File.join(@assets_path, "git") with_custom_git_dir(git_dir) do recipe.cook end end end def after_all super stop_webrick # leave test files for inspection end def exe_name case when MiniPortile.windows? then "hello.exe" else "hello" end end def test_cmake_inherits_from_base assert(MiniPortileCMake <= MiniPortile) end def test_configure cmakecache = File.join(work_dir, "CMakeCache.txt") assert File.exist?(cmakecache), cmakecache assert_includes(IO.read(cmakecache), "CMAKE_INSTALL_PREFIX:PATH=#{recipe.path}") end def test_compile binary = File.join(work_dir, exe_name) assert File.exist?(binary), binary end def test_install binary = File.join(recipe.path, "bin", exe_name) assert File.exist?(binary), binary end end class TestCMakeConfig < TestCase def test_make_command_configuration MiniPortile.stub(:mswin?, false) do without_env("MAKE") do assert_equal("make", MiniPortileCMake.new("test", "1.0.0").make_cmd) assert_equal("xyzzy", MiniPortileCMake.new("test", "1.0.0", make_command: "xyzzy").make_cmd) end with_env("MAKE"=>"asdf") do assert_equal("asdf", MiniPortileCMake.new("test", "1.0.0").make_cmd) assert_equal("asdf", MiniPortileCMake.new("test", "1.0.0", make_command: "xyzzy").make_cmd) end end MiniPortile.stub(:mswin?, true) do assert_equal("nmake", MiniPortileCMake.new("test", "1.0.0").make_cmd) end end def test_cmake_command_configuration without_env("CMAKE") do assert_equal("cmake", MiniPortileCMake.new("test", "1.0.0").cmake_cmd) assert_equal("xyzzy", MiniPortileCMake.new("test", "1.0.0", cmake_command: "xyzzy").cmake_cmd) end with_env("CMAKE"=>"asdf") do assert_equal("asdf", MiniPortileCMake.new("test", "1.0.0").cmake_cmd) assert_equal("asdf", MiniPortileCMake.new("test", "1.0.0", cmake_command: "xyzzy").cmake_cmd) end end end mini_portile2-2.7.1/test/test_download.rb0000644000004100000410000000337314135542067020514 0ustar www-datawww-datarequire File.expand_path('../helper', __FILE__) describe "recipe download" do include Minitest::Hooks attr :recipe def server_must_receive_connection(connections = 3, &block) request_count = 0 server = TCPServer.open('localhost', TestCase::HTTP_PORT) thread = Thread.new do connections.times do conn = server.accept request_count += 1 conn.puts "CONNECTION SUCESSFULLY MADE" rescue SystemCallError conn.close end end begin block.call ensure thread.kill server.close end request_count.must_be :>, 0 end before do @request_count = 0 @recipe = MiniPortile.new("test-download", "1.1.1") end describe "urls" do it "ftp" do @recipe.files << "ftp://localhost:#{TestCase::HTTP_PORT}/foo" server_must_receive_connection 1 do @recipe.download end end it "handles http" do @recipe.files << "http://localhost:#{TestCase::HTTP_PORT}/foo" server_must_receive_connection 3 do @recipe.download end end it "handles https" do @recipe.files << "https://localhost:#{TestCase::HTTP_PORT}/foo" server_must_receive_connection 3 do @recipe.download end end it "file" do dest = "ports/archives/test-download-archive.tar.gz" FileUtils.rm_f dest path = File.expand_path(File.join(File.dirname(__FILE__), "assets", "test-download-archive.tar.gz")) @recipe.files << "file://#{path}" @recipe.download assert File.exist?(dest) Digest::MD5.file(dest).hexdigest.must_equal "ee0e9f44e72213015ef976d5ac23931d" end it "other" do @recipe.files << "foo://foo" proc { @recipe.download }.must_raise ArgumentError end end end mini_portile2-2.7.1/test/test_proxy.rb0000644000004100000410000000675314135542067020073 0ustar www-datawww-data# Encoding: utf-8 require File.expand_path('../helper', __FILE__) require 'socket' class TestProxy < TestCase def with_dummy_proxy(username=nil, password=nil) gs = TCPServer.open('localhost', 0) th = Thread.new do s = gs.accept gs.close begin req = ''.dup while (l=s.gets) && !l.chomp.empty? req << l end req ensure s.close end end if username && password yield "http://#{ERB::Util.url_encode(username)}:#{ERB::Util.url_encode(password)}@localhost:#{gs.addr[1]}" else yield "http://localhost:#{gs.addr[1]}" end # Set timeout for reception of the request Thread.new do sleep 1 th.kill end th.value end def setup # remove any download files FileUtils.rm_rf("port/archives") end def assert_proxy_auth(expected, request) if request =~ /^Proxy-Authorization: Basic (.*)/ assert_equal 'user: @name:@12: üMp', $1.unpack("m")[0].force_encoding(__ENCODING__) else flunk "No authentication request" end end def test_http_proxy recipe = MiniPortile.new("test http_proxy", "1.0.0") recipe.files << "http://myserver/path/to/tar.gz" request = with_dummy_proxy do |url, thread| ENV['http_proxy'] = url recipe.download rescue RuntimeError ENV.delete('http_proxy') end assert_match(/GET http:\/\/myserver\/path\/to\/tar.gz/, request) end def test_http_proxy_with_basic_auth recipe = MiniPortile.new("test http_proxy", "1.0.0") recipe.files << "http://myserver/path/to/tar.gz" request = with_dummy_proxy('user: @name', '@12: üMp') do |url, thread| ENV['http_proxy'] = url recipe.download rescue RuntimeError ENV.delete('http_proxy') end assert_match(/GET http:\/\/myserver\/path\/to\/tar.gz/, request) assert_proxy_auth 'user: @name:@12: üMp', request end def test_https_proxy recipe = MiniPortile.new("test https_proxy", "1.0.0") recipe.files << "https://myserver/path/to/tar.gz" request = with_dummy_proxy do |url, thread| ENV['https_proxy'] = url recipe.download rescue RuntimeError ENV.delete('https_proxy') end assert_match(/CONNECT myserver:443/, request) end def test_https_proxy_with_basic_auth recipe = MiniPortile.new("test https_proxy", "1.0.0") recipe.files << "https://myserver/path/to/tar.gz" request = with_dummy_proxy('user: @name', '@12: üMp') do |url, thread| ENV['https_proxy'] = url recipe.download rescue RuntimeError ENV.delete('https_proxy') end assert_match(/CONNECT myserver:443/, request) assert_proxy_auth 'user: @name:@12: üMp', request end def test_ftp_proxy recipe = MiniPortile.new("test ftp_proxy", "1.0.0") recipe.files << "ftp://myserver/path/to/tar.gz" request = with_dummy_proxy do |url, thread| ENV['ftp_proxy'] = url recipe.download rescue RuntimeError ENV.delete('ftp_proxy') end assert_match(/GET ftp:\/\/myserver\/path\/to\/tar.gz/, request) end def test_ftp_proxy_with_basic_auth recipe = MiniPortile.new("test ftp_proxy", "1.0.0") recipe.files << "ftp://myserver/path/to/tar.gz" request = with_dummy_proxy('user: @name', '@12: üMp') do |url, thread| ENV['ftp_proxy'] = url recipe.download rescue RuntimeError ENV.delete('ftp_proxy') end assert_match(/GET ftp:\/\/myserver\/path\/to\/tar.gz/, request) assert_proxy_auth 'user: @name:@12: üMp', request end end mini_portile2-2.7.1/README.md0000644000004100000410000002363114135542067015620 0ustar www-datawww-data# MiniPortile This documents versions 2 and up, for which the require file was renamed to `mini_portile2`. For mini_portile versions 0.6.x and previous, please visit [the v0.6.x branch](https://github.com/flavorjones/mini_portile/tree/v0.6.x). [![Continuous Integration](https://github.com/flavorjones/mini_portile/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/flavorjones/mini_portile/actions/workflows/ci.yml) [![Tidelift dependencies](https://tidelift.com/badges/package/rubygems/mini_portile2)](https://tidelift.com/subscription/pkg/rubygems-mini.portile2?utm_source=undefined&utm_medium=referral&utm_campaign=readme) * Documentation: http://www.rubydoc.info/github/flavorjones/mini_portile * Source Code: https://github.com/flavorjones/mini_portile * Bug Reports: https://github.com/flavorjones/mini_portile/issues This project is a minimalistic implementation of a port/recipe system **for developers**. Because _"Works on my machine"_ is unacceptable for a library maintainer. ## Not Another Package Management System `mini_portile2` is not a general package management system. It is not aimed to replace apt, macports or homebrew. It's intended primarily to make sure that you, as the developer of a library, can reproduce a user's dependencies and environment by specifying a specific version of an underlying dependency that you'd like to use. So, if a user says, "This bug happens on my system that uses libiconv 1.13.1", `mini_portile2` should make it easy for you to download, compile and link against libiconv 1.13.1; and run your test suite against it. This scenario might be simplified with something like this: ``` rake compile LIBICONV_VERSION=1.13.1 ``` (For your homework, you can make libiconv version be taken from the appropriate `ENV` variables.) ## Sounds easy, but where's the catch? At this time `mini_portile2` only supports **autoconf**- or **configure**-based projects. (That is, it assumes the library you want to build contains a `configure` script, which all the autoconf-based libraries do.) As of v2.2.0, there is experimental support for **CMake**-based projects. We welcome your feedback on this, particularly for Windows platforms. ### How to use (for autoconf projects) Now that you know the catch, and you're still reading this, here is a quick example: ```ruby gem "mini_portile2", "~> 2.0.0" # NECESSARY if used in extconf.rb. see below. require "mini_portile2" recipe = MiniPortile.new("libiconv", "1.13.1") recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz"] recipe.cook recipe.activate ``` The gem version constraint makes sure that your extconf.rb is protected against possible backwards-incompatible changes to `mini_portile2`. This constraint is REQUIRED if you're using `mini_portile2` within a gem installation process (e.g., extconf.rb), because Bundler doesn't enforce gem version constraints at install-time (only at run-time. `#cook` will download, extract, patch, configure and compile the library into a namespaced structure. `#activate` ensures GCC will find this library and prefer it over a system-wide installation. Some keyword arguments can be passed to the constructor to configure the commands used: #### `gcc_command` The compiler command that is used is configurable, and in order of preference will use: - the `CC` environment variable (if present) - the `gcc_command` value passed in to the constructor - `RbConfig::CONFIG["CC"]` - `"gcc"` You can pass it in like so: ``` ruby MiniPortile.new("libiconv", "1.13.1", gcc_command: "cc") ``` #### `make_command` The configuration/make command that is used is configurable, and in order of preference will use: - the `MAKE` environment variable (if present) - the `make_command` value passed in to the constructor - the `make` environment variable (if present) - `"make"` You can pass it in like so: ``` ruby MiniPortile.new("libiconv", "1.13.1", make_command: "nmake") ``` ### How to use (for cmake projects) Same as above, but instead of `MiniPortile.new`, call `MiniPortileCMake.new`. #### `make_command` This is configurable as above, except for Windows systems where it's hardcoded to `"nmake"`. #### `cmake_command` The cmake command used is configurable, and in order of preference will use: - the `CMAKE` environment variable (if present) - the `cmake_command` value passed in to the constructor - `"cmake"` You can pass it in like so: ``` ruby MiniPortileCMake.new("libfoobar", "1.3.5", cmake_command: "cmake3") ``` ### Local source directories Instead of downloading a remote file, you can also point mini_portile2 at a local source directory. In particular, this may be useful for testing or debugging: ``` ruby gem "mini_portile2", "~> 2.0.0" # NECESSARY if used in extconf.rb. see below. require "mini_portile2" recipe = MiniPortile.new("libiconv", "1.13.1") recipe.source_directory = "/path/to/local/source/for/library-1.2.3" ``` ### Directory Structure Conventions `mini_portile2` follows the principle of **convention over configuration** and established a folder structure where is going to place files and perform work. Take the above example, and let's draw some picture: ``` mylib |-- ports | |-- archives | | `-- libiconv-1.13.1.tar.gz | `-- | `-- libiconv | `-- 1.13.1 | |-- bin | |-- include | `-- lib `-- tmp `-- `-- ports ``` In above structure, `` refers to the architecture that represents the operating system you're using (e.g. i686-linux, i386-mingw32, etc). Inside the platform folder, `mini_portile2` will store the artifacts that result from the compilation process. The library is versioned so you can keep multiple versions around on disk without clobbering anything. `archives` is where downloaded source files are cached. It is recommended you avoid trashing that folder to avoid downloading the same file multiple times (save bandwidth, save the world). `tmp` is where compilation is performed and can be safely discarded. Use the recipe's `#path` to obtain the full path to the installation directory: ```ruby recipe.cook recipe.path # => /home/luis/projects/myapp/ports/i686-linux/libiconv/1.13.1 ``` ### How can I combine this with my compilation task? In the simplest case, your rake `compile` task will depend on `mini_portile2` compilation and most important, activation. Example: ```ruby task :libiconv do recipe = MiniPortile.new("libiconv", "1.13.1") recipe.files << { url: "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.13.1.tar.gz"], sha256: "55a36168306089009d054ccdd9d013041bfc3ab26be7033d107821f1c4949a49" } checkpoint = ".#{recipe.name}-#{recipe.version}.installed" unless File.exist?(checkpoint) recipe.cook touch checkpoint end recipe.activate end task :compile => [:libiconv] do # ... your library's compilation task ... end ``` The above example will: * **download** and verify integrity the sources only once * **compile** the library only once (using a timestamp file) * ensure compiled library is **activated** * make the compile task depend upon compiled library activation As an exercise for the reader, you could specify the libiconv version in an environment variable or a configuration file. ### Download verification MiniPortile supports HTTPS, HTTP, FTP and FILE sources for download. The integrity of the downloaded file can be verified per hash value or PGP signature. This is particular important for untrusted sources (non-HTTPS). #### Hash digest verification MiniPortile can verify the integrity of the downloaded file per SHA256, SHA1 or MD5 hash digest. ```ruby recipe.files << { url: "http://your.host/file.tar.bz2", sha256: "<32 byte hex value>", } ``` #### PGP signature verification MiniPortile can also verify the integrity of the downloaded file per PGP signature. ```ruby public_key = <<-EOT -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 mQENBE7SKu8BCADQo6x4ZQfAcPlJMLmL8zBEBUS6GyKMMMDtrTh3Yaq481HB54oR [...] -----END PGP PUBLIC KEY BLOCK----- EOT recipe.files << { url: "http://your.host/file.tar.bz2", gpg: { key: public_key, signature_url: "http://your.host/file.tar.bz2.sig" } } ``` Please note, that the `gpg` executable is required to verify the signature. It is therefore recommended to use the hash verification method instead of PGP, when used in `extconf.rb` while `gem install`. ### Native and/or Cross Compilation The above example covers the normal use case: compiling dependencies natively. `MiniPortile` also covers another use case, which is the cross-compilation of the dependencies to be used as part of a binary gem compilation. It is the perfect complementary tool for [`rake-compiler`](https://github.com/rake-compiler/rake-compiler) and its `cross` rake task. Depending on your usage of `rake-compiler`, you will need to use `host` to match the installed cross-compiler toolchain. Please refer to the examples directory for simplified and practical usage. ### Supported Scenarios As mentioned before, `MiniPortile` requires a GCC compiler toolchain. This has been tested against Ubuntu, OSX and even Windows (RubyInstaller with DevKit) ## Support The bug tracker is available here: * https://github.com/flavorjones/mini_portile/issues Consider subscribing to [Tidelift][tidelift] which provides license assurances and timely security notifications for your open source dependencies, including Loofah. [Tidelift][tidelift] subscriptions also help the Loofah maintainers fund our [automated testing](https://ci.nokogiri.org) which in turn allows us to ship releases, bugfixes, and security updates more often. [tidelift]: https://tidelift.com/subscription/pkg/rubygems-mini.portile2?utm_source=rubygems-mini.portile2&utm_medium=referral&utm_campaign=enterprise ## Security See [`SECURITY.md`](SECURITY.md) for vulnerability reporting details. ## License This library is licensed under MIT license. Please see LICENSE.txt for details. mini_portile2-2.7.1/CHANGELOG.md0000644000004100000410000002006114135542067016144 0ustar www-datawww-data## mini_portile changelog ### 2.7.1 / 2021-10-20 #### Packaging A test artifact that has been included in the gem was being flagged by some users' security scanners because it wasn't a real tarball. That artifact has been updated to be a real tarball. [#108] ### 2.7.0 / 2021-08-31 ### Added The commands used for "make", "compile", and "cmake" are configurable via keyword arguments. [#107] (Thanks, @cosmo0920!) ### 2.6.1 / 2021-05-31 #### Dependencies Make `net-ftp` an optional dependency, since requiring it as a hard dependency in v2.5.2 caused warnings to be emitted by Ruby 2.7 and earlier. A warning message is emitted if FTP functionality is called and `net-ftp` isn't available; this should only happen in Ruby 3.1 and later. ### 2.5.3 / 2021-05-31 #### Dependencies Make `net-ftp` an optional dependency, since requiring it as a hard dependency in v2.5.2 caused warnings to be emitted by Ruby 2.7 and earlier. A warning message is emitted if FTP functionality is called and `net-ftp` isn't available; this should only happen in Ruby 3.1 and later. ### 2.6.0 / 2021-05-31 ### Added Recipes may build against a local directory by specifying `source_directory` instead of `files`. In particular, this may be useful for debugging problems with the upstream dependency (e.g., use `git bisect` in a local clone) or for continuous integration with upstream HEAD. ### 2.5.2 / 2021-05-28 #### Dependencies Add `net-ftp` as an explicit dependency to accommodate the upcoming Ruby 3.1 changes that move this and other gems out of the "default" gem set and into the "bundled" gem set. See https://bugs.ruby-lang.org/issues/17873 [#101] ### 2.5.1 / 2021-04-28 #### Dependencies This release ends support for ruby < 2.3.0. If you're on 2.2.x or earlier, we strongly suggest that you find the time to upgrade, because [official support for Ruby 2.2 ended on 2018-03-31](https://www.ruby-lang.org/en/news/2018/06/20/support-of-ruby-2-2-has-ended/). #### Enhancements * `MiniPortile.execute` now takes an optional `:env` hash, which is merged into the environment variables for the subprocess. Likely this is only useful for specialized use cases. [#99] * Experimental support for cmake-based projects extended to Windows. (Thanks, @larskanis!) ### 2.5.0 / 2020-02-24 #### Enhancements * When verifying GPG signatures, remove all imported pubkeys from keyring [#90] (Thanks, @hanazuki!) ### 2.4.0 / 2018-12-02 #### Enhancements * Skip progress report when Content-Length is unavailable. [#85] (Thanks, @eagletmt!) ### 2.3.0 / 2017-09-13 #### Enhancements * Verify checksums of files at extraction time (in addition to at download time). (#56) * Clarify error message if a `tar` command can't be found. (#81) ### 2.2.0 / 2017-06-04 #### Enhancements * Remove MD5 hashing of configure options, not avialbale in FIPS mode. (#78) * Add experimental support for cmake-based projects. * Retry on HTTP failures during downloads. [#63] (Thanks, @jtarchie and @jvshahid!) * Support Ruby 2.4 frozen string literals. * Support applying patches for users with misconfigured git worktree. [#69] * Support gpg signature verification of download resources. ### 2.1.0 / 2016-01-06 #### Enhancements * Add support for `file:` protocol for tarballs #### Bugfixes * Raise exception on unsupported URI protocols * Ignore git whitespace config when patching (Thanks, @e2!) (#67) ### 2.0.0 / 2015-11-30 Many thanks to @larskanis, @knu, and @kirikak2, who all contributed code, ideas, or both to this release. Note that the 0.7.0.rc* series was not released as 0.7.0 final, and instead became 2.0.0 due to backwards-incompatible behavioral changes which can appear because rubygems doesn't enforce loading the declared dependency version at installation-time (only run-time). If you use MiniPortile in an `extconf.rb` file, please make sure you're setting a gem version constraint before `require "mini_portile2"` . Note also that 2.0.0 doesn't include the backwards-compatible "escaped string" behavior from 0.7.0.rc3. #### Enhancements * In patch task, use git(1) or patch(1), whichever is available. * Append outputs to patch.log instead of clobbering it for every patch command. * Take `configure_options` literally without running a subshell. This changes allows for embedded spaces in a path, among other things. Please unescape `configure_options` where you have been doing it yourself. * Print last 20 lines of the given log file, for convenience. * Allow SHA1, SHA256 and MD5 hash verification of downloads #### Bugfixes * Fix issue when proxy username/password use escaped characters. * Fix use of https and ftp proxy. ### 0.7.0.rc4 / 2015-08-24 * Updated tests for Windows. No functional change. Final release candidate? ### 0.7.0.rc3 / 2015-08-24 * Restore backwards-compatible behavior with respect to escaped strings. ### 0.7.0.rc2 / 2015-08-24 * Restore support for Ruby 1.9.2 * Add Ruby 2.0.0 and Ruby 2.1.x to Appveyor suite ### 0.7.0.rc1 / 2015-08-24 Many thanks to @larskanis, @knu, and @kirikak2, who all contributed code, ideas, or both to this release. #### Enhancements * In patch task, use git(1) or patch(1), whichever is available. * Append outputs to patch.log instead of clobbering it for every patch command. * Take `configure_options` literally without running a subshell. This changes allows for embedded spaces in a path, among other things. Please unescape `configure_options` where you have been doing it yourself. * Print last 20 lines of the given log file, for convenience. * Allow SHA1, SHA256 and MD5 hash verification of downloads #### Bugfixes * Fix issue when proxy username/password use escaped characters. * Fix use of https and ftp proxy. ### 0.6.2 / 2014-12-30 * Updated gemspec, license and README to reflect new maintainer. ### 0.6.1 / 2014-08-03 * Enhancements: * Expand path to logfile to easier debugging on failures. Pull #33 [marvin2k] ### 0.6.0 / 2014-04-18 * Enhancements: * Add default cert store and custom certs from `SSL_CERT_FILE` if present. This increases compatibility with Ruby 1.8.7. * Bugfixes: * Specify Accept-Encoding to make sure a raw file content is downloaded. Pull #30. [knu] * Internal: * Improve examples and use them as test harness. ### 0.5.3 / 2014-03-24 * Bugfixes: * Shell escape paths in tar command. Pull #29. [quickshiftin] * Support older versions of tar that cannot auto-detect the compression type. Pull #27. Closes #21. [b-dean] * Try RbConfig's CC before fall back to 'gcc'. Ref #28. ### 0.5.2 / 2013-10-23 * Bugfixes: * Change tar detection order to support NetBSD 'gtar'. Closes #24 * Trick 'git-apply' when applying patches on nested Git checkouts. [larskanis] * Respect ENV's MAKE before fallback to 'make'. [larskanis] * Respect ENV's CC variable before fallback to 'gcc'. * Avoid non-ASCII output of GCC cause host detection issues. Closes #22 ### 0.5.1 / 2013-07-07 * Bugfixes: * Detect tar executable without shelling out. [jtimberman] ### 0.5.0 / 2012-11-17 * Enhancements: * Allow patching extracted files using `git apply`. [metaskills] ### 0.4.1 / 2012-10-24 * Bugfixes: * Syntax to process FTp binary chunks differs between Ruby 1.8.7 and 1.9.x ### 0.4.0 / 2012-10-24 * Enhancements: * Allow fetching of FTP URLs along HTTP ones. [metaskills] ### 0.3.0 / 2012-03-23 * Enhancements: * Use `gcc -v` to determine original host (platform) instead of Ruby one. * Deprecations: * Dropped support for Rubies older than 1.8.7 ### 0.2.2 / 2011-04-11 * Minor enhancements: * Use LDFLAGS when activating recipes for cross-compilation. Closes #6 * Bugfixes: * Remove memoization of *_path helpers. Closes #7 ### 0.2.1 / 2011-04-06 * Minor enhancements: * Provide MiniPortile#path to obtain full path to installation directory. Closes GH-5 ### 0.2.0 / 2011-04-05 * Enhancements: * Improve tar detection * Improve and refactor configure_options * Detect configure_options changes. Closes GH-1 * Add recipe examples * Bugfixes: * MiniPortile#target can be changed now. Closes GH-2 * Always redirect tar output properly ### 0.1.0 / 2011-03-08 * Initial release. Welcome to this world! mini_portile2-2.7.1/.gitignore0000644000004100000410000000004314135542067016321 0ustar www-datawww-data.bundle Gemfile.lock pkg ports tmp mini_portile2-2.7.1/mini_portile2.gemspec0000644000004100000410000000310014135542067020447 0ustar www-datawww-data# coding: utf-8 lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require "mini_portile2/version" Gem::Specification.new do |spec| spec.name = "mini_portile2" spec.version = MiniPortile::VERSION spec.authors = ["Luis Lavena", "Mike Dalessio", "Lars Kanis"] spec.email = "mike.dalessio@gmail.com" spec.summary = "Simplistic port-like solution for developers" spec.description = "Simplistic port-like solution for developers. It provides a standard and simplified way to compile against dependency libraries without messing up your system." spec.homepage = "https://github.com/flavorjones/mini_portile" spec.licenses = ["MIT"] begin spec.files = `git ls-files -z`.split("\x0") rescue Exception => e warn "WARNING: could not set spec.files: #{e.class}: #{e}" end # omit the `examples` directory from the gem, because it's large and # not necessary to be packaged in the gem. example_files = spec.files.grep(%r{^examples/}) spec.files -= example_files spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test|spec|features|examples)/}) spec.require_paths = ["lib"] spec.required_ruby_version = ">= 2.3.0" spec.add_development_dependency "bundler", "~> 2.1" spec.add_development_dependency "minitar", "~> 0.7" spec.add_development_dependency "minitest", "~> 5.11" spec.add_development_dependency "minitest-hooks", "~> 1.5.0" spec.add_development_dependency "rake", "~> 13.0" spec.add_development_dependency "webrick", "~> 1.0" end mini_portile2-2.7.1/Rakefile0000644000004100000410000000111414135542067015776 0ustar www-datawww-datarequire "rake/clean" require "bundler/gem_tasks" namespace :test do desc "Test MiniPortile by running unit tests" task :unit do sh "ruby -w -W2 -I. -Ilib -e \"#{Dir["test/test_*.rb"].map { |f| "require '#{f}';" }.join}\" -- #{ENV["TESTOPTS"]} -v" end desc "Test MiniPortile by compiling examples" task :examples do Dir.chdir("examples") do sh "rake ports:all" end end end task :clean do FileUtils.rm_rf ["examples/ports", "examples/tmp"], :verbose => true end desc "Run all tests" task :test => ["test:unit", "test:examples"] task :default => [:test] mini_portile2-2.7.1/lib/0000755000004100000410000000000014135542067015102 5ustar www-datawww-datamini_portile2-2.7.1/lib/mini_portile2/0000755000004100000410000000000014135542067017656 5ustar www-datawww-datamini_portile2-2.7.1/lib/mini_portile2/version.rb0000644000004100000410000000005214135542067021665 0ustar www-datawww-dataclass MiniPortile VERSION = "2.7.1" end mini_portile2-2.7.1/lib/mini_portile2/mini_portile_cmake.rb0000644000004100000410000000234314135542067024037 0ustar www-datawww-datarequire 'mini_portile2/mini_portile' class MiniPortileCMake < MiniPortile def configure_prefix "-DCMAKE_INSTALL_PREFIX=#{File.expand_path(port_path)}" end def initialize(name, version, **kwargs) super(name, version, **kwargs) @cmake_command = kwargs[:cmake_command] end def configure_defaults if MiniPortile.mswin? ['-G', 'NMake Makefiles'] elsif MiniPortile.mingw? ['-G', 'MSYS Makefiles'] else [] end end def configure return if configured? cache_file = File.join(tmp_path, 'configure.options_cache') File.open(cache_file, "w") { |f| f.write computed_options.to_s } execute('configure', [cmake_cmd] + computed_options + ["."]) end def configured? configure = File.join(work_path, 'configure') makefile = File.join(work_path, 'CMakefile') 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 def make_cmd return "nmake" if MiniPortile.mswin? super end def cmake_cmd (ENV["CMAKE"] || @cmake_command || "cmake").dup end end mini_portile2-2.7.1/lib/mini_portile2/mini_portile.rb0000644000004100000410000004066714135542067022712 0ustar www-datawww-datarequire 'rbconfig' require 'net/http' require 'net/https' require 'fileutils' require 'tempfile' require 'digest' require 'open-uri' require 'cgi' require 'rbconfig' require 'shellwords' # Monkey patch for Net::HTTP by ruby open-uri fix: # https://github.com/ruby/ruby/commit/58835a9 class Net::HTTP private remove_method(:edit_path) def edit_path(path) if proxy? if path.start_with?("ftp://") || use_ssl? path else "http://#{addr_port}#{path}" end else path end end end class MiniPortile attr_reader :name, :version, :original_host attr_writer :configure_options attr_accessor :host, :files, :patch_files, :target, :logger, :source_directory def self.windows? RbConfig::CONFIG['target_os'] =~ /mswin|mingw/ end # GNU MinGW compiled Ruby? def self.mingw? RbConfig::CONFIG['target_os'] =~ /mingw/ end # MS Visual-C compiled Ruby? def self.mswin? RbConfig::CONFIG['target_os'] =~ /mswin/ end def initialize(name, version, **kwargs) @name = name @version = version @target = 'ports' @files = [] @patch_files = [] @log_files = {} @logger = STDOUT @source_directory = nil @original_host = @host = detect_host @gcc_command = kwargs[:gcc_command] @make_command = kwargs[:make_command] end def source_directory=(path) @source_directory = File.expand_path(path) end def prepare_build_directory raise "source_directory is not set" if source_directory.nil? output "Building #{@name} #{@version} 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 def download files_hashs.each do |file| download_file(file[:url], file[:local_path]) verify_file(file) end end def extract files_hashs.each do |file| verify_file(file) extract_file(file[:local_path], tmp_path) end end 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}... " # By --work-tree=. git-apply uses the current directory as # the project root and will not search upwards for .git. execute('patch', ["git", "--git-dir=.", "--work-tree=.", "apply", "--whitespace=warn", file], :initial_message => false) } 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 def patch @patch_files.each do |full_path| next unless File.exist?(full_path) apply_patch(full_path) end end def configure_options @configure_options ||= configure_defaults end 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) end def compile execute('compile', make_cmd) end def install return if installed? execute('install', %Q(#{make_cmd} install)) end def downloaded? missing = files_hashs.detect do |file| !File.exist?(file[:local_path]) end missing ? false : true end 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 def installed? makefile = File.join(work_path, 'Makefile') target_dir = Dir.glob("#{port_path}/*").find { |d| File.directory?(d) } newer?(target_dir, makefile) end 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 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 def path File.expand_path(port_path) end def gcc_cmd (ENV["CC"] || @gcc_command || RbConfig::CONFIG["CC"] || "gcc").dup end def make_cmd (ENV["MAKE"] || @make_command || ENV["make"] || "make").dup end private def tmp_path "tmp/#{@host}/ports/#{@name}/#{@version}" end def port_path "#{@target}/#{@host}/#{@name}/#{@version}" end def archives_path "#{@target}/archives" end def work_path Dir.glob("#{tmp_path}/*").find { |d| File.directory?(d) } end def configure_defaults [ "--host=#{@host}", # build for specific target (host) "--enable-static", # build static library "--disable-shared" # disable generation of shared object ] end def configure_prefix "--prefix=#{File.expand_path(port_path)}" end def computed_options [ configure_options, # customized or default options configure_prefix, # installation target ].flatten end 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 KEYRING_NAME = "mini_portile_keyring.gpg" 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_status = IO.popen([gpg_exe, "--status-fd", "1", "--no-default-keyring", "--keyring", KEYRING_NAME, "--import"], "w+") do |io| io.write gpg[:key] io.close_write io.read end key_ids = gpg_status.scan(/\[GNUPG:\] IMPORT_OK \d+ (?[0-9a-f]+)/i).map(&:first) raise "invalid gpg key provided" if key_ids.empty? # verify the signature against our keyring gpg_status = IO.popen([gpg_exe, "--status-fd", "1", "--no-default-keyring", "--keyring", KEYRING_NAME, "--verify", signature_file, file[:local_path]], &:read) # 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 raise "signature mismatch" unless gpg_status.match(/^\[GNUPG:\] VALIDSIG/) 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 def log_file(action) @log_files[action] ||= File.expand_path("#{action}.log", tmp_path).tap { |file| File.unlink(file) if File.exist?(file) } end TAR_EXECUTABLES = %w[gtar bsdtar tar basic-bsdtar] 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 def tar_compression_switch(filename) case File.extname(filename) when '.gz', '.tgz' 'z' when '.bz2', '.tbz2' 'j' when '.Z' 'Z' else '' end end # From: http://stackoverflow.com/a/5471032/7672 # Thanks, Mislav! # # Cross-platform way of finding an executable in the $PATH. # # which('ruby') #=> /usr/bin/ruby 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 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] end @detect_host ensure ENV["LC_ALL"] = old_lc_all end end def extract_file(file, target) filename = File.basename(file) FileUtils.mkdir_p target message "Extracting #{filename} into #{target}... " execute('extract', [tar_exe, "#{tar_compression_switch(filename)}xf", file, "-C", target], {:cd => Dir.pwd, :initial_message => false}) end # command could be an array of args, or one string containing a command passed to the shell. See # Process.spawn for more information. 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 } 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 if File.exist? log_out output "ERROR, review '#{log_out}' to see what happened. Last lines are:" output("=" * 72) log_lines = File.readlines(log_out) output(log_lines[-[log_lines.length, 20].min .. -1]) output("=" * 72) end raise "Failed to complete #{action} task" end end end def newer?(target, checkpoint) if (target && File.exist?(target)) && (checkpoint && File.exist?(checkpoint)) File.mtime(target) > File.mtime(checkpoint) else false end end # print out a message with the logger def message(text) @logger.print text @logger.flush end # print out a message using the logger but return to a new line def output(text = "") @logger.puts text @logger.flush end # Slighly modified from RubyInstaller uri_ext, Rubinius configure # and adaptations of Wayne's RailsInstaller 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 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 } } 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 puts "#{count} retrie(s) left for #{filename}" if count > 0 sleep 1 return download_file_http(url, full_path, count) end output e.message return false end end end def download_file_file(uri, full_path) FileUtils.mkdir_p File.dirname(full_path) FileUtils.cp uri.path, full_path end 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] } } 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 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 end mini_portile2-2.7.1/lib/mini_portile2.rb0000644000004100000410000000016014135542067020200 0ustar www-datawww-datarequire "mini_portile2/version" require "mini_portile2/mini_portile" require "mini_portile2/mini_portile_cmake" mini_portile2-2.7.1/Gemfile0000644000004100000410000000030614135542067015626 0ustar www-datawww-datasource 'https://rubygems.org' gem "net-ftp" if Gem::Requirement.new("> 3.1.0.dev").satisfied_by?(Gem::Version.new(RUBY_VERSION)) # Specify your gem's dependencies in mini_portile2.gemspec gemspec mini_portile2-2.7.1/.github/0000755000004100000410000000000014135542067015674 5ustar www-datawww-datamini_portile2-2.7.1/.github/FUNDING.yml0000644000004100000410000000004314135542067017506 0ustar www-datawww-datatidelift: "rubygems/mini_portile2" mini_portile2-2.7.1/.github/workflows/0000755000004100000410000000000014135542067017731 5ustar www-datawww-datamini_portile2-2.7.1/.github/workflows/ci.yml0000644000004100000410000000373014135542067021052 0ustar www-datawww-dataname: Continuous Integration concurrency: group: "${{github.workflow}}-${{github.ref}}" cancel-in-progress: true on: workflow_dispatch: push: branches: - main - v*.*.x tags: - v*.*.* pull_request: types: [opened, synchronize] branches: - "*" schedule: - cron: "0 8 * * 5" # At 08:00 on Friday # https://crontab.guru/#0_8_*_*_5 jobs: test-unit: env: MAKEFLAGS: -j2 strategy: fail-fast: false matrix: platform: [ubuntu-latest, windows-latest] ruby: ["2.3", "2.4", "2.5", "2.6", "2.7", "3.0", "head"] runs-on: ${{ matrix.platform }} steps: - name: configure git crlf on windows if: matrix.platform == 'windows-latest' run: | git config --system core.autocrlf false git config --system core.eol lf - uses: actions/checkout@v2 - uses: MSP-Greg/setup-ruby-pkgs@v1 with: apt-get: _update_ build-essential cmake mingw: _upgrade_ cmake ruby-version: ${{ matrix.ruby }} bundler-cache: true - run: bundle exec rake test:unit test-examples: env: MAKEFLAGS: -j2 strategy: fail-fast: false matrix: platform: [ubuntu-latest, windows-latest] ruby: ["3.0"] runs-on: ${{ matrix.platform }} steps: - name: configure git crlf on windows if: matrix.platform == 'windows-latest' run: | git config --system core.autocrlf false git config --system core.eol lf - uses: actions/checkout@v2 - uses: MSP-Greg/setup-ruby-pkgs@v1 with: apt-get: _update_ build-essential cmake mingw: _upgrade_ cmake ruby-version: ${{ matrix.ruby }} bundler-cache: true - uses: actions/cache@v2 with: path: examples/ports/archives key: ${{ matrix.platform }}-examples-${{ hashFiles('examples/Rakefile') }} - run: bundle exec rake test:examples mini_portile2-2.7.1/SECURITY.md0000644000004100000410000000174314135542067016132 0ustar www-datawww-data# Security and Vulnerability Reporting The mini_portile core contributors take security very seriously and investigate all reported vulnerabilities. If you would like to report a vulnerablity or have a security concern regarding mini_portile, please [report it via Tidelift](https://tidelift.com/security). Your report will be acknowledged within 48 hours, and you'll receive a more detailed response within 96 hours indicating next steps in handling your report. If you have not received a reply to your submission within 96 hours, Contact the current security coordinator, Mike Dalessio . The information you share with the mini_portile core contributors as part of this process will be kept confidential within the team, unless or until we need to share information upstream with our dependent libraries' core teams, at which point we will notify you. If a vulnerability is first reported by you, we will credit you with the discovery in the public disclosure. mini_portile2-2.7.1/LICENSE.txt0000644000004100000410000000206614135542067016163 0ustar www-datawww-dataCopyright (c) 2011-2016 Luis Lavena and Mike Dalessio Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.