pdk 1.17.0 → 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
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