pdk 1.17.0 → 1.18.0

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 (63) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +71 -2
  3. data/lib/pdk/cli/convert.rb +7 -9
  4. data/lib/pdk/cli/new/class.rb +2 -1
  5. data/lib/pdk/cli/new/defined_type.rb +2 -1
  6. data/lib/pdk/cli/new/provider.rb +2 -1
  7. data/lib/pdk/cli/new/task.rb +2 -1
  8. data/lib/pdk/cli/new/test.rb +2 -1
  9. data/lib/pdk/cli/new/transport.rb +2 -1
  10. data/lib/pdk/cli/remove/config.rb +80 -0
  11. data/lib/pdk/cli/remove.rb +20 -0
  12. data/lib/pdk/cli/set/config.rb +119 -0
  13. data/lib/pdk/cli/set.rb +20 -0
  14. data/lib/pdk/cli/update.rb +6 -8
  15. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  16. data/lib/pdk/cli/util.rb +1 -0
  17. data/lib/pdk/cli.rb +2 -0
  18. data/lib/pdk/config.rb +96 -13
  19. data/lib/pdk/context.rb +8 -5
  20. data/lib/pdk/generate/defined_type.rb +25 -32
  21. data/lib/pdk/generate/module.rb +11 -10
  22. data/lib/pdk/generate/provider.rb +16 -65
  23. data/lib/pdk/generate/puppet_class.rb +25 -31
  24. data/lib/pdk/generate/puppet_object.rb +83 -187
  25. data/lib/pdk/generate/resource_api_object.rb +55 -0
  26. data/lib/pdk/generate/task.rb +28 -46
  27. data/lib/pdk/generate/transport.rb +21 -75
  28. data/lib/pdk/generate.rb +1 -0
  29. data/lib/pdk/module/convert.rb +41 -23
  30. data/lib/pdk/module/release.rb +1 -1
  31. data/lib/pdk/module/update.rb +6 -10
  32. data/lib/pdk/module/update_manager.rb +7 -0
  33. data/lib/pdk/module.rb +0 -1
  34. data/lib/pdk/template/fetcher/git.rb +85 -0
  35. data/lib/pdk/template/fetcher/local.rb +28 -0
  36. data/lib/pdk/template/fetcher.rb +98 -0
  37. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
  38. data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
  39. data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
  40. data/lib/pdk/template/renderer/v1.rb +25 -0
  41. data/lib/pdk/template/renderer.rb +96 -0
  42. data/lib/pdk/template/template_dir.rb +67 -0
  43. data/lib/pdk/template.rb +59 -0
  44. data/lib/pdk/tests/unit.rb +5 -0
  45. data/lib/pdk/util/json_finder.rb +84 -0
  46. data/lib/pdk/util/puppet_strings.rb +3 -3
  47. data/lib/pdk/util/template_uri.rb +4 -6
  48. data/lib/pdk/util.rb +4 -35
  49. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  50. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  51. data/lib/pdk/validate/invokable_validator.rb +2 -3
  52. data/lib/pdk/validate/validator.rb +7 -0
  53. data/lib/pdk/validate/validator_group.rb +1 -0
  54. data/lib/pdk/validate.rb +17 -10
  55. data/lib/pdk/version.rb +1 -1
  56. data/lib/pdk.rb +1 -1
  57. data/locales/pdk.pot +356 -228
  58. metadata +33 -12
  59. data/lib/pdk/module/template_dir/base.rb +0 -268
  60. data/lib/pdk/module/template_dir/git.rb +0 -91
  61. data/lib/pdk/module/template_dir/local.rb +0 -21
  62. data/lib/pdk/module/template_dir.rb +0 -115
  63. data/lib/pdk/template_file.rb +0 -96
@@ -3,44 +3,21 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class Task < PuppetObject
6
- OBJECT_TYPE = :task
6
+ def friendly_name
7
+ 'Task'
8
+ end
7
9
 
8
- # Prepares the data needed to render the new task template.
9
- #
10
- # @return [Hash{Symbol => Object}] a hash of information that will be
11
- # provided to the task template during rendering. Additionally, this hash
12
- # (with the :name key removed) makes up the task metadata.
13
- def template_data
10
+ def template_files
11
+ return {} if spec_only?
14
12
  {
15
- name: object_name,
16
- puppet_task_version: 1,
17
- supports_noop: false,
18
- description: options.fetch(:description, 'A short description of this task'),
19
- parameters: {},
13
+ 'task.erb' => File.join('tasks', task_name + '.sh'),
20
14
  }
21
15
  end
22
16
 
23
- # Calculates the path to the file where the new task will be written.
24
- #
25
- # @return [String] the path to the task file.
26
- def target_object_path
27
- @target_object_path ||= File.join(module_dir, 'tasks', "#{task_name}.sh")
28
- end
29
-
30
- # Calculates the path to the file where the tests for the new task will
31
- # be written.
32
- #
33
- # @return [nil] as there is currently no test framework for Tasks.
34
- def target_spec_path
35
- nil
36
- end
37
-
38
- def run
39
- check_if_task_already_exists
40
-
41
- super
42
-
43
- write_task_metadata
17
+ def template_data
18
+ {
19
+ name: object_name,
20
+ }
44
21
  end
45
22
 
46
23
  # Checks that the task has not already been defined with a different
@@ -48,30 +25,26 @@ module PDK
48
25
  #
49
26
  # @raise [PDK::CLI::ExitWithError] if files with the same name as the
50
27
  # task exist in the <module>/tasks/ directory
51
- #
52
- # @api private
53
- def check_if_task_already_exists
28
+ def check_preconditions
29
+ super
30
+
54
31
  error = _("A task named '%{name}' already exists in this module; defined in %{file}")
55
32
  allowed_extensions = %w[.md .conf]
56
33
 
57
- PDK::Util::Filesystem.glob(File.join(module_dir, 'tasks', "#{task_name}.*")).each do |file|
34
+ PDK::Util::Filesystem.glob(File.join(context.root_path, 'tasks', task_name + '.*')).each do |file|
58
35
  next if allowed_extensions.include?(File.extname(file))
59
36
 
60
37
  raise PDK::CLI::ExitWithError, error % { name: task_name, file: file }
61
38
  end
62
39
  end
63
40
 
64
- # Writes the <module>/tasks/<task_name>.json metadata file for the task.
65
- #
66
- # @api private
67
- def write_task_metadata
68
- write_file(File.join(module_dir, 'tasks', "#{task_name}.json")) do
69
- task_metadata = template_data.dup
70
- task_metadata.delete(:name)
71
- JSON.pretty_generate(task_metadata)
72
- end
41
+ def non_template_files
42
+ task_metadata_file = File.join('tasks', task_name + '.json')
43
+ { task_metadata_file => JSON.pretty_generate(task_metadata) }
73
44
  end
74
45
 
46
+ private
47
+
75
48
  # Calculates the file name of the task files ('init' if the task has the
76
49
  # same name as the module, otherwise use the specified task name).
77
50
  #
@@ -81,6 +54,15 @@ module PDK
81
54
  def task_name
82
55
  (object_name == module_name) ? 'init' : object_name
83
56
  end
57
+
58
+ def task_metadata
59
+ {
60
+ puppet_task_version: 1,
61
+ supports_noop: false,
62
+ description: options.fetch(:description, 'A short description of this task'),
63
+ parameters: {},
64
+ }
65
+ end
84
66
  end
85
67
  end
86
68
  end
@@ -2,85 +2,31 @@ require 'pdk'
2
2
 
3
3
  module PDK
4
4
  module Generate
5
- class Transport < PuppetObject
6
- OBJECT_TYPE = :transport
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
- transport_class: Transport.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 transport needs some local configuration in your module.' \
24
- ' Please follow the docs at https://github.com/puppetlabs/puppet-resource_api#getting-started.') % { 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 transport will be written.
56
- def target_object_path
57
- @target_object_path ||= File.join(module_dir, 'lib', 'puppet', 'transport', object_name) + '.rb'
5
+ class Transport < ResourceAPIObject
6
+ def friendly_name
7
+ 'Resource API Transport'.freeze
58
8
  end
59
9
 
60
- # @return [String] the path where the new schema will be written.
61
- def target_type_path
62
- @target_type_path ||= File.join(module_dir, 'lib', 'puppet', 'transport', 'schema', object_name) + '.rb'
63
- end
64
-
65
- # @return [String] the path where the deviceshim for the transport will be written.
66
- def target_device_path
67
- @target_device_path ||= File.join(module_dir, 'lib', 'puppet', 'util', 'network_device', object_name, 'device.rb')
68
- end
69
-
70
- # @return [String] the path where the tests for the new transport
71
- # will be written.
72
- def target_spec_path
73
- @target_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'transport', object_name) + '_spec.rb'
74
- end
75
-
76
- # @return [String] the path where the tests for the new schema will be written.
77
- def target_type_spec_path
78
- @target_type_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'transport', 'schema', object_name) + '_spec.rb'
10
+ def template_files
11
+ # Note : Due to how the V1 templates work, the names of the source template files may be mismatched to
12
+ # their destination, e.g. transport_type.erb is really a transport schema
13
+ files = {
14
+ 'transport_spec.erb' => File.join('spec', 'unit', 'puppet', 'transport', object_name) + '_spec.rb',
15
+ 'transport_type_spec.erb' => File.join('spec', 'unit', 'puppet', 'transport', 'schema', object_name) + '_spec.rb',
16
+ }
17
+ return files if spec_only?
18
+ files.merge(
19
+ 'transport.erb' => File.join('lib', 'puppet', 'transport', object_name) + '.rb',
20
+ 'transport_device.erb' => File.join('lib', 'puppet', 'util', 'network_device', object_name, 'device.rb'),
21
+ 'transport_type.erb' => File.join('lib', 'puppet', 'transport', 'schema', object_name) + '.rb',
22
+ )
79
23
  end
80
24
 
81
- # transform a object name into a ruby class name
82
- def self.class_name_from_object_name(object_name)
83
- object_name.to_s.split('_').map(&:capitalize).join
25
+ def template_data
26
+ {
27
+ name: object_name,
28
+ transport_class: class_name_from_object_name(object_name),
29
+ }
84
30
  end
85
31
  end
86
32
  end
data/lib/pdk/generate.rb CHANGED
@@ -7,6 +7,7 @@ module PDK
7
7
  autoload :Provider, 'pdk/generate/provider'
8
8
  autoload :PuppetClass, 'pdk/generate/puppet_class'
9
9
  autoload :PuppetObject, 'pdk/generate/puppet_object'
10
+ autoload :ResourceAPIObject, 'pdk/generate/resource_api_object'
10
11
  autoload :Task, 'pdk/generate/task'
11
12
  autoload :Transport, 'pdk/generate/transport'
12
13
 
@@ -26,6 +26,7 @@ module PDK
26
26
  unless update_manager.changes?
27
27
  if adding_tests?
28
28
  add_tests!
29
+ print_result 'Convert completed'
29
30
  else
30
31
  require 'pdk/report'
31
32
 
@@ -53,18 +54,15 @@ module PDK
53
54
  return unless continue
54
55
  end
55
56
 
56
- # Remove these files straight away as these changes are not something that the user needs to review.
57
- if needs_bundle_update?
58
- update_manager.unlink_file('Gemfile.lock')
59
- update_manager.unlink_file(File.join('.bundle', 'config'))
60
- end
57
+ # Remove these files straight away as these changes are not something
58
+ # that the user needs to review.
59
+ update_manager.unlink_file('Gemfile.lock')
60
+ update_manager.unlink_file(File.join('.bundle', 'config'))
61
61
 
62
62
  update_manager.sync_changes!
63
63
 
64
- if needs_bundle_update?
65
- require 'pdk/util/bundler'
66
- PDK::Util::Bundler.ensure_bundle!
67
- end
64
+ require 'pdk/util/bundler'
65
+ PDK::Util::Bundler.ensure_bundle!
68
66
 
69
67
  add_tests! if adding_tests?
70
68
 
@@ -88,41 +86,59 @@ module PDK
88
86
  end
89
87
 
90
88
  def missing_tests?
91
- test_generators.any? { |gen| gen.can_run? }
89
+ !available_test_generators.empty?
90
+ end
91
+
92
+ def available_test_generators
93
+ # Only select generators which can run and have no pre-existing files
94
+ test_generators.select do |gen|
95
+ if gen.can_run?
96
+ gen.template_files.none? { |_, dst_path| PDK::Util::Filesystem.exist?(File.join(gen.context.root_path, dst_path)) }
97
+ else
98
+ false
99
+ end
100
+ end
92
101
  end
93
102
 
94
- def test_generators
103
+ def test_generators(context = PDK.context)
95
104
  return @test_generators unless @test_generators.nil?
96
105
  require 'pdk/util/puppet_strings'
97
106
 
98
107
  test_gens = PDK::Util::PuppetStrings.all_objects.map do |generator, objects|
99
108
  (objects || []).map do |obj|
100
- generator.new(module_dir, obj['name'], spec_only: true)
109
+ generator.new(context, obj['name'], spec_only: true)
101
110
  end
102
111
  end
103
112
 
104
113
  @test_generators = test_gens.flatten
105
114
  end
106
115
 
107
- def add_tests!
108
- test_generators.each do |gen|
109
- gen.run if gen.can_run?
116
+ def stage_tests!(manager)
117
+ available_test_generators.each do |gen|
118
+ gen.stage_changes(manager)
110
119
  end
120
+ manager
111
121
  end
112
122
 
113
- def needs_bundle_update?
114
- update_manager.changed?('Gemfile')
123
+ def add_tests!
124
+ update_manager.clear!
125
+ stage_tests!(update_manager)
126
+
127
+ if update_manager.changes?
128
+ update_manager.sync_changes!
129
+ print_summary
130
+ else
131
+ PDK::Report.default_target.puts(_('No test changes required.'))
132
+ end
115
133
  end
116
134
 
117
- def stage_changes!
135
+ def stage_changes!(context = PDK.context)
118
136
  require 'pdk/util/filesystem'
119
137
 
120
138
  metadata_path = File.join(module_dir, 'metadata.json')
121
139
 
122
- PDK::Module::TemplateDir.with(template_uri, nil, true) do |templates|
123
- new_metadata = update_metadata(metadata_path, templates.metadata)
124
- templates.module_metadata = new_metadata.data unless new_metadata.nil?
125
-
140
+ PDK::Template.with(template_uri, context) do |template_dir|
141
+ new_metadata = update_metadata(metadata_path, template_dir.metadata)
126
142
  if options[:noop] && new_metadata.nil?
127
143
  update_manager.add_file(metadata_path, '')
128
144
  elsif PDK::Util::Filesystem.file?(metadata_path)
@@ -131,7 +147,9 @@ module PDK
131
147
  update_manager.add_file(metadata_path, new_metadata.to_json)
132
148
  end
133
149
 
134
- templates.render do |relative_file_path, file_content, file_status|
150
+ # new_metadata == nil when creating a new module but with --noop@
151
+ module_name = new_metadata.nil? ? 'new-module' : new_metadata.data['name']
152
+ template_dir.render_new_module(module_name) do |relative_file_path, file_content, file_status|
135
153
  absolute_file_path = File.join(module_dir, relative_file_path)
136
154
  case file_status
137
155
  when :unmanage
@@ -111,7 +111,7 @@ module PDK
111
111
 
112
112
  PDK::Util::Bundler.ensure_bundle!(puppet_env[:gemset])
113
113
 
114
- validator_exit_code, = PDK::Validate.invoke_validators_by_name(PDK::Validate.validator_names, false, options)
114
+ validator_exit_code, = PDK::Validate.invoke_validators_by_name(PDK.context, PDK::Validate.validator_names, false, options)
115
115
  raise PDK::CLI::ExitWithError, _('An error occured during validation') unless validator_exit_code.zero?
116
116
  end
117
117
 
@@ -33,19 +33,15 @@ module PDK
33
33
  return unless PDK::CLI::Util.prompt_for_yes(message)
34
34
  end
35
35
 
36
- # Remove these files straight away as these changes are not something that the user needs to review.
37
- if needs_bundle_update?
38
- update_manager.unlink_file('Gemfile.lock')
39
- update_manager.unlink_file(File.join('.bundle', 'config'))
40
- end
36
+ # Remove these files straight away as these changes are not something
37
+ # that the user needs to review.
38
+ update_manager.unlink_file('Gemfile.lock')
39
+ update_manager.unlink_file(File.join('.bundle', 'config'))
41
40
 
42
41
  update_manager.sync_changes!
43
42
 
44
- if needs_bundle_update?
45
- require 'pdk/util/bundler'
46
-
47
- PDK::Util::Bundler.ensure_bundle!
48
- end
43
+ require 'pdk/util/bundler'
44
+ PDK::Util::Bundler.ensure_bundle!
49
45
 
50
46
  print_result 'Update completed'
51
47
  end
@@ -75,6 +75,13 @@ module PDK
75
75
  changes[:modified].key?(path)
76
76
  end
77
77
 
78
+ def clear!
79
+ @modified_files.clear
80
+ @added_files.clear
81
+ @removed_files.clear
82
+ nil
83
+ end
84
+
78
85
  # Apply any pending changes stored in the UpdateManager to the module.
79
86
  #
80
87
  # @raise (see #calculate_diffs)
data/lib/pdk/module.rb CHANGED
@@ -4,7 +4,6 @@ module PDK
4
4
  autoload :Convert, 'pdk/module/convert'
5
5
  autoload :Metadata, 'pdk/module/metadata'
6
6
  autoload :Release, 'pdk/module/release'
7
- autoload :TemplateDir, 'pdk/module/template_dir'
8
7
  autoload :UpdateManager, 'pdk/module/update_manager'
9
8
  autoload :Update, 'pdk/module/update'
10
9
 
@@ -0,0 +1,85 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ class Git < PDK::Template::Fetcher::AbstractFetcher
7
+ # Whether the passed uri is fetchable by Git.
8
+ # @see PDK::Template::Fetcher.instance
9
+ # @return [Boolean]
10
+ def self.fetchable?(uri, _options = {})
11
+ PDK::Util::Git.repo?(uri.bare_uri)
12
+ end
13
+
14
+ # @see PDK::Template::Fetcher::AbstractTemplateFetcher.fetch!
15
+ def fetch!
16
+ return if fetched
17
+ super
18
+
19
+ # Default metadata for all git fetching methods
20
+ @metadata['template-url'] = uri.metadata_format
21
+
22
+ # We don't do a checkout of local-path repos. There are lots of edge
23
+ # cases or user un-expectations.
24
+ if PDK::Util::Git.work_tree?(uri.shell_path)
25
+ PDK.logger.warn _("Repository '%{repo}' has a work-tree; skipping git reset.") % {
26
+ repo: uri.shell_path,
27
+ }
28
+ @path = uri.shell_path
29
+ @temporary = false
30
+ @metadata['template-ref'] = describe_path_and_ref(@path)
31
+ return
32
+ end
33
+
34
+ # This is either a bare local repo or a remote. either way it needs cloning.
35
+ # A "remote" can also be git repo on the local filsystem.
36
+ # @todo When switching this over to using rugged, cache the cloned
37
+ # template repo in `%AppData%` or `$XDG_CACHE_DIR` and update before
38
+ # use.
39
+ require 'pdk/util'
40
+ require 'pdk/util/git'
41
+
42
+ temp_dir = PDK::Util.make_tmpdir_name('pdk-templates')
43
+ @temporary = true
44
+ origin_repo = uri.bare_uri
45
+ git_ref = uri.uri_fragment
46
+
47
+ # Clone the repository
48
+ clone_result = PDK::Util::Git.git('clone', origin_repo, temp_dir)
49
+ unless clone_result[:exit_code].zero?
50
+ PDK.logger.error clone_result[:stdout]
51
+ PDK.logger.error clone_result[:stderr]
52
+ raise PDK::CLI::FatalError, _("Unable to clone git repository at '%{repo}' into '%{dest}'.") % { repo: origin_repo, dest: temp_dir }
53
+ end
54
+ @path = PDK::Util.canonical_path(temp_dir)
55
+
56
+ # Checkout the git reference
57
+ if PDK::Util::Git.work_dir_clean?(temp_dir)
58
+ Dir.chdir(temp_dir) do
59
+ full_ref = PDK::Util::Git.ls_remote(temp_dir, git_ref)
60
+ @metadata['template-ref'] = describe_path_and_ref(temp_dir, full_ref)
61
+ reset_result = PDK::Util::Git.git('reset', '--hard', full_ref)
62
+ return if reset_result[:exit_code].zero?
63
+
64
+ PDK.logger.error reset_result[:stdout]
65
+ PDK.logger.error reset_result[:stderr]
66
+ raise PDK::CLI::FatalError, _("Unable to checkout '%{ref}' of git repository at '%{path}'.") % { ref: git_ref, path: temp_dir }
67
+ end
68
+ else
69
+ PDK.logger.warn _("Uncommitted changes found when attempting to checkout '%{ref}' of git repository at '%{path}'; skipping git reset.") % { ref: git_ref, path: temp_dir }
70
+ @metadata['template-ref'] = describe_path_and_ref(temp_dir)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ #:nocov: This is a just a wrapper for another method
77
+ def describe_path_and_ref(path, ref = nil)
78
+ require 'pdk/util/git'
79
+ PDK::Util::Git.describe(File.join(path, '.git'), ref)
80
+ end
81
+ #:nocov:
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,28 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ class Local < PDK::Template::Fetcher::AbstractFetcher
7
+ # Whether the passed uri is fetchable. This is a catch-all and all URIs
8
+ # are considered on-disk already.
9
+ #
10
+ # @see PDK::Template::Fetcher.instance
11
+ # @return [Boolean]
12
+ def self.fetchable?(_uri, _options = {})
13
+ true
14
+ end
15
+
16
+ # @see PDK::Template::Fetcher::AbstractTemplateFetcher.fetch!
17
+ def fetch!
18
+ return if fetched
19
+ super
20
+
21
+ @path = uri.shell_path
22
+ @temporary = false
23
+ @metadata['template-url'] = uri.bare_uri
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,98 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Template
5
+ module Fetcher
6
+ autoload :Git, 'pdk/template/fetcher/git'
7
+ autoload :Local, 'pdk/template/fetcher/local'
8
+
9
+ # Returns a Template Fetcher implementation for the given Template URI
10
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch
11
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
12
+ #
13
+ # @return [PDK::Template::Fetcher::AbstractTemplateFetcher] An instance of a class which implements the AbstractFetcher class
14
+ def self.instance(uri, options = {})
15
+ return Git.new(uri, options) if Git.fetchable?(uri, options)
16
+ Local.new(uri, options)
17
+ end
18
+
19
+ # Creates an instance of a PDK::Template::Fetcher::AbstractTemplateFetcher object with the path or URL to the template
20
+ # and the block of code to run to be run while the template is fetched.
21
+ #
22
+ # The fetched directory is only guaranteed to be available on disk
23
+ # within the scope of the block passed to this method.
24
+ #
25
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch.
26
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
27
+ #
28
+ # @yieldparam fetcher [PDK::Template::Fetcher::AbstractTemplateFetcher] The initialised fetcher with
29
+ # the template already fetched
30
+ #
31
+ # @example Using a git repository as a template
32
+ # PDK::Template::Fetcher.with('https://github.com/puppetlabs/pdk-templates') do |fetcher|
33
+ # end
34
+ #
35
+ # @raise [ArgumentError] If no block is given to this method.
36
+ # @return [void]
37
+ def self.with(uri, options = {})
38
+ raise ArgumentError, _('%{class_name}.with must be passed a block.') % { class_name: name } unless block_given?
39
+ fetcher = instance(uri, options)
40
+
41
+ begin
42
+ fetcher.fetch!
43
+ yield fetcher
44
+ ensure
45
+ # If the the path is temporary, clean it up
46
+ PDK::Util::Filesystem.rm_rf(fetcher.path) if fetcher.temporary
47
+ end
48
+ nil
49
+ end
50
+
51
+ # An abstract class which all Template Fetchers should subclass. This class is responsible for
52
+ # downloading or copying a Template Directory that is pointed to by a Template URI
53
+ #
54
+ # @api private
55
+ # @abstract
56
+ class AbstractFetcher
57
+ # @return [PDK::Util::TemplateURI] The URI of the template that is to be fetched
58
+ attr_reader :uri
59
+
60
+ # @return [String] The local filesystem path of the fetched template
61
+ attr_reader :path
62
+
63
+ # @return [Boolean] Whether the fetched path should be considered temporary and be deleted after use
64
+ attr_reader :temporary
65
+
66
+ # @return [Boolean] Whether the template has been fetched yet
67
+ attr_reader :fetched
68
+
69
+ # @return [Hash] The metadata hash for this template.
70
+ attr_reader :metadata
71
+
72
+ # @param uri [PDK::Util::TemplateURI] The URI of the template to fetch
73
+ # @param options [Hash{Object => Object}] A list of options to pass through to the fetcher.
74
+ def initialize(uri, options)
75
+ @uri = uri
76
+ # Defaults
77
+ @path = nil
78
+ @metadata = {
79
+ 'pdk-version' => PDK::Util::Version.version_string,
80
+ 'template-url' => nil,
81
+ 'template-ref' => nil,
82
+ }
83
+ @fetched = false
84
+ @temporary = false
85
+ @options = options
86
+ end
87
+
88
+ # Fetches the template directory and populates the path property
89
+ #
90
+ # @return [void]
91
+ # @abstract
92
+ def fetch!
93
+ @fetched = true
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end