chef-gen-flavors 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/.rubocop.yml +23 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +242 -0
  7. data/Guardfile +15 -0
  8. data/History.md +10 -0
  9. data/LICENSE +15 -0
  10. data/Manifest.txt +46 -0
  11. data/README.md +311 -0
  12. data/Rakefile +85 -0
  13. data/chef-gen-flavors.gemspec +75 -0
  14. data/lib/chef_gen/flavor.rb +5 -0
  15. data/lib/chef_gen/flavor_base.rb +230 -0
  16. data/lib/chef_gen/flavors.rb +173 -0
  17. data/lib/chef_gen/snippet/attributes.rb +22 -0
  18. data/lib/chef_gen/snippet/chef_spec.rb +41 -0
  19. data/lib/chef_gen/snippet/cookbook_base.rb +64 -0
  20. data/lib/chef_gen/snippet/example_file.rb +23 -0
  21. data/lib/chef_gen/snippet/example_template.rb +25 -0
  22. data/lib/chef_gen/snippet/recipes.rb +22 -0
  23. data/lib/chef_gen/snippet/resource_provider.rb +24 -0
  24. data/lib/chef_gen/snippet/standard_ignore.rb +97 -0
  25. data/lib/chef_gen/snippet/style_rubocop.rb +14 -0
  26. data/lib/chef_gen/snippet/test_kitchen.rb +51 -0
  27. data/lib/chef_gen/snippets.rb +15 -0
  28. data/spec/lib/chef_gen/flavor_base_spec.rb +164 -0
  29. data/spec/lib/chef_gen/flavors_spec.rb +114 -0
  30. data/spec/lib/chef_gen/snippet/attributes_spec.rb +45 -0
  31. data/spec/lib/chef_gen/snippet/chef_spec_spec.rb +45 -0
  32. data/spec/lib/chef_gen/snippet/cookbook_base_spec.rb +37 -0
  33. data/spec/lib/chef_gen/snippet/example_file_spec.rb +45 -0
  34. data/spec/lib/chef_gen/snippet/example_template_spec.rb +45 -0
  35. data/spec/lib/chef_gen/snippet/recipes_spec.rb +45 -0
  36. data/spec/lib/chef_gen/snippet/resource_provider_spec.rb +45 -0
  37. data/spec/lib/chef_gen/snippet/standard_ignore_spec.rb +40 -0
  38. data/spec/lib/chef_gen/snippet/style_rubocop_spec.rb +36 -0
  39. data/spec/lib/chef_gen/snippet/test_kitchen_spec.rb +49 -0
  40. data/spec/spec_helper.rb +38 -0
  41. data/spec/support/fixtures/code_generator/metadata.rb +2 -0
  42. data/spec/support/fixtures/code_generator/recipes/cookbook.rb +1 -0
  43. data/spec/support/fixtures/code_generator_2/metadata.rb +2 -0
  44. data/spec/support/fixtures/code_generator_2/recipes/cookbook.rb +1 -0
  45. data/spec/support/fixtures/lib/chef_gen/flavor/bar.rb +21 -0
  46. data/spec/support/fixtures/lib/chef_gen/flavor/baz.rb +6 -0
  47. data/spec/support/fixtures/lib/chef_gen/flavor/foo.rb +9 -0
  48. metadata +317 -0
data/Rakefile ADDED
@@ -0,0 +1,85 @@
1
+ require 'chef_gen/flavors'
2
+
3
+ begin
4
+ require 'hoe'
5
+ Hoe.plugin :gemspec
6
+ Hoe.plugins.delete :test
7
+ Hoe.spec 'chef-gen-flavors' do |s|
8
+ s.version = ChefGen::Flavors::VERSION
9
+ developer 'James FitzGibbon', 'james.i.fitzgibbon@nordstrom.com'
10
+ license 'apache2'
11
+ extra_deps << ['little-plugger', '~> 1.1']
12
+ extra_deps << ['bogo-ui', '~> 0.1']
13
+ extra_dev_deps << ['chef-dk', '~> 0.5']
14
+ extra_dev_deps << ['hoe', '~> 3.13']
15
+ extra_dev_deps << ['hoe-gemspec', '~> 1.0']
16
+ extra_dev_deps << ['rake', '~> 10.3']
17
+ extra_dev_deps << ['rspec', '~> 3.1']
18
+ extra_dev_deps << ['guard', '~> 2.12']
19
+ extra_dev_deps << ['guard-rspec', '~> 4.2']
20
+ extra_dev_deps << ['guard-rake', '~> 0.0']
21
+ extra_dev_deps << ['guard-rubocop', '~> 1.2']
22
+ extra_dev_deps << ['simplecov', '~> 0.9']
23
+ extra_dev_deps << ['simplecov-console', '~> 0.2']
24
+ extra_dev_deps << ['yard', '~> 0.8']
25
+ end
26
+ # re-generate our gemspec before packaging
27
+ task package: 'gem:spec'
28
+ rescue LoadError
29
+ puts 'hoe not available; disabling tasks'
30
+ end
31
+
32
+ # Style Tests
33
+ begin
34
+ require 'rubocop/rake_task'
35
+ RuboCop::RakeTask.new do |t|
36
+ t.formatters = ['progress']
37
+ t.options = ['-D']
38
+ t.patterns = %w(
39
+ lib/**/*.rb
40
+ spec/**/*.rb
41
+ ./Rakefile
42
+ )
43
+ end
44
+ desc 'Run Style Tests'
45
+ task style: [:rubocop]
46
+ rescue LoadError
47
+ puts 'rubocop not available; disabling tasks'
48
+ end
49
+
50
+ # Unit Tests
51
+ begin
52
+ require 'rspec/core/rake_task'
53
+ RSpec::Core::RakeTask.new
54
+
55
+ # Coverage
56
+ desc 'Generate unit test coverage report'
57
+ task :coverage do
58
+ ENV['COVERAGE'] = 'true'
59
+ Rake::Task[:test].invoke
60
+ end
61
+ rescue LoadError
62
+ puts 'rspec not available; disabling tasks'
63
+ # create a no-op task so that :default works
64
+ task :test
65
+ end
66
+
67
+ # Documentation
68
+ begin
69
+ require 'yard'
70
+ require 'yard/rake/yardoc_task'
71
+ YARD::Rake::YardocTask.new(:doc) do |t|
72
+ t.options = ['-m', 'markdown', '--private']
73
+ t.stats_options = ['--list-undoc']
74
+ end
75
+ rescue LoadError
76
+ puts 'yard not available; disabling tasks'
77
+ end
78
+
79
+ # test is an alias for spec
80
+ desc 'runs unit tests'
81
+ task test: [:spec]
82
+
83
+ # default is to test everything
84
+ desc 'runs all tests'
85
+ task default: :test
@@ -0,0 +1,75 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # stub: chef-gen-flavors 0.3.0.20150514061941 ruby lib
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "chef-gen-flavors"
6
+ s.version = "0.3.0.20150514061941"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["James FitzGibbon"]
11
+ s.date = "2015-05-14"
12
+ s.description = "chef-gen-flavors is a framework for creating custom templates for the\n'chef generate' command provided by ChefDK.\n\nThis gem simply provides a framework; templates are provided by separate\ngems, which you can host privately for use within your organization or\npublicly for the Chef community to use.\n\nAt present this is focused primarily on providing templates for generation of\ncookbooks, as this is where most organization-specific customization takes place.\nSupport for the other artifacts that ChefDK can generate may work, but is not\nthe focus of early releases."
13
+ s.email = ["james.i.fitzgibbon@nordstrom.com"]
14
+ s.extra_rdoc_files = ["History.md", "Manifest.txt", "README.md"]
15
+ s.files = [".rspec", ".rubocop.yml", ".travis.yml", "Gemfile", "Gemfile.lock", "Guardfile", "History.md", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "chef-gen-flavors.gemspec", "lib/chef_gen/flavor.rb", "lib/chef_gen/flavor_base.rb", "lib/chef_gen/flavors.rb", "lib/chef_gen/snippet/attributes.rb", "lib/chef_gen/snippet/chef_spec.rb", "lib/chef_gen/snippet/cookbook_base.rb", "lib/chef_gen/snippet/example_file.rb", "lib/chef_gen/snippet/example_template.rb", "lib/chef_gen/snippet/recipes.rb", "lib/chef_gen/snippet/resource_provider.rb", "lib/chef_gen/snippet/standard_ignore.rb", "lib/chef_gen/snippet/style_rubocop.rb", "lib/chef_gen/snippet/test_kitchen.rb", "lib/chef_gen/snippets.rb", "spec/lib/chef_gen/flavor_base_spec.rb", "spec/lib/chef_gen/flavors_spec.rb", "spec/lib/chef_gen/snippet/attributes_spec.rb", "spec/lib/chef_gen/snippet/chef_spec_spec.rb", "spec/lib/chef_gen/snippet/cookbook_base_spec.rb", "spec/lib/chef_gen/snippet/example_file_spec.rb", "spec/lib/chef_gen/snippet/example_template_spec.rb", "spec/lib/chef_gen/snippet/recipes_spec.rb", "spec/lib/chef_gen/snippet/resource_provider_spec.rb", "spec/lib/chef_gen/snippet/standard_ignore_spec.rb", "spec/lib/chef_gen/snippet/style_rubocop_spec.rb", "spec/lib/chef_gen/snippet/test_kitchen_spec.rb", "spec/spec_helper.rb", "spec/support/fixtures/code_generator/metadata.rb", "spec/support/fixtures/code_generator/recipes/cookbook.rb", "spec/support/fixtures/code_generator_2/metadata.rb", "spec/support/fixtures/code_generator_2/recipes/cookbook.rb", "spec/support/fixtures/lib/chef_gen/flavor/bar.rb", "spec/support/fixtures/lib/chef_gen/flavor/baz.rb", "spec/support/fixtures/lib/chef_gen/flavor/foo.rb"]
16
+ s.homepage = "https://github.com/Nordstrom/chef-gen-flavors"
17
+ s.licenses = ["apache2"]
18
+ s.rdoc_options = ["--main", "README.md"]
19
+ s.rubygems_version = "2.4.4"
20
+ s.summary = "chef-gen-flavors is a framework for creating custom templates for the 'chef generate' command provided by ChefDK"
21
+
22
+ if s.respond_to? :specification_version then
23
+ s.specification_version = 4
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ s.add_runtime_dependency(%q<little-plugger>, ["~> 1.1"])
27
+ s.add_runtime_dependency(%q<bogo-ui>, ["~> 0.1"])
28
+ s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
29
+ s.add_development_dependency(%q<chef-dk>, ["~> 0.5"])
30
+ s.add_development_dependency(%q<hoe>, ["~> 3.13"])
31
+ s.add_development_dependency(%q<hoe-gemspec>, ["~> 1.0"])
32
+ s.add_development_dependency(%q<rake>, ["~> 10.3"])
33
+ s.add_development_dependency(%q<rspec>, ["~> 3.1"])
34
+ s.add_development_dependency(%q<guard>, ["~> 2.12"])
35
+ s.add_development_dependency(%q<guard-rspec>, ["~> 4.2"])
36
+ s.add_development_dependency(%q<guard-rake>, ["~> 0.0"])
37
+ s.add_development_dependency(%q<guard-rubocop>, ["~> 1.2"])
38
+ s.add_development_dependency(%q<simplecov>, ["~> 0.9"])
39
+ s.add_development_dependency(%q<simplecov-console>, ["~> 0.2"])
40
+ s.add_development_dependency(%q<yard>, ["~> 0.8"])
41
+ else
42
+ s.add_dependency(%q<little-plugger>, ["~> 1.1"])
43
+ s.add_dependency(%q<bogo-ui>, ["~> 0.1"])
44
+ s.add_dependency(%q<rdoc>, ["~> 4.0"])
45
+ s.add_dependency(%q<chef-dk>, ["~> 0.5"])
46
+ s.add_dependency(%q<hoe>, ["~> 3.13"])
47
+ s.add_dependency(%q<hoe-gemspec>, ["~> 1.0"])
48
+ s.add_dependency(%q<rake>, ["~> 10.3"])
49
+ s.add_dependency(%q<rspec>, ["~> 3.1"])
50
+ s.add_dependency(%q<guard>, ["~> 2.12"])
51
+ s.add_dependency(%q<guard-rspec>, ["~> 4.2"])
52
+ s.add_dependency(%q<guard-rake>, ["~> 0.0"])
53
+ s.add_dependency(%q<guard-rubocop>, ["~> 1.2"])
54
+ s.add_dependency(%q<simplecov>, ["~> 0.9"])
55
+ s.add_dependency(%q<simplecov-console>, ["~> 0.2"])
56
+ s.add_dependency(%q<yard>, ["~> 0.8"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<little-plugger>, ["~> 1.1"])
60
+ s.add_dependency(%q<bogo-ui>, ["~> 0.1"])
61
+ s.add_dependency(%q<rdoc>, ["~> 4.0"])
62
+ s.add_dependency(%q<chef-dk>, ["~> 0.5"])
63
+ s.add_dependency(%q<hoe>, ["~> 3.13"])
64
+ s.add_dependency(%q<hoe-gemspec>, ["~> 1.0"])
65
+ s.add_dependency(%q<rake>, ["~> 10.3"])
66
+ s.add_dependency(%q<rspec>, ["~> 3.1"])
67
+ s.add_dependency(%q<guard>, ["~> 2.12"])
68
+ s.add_dependency(%q<guard-rspec>, ["~> 4.2"])
69
+ s.add_dependency(%q<guard-rake>, ["~> 0.0"])
70
+ s.add_dependency(%q<guard-rubocop>, ["~> 1.2"])
71
+ s.add_dependency(%q<simplecov>, ["~> 0.9"])
72
+ s.add_dependency(%q<simplecov-console>, ["~> 0.2"])
73
+ s.add_dependency(%q<yard>, ["~> 0.8"])
74
+ end
75
+ end
@@ -0,0 +1,5 @@
1
+ # chef generators
2
+ module ChefGen
3
+ # a namespace for template flavors
4
+ module Flavor; end
5
+ end
@@ -0,0 +1,230 @@
1
+ require 'chef-dk/generator'
2
+
3
+ module ChefGen
4
+ # a base for ChefDK Template Flavors
5
+ class FlavorBase
6
+ # the target path of 'chef generate'
7
+ # @return [String] path
8
+ attr_reader :target_path
9
+
10
+ # directories to create
11
+ # @return [Array] list of directories
12
+ attr_reader :directories
13
+
14
+ # the file patterns to write to the chefignore files
15
+ # @return [Array] list of file patterns
16
+ attr_reader :chefignore_files
17
+
18
+ # the file patterns to add to .gitignore
19
+ # @return [Array] list of file patterns
20
+ attr_reader :gitignore_files
21
+
22
+ # files to create unconditionally
23
+ # @return [Array] list of destination filenames
24
+ attr_reader :files
25
+
26
+ # files to create only if they do not exist
27
+ # @return [Array] list of destination filenames
28
+ attr_reader :files_if_missing
29
+
30
+ # templates to render unconditionally
31
+ # @return [Array] list of destination filenames
32
+ attr_reader :templates
33
+
34
+ # templates to render only if they do not exist
35
+ # @return [Array] list of destination filenames
36
+ attr_reader :templates_if_missing
37
+
38
+ # an informational block about how the user should proceed
39
+ # @return [String] instructions
40
+ attr_accessor :next_steps
41
+
42
+ # whether to fail if files would be overwritten
43
+ # @return [Boolean] true to fail on attempted overwrite
44
+ attr_accessor :fail_on_clobber
45
+
46
+ # whether to report the actions that were taken
47
+ # @return [Boolean] true to report actions
48
+ attr_accessor :report_actions
49
+
50
+ # creates a new flavor object
51
+ # @param recipe [Chef::Recipe] the recipe into which
52
+ # resources will be injected
53
+ # @return [self]
54
+ def initialize(recipe)
55
+ # store the recipe we'll be injecting resources into
56
+ @recipe = recipe
57
+
58
+ # derive our target path
59
+ ctx = ChefDK::Generator.context
60
+ @target_path = File.expand_path(
61
+ File.join(ctx.cookbook_root, ctx.cookbook_name)
62
+ )
63
+
64
+ # set defaults
65
+ @report_actions = true
66
+ @fail_on_clobber = !ctx.respond_to?(:clobber)
67
+ @directories = [''] # root directory
68
+ %w(files files_if_missing templates templates_if_missing
69
+ chefignore_files gitignore_files actions_taken failures)
70
+ .each do |varname|
71
+ instance_variable_set("@#{varname}".to_sym, [])
72
+ end
73
+ end
74
+
75
+ # generates the Chef resources that the plugin has declared
76
+ # @return [void]
77
+ def generate
78
+ run_mixins
79
+ add_directories
80
+ add_files
81
+ add_templates
82
+ unless @failures.empty?
83
+ @failures.each { |f| $stderr.puts f }
84
+ fail 'errors during generation'
85
+ end
86
+ build_ignore('.gitignore', @gitignore_files)
87
+ build_ignore('chefignore', @chefignore_files)
88
+ report_actions_taken(@actions_taken) \
89
+ if @report_actions && @actions_taken
90
+ display_next_steps(@next_steps) if @next_steps
91
+ end
92
+
93
+ # given a destination file, returns a flattened source
94
+ # filename by replacing / and . with _
95
+ # @param path [String] the destination file
96
+ # @return [String] the flattened source file
97
+ # @example convert a destination file
98
+ # source_path('spec/spec_helper.rb') #=> 'spec_spec_helper_rb'
99
+ def source_path(path)
100
+ path.tr('/.', '_')
101
+ end
102
+
103
+ private
104
+
105
+ # find all public methods of the plugin starting with snippet_
106
+ # and calls them
107
+ # @return [void]
108
+ # @yield [Chef::Recipe] the recipe into which the mixin can inject
109
+ # resources
110
+ # @api private
111
+ def run_mixins
112
+ snippets = public_methods.select do |m|
113
+ m.to_s =~ /^snippet_/
114
+ end
115
+ snippets.each do |m|
116
+ send(m, @recipe)
117
+ end
118
+ end
119
+
120
+ # declares a directory resource for each element of @directories
121
+ # @return [void]
122
+ # @api private
123
+ def add_directories
124
+ @directories.flatten.each do |dirname|
125
+ path = File.join(@target_path, dirname)
126
+ @recipe.send(:directory, path)
127
+ @actions_taken << "create directory #{path}"
128
+ end
129
+ end
130
+
131
+ # declares a cookbook_file resource for each element of '#files' and
132
+ # '#files_if_missing', respecting the value of '#fail_on_clobber'
133
+ # @return [void]
134
+ # @api private
135
+ def add_files
136
+ _add_files(
137
+ @files, nil, @fail_on_clobber, :cookbook_file, :create
138
+ )
139
+ _add_files(
140
+ @files_if_missing, nil, false, :cookbook_file, :create_if_missing
141
+ )
142
+ end
143
+
144
+ # declares a template resource for each element of '#templates' and
145
+ # '#templates_if_missing', respecting the value of '#fail_on_clobber'
146
+ # @return [void]
147
+ # @api private
148
+ def add_templates
149
+ _add_files(
150
+ @templates, '.erb', @fail_on_clobber, :template, :create
151
+ )
152
+ _add_files(
153
+ @templates_if_missing, '.erb', false, :template, :create_if_missing
154
+ )
155
+ end
156
+
157
+ # does the heavy lifting for add_files and add_templates
158
+ # @param files [Array] the list of things to declare
159
+ # @param suffix [String] a suffix to add to the source file
160
+ # @param clobberfail [Boolean] whether to protect against
161
+ # overwriting files
162
+ # @param resource [Symbol] the symbolized Chef resource to declare
163
+ # @param resource_action [Symbol] the action to give the resource
164
+ # @return [void]
165
+ # @api private
166
+ def _add_files(files, suffix, clobberfail, resource, resource_action)
167
+ files.flatten.each do |filename|
168
+ src = "#{source_path(filename)}#{suffix}"
169
+ dst = File.join(@target_path, filename)
170
+ if clobberfail && File.exist?(dst)
171
+ @failures << "tried to overwrite file #{dst}"
172
+ else
173
+ @recipe.send(resource, dst) do
174
+ # :nocov:
175
+ source src
176
+ action resource_action
177
+ helpers(ChefDK::Generator::TemplateHelper) \
178
+ if :template == resource
179
+ # :nocov:
180
+ end
181
+ @actions_taken << "create file #{dst}"
182
+ end
183
+ end
184
+ end
185
+
186
+ # creates a .gitignore or chefignore file
187
+ # @param dstfile [String] the destination file
188
+ # @param files [Array] an array of lines to write to the file
189
+ # @return [void]
190
+ # @api private
191
+ def build_ignore(dstfile, files)
192
+ return if files.empty?
193
+ dst = File.join(@target_path, dstfile)
194
+ @recipe.send(:file, dst) do
195
+ # :nocov:
196
+ content files.flatten.join("\n")
197
+ # :nocov:
198
+ end
199
+ @actions_taken << "create ignore file #{dst}"
200
+ end
201
+
202
+ # reports on the actions taken by the plugin
203
+ # @param actions [Array] the list of actions taken
204
+ # @return [void]
205
+ # @api private
206
+ def report_actions_taken(actions)
207
+ @recipe.send(:ruby_block, 'report_actions_taken') do
208
+ # :nocov:
209
+ block do
210
+ $stdout.puts "\n\nactions taken:"
211
+ actions.each { |a| $stdout.puts " #{a}" }
212
+ end
213
+ # :nocov:
214
+ end
215
+ end
216
+
217
+ # displays the next steps for the user to take
218
+ # @return [void]
219
+ # @api private
220
+ def display_next_steps(next_steps)
221
+ @recipe.send(:ruby_block, 'display_next_steps') do
222
+ # :nocov:
223
+ block do
224
+ $stdout.puts next_steps
225
+ end
226
+ # :nocov:
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,173 @@
1
+ require 'little-plugger'
2
+
3
+ require 'chef_gen/flavor'
4
+
5
+ # chef generators
6
+ module ChefGen
7
+ # a plugin framework for creating ChefDK generator flavors
8
+ class Flavors
9
+ # the version of the gem
10
+ VERSION = '0.3.0'
11
+
12
+ extend LittlePlugger path: 'chef_gen/flavor',
13
+ module: ChefGen::Flavor
14
+
15
+ class << self
16
+ # return the path to to the code_generator cookbook for
17
+ # the selected ChefGen Flavor
18
+ # @return [String] the path to the code_generator cookbook
19
+ def path
20
+ # validate what LittlePlugger found
21
+ validate_plugins
22
+ # then take a copy so we can augment it
23
+ @plugins = plugins.dup
24
+ add_builtin_template
25
+ selected = plugin_from_env ||
26
+ only_plugin ||
27
+ prompt_for_plugin ||
28
+ fail('no ChefGen flavors found!')
29
+ path = generator_path(selected)
30
+ $stdout.puts "using ChefGen flavor '#{selected}' in #{path}"
31
+ path
32
+ end
33
+
34
+ private
35
+
36
+ # validates all plugins found by LittlePlugger
37
+ # @raise RuntimeError if any plugin is invalid
38
+ # @return [void]
39
+ # @api private
40
+ def validate_plugins
41
+ plugins.each do |name, klass|
42
+ fail "no description for plugin #{name}" \
43
+ unless klass.respond_to?(:description)
44
+ end
45
+ end
46
+
47
+ # checks if the plugin to use has been specified in the environment
48
+ # variable CHEFGEN_FLAVOR
49
+ # @return [Symbol,nil] the plugin if specified and found, nil otherwise
50
+ # @api private
51
+ def plugin_from_env
52
+ if ENV.key?('CHEFGEN_FLAVOR')
53
+ candidate = ENV['CHEFGEN_FLAVOR'].downcase.to_sym
54
+ return candidate if plugins.key?(candidate)
55
+ end
56
+ nil
57
+ end
58
+
59
+ # if the environment variable CHEFDK_FLAVOR is defined, adds
60
+ # the built-in template that comes with ChefDK to the list of available
61
+ # plugins
62
+ # @return [void]
63
+ # @api private
64
+ def add_builtin_template
65
+ @plugins[:builtin] = true if ENV.key?('CHEFDK_FLAVOR')
66
+ end
67
+
68
+ # returns the sole installed plugin if only one is found
69
+ # @return [Symbol,nil] the plugin if only one is installed,
70
+ # nil otherwise
71
+ # @api private
72
+ def only_plugin
73
+ @plugins.keys.size == 1 ? @plugins.keys.first : nil
74
+ end
75
+
76
+ # :nocov:
77
+
78
+ # prompts the user for a plugin to use if more than one is available
79
+ # @return [Symbol] the selected plugin
80
+ # @raise RuntimeError if an invalid plugin is chosen
81
+ # @api private
82
+ def prompt_for_plugin
83
+ return nil unless @plugins.keys.size >= 1
84
+ require 'bogo-ui'
85
+ ui = Bogo::Ui.new(app_name: 'ChefGen Flavor Selector')
86
+ valid = plugin_selection(ui)
87
+ response = ui.ask_question('Enter selection').to_i
88
+ return valid[response.to_i] if valid[response]
89
+ ui.fatal 'Invalid flavor chosen'
90
+ fail 'Invalid ChefGen Flavor'
91
+ end
92
+
93
+ # builds a list of plugins and displays them with as
94
+ # a number selection list
95
+ # @param ui [Bogo::Ui] the ui object to use for display
96
+ # @return [Hash] a hash of valid options
97
+ # @api private
98
+ def plugin_selection(ui)
99
+ output = [ui.color('Flavors on the menu', :bold)]
100
+ idx = 1
101
+ valid = {}
102
+ @plugins.each do |name, klass|
103
+ valid[idx] = name
104
+ if true == klass
105
+ output << "#{idx}. ChefDK built-in template"
106
+ else
107
+ output << "#{idx}. #{name}: #{klass.description}"
108
+ end
109
+ idx += 1
110
+ end
111
+ ui.info "#{output.join("\n")}\n"
112
+ valid
113
+ end
114
+ # :nocov:
115
+
116
+ # returns the path to the code_generator cookbook for the
117
+ # selected plugin. Handles the built-in template path,
118
+ # a plugin that overrides the path and a plugin that uses
119
+ # the default path
120
+ # @param plugin [Symbol] the selected plugin
121
+ # @return [String] the path to the code_generator cookbook
122
+ # @api private
123
+ def generator_path(plugin)
124
+ return builtin_code_generator_path if :builtin == plugin
125
+ klass = @plugins[plugin]
126
+ classfile = path_to_plugin(klass)
127
+ if klass.respond_to?(:code_generator_path)
128
+ klass.code_generator_path(classfile)
129
+ else
130
+ default_code_generator_path(classfile)
131
+ end
132
+ end
133
+
134
+ # returns the path of the file where the description method
135
+ # is defined for a given class
136
+ # @param klass [Class] the class to look up the method in
137
+ # @return [String] the path to the source file for the class
138
+ # @api private
139
+ def path_to_plugin(klass)
140
+ klass.method(:description).source_location[0]
141
+ end
142
+
143
+ # returns the default path to the code generator cookbook for
144
+ # a plugin, which is a directory named 'code_generator' four
145
+ # levels above the file which defines the plugin class
146
+ # @param classfile [String] the path to the class source, as
147
+ # returned from ::path_to_plugin
148
+ # @return [String] the path to the code_generator cookbook
149
+ # @api private
150
+ def default_code_generator_path(classfile)
151
+ File.expand_path(
152
+ File.join(
153
+ classfile,
154
+ '..', '..', '..', '..',
155
+ 'code_generator'
156
+ )
157
+ )
158
+ end
159
+
160
+ # return the path to the code_generator cookbook that comes
161
+ # with ChefDK
162
+ # @return [String] the path to the code_generator cookbook
163
+ # @api private
164
+ def builtin_code_generator_path
165
+ require 'rubygems'
166
+ spec = Gem::Specification.find_by_name('chef-dk')
167
+ File.join(
168
+ spec.gem_dir, 'lib', 'chef-dk', 'skeletons', 'code_generator'
169
+ )
170
+ end
171
+ end
172
+ end
173
+ end