Skip to content

Commit

Permalink
Merge branch 'master' of github.com:BaxterStockman/fpm-cookery
Browse files Browse the repository at this point in the history
* 'master' of github.com:BaxterStockman/fpm-cookery:
  Add default package version and guard against nil/empty versions (bernd#176)
  Ensure consistent extracted source value from all source handlers
  Make vendor delimiter configurable
  Avoid cache with directory source handler and check absolute path
  Also peg json_pure version to run on Ruby 1.9.3 again
  Fix example for inspect command
  Pegged json dependency to version compatible with pre-2.0 Rubies (bernd#166)
  Add `inspect` subcommand (bernd#165)
  Fix typo and add missing tests (bernd#163)
  Add alpine (apk) support (bernd#162)
  Rejiggered Facter-related code to use Facter.value rather than Facter.fact
  Reworked generation of cookie names (bernd#157)
  Add lsbcodename (bernd#158)
  • Loading branch information
Matt Schreiber authored and Matt Schreiber committed Oct 23, 2016
2 parents 58fccc0 + fded99b commit 2de54f3
Show file tree
Hide file tree
Showing 19 changed files with 376 additions and 134 deletions.
4 changes: 3 additions & 1 deletion fpm-cookery.gemspec
Expand Up @@ -18,7 +18,7 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]

s.add_development_dependency "rspec", "~> 3.0"
s.add_development_dependency "rspec", "~> 3.3"
s.add_development_dependency "rake"
s.add_development_dependency "pry"
s.add_development_dependency "simplecov", "~> 0.11"
Expand All @@ -27,4 +27,6 @@ Gem::Specification.new do |s|
s.add_runtime_dependency "puppet", "~> 3.4"
s.add_runtime_dependency "addressable", "~> 2.3.8"
s.add_runtime_dependency "systemu"
s.add_runtime_dependency "json", ">= 1.7.7", "< 2.0"
s.add_runtime_dependency "json_pure", ">= 1.7.7", "< 2.0"
end
4 changes: 2 additions & 2 deletions lib/fpm/cookery/book.rb
Expand Up @@ -15,10 +15,10 @@ def initialize
# Load the given file and instantiate an object. Wrap the class in an
# anonymous module to avoid namespace cluttering. (see Kernel.load)
def load_recipe(filename, config, &callback)
@filename = FPM::Cookery::Path.new(filename)
@filename = FPM::Cookery::Path.new(filename).realpath
@config = config

Kernel.load(filename, true)
Kernel.load(@filename.to_path, true)
callback.call(@recipe.new)
end

Expand Down
44 changes: 39 additions & 5 deletions lib/fpm/cookery/cli.rb
Expand Up @@ -33,8 +33,14 @@ class CLI < Clamp::Command
:attribute_name => 'hiera_config'
option '--skip-package', :flag, 'do not call FPM to build the package',
:attribute_name => 'skip_package'
option '--vendor-delimiter', 'DELIMITER', 'vendor delimiter for version string',
:attribute_name => 'vendor_delimiter'

class Command < self
def self.add_recipe_parameter!
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
end

def recipe_file
file = File.expand_path(recipe)

Expand Down Expand Up @@ -108,7 +114,7 @@ def init_logging
end

class PackageCmd < Command
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
add_recipe_parameter!

def exec(config, recipe, packager)
if recipe.omnibus_package == true
Expand All @@ -122,23 +128,23 @@ def exec(config, recipe, packager)
end

class CleanCmd < Command
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
add_recipe_parameter!

def exec(config, recipe, packager)
packager.cleanup
end
end

class InstallDepsCmd < Command
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
add_recipe_parameter!

def exec(config, recipe, packager)
packager.install_deps
end
end

class InstallBuildDepsCmd < Command
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
add_recipe_parameter!

def exec(config, recipe, packager)
if recipe.omnibus_package == true
Expand All @@ -152,20 +158,48 @@ def exec(config, recipe, packager)
end

class ShowDepsCmd < Command
parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
add_recipe_parameter!

def exec(config, recipe, packager)
puts recipe.depends_all.join(' ')
end
end

class InspectCmd < Command
add_recipe_parameter!

option ['-F', '--format'], 'TEMPLATE', 'ERB template string'
option '--terse', :flag, 'show recipe data in compact form'

self.description = <<DESCRIPTION
With --format, templates and prints an ERB string with recipe attributes.
Example:
# Given a recipe with name "foo", version "1.1", revision "12":
$ fpm-cook inspect -t rpm --format "<%= name %>-<%= version %>-<%= revision %>.rpm"
foo-1.1-12.rpm
Without --format, prints a JSON representation of the recipe.
DESCRIPTION

def exec(config, recipe, packager)
unless format.nil?
puts recipe.template(format)
else
puts terse? ? recipe.to_json : recipe.to_pretty_json
end
end
end

self.default_subcommand = 'package'

subcommand 'package', 'builds the package', PackageCmd
subcommand 'clean', 'cleans up', CleanCmd
subcommand 'install-deps', 'installs build and runtime dependencies', InstallDepsCmd
subcommand 'install-build-deps', 'installs build dependencies', InstallBuildDepsCmd
subcommand 'show-deps', 'show build and runtime dependencies', ShowDepsCmd
subcommand 'inspect', 'inspect recipe attributes', InspectCmd
end
end
end
3 changes: 2 additions & 1 deletion lib/fpm/cookery/config.rb
Expand Up @@ -7,7 +7,8 @@ class Config
ATTRIBUTES = [
:color, :debug, :target, :platform, :maintainer, :vendor,
:skip_package, :keep_destdir, :dependency_check, :quiet,
:tmp_root, :pkg_dir, :cache_dir, :data_dir, :hiera_config
:tmp_root, :pkg_dir, :cache_dir, :data_dir, :hiera_config,
:vendor_delimiter
].freeze

DEFAULTS = {
Expand Down
85 changes: 50 additions & 35 deletions lib/fpm/cookery/facts.rb
Expand Up @@ -3,41 +3,56 @@
module FPM
module Cookery
class Facts
def self.arch
@arch ||= Facter.fact(:architecture).value.downcase.to_sym
end

def self.platform
@platform ||= Facter.fact(:operatingsystem).value.downcase.to_sym
end

def self.platform=(value)
@platform = value.downcase.to_sym
end

def self.osrelease
@osrelease ||= Facter.fact(:operatingsystemrelease).value
end

def self.osmajorrelease
@osmajorrelease ||= Facter.fact(:operatingsystemmajrelease).value
end

def self.target
@target ||= case platform
when :centos, :redhat, :fedora, :amazon,
:scientific, :oraclelinux then :rpm
when :debian, :ubuntu then :deb
when :darwin then :osxpkg
end
end

def self.target=(value)
@target = value.to_sym
end

def self.reset!
instance_variables.each {|v| instance_variable_set(v, nil) }
class << self
def arch
@arch ||= value(:architecture)
end

def platform
@platform ||= value(:operatingsystem)
end

def platform=(value)
@platform = value.downcase.to_sym
end

def osrelease
@osrelease ||= value(:operatingsystemrelease, false)
end

def lsbcodename
@lsbcodename ||= value(:lsbcodename)
end

def osmajorrelease
@osmajorrelease ||= value(:operatingsystemmajrelease, false)
end

def target
@target ||= case platform
when :centos, :redhat, :fedora, :amazon,
:scientific, :oraclelinux then :rpm
when :debian, :ubuntu then :deb
when :darwin then :osxpkg
when :alpine then :apk
end
end

def target=(value)
@target = value.to_sym
end

def reset!
instance_variables.each {|v| instance_variable_set(v, nil) }
end

private

def value(fact_name, symbolize = true)
v = Facter.value(fact_name)
return v if v.nil? or !symbolize
return v.downcase.to_sym
end
end
end
end
Expand Down
15 changes: 11 additions & 4 deletions lib/fpm/cookery/package/version.rb
Expand Up @@ -16,7 +16,11 @@ class Version
:default => '-'
}

attr_reader :version, :epoch, :revision
# fpm sets the default version in FPM::Command; since we bypass the
# command line interface, we need to set our own value.
DEFAULT_VERSION = '1.0'

attr_reader :epoch, :revision

def initialize(recipe, target, config)
@recipe = recipe
Expand All @@ -30,11 +34,16 @@ def vendor
@config[:vendor] || @recipe.vendor
end

def version
@version ||= DEFAULT_VERSION
end

def revision_delimiter
REVISION_DELIMITER[:default]
end

def vendor_delimiter
return @config[:vendor_delimiter] if @config[:vendor_delimiter]
VENDOR_DELIMITER[@target.to_sym] || VENDOR_DELIMITER[:default]
end

Expand All @@ -49,9 +58,7 @@ def to_s
private

def split_version(version)
epoch, version = version.split(':', 2)

version.nil? ? [epoch, nil] : [version, epoch]
(version || '').split(':', 2).reject(&:empty?).reverse
end
end
end
Expand Down
15 changes: 9 additions & 6 deletions lib/fpm/cookery/packager.rb
Expand Up @@ -58,10 +58,12 @@ def install_deps
Log.info("All dependencies installed!")
end

def package_name
[recipe.name, recipe.version, recipe.revision].compact.join('-')
end

def dispense
env = ENV.to_hash
package_name = "#{recipe.name}-#{recipe.version}"
platform = FPM::Cookery::Facts.platform
target = FPM::Cookery::Facts.target

Expand Down Expand Up @@ -113,7 +115,7 @@ def dispense
recipe.builddir.mkdir
Dir.chdir(recipe.builddir) do
recipe.run_lifecycle_hook(:before_source_extraction)
extract_cookie = extract_cookie_name(package_name)
extract_cookie = extract_cookie_name

# Do not extract source again because it might destroy changes
# that have been made to the source. (like patches)
Expand All @@ -131,7 +133,7 @@ def dispense
end

# Make the path to the extracted source available in the recipe.
recipe.sourcedir = recipe.builddir(extracted_source)
recipe.sourcedir = extracted_source
recipe.run_lifecycle_hook(:after_source_extraction, recipe.sourcedir)

Log.info "Using source directory: #{extracted_source}"
Expand All @@ -147,7 +149,8 @@ def dispense
else
recipe.run_lifecycle_hook(:before_build)
Log.info "Building in #{File.expand_path(extracted_source, recipe.builddir)}"
recipe.build and FileUtils.touch(build_cookie)
recipe.build
FileUtils.touch(build_cookie)
recipe.run_lifecycle_hook(:after_build)
end

Expand Down Expand Up @@ -177,11 +180,11 @@ def dispense
ENV.replace(env)
end

def extract_cookie_name(name)
def extract_cookie_name(name = package_name)
(recipe.builddir/".extract-cookie-#{name.gsub(/[^\w]/,'_')}").to_s
end

def build_cookie_name(name)
def build_cookie_name(name = package_name)
(recipe.builddir/".build-cookie-#{name.gsub(/[^\w]/,'_')}").to_s
end

Expand Down
25 changes: 25 additions & 0 deletions lib/fpm/cookery/recipe.rb
@@ -1,5 +1,7 @@
require 'erb'
require 'forwardable'
require 'fileutils'
require 'json'
require 'fpm/cookery/facts'
require 'fpm/cookery/hiera'
require 'fpm/cookery/inheritable_attr'
Expand Down Expand Up @@ -141,6 +143,29 @@ def initialize(defer_application = false)
apply unless defer_application
end

def to_h
attr_registry.values.flatten.each_with_object({}) do |m, a|
a[m] = send(m) unless m == :attr_registry
end
end

def to_json
JSON.unparse(to_h)
end

def to_pretty_json
JSON.pretty_generate(to_h)
end

def template(format)
renderer = ERB.new(format, nil, '-')
renderer.result(binding)
rescue NameError, NoMethodError => e
message = "Error evaluating format string: no attribute `#{e.name}' for recipe"
Log.error message
raise Error::ExecutionFailure, message
end

class << self
def source(source = nil, spec = {})
#puts "#=> SOURCE: #{@source.inspect}"
Expand Down
15 changes: 14 additions & 1 deletion lib/fpm/cookery/source_handler.rb
Expand Up @@ -14,6 +14,7 @@ module Cookery
class SourceHandler
DEFAULT_HANDLER = :curl
LOCAL_HANDLER = :local_path
REQUIRED_METHODS = [:fetch, :extract]

extend Forwardable
def_delegators :@handler, :fetch, :extract, :local_path, :checksum?
Expand Down Expand Up @@ -46,7 +47,19 @@ def get_source_handler(provider)

def handler_to_class(provider)
begin
self.class.const_get(provider.to_s.split('_').map(&:capitalize).join)
maybe_klass = self.class.const_get(provider.to_s.split('_').map(&:capitalize).join)

instance_method_map = Hash[maybe_klass.instance_methods.map { |m| [m, true] }]
missing_methods = REQUIRED_METHODS.find_all { |m| !instance_method_map.key?(m) }

unless missing_methods.empty?
formatted_missing = missing_methods.map { |m| "`#{m}'" }.join(', ')
message = %{#{maybe_klass} does not implement required method(s): #{formatted_missing}}
Log.error message
raise Error::Misconfiguration, message
end

maybe_klass
rescue NameError => e
Log.error "Specified provider #{provider} does not exist."
raise Error::Misconfiguration, e.message
Expand Down

0 comments on commit 2de54f3

Please sign in to comment.