fpm-cookery 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.travis.yml +10 -0
  2. data/CHANGELOG.md +8 -0
  3. data/bin/fpm-cook +1 -1
  4. data/fpm-cookery.gemspec +2 -1
  5. data/lib/fpm/cookery/chain_packager.rb +58 -0
  6. data/lib/fpm/cookery/cli.rb +93 -104
  7. data/lib/fpm/cookery/config.rb +86 -0
  8. data/lib/fpm/cookery/dependency_inspector.rb +7 -3
  9. data/lib/fpm/cookery/exceptions.rb +11 -0
  10. data/lib/fpm/cookery/facts.rb +1 -0
  11. data/lib/fpm/cookery/log.rb +1 -1
  12. data/lib/fpm/cookery/package/dir.rb +11 -35
  13. data/lib/fpm/cookery/package/gem.rb +25 -0
  14. data/lib/fpm/cookery/package/maintainer.rb +39 -0
  15. data/lib/fpm/cookery/package/package.rb +100 -0
  16. data/lib/fpm/cookery/package/version.rb +48 -0
  17. data/lib/fpm/cookery/packager.rb +65 -97
  18. data/lib/fpm/cookery/path.rb +4 -0
  19. data/lib/fpm/cookery/recipe.rb +59 -19
  20. data/lib/fpm/cookery/shellout.rb +35 -0
  21. data/lib/fpm/cookery/source_handler/curl.rb +12 -2
  22. data/lib/fpm/cookery/version.rb +1 -1
  23. data/recipes/arr-pm/recipe.rb +4 -0
  24. data/recipes/backports/recipe.rb +4 -0
  25. data/recipes/cabin/recipe.rb +4 -0
  26. data/recipes/clamp/recipe.rb +4 -0
  27. data/recipes/facter/recipe.rb +4 -0
  28. data/recipes/fpm-cookery-gem/addressable.rb +4 -0
  29. data/recipes/fpm-cookery-gem/arr-pm.rb +4 -0
  30. data/recipes/fpm-cookery-gem/backports.rb +4 -0
  31. data/recipes/fpm-cookery-gem/cabin.rb +4 -0
  32. data/recipes/fpm-cookery-gem/childprocess.rb +7 -0
  33. data/recipes/fpm-cookery-gem/clamp.rb +4 -0
  34. data/recipes/fpm-cookery-gem/facter.rb +4 -0
  35. data/recipes/fpm-cookery-gem/ffi.rb +4 -0
  36. data/recipes/fpm-cookery-gem/fpm.rb +7 -0
  37. data/recipes/fpm-cookery-gem/ftw.rb +7 -0
  38. data/recipes/fpm-cookery-gem/hiera.rb +7 -0
  39. data/recipes/fpm-cookery-gem/http_parser.rb.rb +4 -0
  40. data/recipes/fpm-cookery-gem/json.rb +4 -0
  41. data/recipes/fpm-cookery-gem/json_pure.rb +4 -0
  42. data/recipes/fpm-cookery-gem/puppet.rb +7 -0
  43. data/recipes/fpm-cookery-gem/recipe.rb +7 -0
  44. data/recipes/fpm-cookery-gem/rgen.rb +4 -0
  45. data/recipes/fpm-cookery/recipe.rb +1 -1
  46. data/recipes/fpm-cookery/ruby.rb +20 -10
  47. data/recipes/fpm/recipe.rb +4 -0
  48. data/recipes/json/recipe.rb +4 -0
  49. data/recipes/open4/recipe.rb +4 -0
  50. data/spec/config_spec.rb +167 -0
  51. data/spec/facts_spec.rb +7 -0
  52. data/spec/fixtures/test-config-1.yml +2 -0
  53. data/spec/package_maintainer_spec.rb +79 -0
  54. data/spec/package_spec.rb +182 -0
  55. data/spec/package_version_spec.rb +119 -0
  56. data/spec/recipe_spec.rb +18 -0
  57. data/spec/spec_helper.rb +1 -0
  58. metadata +61 -6
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ script: rake test
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - ruby-head
7
+
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: ruby-head
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # v0.16.0 (2013-09-21)
2
+ * Chain packager. (smasset)
3
+ * Add show-depends CLI option. (unakatsuo)
4
+ * Add fpm-cookery chain packager gem recipes. (smasset)
5
+ * Compatibility fixes for the latest FPM releases. (skiold)
6
+ * Fix problems with tar files that contain no directories. (narkisr)
7
+ * New CLI options parsing backend. (using clamp)
8
+
1
9
  # v0.15.0 (2013-06-13)
2
10
  * Add --no-deps option to disable dependency checks.
3
11
 
data/bin/fpm-cook CHANGED
@@ -4,4 +4,4 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
4
 
5
5
  require 'fpm/cookery/cli'
6
6
 
7
- FPM::Cookery::CLI.new.args(ARGV).run
7
+ FPM::Cookery::CLI.run
data/fpm-cookery.gemspec CHANGED
@@ -18,10 +18,11 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_development_dependency "minitest", "~> 4.0"
21
+ s.add_development_dependency "minitest", "~> 5.0"
22
22
  s.add_development_dependency "rake"
23
23
  s.add_runtime_dependency "fpm", "~> 0.4"
24
24
  s.add_runtime_dependency "facter"
25
25
  s.add_runtime_dependency "puppet"
26
26
  s.add_runtime_dependency "addressable"
27
+ s.add_runtime_dependency "systemu"
27
28
  end
@@ -0,0 +1,58 @@
1
+ require 'fpm/cookery/packager'
2
+ require 'fpm/cookery/omnibus_packager'
3
+
4
+ module FPM
5
+ module Cookery
6
+ class ChainPackager
7
+ include FPM::Cookery::Utils
8
+
9
+ attr_reader :packager, :recipe, :config
10
+
11
+ def initialize(packager, config = {})
12
+ @packager = packager
13
+ @recipe = packager.recipe
14
+ @config = config
15
+ end
16
+
17
+ def run
18
+ Log.info "Recipe #{recipe.name} is a chain package; looking for child recipes to build"
19
+
20
+ recipe.chain_recipes.each do |name|
21
+ recipe_file = build_recipe_file_path(name)
22
+
23
+ unless File.exists?(recipe_file)
24
+ Log.fatal "Cannot find a recipe for #{name} at #{recipe_file}"
25
+ exit 1
26
+ end
27
+
28
+ Log.info "Located recipe at #{recipe_file} for child recipe #{name}; starting build"
29
+
30
+ FPM::Cookery::Book.instance.load_recipe(recipe_file) do |dep_recipe|
31
+ depPackager = FPM::Cookery::Packager.new(dep_recipe, config)
32
+ depPackager.target = FPM::Cookery::Facts.target.to_s
33
+
34
+ #Chain, chain, chain ...
35
+ if dep_recipe.omnibus_package == true
36
+ FPM::Cookery::OmnibusPackager.new(depPackager, config).run
37
+ elsif dep_recipe.chain_package == true
38
+ FPM::Cookery::ChainPackager.new(depPackager, config).run
39
+ else
40
+ depPackager.dispense
41
+ end
42
+ end
43
+
44
+ Log.info "Finished building #{name}, moving on to next recipe"
45
+ end
46
+
47
+ packager.dispense
48
+ end
49
+
50
+ private
51
+
52
+ def build_recipe_file_path(name)
53
+ # Look for recipes in the same dir as the recipe we loaded
54
+ File.expand_path(File.dirname(recipe.filename) + "/#{name}.rb")
55
+ end
56
+ end
57
+ end
58
+ end
@@ -2,51 +2,74 @@ require 'fpm/cookery/book_hook'
2
2
  require 'fpm/cookery/recipe'
3
3
  require 'fpm/cookery/facts'
4
4
  require 'fpm/cookery/packager'
5
+ require 'fpm/cookery/chain_packager'
5
6
  require 'fpm/cookery/omnibus_packager'
6
7
  require 'fpm/cookery/log'
7
8
  require 'fpm/cookery/log/output/console'
8
9
  require 'fpm/cookery/log/output/console_color'
9
- require 'optparse'
10
+ require 'fpm/cookery/config'
11
+ require 'clamp'
10
12
 
11
13
  module FPM
12
14
  module Cookery
13
- class CLI
14
- def initialize
15
- @colors = true
16
- @debug = false
17
- end
15
+ class CLI < Clamp::Command
16
+ option ['-c', '--color'], :flag, 'toggle color'
17
+ option ['-D', '--debug'], :flag, 'enable debug output'
18
+ option ['-t', '--target'], 'TARGET', 'set desired fpm output target (deb, rpm, etc)'
19
+ option ['-p', '--platform'], 'PLATFORM', 'set the target platform (centos, ubuntu, debian)'
20
+ option ['-V', '--version'], :flag, 'show fpm-cookery and fpm version'
21
+ option '--[no-]deps', :flag, 'enable/disable dependency checking',
22
+ :attribute_name => 'dependency_check'
23
+
24
+ class Command < self
25
+ def recipe_file
26
+ file = File.expand_path(recipe)
18
27
 
19
- def args(argv)
20
- program = File.basename($0)
21
- options = OptionParser.new
22
- options.banner = \
23
- "Usage: #{program} [options] [path/to/recipe.rb] action [...]"
24
- options.separator "Actions:"
25
- options.separator " package - builds the package"
26
- options.separator " clean - cleans up"
27
- options.separator " install-deps - installs build and runtime dependencies"
28
- options.separator "Options:"
29
-
30
- options.on("-c", "--color",
31
- "Toggle color. (default #{@colors.inspect})") do |o|
32
- @colors = !@colors
33
- end
28
+ # Allow giving the directory containing a recipe.rb
29
+ if File.directory?(file) && File.exists?(File.join(file, 'recipe.rb'))
30
+ file = File.join(file, 'recipe.rb')
31
+ end
34
32
 
35
- options.on("-D", "--debug", "Enable debug output.") do |o|
36
- @debug = true
33
+ file
37
34
  end
38
35
 
39
- options.on("-t TARGET", "--target TARGET",
40
- "Set the desired fpm output target (deb, rpm, etc)") do |o|
41
- @target = o
36
+ def validate
37
+ unless File.exists?(recipe_file)
38
+ Log.error 'No recipe.rb found in the current directory, abort.'
39
+ exit 1
40
+ end
41
+
42
+ # Override the detected platform.
43
+ if platform
44
+ FPM::Cookery::Facts.platform = platform
45
+ end
46
+
47
+ if target
48
+ FPM::Cookery::Facts.target = target
49
+ end
50
+
51
+ if FPM::Cookery::Facts.target.nil?
52
+ Log.error "No target given and we're unable to detect your platform"
53
+ exit 1
54
+ end
42
55
  end
43
56
 
44
- options.on("-p PLATFORM", "--platform PLATFORM",
45
- "Set the target platform. (centos, ubuntu, debian)") do |o|
46
- @platform = o
57
+ def execute
58
+ show_version if version?
59
+ init_logging
60
+ validate
61
+
62
+ FPM::Cookery::BaseRecipe.send(:include, FPM::Cookery::BookHook)
63
+
64
+ FPM::Cookery::Book.instance.load_recipe(recipe_file) do |recipe|
65
+ packager = FPM::Cookery::Packager.new(recipe, :dependency_check => config.dependency_check)
66
+ packager.target = FPM::Cookery::Facts.target.to_s
67
+
68
+ exec(config, recipe, packager)
69
+ end
47
70
  end
48
71
 
49
- options.on("-V", "--version", "Show fpm-cookery and fpm version") do
72
+ def show_version
50
73
  require 'fpm/version'
51
74
  require 'fpm/cookery/version'
52
75
 
@@ -54,99 +77,65 @@ module FPM
54
77
  exit 0
55
78
  end
56
79
 
57
- options.on("--no-deps", "Disable dependency checking") do |o|
58
- @nodep = true
80
+ def config
81
+ @config ||= FPM::Cookery::Config.from_cli(self)
59
82
  end
60
83
 
61
- # Parse flags and such, remainder is all non-option args.
62
- remainder = options.parse(argv)
84
+ def init_logging
85
+ FPM::Cookery::Log.enable_debug(config.debug)
63
86
 
64
- # Initialize logging.
65
- FPM::Cookery::Log.enable_debug(@debug)
66
- if @colors
67
- FPM::Cookery::Log.output(FPM::Cookery::Log::Output::ConsoleColor.new)
68
- else
69
- FPM::Cookery::Log.output(FPM::Cookery::Log::Output::Console.new)
87
+ if config.color?
88
+ FPM::Cookery::Log.output(FPM::Cookery::Log::Output::ConsoleColor.new)
89
+ else
90
+ FPM::Cookery::Log.output(FPM::Cookery::Log::Output::Console.new)
91
+ end
70
92
  end
93
+ end
71
94
 
72
- # Default recipe to find is in current directory named 'recipe.rb'
73
- @filename = File.expand_path('recipe.rb')
74
-
75
- # See if something that looks like a recipe path is in arguments
76
- remainder.each do |arg|
77
- # If 'foo.rb' was given, and it exists, use it.
78
- if arg =~ /\.rb$/ and File.exists?(arg)
79
- remainder.delete(arg)
80
- @filename = arg
81
- break
82
- end
95
+ class PackageCmd < Command
96
+ parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
83
97
 
84
- # Allow giving the directory containing a recipe.rb
85
- if File.directory?(arg) and File.exists?(File.join(arg, "recipe.rb"))
86
- remainder.delete(arg)
87
- @filename = File.join(arg, "recipe.rb")
88
- break
98
+ def exec(config, recipe, packager)
99
+ if recipe.omnibus_package == true
100
+ FPM::Cookery::OmnibusPackager.new(packager).run
101
+ elsif recipe.chain_package == true
102
+ FPM::Cookery::ChainPackager.new(packager, :dependency_check => config.dependency_check).run
103
+ else
104
+ packager.dispense
89
105
  end
90
106
  end
91
-
92
- # Everything that's not the recipe filename is an action.
93
- @actions = remainder
94
- return self
95
107
  end
96
108
 
97
- def validate
98
- unless File.exists?(@filename)
99
- Log.error 'No recipe.rb found in the current directory, abort.'
100
- exit 1
101
- end
102
-
103
- # Default action is "package"
104
- if @actions.empty?
105
- @actions = ["package"]
106
- end
109
+ class CleanCmd < Command
110
+ parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
107
111
 
108
- # Override the detected platform.
109
- if @platform
110
- FPM::Cookery::Facts.platform = @platform
112
+ def exec(config, recipe, packager)
113
+ packager.cleanup
111
114
  end
115
+ end
112
116
 
113
- if @target
114
- FPM::Cookery::Facts.target = @target
115
- end
117
+ class InstallDepsCmd < Command
118
+ parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
116
119
 
117
- if FPM::Cookery::Facts.target.nil?
118
- Log.error "No target given and we're unable to detect your platform"
119
- exit 1
120
+ def exec(config, recipe, packager)
121
+ packager.install_deps
120
122
  end
121
-
122
123
  end
123
124
 
124
- def run
125
- validate
126
-
127
- FPM::Cookery::Recipe.send(:include, FPM::Cookery::BookHook)
128
-
129
- FPM::Cookery::Book.instance.load_recipe(@filename) do |recipe|
130
- packager = FPM::Cookery::Packager.new(recipe, :dependency_check => !@nodep)
131
- packager.target = FPM::Cookery::Facts.target.to_s
132
-
133
- @actions.each do |action|
134
- case action
135
- when "clean" ; packager.cleanup
136
- when "package"
137
- if recipe.omnibus_package == true
138
- FPM::Cookery::OmnibusPackager.new(packager).run
139
- else
140
- packager.dispense
141
- end
142
- when "install-deps" ; packager.install_deps
143
- else
144
- # TODO(sissel): fail if this happens
145
- Log.error "Unknown action: #{action}"
146
- end
147
- end
125
+ class ShowDepsCmd < Command
126
+ parameter '[RECIPE]', 'the recipe file', :default => 'recipe.rb'
127
+
128
+ def exec(config, recipe, packager)
129
+ puts recipe.depends_all.join(' ')
148
130
  end
149
131
  end
132
+
133
+ self.default_subcommand = 'package'
134
+
135
+ subcommand 'package', 'builds the package', PackageCmd
136
+ subcommand 'clean', 'cleans up', CleanCmd
137
+ subcommand 'install-deps', 'installs build and runtime dependencies', InstallDepsCmd
138
+ subcommand 'show-deps', 'show build and runtime dependencies', ShowDepsCmd
150
139
  end
151
140
  end
152
141
  end
@@ -0,0 +1,86 @@
1
+ require 'yaml'
2
+ require 'fpm/cookery/exceptions'
3
+
4
+ module FPM
5
+ module Cookery
6
+ class Config
7
+ ATTRIBUTES = [
8
+ :color, :debug, :target, :platform, :maintainer, :vendor,
9
+ :skip_package, :keep_destdir, :dependency_check
10
+ ].freeze
11
+
12
+ DEFAULTS = {
13
+ :color => true,
14
+ :debug => false,
15
+ :dependency_check => true,
16
+ :skip_package => false,
17
+ :keep_destdir => false
18
+ }.freeze
19
+
20
+ def self.load_file(paths)
21
+ path = Array(paths).find {|p| File.exist?(p) }
22
+
23
+ path ? new(YAML.load_file(path)) : new
24
+ end
25
+
26
+ def self.from_cli(cli)
27
+ new.tap do |config|
28
+ ATTRIBUTES.each do |name|
29
+ if cli.respond_to?("#{name}?")
30
+ value = cli.__send__("#{name}?")
31
+ elsif cli.respond_to?(name)
32
+ value = cli.__send__(name)
33
+ else
34
+ value = nil
35
+ end
36
+
37
+ config.__send__("#{name}=", value) unless value.nil?
38
+ end
39
+ end
40
+ end
41
+
42
+ attr_accessor *ATTRIBUTES
43
+
44
+ ATTRIBUTES.each do |name|
45
+ class_eval %Q(
46
+ def #{name}?
47
+ !!#{name}
48
+ end
49
+ )
50
+ end
51
+
52
+ def initialize(data = {})
53
+ validate_input(data)
54
+
55
+ DEFAULTS.merge(data).each do |key, value|
56
+ self.__send__("#{key}=", value)
57
+ end
58
+ end
59
+
60
+ def to_hash
61
+ ATTRIBUTES.inject({}) do |hash, attribute|
62
+ hash[attribute] = __send__(attribute)
63
+ hash
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def validate_input(data)
70
+ errors = []
71
+
72
+ data.keys.each do |key|
73
+ unless ATTRIBUTES.include?(key.to_sym)
74
+ errors << key
75
+ end
76
+ end
77
+
78
+ unless errors.empty?
79
+ e = Error::InvalidConfigKey.new("Invalid config keys: #{errors.join(', ')}")
80
+ e.invalid_keys = errors
81
+ raise e
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -15,9 +15,7 @@ module FPM
15
15
 
16
16
  Log.info "Verifying build_depends and depends with Puppet"
17
17
 
18
- missing = (build_depends + depends).reject do |package|
19
- self.package_installed?(package)
20
- end
18
+ missing = missing_packages(build_depends + depends)
21
19
 
22
20
  if missing.length == 0
23
21
  Log.info "All build_depends and depends packages installed"
@@ -36,6 +34,12 @@ module FPM
36
34
 
37
35
  end
38
36
 
37
+ def self.missing_packages(*pkgs)
38
+ pkgs.flatten.reject do |package|
39
+ self.package_installed?(package)
40
+ end
41
+ end
42
+
39
43
  def self.package_installed?(package)
40
44
  Log.info("Verifying package: #{package}")
41
45
  return unless self.package_suitable?(package)