pdk 1.17.0 → 2.1.1

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +148 -11
  3. data/README.md +1 -1
  4. data/lib/pdk.rb +1 -1
  5. data/lib/pdk/cli.rb +7 -1
  6. data/lib/pdk/cli/convert.rb +7 -9
  7. data/lib/pdk/cli/env.rb +52 -0
  8. data/lib/pdk/cli/exec/command.rb +11 -1
  9. data/lib/pdk/cli/new.rb +2 -0
  10. data/lib/pdk/cli/new/class.rb +2 -1
  11. data/lib/pdk/cli/new/defined_type.rb +2 -1
  12. data/lib/pdk/cli/new/fact.rb +29 -0
  13. data/lib/pdk/cli/new/function.rb +29 -0
  14. data/lib/pdk/cli/new/provider.rb +2 -1
  15. data/lib/pdk/cli/new/task.rb +2 -1
  16. data/lib/pdk/cli/new/test.rb +2 -1
  17. data/lib/pdk/cli/new/transport.rb +2 -1
  18. data/lib/pdk/cli/release.rb +1 -1
  19. data/lib/pdk/cli/release/publish.rb +11 -1
  20. data/lib/pdk/cli/remove.rb +20 -0
  21. data/lib/pdk/cli/remove/config.rb +80 -0
  22. data/lib/pdk/cli/set.rb +20 -0
  23. data/lib/pdk/cli/set/config.rb +119 -0
  24. data/lib/pdk/cli/update.rb +6 -8
  25. data/lib/pdk/cli/util.rb +1 -0
  26. data/lib/pdk/cli/util/option_validator.rb +6 -0
  27. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  28. data/lib/pdk/config.rb +96 -13
  29. data/lib/pdk/context.rb +8 -5
  30. data/lib/pdk/generate/defined_type.rb +25 -32
  31. data/lib/pdk/generate/fact.rb +25 -0
  32. data/lib/pdk/generate/function.rb +48 -0
  33. data/lib/pdk/generate/module.rb +11 -10
  34. data/lib/pdk/generate/provider.rb +15 -64
  35. data/lib/pdk/generate/puppet_class.rb +25 -31
  36. data/lib/pdk/generate/puppet_object.rb +83 -187
  37. data/lib/pdk/generate/task.rb +28 -46
  38. data/lib/pdk/generate/transport.rb +20 -74
  39. data/lib/pdk/module.rb +1 -1
  40. data/lib/pdk/module/convert.rb +43 -23
  41. data/lib/pdk/module/metadata.rb +6 -2
  42. data/lib/pdk/module/release.rb +8 -2
  43. data/lib/pdk/module/update.rb +7 -11
  44. data/lib/pdk/module/update_manager.rb +7 -0
  45. data/lib/pdk/report.rb +3 -3
  46. data/lib/pdk/report/event.rb +8 -2
  47. data/lib/pdk/template.rb +59 -0
  48. data/lib/pdk/template/fetcher.rb +98 -0
  49. data/lib/pdk/template/fetcher/git.rb +85 -0
  50. data/lib/pdk/template/fetcher/local.rb +28 -0
  51. data/lib/pdk/template/renderer.rb +96 -0
  52. data/lib/pdk/template/renderer/v1.rb +25 -0
  53. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
  54. data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
  55. data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
  56. data/lib/pdk/template/template_dir.rb +67 -0
  57. data/lib/pdk/tests/unit.rb +8 -1
  58. data/lib/pdk/util.rb +4 -35
  59. data/lib/pdk/util/bundler.rb +1 -1
  60. data/lib/pdk/util/changelog_generator.rb +20 -3
  61. data/lib/pdk/util/json_finder.rb +85 -0
  62. data/lib/pdk/util/puppet_strings.rb +3 -3
  63. data/lib/pdk/util/puppet_version.rb +2 -2
  64. data/lib/pdk/util/ruby_version.rb +5 -1
  65. data/lib/pdk/util/template_uri.rb +9 -11
  66. data/lib/pdk/util/vendored_file.rb +1 -2
  67. data/lib/pdk/validate.rb +17 -10
  68. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  69. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  70. data/lib/pdk/validate/invokable_validator.rb +8 -4
  71. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +1 -1
  72. data/lib/pdk/validate/validator.rb +7 -0
  73. data/lib/pdk/validate/validator_group.rb +1 -0
  74. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +2 -2
  75. data/lib/pdk/version.rb +1 -1
  76. data/locales/pdk.pot +356 -228
  77. metadata +65 -28
  78. data/lib/pdk/module/template_dir.rb +0 -115
  79. data/lib/pdk/module/template_dir/base.rb +0 -268
  80. data/lib/pdk/module/template_dir/git.rb +0 -91
  81. data/lib/pdk/module/template_dir/local.rb +0 -21
  82. data/lib/pdk/template_file.rb +0 -96
@@ -3,47 +3,40 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class DefinedType < PuppetObject
6
- OBJECT_TYPE = :defined_type
7
6
  PUPPET_STRINGS_TYPE = 'defined_types'.freeze
8
7
 
9
- # Prepares the data needed to render the new defined type template.
10
- #
11
- # @return [Hash{Symbol => Object}] a hash of information that will be
12
- # provided to the defined type and defined type spec templates during
13
- # rendering.
14
- def template_data
15
- data = { name: object_name }
8
+ def initialize(*_args)
9
+ super
10
+ object_name_parts = @object_name.split('::')
16
11
 
17
- data
12
+ @object_name = if object_name_parts.first == module_name
13
+ object_name
14
+ else
15
+ [module_name, object_name].join('::')
16
+ end
18
17
  end
19
18
 
20
- # Calculates the path to the .pp file that the new defined type will be
21
- # written to.
22
- #
23
- # @return [String] the path where the new defined type will be written.
24
- def target_object_path
25
- @target_pp_path ||= begin
26
- define_name_parts = object_name.split('::')[1..-1]
27
- define_name_parts << 'init' if define_name_parts.empty?
28
-
29
- "#{File.join(module_dir, 'manifests', *define_name_parts)}.pp"
30
- end
19
+ def friendly_name
20
+ 'Defined Type'.freeze
31
21
  end
32
22
 
33
- # Calculates the path to the file where the tests for the new defined
34
- # type will be written.
35
- #
36
- # @return [String] the path where the tests for the new defined type
37
- # will be written.
38
- def target_spec_path
39
- @target_spec_path ||= begin
40
- define_name_parts = object_name.split('::')
23
+ def template_files
24
+ # Calculate the defined type tests name
25
+ define_name_parts = object_name.split('::')
26
+ # drop the module name if the object name contains multiple parts
27
+ define_name_parts.delete_at(0) if define_name_parts.length > 1
28
+ files = { 'defined_type_spec.erb' => File.join('spec', 'defines', *define_name_parts) + '_spec.rb' }
29
+ return files if spec_only?
30
+
31
+ define_name_parts = object_name.split('::')[1..-1]
32
+ define_name_parts << 'init' if define_name_parts.empty?
33
+ files['defined_type.erb'] = File.join('manifests', *define_name_parts) + '.pp'
41
34
 
42
- # drop the module name if the object name contains multiple parts
43
- define_name_parts.delete_at(0) if define_name_parts.length > 1
35
+ files
36
+ end
44
37
 
45
- "#{File.join(module_dir, 'spec', 'defines', *define_name_parts)}_spec.rb"
46
- end
38
+ def template_data
39
+ { name: object_name }
47
40
  end
48
41
  end
49
42
  end
@@ -0,0 +1,25 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Generate
5
+ class Fact < PuppetObject
6
+ def friendly_name
7
+ 'Custom Fact'.freeze
8
+ end
9
+
10
+ def template_files
11
+ files = {
12
+ 'fact_spec.erb' => File.join('spec', 'unit', 'facter', object_name) + '_spec.rb',
13
+ }
14
+ return files if spec_only?
15
+ files.merge(
16
+ 'fact.erb' => File.join('lib', 'facter', object_name) + '.rb',
17
+ )
18
+ end
19
+
20
+ def template_data
21
+ { name: object_name }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Generate
5
+ class Function < PuppetObject
6
+ def initialize(*_args)
7
+ super
8
+ object_name_parts = @object_name.split('::')
9
+
10
+ @object_name = if object_name_parts.first == module_name
11
+ object_name
12
+ else
13
+ [module_name, object_name].join('::')
14
+ end
15
+ end
16
+
17
+ def friendly_name
18
+ 'Function'.freeze
19
+ end
20
+
21
+ def template_files
22
+ # Calculate the function tests name
23
+ func_name_parts = object_name.split('::')
24
+ # Drop the module name if the object name contains multiple parts
25
+ func_name_parts.delete_at(0) if func_name_parts.length > 1
26
+ files = {
27
+ File.join('functions', 'function_spec.erb') => File.join('spec', 'functions', *func_name_parts) + '_spec.rb',
28
+ }
29
+ return files if spec_only?
30
+ func_name_parts = object_name.split('::')[1..-1]
31
+ template_file = File.join('functions', "#{options[:type]}_function.erb")
32
+
33
+ files[template_file] = if options[:type].eql?('v4')
34
+ File.join('lib', 'puppet', 'functions', module_name, *func_name_parts) + '.rb'
35
+ else
36
+ File.join('functions', *func_name_parts) + '.pp'
37
+ end
38
+ files
39
+ end
40
+
41
+ def template_data
42
+ func_name = object_name.split('::').last
43
+ namespace = object_name.split('::')[0...-1].join('::')
44
+ { name: object_name, func_name: func_name, namespace: namespace }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -58,17 +58,18 @@ module PDK
58
58
  end
59
59
 
60
60
  begin
61
- PDK::Module::TemplateDir.with(template_uri, metadata.data, true) do |templates|
62
- templates.render do |file_path, file_content, file_status|
63
- next if file_status == :delete
64
- file = Pathname.new(temp_target_dir) + file_path
61
+ context = PDK::Context::None.new(temp_target_dir)
62
+ PDK::Template.with(template_uri, context) do |template_dir|
63
+ template_dir.render_new_module(metadata.data['name'], metadata.data) do |relative_file_path, file_content, file_status|
64
+ next if [:delete, :unmanage].include?(file_status)
65
+ file = Pathname.new(temp_target_dir) + relative_file_path
65
66
  file.dirname.mkpath
66
67
  PDK::Util::Filesystem.write_file(file, file_content)
67
68
  end
68
69
 
69
70
  # Add information about the template used to generate the module to the
70
71
  # metadata (for a future update command).
71
- metadata.update!(templates.metadata)
72
+ metadata.update!(template_dir.metadata)
72
73
 
73
74
  metadata.write!(File.join(temp_target_dir, 'metadata.json'))
74
75
  end
@@ -82,11 +83,11 @@ module PDK
82
83
  # If the user specifies our default template url via the command
83
84
  # line, remove the saved template-url answer so that the template_uri
84
85
  # resolution can find new default URLs in the future.
85
- PDK.config.user['module_defaults']['template-url'] = nil if opts.key?(:'template-url')
86
+ PDK.config.set(%w[user module_defaults template-url], nil) if opts.key?(:'template-url')
86
87
  else
87
88
  # Save the template-url answers if the module was generated using a
88
89
  # template/reference other than ours.
89
- PDK.config.user['module_defaults']['template-url'] = template_uri.metadata_format
90
+ PDK.config.set(%w[user module_defaults template-url], template_uri.metadata_format)
90
91
  end
91
92
 
92
93
  begin
@@ -342,9 +343,9 @@ module PDK
342
343
  end
343
344
 
344
345
  require 'pdk/answer_file'
345
- PDK.config.user['module_defaults']['forge_username'] = opts[:username] unless opts[:username].nil?
346
- PDK.config.user['module_defaults']['author'] = answers['author'] unless answers['author'].nil?
347
- PDK.config.user['module_defaults']['license'] = answers['license'] unless answers['license'].nil?
346
+ PDK.config.set(%w[user module_defaults forge_username], opts[:username]) unless opts[:username].nil?
347
+ PDK.config.set(%w[user module_defaults author], answers['author']) unless answers['author'].nil?
348
+ PDK.config.set(%w[user module_defaults license], answers['license']) unless answers['license'].nil?
348
349
  end
349
350
  end
350
351
  end
@@ -3,74 +3,25 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class Provider < PuppetObject
6
- OBJECT_TYPE = :provider
7
-
8
- # Prepares the data needed to render the new defined type template.
9
- #
10
- # @return [Hash{Symbol => Object}] a hash of information that will be
11
- # provided to the defined type and defined type spec templates during
12
- # rendering.
13
- def template_data
14
- data = {
15
- name: object_name,
16
- provider_class: Provider.class_name_from_object_name(object_name),
17
- }
18
-
19
- data
20
- end
21
-
22
- def raise_precondition_error(error)
23
- raise PDK::CLI::ExitWithError, _('%{error}: Creating a provider needs some local configuration in your module.' \
24
- ' Please follow the docs at https://puppet.com/docs/puppet/latest/create_types_and_providers_resource_api.html.') % { error: error }
25
- end
26
-
27
- def check_preconditions
28
- super
29
- # These preconditions can be removed once the pdk-templates are carrying the puppet-resource_api gem by default, and have switched
30
- # the default mock_with value.
31
- sync_path = PDK::Util.find_upwards('.sync.yml')
32
- if sync_path.nil?
33
- raise_precondition_error(_('.sync.yml not found'))
34
- end
35
- sync = YAML.load_file(sync_path)
36
- if !sync.is_a? Hash
37
- raise_precondition_error(_('.sync.yml contents is not a Hash'))
38
- elsif !sync.key? 'Gemfile'
39
- raise_precondition_error(_('Gemfile configuration not found'))
40
- elsif !sync['Gemfile'].key? 'optional'
41
- raise_precondition_error(_('Gemfile.optional configuration not found'))
42
- elsif !sync['Gemfile']['optional'].key? ':development'
43
- raise_precondition_error(_('Gemfile.optional.:development configuration not found'))
44
- elsif sync['Gemfile']['optional'][':development'].none? { |g| g['gem'] == 'puppet-resource_api' }
45
- raise_precondition_error(_('puppet-resource_api not found in the Gemfile config'))
46
- elsif !sync.key? 'spec/spec_helper.rb'
47
- raise_precondition_error(_('spec/spec_helper.rb configuration not found'))
48
- elsif !sync['spec/spec_helper.rb'].key? 'mock_with'
49
- raise_precondition_error(_('spec/spec_helper.rb.mock_with configuration not found'))
50
- elsif !sync['spec/spec_helper.rb']['mock_with'] == ':rspec'
51
- raise_precondition_error(_('spec/spec_helper.rb.mock_with not set to \':rspec\''))
52
- end
53
- end
54
-
55
- # @return [String] the path where the new provider will be written.
56
- def target_object_path
57
- @target_object_path ||= File.join(module_dir, 'lib', 'puppet', 'provider', object_name, object_name) + '.rb'
6
+ def friendly_name
7
+ 'Resource API Provider'.freeze
58
8
  end
59
9
 
60
- # @return [String] the path where the new type will be written.
61
- def target_type_path
62
- @target_type_path ||= File.join(module_dir, 'lib', 'puppet', 'type', object_name) + '.rb'
63
- end
64
-
65
- # @return [String] the path where the tests for the new provider
66
- # will be written.
67
- def target_spec_path
68
- @target_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'provider', object_name, object_name) + '_spec.rb'
10
+ def template_files
11
+ files = {
12
+ 'provider_spec.erb' => File.join('spec', 'unit', 'puppet', 'provider', object_name, object_name) + '_spec.rb',
13
+ 'provider_type_spec.erb' => File.join('spec', 'unit', 'puppet', 'type', object_name) + '_spec.rb',
14
+ }
15
+ return files if spec_only?
16
+ files.merge(
17
+ 'provider.erb' => File.join('lib', 'puppet', 'provider', object_name, object_name) + '.rb',
18
+ 'provider_type.erb' => File.join('lib', 'puppet', 'type', object_name) + '.rb',
19
+ )
69
20
  end
70
21
 
71
- # @return [String] the path where the tests for the new type will be written.
72
- def target_type_spec_path
73
- @target_type_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'type', object_name) + '_spec.rb'
22
+ def template_data
23
+ { name: object_name,
24
+ provider_class: class_name_from_object_name(object_name) }
74
25
  end
75
26
  end
76
27
  end
@@ -3,46 +3,40 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class PuppetClass < PuppetObject
6
- OBJECT_TYPE = :class
7
6
  PUPPET_STRINGS_TYPE = 'puppet_classes'.freeze
8
7
 
9
- # Prepares the data needed to render the new Puppet class template.
10
- #
11
- # @return [Hash{Symbol => Object}] a hash of information that will be
12
- # provided to the class and class spec templates during rendering.
13
- def template_data
14
- data = { name: object_name }
8
+ def initialize(*_args)
9
+ super
10
+ object_name_parts = @object_name.split('::')
15
11
 
16
- data
12
+ @object_name = if object_name_parts.first == module_name
13
+ object_name
14
+ else
15
+ [module_name, object_name].join('::')
16
+ end
17
17
  end
18
18
 
19
- # Calculates the path to the .pp file that the new class will be written
20
- # to.
21
- #
22
- # @return [String] the path where the new class will be written.
23
- def target_object_path
24
- @target_pp_path ||= begin
25
- class_name_parts = object_name.split('::')[1..-1]
26
- class_name_parts << 'init' if class_name_parts.empty?
27
-
28
- "#{File.join(module_dir, 'manifests', *class_name_parts)}.pp"
29
- end
19
+ def friendly_name
20
+ 'Puppet Class'.freeze
30
21
  end
31
22
 
32
- # Calculates the path to the file where the tests for the new class will
33
- # be written.
34
- #
35
- # @return [String] the path where the tests for the new class will be
36
- # written.
37
- def target_spec_path
38
- @target_spec_path ||= begin
39
- class_name_parts = object_name.split('::')
23
+ def template_files
24
+ # Calculate the class tests name
25
+ class_name_parts = object_name.split('::')
26
+ # Drop the module name if the object name contains multiple parts
27
+ class_name_parts.delete_at(0) if class_name_parts.length > 1
28
+ files = { 'class_spec.erb' => File.join('spec', 'classes', *class_name_parts) + '_spec.rb' }
29
+ return files if spec_only?
30
+
31
+ class_name_parts = object_name.split('::')[1..-1]
32
+ class_name_parts << 'init' if class_name_parts.empty?
33
+ files['class.erb'] = File.join('manifests', *class_name_parts) + '.pp'
40
34
 
41
- # drop the module name if the object name contains multiple parts
42
- class_name_parts.delete_at(0) if class_name_parts.length > 1
35
+ files
36
+ end
43
37
 
44
- "#{File.join(module_dir, 'spec', 'classes', *class_name_parts)}_spec.rb"
45
- end
38
+ def template_data
39
+ { name: object_name }
46
40
  end
47
41
  end
48
42
  end
@@ -3,7 +3,7 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class PuppetObject
6
- attr_reader :module_dir
6
+ attr_reader :context
7
7
  attr_reader :object_name
8
8
  attr_reader :options
9
9
 
@@ -20,228 +20,124 @@ module PDK
20
20
  # will contain the object.
21
21
  # @param object_name [String] The name of the object.
22
22
  # @param options [Hash{Symbol => Object}]
23
- #
24
- # @api public
25
- def initialize(module_dir, object_name, options)
26
- @module_dir = module_dir
23
+ def initialize(context, object_name, options)
24
+ raise ArgumentError, _('Expected PDK::Context::AbstractContext but got \'%{klass}\' for context') % { klass: context.class } unless context.is_a?(PDK::Context::AbstractContext)
25
+ @context = context
27
26
  @options = options
28
27
  @object_name = object_name
29
-
30
- if [:class, :defined_type].include?(object_type) # rubocop:disable Style/GuardClause
31
- object_name_parts = object_name.split('::')
32
-
33
- @object_name = if object_name_parts.first == module_name
34
- object_name
35
- else
36
- [module_name, object_name].join('::')
37
- end
38
- end
39
28
  end
40
29
 
30
+ # Whether the generator should only return test (spec) files
31
+ # @return [Boolean]
41
32
  def spec_only?
42
33
  @options[:spec_only]
43
34
  end
44
35
 
45
- # @abstract Subclass and implement {#template_data} to provide data to
46
- # the templates during rendering. Implementations of this method should
47
- # return a Hash!{Symbol => Object}.
48
- def template_data
36
+ # Subclass and implement {#friendly_name} to provide a nice name to show users in CLI
37
+ # @abstract
38
+ # @return String
39
+ def friendly_name
49
40
  raise NotImplementedError
50
41
  end
51
42
 
52
- # @abstract Subclass and implement {#target_object_path}. Implementations
53
- # of this method should return a String containing the destination path
54
- # of the object being generated.
55
- def target_object_path
43
+ # Subclass and implement {#template_files} to provide the template files to
44
+ # render. Implementations of this method should return a Hash!{String => String}.
45
+ # @abstract
46
+ # @return Hash{String => String} Hash key is the source template file and the Hash value is
47
+ # the relative destination path
48
+ def template_files
56
49
  raise NotImplementedError
57
50
  end
58
51
 
59
- # @abstract Subclass and implement {#target_type_path}. Implementations
60
- # of this method should return a String containing the destination path
61
- # of the additional object file being generated.
62
- # @return [String] returns nil if there is no additional object file
63
- def target_type_path
64
- nil
65
- end
66
-
67
- # @abstract Subclass and implement {#target_spec_path}. Implementations
68
- # of this method should return a String containing the destination path
69
- # of the tests for the object being generated.
70
- def target_spec_path
52
+ # Subclass and implement {#template_data} to provide data to the templates during rendering.
53
+ # @abstract
54
+ # @return Hash{Symbol => Object}
55
+ def template_data
71
56
  raise NotImplementedError
72
57
  end
73
58
 
74
- # @abstract Subclass and implement {#target_type_spec_path}. Implementations
75
- # of this method should return a String containing the destination path
76
- # of the tests for the object being generated.
77
- def target_type_spec_path
78
- nil
79
- end
80
-
81
- # @abstract Subclass and implement {#target_device_path}. Implementations
82
- # of this method should return a String containing the destination path
83
- # of the device class being generated.
84
- def target_device_path
85
- nil
86
- end
87
-
88
- # Retrieves the type of the object being generated, e.g. :class,
89
- # :defined_type, etc. This is specified in the subclass' OBJECT_TYPE
90
- # constant.
59
+ # Raises an error if any pre-conditions are not met
91
60
  #
92
- # @return [Symbol] the type of the object being generated.
93
- #
94
- # @api private
95
- def object_type
96
- self.class::OBJECT_TYPE
61
+ # @return [void]
62
+ # @abstract
63
+ def check_preconditions
64
+ raise ArgumentError, _('Expected a module context but got %{context_name}') % { context_name: context.display_name } unless context.is_a?(PDK::Context::Module)
97
65
  end
98
66
 
99
- # Retrieves the type of the object being generated as represented in
100
- # the JSON output of puppet-strings.
67
+ # Check the preconditions of this template group, behaving as a predicate rather than raising an exception.
101
68
  #
102
- # @return [String] the type of the object being generated or nil if
103
- # there is no mapping.
104
- #
105
- # @api private
106
- def self.puppet_strings_type
107
- return nil unless const_defined?(:PUPPET_STRINGS_TYPE)
108
-
109
- self::PUPPET_STRINGS_TYPE
69
+ # @return [Boolean] true if the generator is safe to run, otherwise false.
70
+ def can_run?
71
+ check_preconditions
72
+ true
73
+ rescue StandardError
74
+ false
110
75
  end
111
76
 
112
- # Returns an array of possible target path strings.
113
- def targets
114
- targets = [
115
- target_spec_path,
116
- target_type_spec_path,
117
- ]
118
-
119
- unless spec_only?
120
- targets += [
121
- target_object_path,
122
- target_type_path,
123
- target_device_path,
124
- ]
125
- end
126
-
127
- targets.compact
77
+ # Creates an instance of an update manager
78
+ # @api private
79
+ def update_manager_instance
80
+ require 'pdk/module/update_manager'
81
+ PDK::Module::UpdateManager.new
128
82
  end
129
83
 
130
- # Check preconditions of this template group. By default this only makes sure that the target files do not
131
- # already exist. Override this (and call super) to add your own preconditions.
132
- #
133
- # @raise [PDK::CLI::ExitWithError] if the target files already exist.
84
+ # Stages and then executes the changes for the templates to be rendereed.
85
+ # This is the main entry point for the class.
134
86
  #
87
+ # @see #stage_changes
88
+ # @return [PDK::Module::UpdateManager] The update manager which implemented the changes
135
89
  # @api public
136
- def check_preconditions
137
- require 'pdk/util/filesystem'
138
-
139
- targets.each do |target_file|
140
- next unless PDK::Util::Filesystem.exist?(target_file)
141
-
142
- raise PDK::CLI::ExitWithError, _("Unable to generate %{object_type}; '%{file}' already exists.") % {
143
- file: target_file,
144
- object_type: spec_only? ? 'unit test' : object_type,
145
- }
146
- end
147
- end
148
-
149
- # Check the preconditions of this template group, behaving as a
150
- # predicate rather than raising an exception.
151
- #
152
- # @return [Boolean] true if the generator is safe to run, otherwise
153
- # false.
154
- def can_run?
155
- check_preconditions
156
- true
157
- rescue PDK::CLI::ExitWithError
158
- false
90
+ def run(update_manager = update_manager_instance)
91
+ stage_changes(update_manager).sync_changes!
92
+ update_manager
159
93
  end
160
94
 
161
95
  # Check that the templates can be rendered. Find an appropriate template
162
- # and create the target files from the template. This is the main entry
96
+ # and stages the target files from the template. This is the main entry
163
97
  # point for the class.
164
98
  #
165
99
  # @raise [PDK::CLI::ExitWithError] if the target files already exist.
166
100
  # @raise [PDK::CLI::FatalError] (see #render_file)
167
- #
101
+ # @return [PDK::Module::UpdateManager] The update manager with the staged changes
168
102
  # @api public
169
- def run
103
+ def stage_changes(update_manager)
170
104
  check_preconditions
171
105
 
172
- with_templates do |template_path, config_hash|
173
- data = template_data.merge(configs: config_hash)
106
+ with_templates do |template_dir|
107
+ template_files.each do |source_file, relative_dest_path|
108
+ new_content = template_dir.render_single_item(source_file, template_data)
109
+ next if new_content.nil?
174
110
 
175
- render_file(target_object_path, template_path[:object], data) unless spec_only?
176
- render_file(target_type_path, template_path[:type], data) if template_path[:type]
177
- render_file(target_device_path, template_path[:device], data) if template_path[:device]
178
- render_file(target_spec_path, template_path[:spec], data) if template_path[:spec]
179
- render_file(target_type_spec_path, template_path[:type_spec], data) if template_path[:type_spec]
111
+ stage_change(relative_dest_path, new_content, update_manager)
112
+ end
180
113
  end
114
+ non_template_files.each { |relative_dest_path, content| stage_change(relative_dest_path, content, update_manager) }
115
+
116
+ update_manager
181
117
  end
182
118
 
183
- # Render a file using the provided template and write it to disk.
184
- #
185
- # @param dest_path [String] The path that the rendered file should be
186
- # written to. Any necessary directories will be automatically created.
187
- # @param template_path [String] The path on disk to the file containing
188
- # the template.
189
- # @param data [Hash{Object => Object}] The data to be provided to the
190
- # template when rendering.
191
- #
192
- # @raise [PDK::CLI::FatalError] if the parent directories to `dest_path`
193
- # do not exist and could not be created.
194
- # @raise [PDK::CLI::FatalError] if the rendered file could not be written
195
- # to `dest_path`.
196
- #
119
+ # Stages a single file into the Update Manager.
197
120
  # @return [void]
198
- #
199
121
  # @api private
200
- def render_file(dest_path, template_path, data)
201
- require 'pdk/template_file'
202
-
203
- write_file(dest_path) do
204
- PDK::TemplateFile.new(template_path, data).render
122
+ def stage_change(relative_dest_path, content, update_manager)
123
+ absolute_file_path = File.join(context.root_path, relative_dest_path)
124
+ if PDK::Util::Filesystem.exist?(absolute_file_path)
125
+ raise PDK::CLI::ExitWithError, _("Unable to generate %{object_type}; '%{file}' already exists.") % {
126
+ file: absolute_file_path,
127
+ object_type: spec_only? ? 'unit test' : friendly_name,
128
+ }
205
129
  end
130
+ update_manager.add_file(absolute_file_path, content)
206
131
  end
207
132
 
208
- # Write the result of the block to disk.
209
- #
210
- # @param dest_path [String] The path that the rendered file should be
211
- # written to. Any necessary directories will be automatically created.
212
- # @param &block [String] The content to be written
213
- #
214
- # @raise [PDK::CLI::FatalError] if the parent directories to `dest_path`
215
- # do not exist and could not be created.
216
- # @raise [PDK::CLI::FatalError] if the rendered file could not be written
217
- # to `dest_path`.
218
- #
219
- # @return [void]
133
+ # A subclass may wish to stage files into the Update Manager, but the content is not templated. Subclasses
134
+ # can override this method to stage arbitrary files
220
135
  #
221
136
  # @api private
222
- def write_file(dest_path)
223
- require 'pdk/logger'
224
- require 'pdk/util/filesystem'
225
-
226
- PDK.logger.info(_("Creating '%{file}' from template.") % { file: dest_path })
227
-
228
- file_content = yield
229
-
230
- begin
231
- PDK::Util::Filesystem.mkdir_p(File.dirname(dest_path))
232
- rescue SystemCallError => e
233
- raise PDK::CLI::FatalError, _("Unable to create directory '%{path}': %{message}") % {
234
- path: File.dirname(dest_path),
235
- message: e.message,
236
- }
237
- end
238
-
239
- PDK::Util::Filesystem.write_file(dest_path, file_content)
240
- rescue SystemCallError => e
241
- raise PDK::CLI::FatalError, _("Unable to write to file '%{path}': %{message}") % {
242
- path: dest_path,
243
- message: e.message,
244
- }
137
+ # @return [Hash{String => String}] A Hash with the relative file path as the key and the new file content as the value.
138
+ # @abstract
139
+ def non_template_files
140
+ {}
245
141
  end
246
142
 
247
143
  # Search the possible template directories in order of preference to find
@@ -268,18 +164,15 @@ module PDK
268
164
  next
269
165
  end
270
166
 
271
- PDK::Module::TemplateDir.with(PDK::Util::TemplateURI.new(template[:uri])) do |template_dir|
272
- template_paths = template_dir.object_template_for(object_type)
273
-
274
- if template_paths
275
- config_hash = template_dir.object_config
276
- yield template_paths, config_hash
167
+ PDK::Template.with(PDK::Util::TemplateURI.new(template[:uri]), context) do |template_dir|
168
+ if template_files.any? { |source_file, _| template_dir.has_single_item?(source_file) }
169
+ yield template_dir
277
170
  # TODO: refactor to a search-and-execute form instead
278
171
  return # work is done # rubocop:disable Lint/NonLocalExitFromIterator
279
172
  elsif template[:allow_fallback]
280
- PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: object_type, url: template[:uri] })
173
+ PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: friendly_name, url: template[:uri] })
281
174
  else
282
- raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: object_type, url: template[:uri] }
175
+ raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: friendly_name, url: template[:uri] }
283
176
  end
284
177
  end
285
178
  end
@@ -320,15 +213,18 @@ module PDK
320
213
  #
321
214
  # @api private
322
215
  def module_name
323
- require 'pdk/util'
216
+ return nil unless context.is_a?(PDK::Context::Module)
324
217
 
325
- @module_name ||= PDK::Util.module_metadata['name'].rpartition('-').last
218
+ require 'pdk/util'
219
+ @module_name ||= PDK::Util.module_metadata(context.root_path)['name'].rpartition('-').last
326
220
  rescue ArgumentError => e
327
221
  raise PDK::CLI::FatalError, e
328
222
  end
329
223
 
330
- # transform a object name into a ruby class name
331
- def self.class_name_from_object_name(object_name)
224
+ private
225
+
226
+ # Transform an object name into a ruby class name
227
+ def class_name_from_object_name(object_name)
332
228
  object_name.to_s.split('_').map(&:capitalize).join
333
229
  end
334
230
  end