fpm-fry 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/cabin/nice_output.rb +16 -1
- data/lib/fpm/fry/block_enumerator.rb +6 -3
- data/lib/fpm/fry/channel.rb +13 -0
- data/lib/fpm/fry/chroot.rb +2 -2
- data/lib/fpm/fry/client.rb +81 -6
- data/lib/fpm/fry/command.rb +11 -31
- data/lib/fpm/fry/command/cook.rb +19 -51
- data/lib/fpm/fry/detector.rb +43 -98
- data/lib/fpm/fry/docker_file.rb +3 -11
- data/lib/fpm/fry/exec.rb +76 -0
- data/lib/fpm/fry/inspector.rb +70 -0
- data/lib/fpm/fry/joined_io.rb +1 -1
- data/lib/fpm/fry/plugin/edit_staging.rb +1 -1
- data/lib/fpm/fry/plugin/init.rb +71 -42
- data/lib/fpm/fry/plugin/service.rb +108 -49
- data/lib/fpm/fry/recipe.rb +46 -21
- data/lib/fpm/fry/recipe/builder.rb +26 -13
- data/lib/fpm/fry/source.rb +14 -12
- data/lib/fpm/fry/source/{package.rb → archive.rb} +68 -31
- data/lib/fpm/fry/source/dir.rb +2 -5
- data/lib/fpm/fry/source/git.rb +70 -43
- data/lib/fpm/fry/source/patched.rb +14 -10
- data/lib/fpm/fry/with_data.rb +34 -0
- data/lib/fpm/package/docker.rb +15 -0
- metadata +5 -4
- data/lib/fpm/fry/os_db.rb +0 -36
    
        data/lib/fpm/fry/recipe.rb
    CHANGED
    
    | @@ -1,26 +1,28 @@ | |
| 1 1 | 
             
            require 'fpm/fry/source'
         | 
| 2 | 
            -
            require 'fpm/fry/source/ | 
| 2 | 
            +
            require 'fpm/fry/source/archive'
         | 
| 3 3 | 
             
            require 'fpm/fry/source/dir'
         | 
| 4 4 | 
             
            require 'fpm/fry/source/patched'
         | 
| 5 5 | 
             
            require 'fpm/fry/source/git'
         | 
| 6 6 | 
             
            require 'fpm/fry/plugin'
         | 
| 7 | 
            -
            require 'fpm/fry/ | 
| 7 | 
            +
            require 'fpm/fry/exec'
         | 
| 8 8 | 
             
            require 'shellwords'
         | 
| 9 9 | 
             
            require 'cabin'
         | 
| 10 | 
            -
            require 'open3'
         | 
| 11 10 | 
             
            module FPM; module Fry
         | 
| 12 11 |  | 
| 12 | 
            +
              # A FPM::Fry::Recipe contains all information needed to build a package.
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              # It is usually created by {FPM::Fry::Recipe::Builder}.
         | 
| 13 15 | 
             
              class Recipe
         | 
| 14 16 |  | 
| 17 | 
            +
                # A FPM::Fry::Recipe::Step is a named build step.
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                # @see FPM::Fry::Recipe#steps
         | 
| 15 20 | 
             
                class Step < Struct.new(:name, :value)
         | 
| 16 21 | 
             
                  def to_s
         | 
| 17 22 | 
             
                    value.to_s
         | 
| 18 23 | 
             
                  end
         | 
| 19 24 | 
             
                end
         | 
| 20 25 |  | 
| 21 | 
            -
                class DuplicateDependency < ArgumentError
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 26 | 
             
                class PackageRecipe
         | 
| 25 27 | 
             
                  attr_accessor :name,
         | 
| 26 28 | 
             
                    :iteration,
         | 
| @@ -60,6 +62,10 @@ module FPM; module Fry | |
| 60 62 |  | 
| 61 63 | 
             
                  alias dependencies depends
         | 
| 62 64 |  | 
| 65 | 
            +
                  # Applies settings to output package
         | 
| 66 | 
            +
                  # @param [FPM::Package] package
         | 
| 67 | 
            +
                  # @return [FPM::Package] package
         | 
| 68 | 
            +
                  # @api private
         | 
| 63 69 | 
             
                  def apply_output( package )
         | 
| 64 70 | 
             
                    package.name = name
         | 
| 65 71 | 
             
                    package.version = version
         | 
| @@ -87,8 +93,11 @@ module FPM; module Fry | |
| 87 93 |  | 
| 88 94 | 
             
                  alias apply apply_output
         | 
| 89 95 |  | 
| 96 | 
            +
                  # @api private
         | 
| 90 97 | 
             
                  SYNTAX_CHECK_SHELLS = ['/bin/sh','/bin/bash', '/bin/dash']
         | 
| 91 98 |  | 
| 99 | 
            +
                  # Lints the settings for some common problems
         | 
| 100 | 
            +
                  # @return [Array<String>] problems
         | 
| 92 101 | 
             
                  def lint
         | 
| 93 102 | 
             
                    problems = []
         | 
| 94 103 | 
             
                    problems << "Name is empty." if name.to_s == ''
         | 
| @@ -110,28 +119,37 @@ module FPM; module Fry | |
| 110 119 | 
             
                        problems << "#{type} script doesn't have a valid command in shebang"
         | 
| 111 120 | 
             
                      end
         | 
| 112 121 | 
             
                      if SYNTAX_CHECK_SHELLS.include? args[0]
         | 
| 113 | 
            -
                         | 
| 114 | 
            -
             | 
| 115 | 
            -
                         | 
| 116 | 
            -
             | 
| 117 | 
            -
                          problems << "#{type} script is not valid #{args[0]} code: #{serr.read.chomp}"
         | 
| 122 | 
            +
                        begin
         | 
| 123 | 
            +
                          Exec::exec(args[0],'-n', stdin_data: s)
         | 
| 124 | 
            +
                        rescue Exec::Failed => e
         | 
| 125 | 
            +
                          problems << "#{type} script is not valid #{args[0]} code: #{e.stderr.chomp}"
         | 
| 118 126 | 
             
                        end
         | 
| 119 | 
            -
                        serr.close
         | 
| 120 | 
            -
                        sout.close
         | 
| 121 127 | 
             
                      end
         | 
| 122 128 | 
             
                    end
         | 
| 123 129 | 
             
                    return problems
         | 
| 124 130 | 
             
                  end
         | 
| 125 131 | 
             
                end
         | 
| 126 132 |  | 
| 127 | 
            -
                 | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 133 | 
            +
                # @return [FPM::Fry::Source] the source used for building
         | 
| 134 | 
            +
                attr_accessor :source
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                attr_accessor :build_mounts
         | 
| 137 | 
            +
                attr_accessor :apt_setup
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                # @return [Array<#to_s>] steps that will be carried out before build
         | 
| 140 | 
            +
                attr_accessor :before_build_steps
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                # @return [Array<#to_s>] steps that will be carried out during build
         | 
| 143 | 
            +
                attr_accessor :steps
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                # @return [Array<FPM::Fry::PackageRecipe>] a list of packages that will be created
         | 
| 146 | 
            +
                attr_accessor :packages
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                # @return [Hash<String,Hash>] build dependencies
         | 
| 149 | 
            +
                attr_accessor :build_depends
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                # @return [Array<#call>] hooks that will be called on the input package
         | 
| 152 | 
            +
                attr_accessor :input_hooks
         | 
| 135 153 |  | 
| 136 154 | 
             
                def initialize
         | 
| 137 155 | 
             
                  @source = Source::Null
         | 
| @@ -145,6 +163,8 @@ module FPM; module Fry | |
| 145 163 | 
             
                  @apt_setup = []
         | 
| 146 164 | 
             
                end
         | 
| 147 165 |  | 
| 166 | 
            +
                # Calculates all dependencies of this recipe
         | 
| 167 | 
            +
                # @return [Hash<String,Hash>] the dependencies
         | 
| 148 168 | 
             
                def depends
         | 
| 149 169 | 
             
                  depends = @packages.map(&:depends).inject(:merge)
         | 
| 150 170 | 
             
                  @packages.map(&:name).each do | n |
         | 
| @@ -153,10 +173,15 @@ module FPM; module Fry | |
| 153 173 | 
             
                  return depends
         | 
| 154 174 | 
             
                end
         | 
| 155 175 |  | 
| 176 | 
            +
                # Checks all packages for common errors
         | 
| 177 | 
            +
                # @return [Array<String>] problems
         | 
| 156 178 | 
             
                def lint
         | 
| 157 179 | 
             
                  packages.flat_map(&:lint)
         | 
| 158 180 | 
             
                end
         | 
| 159 181 |  | 
| 182 | 
            +
                # Applies input settings to package
         | 
| 183 | 
            +
                # @param [FPM::Package] package
         | 
| 184 | 
            +
                # @return [FPM::Package]
         | 
| 160 185 | 
             
                def apply_input( package )
         | 
| 161 186 | 
             
                  input_hooks.each{|h| h.call(self, package) }
         | 
| 162 187 | 
             
                  return package
         | 
| @@ -7,13 +7,26 @@ module FPM::Fry | |
| 7 7 | 
             
                class NotFound < StandardError
         | 
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 | 
            -
                class PackageBuilder | 
| 10 | 
            +
                class PackageBuilder
         | 
| 11 11 |  | 
| 12 | 
            +
                  # @return [Hash<Symbol,Object>]
         | 
| 13 | 
            +
                  attr :variables
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # @return [FPM::Fry::PackageRecipe]
         | 
| 16 | 
            +
                  attr :package_recipe
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  # @return [Cabin::Channel]
         | 
| 12 19 | 
             
                  attr :logger
         | 
| 13 20 |  | 
| 14 | 
            -
                   | 
| 15 | 
            -
             | 
| 21 | 
            +
                  # @return [FPM::Fry::Inspector,nil]
         | 
| 22 | 
            +
                  attr :inspector
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # @api private
         | 
| 25 | 
            +
                  def initialize( variables, package_recipe, options = {})
         | 
| 26 | 
            +
                    @variables = variables
         | 
| 27 | 
            +
                    @package_recipe = package_recipe
         | 
| 16 28 | 
             
                    @logger = options.fetch(:logger){ Cabin::Channel.get }
         | 
| 29 | 
            +
                    @inspector = options[:inspector]
         | 
| 17 30 | 
             
                  end
         | 
| 18 31 |  | 
| 19 32 | 
             
                  def flavour
         | 
| @@ -174,17 +187,17 @@ module FPM::Fry | |
| 174 187 |  | 
| 175 188 | 
             
                class Builder < PackageBuilder
         | 
| 176 189 |  | 
| 190 | 
            +
                  # @return [FPM::Fry::Recipe]
         | 
| 177 191 | 
             
                  attr :recipe
         | 
| 178 192 |  | 
| 179 | 
            -
                   | 
| 193 | 
            +
                  # @param [Hash<Symbol,Object>] variables
         | 
| 194 | 
            +
                  # @param [Hash] options
         | 
| 195 | 
            +
                  # @option options [FPM::Fry::Recipe] :recipe (Recipe.new)
         | 
| 196 | 
            +
                  # @option options [Cabin::Channel] :logger (default cabin channel)
         | 
| 197 | 
            +
                  # @option options [FPM::Fry::Inspector] :inspector
         | 
| 198 | 
            +
                  def initialize( variables, options = {} )
         | 
| 199 | 
            +
                    recipe = options.fetch(:recipe){ Recipe.new }
         | 
| 180 200 | 
             
                    variables = variables.dup
         | 
| 181 | 
            -
                    if variables[:distribution] && !variables[:flavour] && OsDb[variables[:distribution]]
         | 
| 182 | 
            -
                      variables[:flavour] = OsDb[variables[:distribution]][:flavour]
         | 
| 183 | 
            -
                    end
         | 
| 184 | 
            -
                    if !variables[:codename] && OsDb[variables[:distribution]] && variables[:distribution_version]
         | 
| 185 | 
            -
                      codename = OsDb[variables[:distribution]][:codenames].find{|name,version| variables[:distribution_version].start_with? version }
         | 
| 186 | 
            -
                      variables[:codename] = codename[0] if codename
         | 
| 187 | 
            -
                    end
         | 
| 188 201 | 
             
                    variables.freeze
         | 
| 189 202 | 
             
                    @recipe = recipe
         | 
| 190 203 | 
             
                    @before_build = false
         | 
| @@ -266,7 +279,7 @@ module FPM::Fry | |
| 266 279 | 
             
                    pr.version = package_recipe.version
         | 
| 267 280 | 
             
                    pr.iteration = package_recipe.iteration
         | 
| 268 281 | 
             
                    recipe.packages << pr
         | 
| 269 | 
            -
                    PackageBuilder.new(variables, pr).instance_eval(&block)
         | 
| 282 | 
            +
                    PackageBuilder.new(variables, pr, logger: logger, inspector: inspector).instance_eval(&block)
         | 
| 270 283 | 
             
                  end
         | 
| 271 284 |  | 
| 272 285 | 
             
                protected
         | 
| @@ -289,7 +302,7 @@ module FPM::Fry | |
| 289 302 |  | 
| 290 303 | 
             
                  def register_default_source_types!
         | 
| 291 304 | 
             
                    register_source_type Source::Git
         | 
| 292 | 
            -
                    register_source_type Source:: | 
| 305 | 
            +
                    register_source_type Source::Archive
         | 
| 293 306 | 
             
                    register_source_type Source::Dir
         | 
| 294 307 | 
             
                  end
         | 
| 295 308 |  | 
    
        data/lib/fpm/fry/source.rb
    CHANGED
    
    | @@ -1,34 +1,35 @@ | |
| 1 | 
            +
            require 'fpm/fry/with_data'
         | 
| 1 2 | 
             
            module FPM; module Fry ; module Source
         | 
| 2 3 |  | 
| 4 | 
            +
              # Raised when building a cache failed.
         | 
| 3 5 | 
             
              class CacheFailed < StandardError
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                attr :data
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def initialize(e, data = {})
         | 
| 8 | 
            -
                  if e.kind_of? Exception
         | 
| 9 | 
            -
                    @data = {reason: e}.merge data
         | 
| 10 | 
            -
                    super(e.message)
         | 
| 11 | 
            -
                  else
         | 
| 12 | 
            -
                    @data = data.dup
         | 
| 13 | 
            -
                    super(e.to_s)
         | 
| 14 | 
            -
                  end
         | 
| 15 | 
            -
                end
         | 
| 6 | 
            +
                include WithData
         | 
| 16 7 | 
             
              end
         | 
| 17 8 |  | 
| 9 | 
            +
              # A special source that is empty.
         | 
| 18 10 | 
             
              module Null
         | 
| 19 11 |  | 
| 12 | 
            +
                # A special cache that is empty.
         | 
| 20 13 | 
             
                module Cache
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # @return [IO] an empty tar
         | 
| 21 16 | 
             
                  def self.tar_io
         | 
| 22 17 | 
             
                    StringIO.new("\x00"*1024)
         | 
| 23 18 | 
             
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # @return [Hash] an empty hash
         | 
| 24 21 | 
             
                  def self.file_map
         | 
| 25 22 | 
             
                    return {}
         | 
| 26 23 | 
             
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  # @return [String] 32 times zero
         | 
| 27 26 | 
             
                  def self.cachekey
         | 
| 28 27 | 
             
                    return '0' * 32
         | 
| 29 28 | 
             
                  end
         | 
| 30 29 | 
             
                end
         | 
| 31 30 |  | 
| 31 | 
            +
                # @see FPM::Fry::Source::Null::Cache
         | 
| 32 | 
            +
                # @return {FPM::Fry::Source::Null::Cache}
         | 
| 32 33 | 
             
                def self.build_cache(*_)
         | 
| 33 34 | 
             
                  return Cache
         | 
| 34 35 | 
             
                end
         | 
| @@ -37,6 +38,7 @@ module FPM; module Fry ; module Source | |
| 37 38 |  | 
| 38 39 | 
             
              class << self
         | 
| 39 40 |  | 
| 41 | 
            +
                # @api private
         | 
| 40 42 | 
             
                def guess_regex(rx, url)
         | 
| 41 43 | 
             
                  if m = rx.match(url.to_s)
         | 
| 42 44 | 
             
                    return m[0].size
         | 
| @@ -4,32 +4,65 @@ require 'net/http' | |
| 4 4 | 
             
            require 'forwardable'
         | 
| 5 5 | 
             
            require 'zlib'
         | 
| 6 6 | 
             
            require 'fpm/fry/source'
         | 
| 7 | 
            +
            require 'fpm/fry/exec'
         | 
| 7 8 | 
             
            require 'cabin'
         | 
| 8 9 | 
             
            module FPM; module Fry ; module Source
         | 
| 9 | 
            -
               | 
| 10 | 
            +
              # Used to build from an archive.
         | 
| 11 | 
            +
              #
         | 
| 12 | 
            +
              # @example in a recipe
         | 
| 13 | 
            +
              #   source 'http://curl.haxx.se/download/curl-7.36.0.tar.gz',
         | 
| 14 | 
            +
              #     checksum: '33015795d5650a2bfdd9a4a28ce4317cef944722a5cfca0d1563db8479840e90'
         | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              # It is highly advised to supply a checksum ( althought it's not mandatory ). 
         | 
| 17 | 
            +
              # This checksum will be used to test for cache validity and data integrity. The 
         | 
| 18 | 
            +
              # checksum algorithm is automatically guessed based on the length of the checksum.
         | 
| 19 | 
            +
              #
         | 
| 20 | 
            +
              #   - 40 characters = sha1
         | 
| 21 | 
            +
              #   - 64 characters = sha256
         | 
| 22 | 
            +
              # 
         | 
| 23 | 
            +
              # Let's be honest: all other checksum algorithms aren't or shouldn't be in use anyway.
         | 
| 24 | 
            +
              class Archive
         | 
| 10 25 |  | 
| 11 26 | 
             
                REGEX = %r!\Ahttps?:!
         | 
| 12 27 |  | 
| 28 | 
            +
                # @return [:archive]
         | 
| 13 29 | 
             
                def self.name
         | 
| 14 30 | 
             
                  :package
         | 
| 15 31 | 
             
                end
         | 
| 16 32 |  | 
| 17 33 | 
             
                def self.aliases
         | 
| 18 | 
            -
                  [:http]
         | 
| 34 | 
            +
                  [:package,:http]
         | 
| 19 35 | 
             
                end
         | 
| 20 36 |  | 
| 37 | 
            +
                # Guesses if the given url is an archive.
         | 
| 38 | 
            +
                # 
         | 
| 39 | 
            +
                # @example not an archive
         | 
| 40 | 
            +
                #   FPM::Fry::Source::Archive.guess("bzr://something") # => nil
         | 
| 41 | 
            +
                #
         | 
| 42 | 
            +
                # @example an archive
         | 
| 43 | 
            +
                #   FPM::Fry::Source::Archive.guess("https://some/thing.tar.gz") #=> 6
         | 
| 44 | 
            +
                #
         | 
| 45 | 
            +
                # @return [nil] when it's not an archive
         | 
| 46 | 
            +
                # @return [Numeric] number of characters used
         | 
| 21 47 | 
             
                def self.guess( url )
         | 
| 22 48 | 
             
                  Source::guess_regex(REGEX, url)
         | 
| 23 49 | 
             
                end
         | 
| 24 50 |  | 
| 51 | 
            +
                # Raised when too many redirects happened.
         | 
| 25 52 | 
             
                class RedirectError < CacheFailed
         | 
| 26 53 | 
             
                end
         | 
| 27 54 |  | 
| 55 | 
            +
                # Raised when the archive type is not known.
         | 
| 56 | 
            +
                class UnknownArchiveType < StandardError
         | 
| 57 | 
            +
                  include WithData
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 28 60 | 
             
                class Cache < Struct.new(:package,:tempdir)
         | 
| 29 61 | 
             
                  extend Forwardable
         | 
| 30 62 |  | 
| 31 | 
            -
                  def_delegators :package, :url, :checksum, :checksum_algorithm, : | 
| 63 | 
            +
                  def_delegators :package, :url, :checksum, :checksum_algorithm, :logger, :file_map
         | 
| 32 64 |  | 
| 65 | 
            +
                  # @return [String] cachekey which is equal to the checksum
         | 
| 33 66 | 
             
                  def cachekey
         | 
| 34 67 | 
             
                    @observed_checksum || checksum
         | 
| 35 68 | 
             
                  end
         | 
| @@ -92,7 +125,7 @@ module FPM; module Fry ; module Source | |
| 92 125 | 
             
                      case(resp)
         | 
| 93 126 | 
             
                      when Net::HTTPRedirection
         | 
| 94 127 | 
             
                        if redirs == 0
         | 
| 95 | 
            -
                          raise RedirectError | 
| 128 | 
            +
                          raise RedirectError.new("Too many redirects", url: url.to_s, location: resp['location'])
         | 
| 96 129 | 
             
                        end
         | 
| 97 130 | 
             
                        logger.debug("Following redirect", url: url.to_s , location: resp['location'])
         | 
| 98 131 | 
             
                        return fetch_url( resp['location'], redirs - 1, &block)
         | 
| @@ -119,9 +152,7 @@ module FPM; module Fry ; module Source | |
| 119 152 |  | 
| 120 153 | 
             
                  def copy_to(dst)
         | 
| 121 154 | 
             
                    update!
         | 
| 122 | 
            -
                     | 
| 123 | 
            -
                    logger.debug("Running tar",cmd: cmd)
         | 
| 124 | 
            -
                    system(*cmd)
         | 
| 155 | 
            +
                    Exec['tar','-xf',tempfile,'-C',dst, logger: logger]
         | 
| 125 156 | 
             
                  end
         | 
| 126 157 |  | 
| 127 158 | 
             
                protected
         | 
| @@ -142,9 +173,7 @@ module FPM; module Fry ; module Source | |
| 142 173 |  | 
| 143 174 | 
             
                  def tar_io
         | 
| 144 175 | 
             
                    update!
         | 
| 145 | 
            -
                     | 
| 146 | 
            -
                    logger.debug("Running bzcat",cmd: cmd)
         | 
| 147 | 
            -
                    return IO.popen(cmd)
         | 
| 176 | 
            +
                    return Exec::popen('bzcat', tempfile, logger: logger)
         | 
| 148 177 | 
             
                  end
         | 
| 149 178 |  | 
| 150 179 | 
             
                end
         | 
| @@ -163,20 +192,14 @@ module FPM; module Fry ; module Source | |
| 163 192 | 
             
                      copy_to( workdir )
         | 
| 164 193 | 
             
                      File.rename(workdir, unpacked_tmpdir)
         | 
| 165 194 | 
             
                    end
         | 
| 166 | 
            -
                     | 
| 167 | 
            -
                    logger.debug("Running tar",cmd: cmd, dir: unpacked_tmpdir)
         | 
| 168 | 
            -
                    ::Dir.chdir(unpacked_tmpdir) do
         | 
| 169 | 
            -
                      return IO.popen(cmd)
         | 
| 170 | 
            -
                    end
         | 
| 195 | 
            +
                    return Exec::popen('tar','-c','.', chdir: unpacked_tmpdir)
         | 
| 171 196 | 
             
                  end
         | 
| 172 197 |  | 
| 173 198 | 
             
                  def copy_to(dst)
         | 
| 174 199 | 
             
                    update!
         | 
| 175 | 
            -
                     | 
| 176 | 
            -
                    logger.debug("Running unzip",cmd: cmd)
         | 
| 177 | 
            -
                    system(*cmd, out: '/dev/null')
         | 
| 200 | 
            +
                    Exec['unzip', tempfile, '-d', dst ]
         | 
| 178 201 | 
             
                  end
         | 
| 179 | 
            -
             | 
| 202 | 
            +
                private
         | 
| 180 203 | 
             
                  def unpacked_tmpdir
         | 
| 181 204 | 
             
                    File.join(tempdir, cachekey)
         | 
| 182 205 | 
             
                  end
         | 
| @@ -186,12 +209,8 @@ module FPM; module Fry ; module Source | |
| 186 209 |  | 
| 187 210 | 
             
                  def tar_io
         | 
| 188 211 | 
             
                    update!
         | 
| 189 | 
            -
                    cmd = ['tar','-c',::File.basename(tempfile)]
         | 
| 190 212 | 
             
                    dir = File.dirname(tempfile)
         | 
| 191 | 
            -
                     | 
| 192 | 
            -
                    ::Dir.chdir(dir) do
         | 
| 193 | 
            -
                      return IO.popen(cmd)
         | 
| 194 | 
            -
                    end
         | 
| 213 | 
            +
                    Exec::popen('tar','-c',::File.basename(tempfile), logger: logger, chdir: dir)
         | 
| 195 214 | 
             
                  end
         | 
| 196 215 |  | 
| 197 216 | 
             
                  def copy_to(dst)
         | 
| @@ -211,26 +230,44 @@ module FPM; module Fry ; module Source | |
| 211 230 | 
             
                  '.bundle' => PlainCache
         | 
| 212 231 | 
             
                }
         | 
| 213 232 |  | 
| 214 | 
            -
                attr :file_map, :data, :url, : | 
| 233 | 
            +
                attr :file_map, :data, :url, :checksum, :checksum_algorithm, :logger
         | 
| 215 234 |  | 
| 235 | 
            +
                # @param [URI] url
         | 
| 236 | 
            +
                # @param [Hash] options
         | 
| 237 | 
            +
                # @option options [Cabin::Channel] :logger (default cabin channel)
         | 
| 238 | 
            +
                # @option options [String] :checksum a checksum of the archive
         | 
| 239 | 
            +
                # @raise [UnknownArchiveType] when the archive type is unknown
         | 
| 216 240 | 
             
                def initialize( url, options = {} )
         | 
| 217 241 | 
             
                  @url = URI(url)
         | 
| 218 | 
            -
                  @ | 
| 219 | 
            -
                    CACHE_CLASSES.keys.find{|ext|
         | 
| 220 | 
            -
                      @url.path.end_with?(ext)
         | 
| 221 | 
            -
                    }
         | 
| 222 | 
            -
                  }
         | 
| 242 | 
            +
                  @cache_class = guess_cache_class(@url)
         | 
| 223 243 | 
             
                  @logger = options.fetch(:logger){ Cabin::Channel.get }
         | 
| 224 244 | 
             
                  @checksum = options[:checksum]
         | 
| 225 245 | 
             
                  @checksum_algorithm = guess_checksum_algorithm(options[:checksum])
         | 
| 226 246 | 
             
                  @file_map = options.fetch(:file_map){ {'' => ''} }
         | 
| 227 247 | 
             
                end
         | 
| 228 248 |  | 
| 249 | 
            +
                # Creates a cache.
         | 
| 250 | 
            +
                #
         | 
| 251 | 
            +
                # @param [String] tempdir
         | 
| 252 | 
            +
                # @return [TarCache] for plain .tar files
         | 
| 253 | 
            +
                # @return [TarGzCache] for .tar.gz files
         | 
| 254 | 
            +
                # @return [TarBz2Cache] for .tar.bz2 files
         | 
| 255 | 
            +
                # @return [ZipCache] for .zip files
         | 
| 256 | 
            +
                # @return [PlainCache] for .bin files
         | 
| 229 257 | 
             
                def build_cache(tempdir)
         | 
| 230 | 
            -
                   | 
| 258 | 
            +
                  @cache_class.new(self, tempdir)
         | 
| 231 259 | 
             
                end
         | 
| 232 260 | 
             
              private
         | 
| 233 261 |  | 
| 262 | 
            +
                def guess_cache_class( url )
         | 
| 263 | 
            +
                  CACHE_CLASSES.each do |ext,klass|
         | 
| 264 | 
            +
                    if url.path.end_with?(ext)
         | 
| 265 | 
            +
                      return klass
         | 
| 266 | 
            +
                    end
         | 
| 267 | 
            +
                  end
         | 
| 268 | 
            +
                  raise UnknownArchiveType.new("Unknown archive type", url: url.to_s, known_extensions: CACHE_CLASSES.keys)
         | 
| 269 | 
            +
                end
         | 
| 270 | 
            +
             | 
| 234 271 | 
             
                def guess_checksum_algorithm( checksum )
         | 
| 235 272 | 
             
                  case(checksum)
         | 
| 236 273 | 
             
                  when nil
         |