class Stove::Packager

Constants

ACCEPTABLE_FILES
ACCEPTABLE_FILES_LIST
TMP_FILES

Attributes

cookbook[R]

The cookbook to package.

@erturn [Stove::Cookbook]

extended_metadata[R]

Whether to include the new extended metadata attributes.

@return [true, false]

Public Class Methods

new(cookbook, extended_metadata = false) click to toggle source

Create a new packager instance.

@param [Stove::Cookbook]

the cookbook to package

@param [true, false] extended_metadata

include new extended metadata attributes
# File lib/stove/packager.rb, line 48
def initialize(cookbook, extended_metadata = false)
  @cookbook = cookbook
  @extended_metadata = extended_metadata
end

Public Instance Methods

gzip(io) click to toggle source

GZip the given IO object (like a File or StringIO).

@param [IO] io

the io object to gzip

@return [IO]

the gzipped IO object
# File lib/stove/packager.rb, line 143
def gzip(io)
  gz = StringIO.new('')
  z = Zlib::GzipWriter.new(gz)
  z.write(io.string)
  z.close

  # z was closed to write the gzip footer, so
  # now we need a new StringIO
  StringIO.new(gz.string)
end
packaging_slip() click to toggle source

A map from physical file path to tarball file path

@example

# Assuming +cookbook.name+ is 'apt'

{
  '/home/user/apt-cookbook/metadata.json' => 'apt/metadata.json',
  '/home/user/apt-cookbook/README.md' => 'apt/README.md'
}

@return [Hash<String, String>]

the map of file paths
# File lib/stove/packager.rb, line 65
def packaging_slip
  root = File.expand_path(cookbook.path)
  path = File.join(root, "{#{ACCEPTABLE_FILES_LIST}}")

  Dir.glob(path, File::FNM_DOTMATCH)
    .reject { |path| %w(. ..).include?(File.basename(path)) }
    .reject { |path| TMP_FILES.any? { |regex| path.match(regex) } }
    .map    { |path| [path, path.sub(/^#{Regexp.escape(root)}/, cookbook.name)] }
    .reduce({}) do |map, (cookbook_file, tarball_file)|
      map[cookbook_file] = tarball_file
    map
  end
end
tar(root, slip) click to toggle source

Create a tar file from the given root and packaging slip

@param [String] root

the root where the tar files are being created

@param [Hash<String, String>] slip

the map from physical file path to tarball file path

@return [StringIO]

the io object that contains the tarball contents
# File lib/stove/packager.rb, line 114
def tar(root, slip)
  io = StringIO.new('', 'r+b')
  Gem::Package::TarWriter.new(io) do |tar|
    slip.each do |original_file, tarball_file|
      mode = File.stat(original_file).mode

      if File.directory?(original_file)
        tar.mkdir(tarball_file, mode)
      else
        tar.add_file(tarball_file, mode) do |tf|
          File.open(original_file, 'rb') { |f| tf.write(f.read) }
        end
      end
    end
  end

  io.rewind
  io
end
tarball() click to toggle source
# File lib/stove/packager.rb, line 79
def tarball
  # Generate the metadata.json on the fly
  metadata_json = File.join(cookbook.path, 'metadata.json')
  json = JSON.fast_generate(cookbook.metadata.to_hash(extended_metadata))
  File.open(metadata_json, 'wb') { |f| f.write(json) }

  io  = tar(File.dirname(cookbook.path), packaging_slip)
  tgz = gzip(io)

  tempfile = Tempfile.new([cookbook.name, '.tar.gz'], Dir.tmpdir)
  tempfile.binmode

  while buffer = tgz.read(1024)
    tempfile.write(buffer)
  end

  tempfile.rewind
  tempfile
ensure
  if defined?(metadata_json) && File.exist?(File.join(cookbook.path, 'metadata.rb'))
    File.delete(metadata_json)
  end
end