pdk 2.3.0 → 2.4.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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1329 -1321
  3. data/LICENSE +201 -201
  4. data/README.md +163 -163
  5. data/exe/pdk +10 -10
  6. data/lib/pdk/analytics/client/google_analytics.rb +143 -143
  7. data/lib/pdk/analytics/client/noop.rb +25 -25
  8. data/lib/pdk/analytics/util.rb +19 -19
  9. data/lib/pdk/analytics.rb +30 -30
  10. data/lib/pdk/answer_file.rb +12 -12
  11. data/lib/pdk/bolt.rb +19 -19
  12. data/lib/pdk/cli/build.rb +82 -82
  13. data/lib/pdk/cli/bundle.rb +48 -48
  14. data/lib/pdk/cli/config/get.rb +26 -26
  15. data/lib/pdk/cli/config.rb +22 -22
  16. data/lib/pdk/cli/console.rb +148 -148
  17. data/lib/pdk/cli/convert.rb +52 -52
  18. data/lib/pdk/cli/env.rb +52 -52
  19. data/lib/pdk/cli/errors.rb +25 -25
  20. data/lib/pdk/cli/exec/command.rb +293 -293
  21. data/lib/pdk/cli/exec/interactive_command.rb +114 -114
  22. data/lib/pdk/cli/exec.rb +84 -84
  23. data/lib/pdk/cli/exec_group.rb +104 -104
  24. data/lib/pdk/cli/get/config.rb +24 -24
  25. data/lib/pdk/cli/get.rb +20 -20
  26. data/lib/pdk/cli/module/build.rb +12 -12
  27. data/lib/pdk/cli/module/generate.rb +47 -47
  28. data/lib/pdk/cli/module.rb +14 -14
  29. data/lib/pdk/cli/new/class.rb +32 -32
  30. data/lib/pdk/cli/new/defined_type.rb +32 -32
  31. data/lib/pdk/cli/new/fact.rb +29 -29
  32. data/lib/pdk/cli/new/function.rb +29 -29
  33. data/lib/pdk/cli/new/module.rb +53 -53
  34. data/lib/pdk/cli/new/provider.rb +29 -29
  35. data/lib/pdk/cli/new/task.rb +34 -34
  36. data/lib/pdk/cli/new/test.rb +52 -52
  37. data/lib/pdk/cli/new/transport.rb +27 -27
  38. data/lib/pdk/cli/new.rb +21 -21
  39. data/lib/pdk/cli/release/prep.rb +39 -39
  40. data/lib/pdk/cli/release/publish.rb +50 -50
  41. data/lib/pdk/cli/release.rb +194 -194
  42. data/lib/pdk/cli/remove/config.rb +80 -80
  43. data/lib/pdk/cli/remove.rb +20 -20
  44. data/lib/pdk/cli/set/config.rb +119 -119
  45. data/lib/pdk/cli/set.rb +20 -20
  46. data/lib/pdk/cli/test/unit.rb +90 -90
  47. data/lib/pdk/cli/test.rb +11 -11
  48. data/lib/pdk/cli/update.rb +64 -64
  49. data/lib/pdk/cli/util/command_redirector.rb +27 -27
  50. data/lib/pdk/cli/util/interview.rb +72 -72
  51. data/lib/pdk/cli/util/option_normalizer.rb +55 -55
  52. data/lib/pdk/cli/util/option_validator.rb +68 -68
  53. data/lib/pdk/cli/util/spinner.rb +13 -13
  54. data/lib/pdk/cli/util/update_manager_printer.rb +82 -82
  55. data/lib/pdk/cli/util.rb +305 -305
  56. data/lib/pdk/cli/validate.rb +116 -116
  57. data/lib/pdk/cli.rb +175 -175
  58. data/lib/pdk/config/analytics_schema.json +26 -26
  59. data/lib/pdk/config/errors.rb +5 -5
  60. data/lib/pdk/config/ini_file.rb +183 -183
  61. data/lib/pdk/config/ini_file_setting.rb +39 -39
  62. data/lib/pdk/config/json.rb +34 -34
  63. data/lib/pdk/config/json_schema_namespace.rb +142 -142
  64. data/lib/pdk/config/json_schema_setting.rb +53 -53
  65. data/lib/pdk/config/json_with_schema.rb +49 -49
  66. data/lib/pdk/config/namespace.rb +354 -354
  67. data/lib/pdk/config/setting.rb +135 -135
  68. data/lib/pdk/config/validator.rb +31 -31
  69. data/lib/pdk/config/yaml.rb +46 -46
  70. data/lib/pdk/config/yaml_with_schema.rb +59 -59
  71. data/lib/pdk/config.rb +390 -390
  72. data/lib/pdk/context/control_repo.rb +60 -60
  73. data/lib/pdk/context/module.rb +28 -28
  74. data/lib/pdk/context/none.rb +22 -22
  75. data/lib/pdk/context.rb +99 -99
  76. data/lib/pdk/control_repo.rb +90 -90
  77. data/lib/pdk/generate/defined_type.rb +43 -43
  78. data/lib/pdk/generate/fact.rb +25 -25
  79. data/lib/pdk/generate/function.rb +48 -48
  80. data/lib/pdk/generate/module.rb +352 -352
  81. data/lib/pdk/generate/provider.rb +28 -28
  82. data/lib/pdk/generate/puppet_class.rb +43 -43
  83. data/lib/pdk/generate/puppet_object.rb +232 -232
  84. data/lib/pdk/generate/task.rb +68 -68
  85. data/lib/pdk/generate/transport.rb +33 -33
  86. data/lib/pdk/generate.rb +24 -24
  87. data/lib/pdk/i18n.rb +4 -4
  88. data/lib/pdk/logger.rb +45 -45
  89. data/lib/pdk/module/build.rb +322 -322
  90. data/lib/pdk/module/convert.rb +296 -296
  91. data/lib/pdk/module/metadata.rb +202 -202
  92. data/lib/pdk/module/release.rb +260 -260
  93. data/lib/pdk/module/update.rb +131 -131
  94. data/lib/pdk/module/update_manager.rb +227 -227
  95. data/lib/pdk/module.rb +30 -30
  96. data/lib/pdk/report/event.rb +370 -370
  97. data/lib/pdk/report.rb +121 -121
  98. data/lib/pdk/template/fetcher/git.rb +85 -85
  99. data/lib/pdk/template/fetcher/local.rb +28 -28
  100. data/lib/pdk/template/fetcher.rb +98 -98
  101. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -116
  102. data/lib/pdk/template/renderer/v1/renderer.rb +132 -132
  103. data/lib/pdk/template/renderer/v1/template_file.rb +102 -102
  104. data/lib/pdk/template/renderer/v1.rb +25 -25
  105. data/lib/pdk/template/renderer.rb +96 -96
  106. data/lib/pdk/template/template_dir.rb +67 -67
  107. data/lib/pdk/template.rb +59 -59
  108. data/lib/pdk/tests/unit.rb +252 -252
  109. data/lib/pdk/util/bundler.rb +259 -259
  110. data/lib/pdk/util/changelog_generator.rb +137 -137
  111. data/lib/pdk/util/env.rb +47 -47
  112. data/lib/pdk/util/filesystem.rb +138 -138
  113. data/lib/pdk/util/git.rb +179 -179
  114. data/lib/pdk/util/json_finder.rb +85 -85
  115. data/lib/pdk/util/puppet_strings.rb +125 -125
  116. data/lib/pdk/util/puppet_version.rb +266 -266
  117. data/lib/pdk/util/ruby_version.rb +179 -179
  118. data/lib/pdk/util/template_uri.rb +295 -295
  119. data/lib/pdk/util/vendored_file.rb +93 -93
  120. data/lib/pdk/util/version.rb +43 -43
  121. data/lib/pdk/util/windows/api_types.rb +82 -82
  122. data/lib/pdk/util/windows/file.rb +36 -36
  123. data/lib/pdk/util/windows/process.rb +79 -79
  124. data/lib/pdk/util/windows/string.rb +16 -16
  125. data/lib/pdk/util/windows.rb +15 -15
  126. data/lib/pdk/util.rb +278 -277
  127. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -23
  128. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -98
  129. data/lib/pdk/validate/external_command_validator.rb +208 -208
  130. data/lib/pdk/validate/internal_ruby_validator.rb +100 -100
  131. data/lib/pdk/validate/invokable_validator.rb +228 -228
  132. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -86
  133. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -78
  134. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -20
  135. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -133
  136. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -66
  137. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -137
  138. data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -21
  139. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -80
  140. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -19
  141. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -88
  142. data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -50
  143. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -20
  144. data/lib/pdk/validate/validator.rb +118 -118
  145. data/lib/pdk/validate/validator_group.rb +104 -104
  146. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -95
  147. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -19
  148. data/lib/pdk/validate.rb +94 -94
  149. data/lib/pdk/version.rb +4 -4
  150. data/lib/pdk.rb +76 -76
  151. data/locales/config.yaml +21 -21
  152. data/locales/pdk.pot +2094 -2094
  153. metadata +5 -6
@@ -1,295 +1,295 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Util
5
- class TemplateURI
6
- SCP_PATTERN = %r{\A(?!\w+://)(?:(?<user>.+?)@)?(?<host>[^:/]+):(?<path>.+)\z}
7
-
8
- PACKAGED_TEMPLATE_KEYWORD = 'pdk-default'.freeze
9
- DEPRECATED_TEMPLATE_URL = 'https://github.com/puppetlabs/pdk-module-template'.freeze
10
- PDK_TEMPLATE_URL = 'https://github.com/puppetlabs/pdk-templates'.freeze
11
-
12
- LEGACY_PACKAGED_TEMPLATE_PATHS = {
13
- 'windows' => 'file:///C:/Program Files/Puppet Labs/DevelopmentKit/share/cache/pdk-templates.git',
14
- 'macos' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git',
15
- 'linux' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git',
16
- }.freeze
17
-
18
- # XXX Previously
19
- # - template_uri used to get the string form of the uri when generating the module and written to pdk answers and metadata
20
- # - template_path or deuri_path used for humans to see and commands to run
21
- # - uri_path used only internally by the template selection code; move out
22
- # - template_ref used by git checkout
23
- attr_reader :uri
24
-
25
- # input/output formats:
26
- #
27
- # file:///c:/foo (git clone location)
28
- # c:/foo (shell paths)
29
- # file:///c:/foo#main (only for metadata)
30
- # c:/foo#main (only for metadata)
31
- #
32
- # non output formats:
33
- #
34
- # /c:/foo (internal use only)
35
- # /c:/foo#main (internal use only)
36
- #
37
- def initialize(opts_or_uri)
38
- require 'addressable'
39
- # If a uri string is passed, skip the valid uri finding code.
40
- @uri = if opts_or_uri.is_a?(self.class)
41
- opts_or_uri.uri
42
- elsif opts_or_uri.is_a?(String)
43
- begin
44
- uri, ref = opts_or_uri.split('#', 2)
45
- if PDK::Util::TemplateURI.packaged_template?(uri)
46
- PDK::Util::TemplateURI.default_template_addressable_uri.tap { |default| default.fragment = ref unless ref.nil? || ref.empty? }
47
- else
48
- Addressable::URI.parse(opts_or_uri)
49
- end
50
- rescue Addressable::URI::InvalidURIError
51
- raise PDK::CLI::FatalError, _('PDK::Util::TemplateURI attempted initialization with a non-uri string: {string}') % { string: opts_or_uri }
52
- end
53
- elsif opts_or_uri.is_a?(Addressable::URI)
54
- opts_or_uri.dup
55
- else
56
- PDK::Util::TemplateURI.first_valid_uri(PDK::Util::TemplateURI.templates(opts_or_uri))
57
- end
58
- end
59
-
60
- def ==(other)
61
- @uri == other.uri
62
- end
63
-
64
- def bare_uri
65
- PDK::Util::TemplateURI.bare_uri(@uri)
66
- end
67
-
68
- # This is the URI represented in a format suitable for writing to
69
- # metadata.
70
- #
71
- # @returns String
72
- def metadata_format
73
- @metadata_format ||= if PDK::Util::TemplateURI.packaged_template?(bare_uri)
74
- PDK::Util::TemplateURI.human_readable("pdk-default##{uri_fragment}")
75
- else
76
- PDK::Util::TemplateURI.human_readable(@uri.to_s)
77
- end
78
- end
79
- alias to_s metadata_format
80
- alias to_str metadata_format
81
-
82
- # Returns the fragment of the URI, of the default template's ref if one does not exist
83
- # @returns String
84
- # @api private
85
- def uri_fragment
86
- @uri.fragment || self.class.default_template_ref(self)
87
- end
88
-
89
- def uri_fragment=(fragment)
90
- @uri.fragment = fragment
91
- end
92
-
93
- def default?
94
- bare_uri == PDK::Util::TemplateURI.bare_uri(PDK::Util::TemplateURI.default_template_addressable_uri)
95
- end
96
-
97
- def default_ref?
98
- uri_fragment == self.class.default_template_ref(self)
99
- end
100
-
101
- def puppetlabs_template?
102
- self.class.packaged_template?(bare_uri) || bare_uri == PDK_TEMPLATE_URL
103
- end
104
-
105
- # Class Methods
106
-
107
- # Remove the fragment off of URI. Useful for removing the branch
108
- # for Git based URIs
109
- def self.bare_uri(uri)
110
- require 'addressable'
111
-
112
- if uri.is_a?(Addressable::URI) && uri.fragment
113
- human_readable(uri.to_s.chomp('#' + uri.fragment))
114
- else
115
- human_readable(uri.to_s)
116
- end
117
- end
118
-
119
- # This is the path of the URI, suitable for accessing directly from the shell.
120
- # @returns String
121
- def shell_path
122
- self.class.human_readable(@uri.path)
123
- end
124
-
125
- # @returns PDK::Util::TemplateURI
126
- def self.default_template_uri
127
- require 'pdk/util'
128
- require 'addressable'
129
-
130
- PDK::Util::TemplateURI.new(default_template_addressable_uri)
131
- end
132
-
133
- # @returns Addressable::URI
134
- # @api private
135
- def self.default_template_addressable_uri
136
- require 'pdk/util'
137
- require 'addressable'
138
-
139
- if PDK::Util.package_install?
140
- Addressable::URI.new(scheme: 'file', host: '', path: File.join(PDK::Util.package_cachedir, 'pdk-templates.git'))
141
- else
142
- Addressable::URI.parse(PDK_TEMPLATE_URL)
143
- end
144
- end
145
-
146
- # `C:...` urls are not URI-safe. They should be of the form `/C:...` to
147
- # be URI-safe. scp-like urls like `user@host:/path` are not URI-safe
148
- # either and so are subsequently converted to ssh:// URIs.
149
- #
150
- # @returns String
151
- def self.uri_safe(string)
152
- url = (Gem.win_platform? && string =~ %r{^[a-zA-Z][\|:]}) ? "/#{string}" : string
153
- parse_scp_url(url)
154
- end
155
-
156
- # If the passed value is a URI-safe windows path such as `/C:...` then it
157
- # should be changed to a human-friendly `C:...` form. Otherwise the
158
- # passed value is left alone.
159
- #
160
- # @returns String
161
- def self.human_readable(string)
162
- (Gem.win_platform? && string =~ %r{^\/[a-zA-Z][\|:]}) ? string[1..-1] : string
163
- end
164
-
165
- def self.parse_scp_url(url)
166
- require 'pathname'
167
- require 'addressable'
168
-
169
- # Valid URIs to avoid catching:
170
- # - absolute local paths
171
- # - have :'s in paths when preceeded by a slash
172
- # - have only digits following the : and preceeding a / or end-of-string that is 0-65535
173
- # The last item is ambiguous in the case of scp/git paths vs. URI port
174
- # numbers, but can be made unambiguous by making the form to
175
- # ssh://git@github.com/1234/repo.git or
176
- # ssh://git@github.com:1234/user/repo.git
177
- scp_url = url.match(SCP_PATTERN)
178
- return url unless Pathname.new(url).relative? && scp_url
179
-
180
- uri = Addressable::URI.new(scheme: 'ssh', user: scp_url[:user], host: scp_url[:host], path: scp_url[:path])
181
- PDK.logger.warn _('%{scp_uri} appears to be an SCP style URL; it will be converted to an RFC compliant URI: %{rfc_uri}') % {
182
- scp_uri: url,
183
- rfc_uri: uri.to_s,
184
- }
185
-
186
- uri.to_s
187
- end
188
-
189
- # @return [Array<Hash{Symbol => Object}>] an array of hashes. Each hash
190
- # contains 3 keys: :type contains a String that describes the template
191
- # directory, :url contains a String with the URL to the template
192
- # directory, and :allow_fallback contains a Boolean that specifies if
193
- # the lookup process should proceed to the next template directory if
194
- # the template file is not in this template directory.
195
- def self.templates(opts)
196
- require 'pdk/answer_file'
197
- require 'pdk/util'
198
- require 'addressable'
199
-
200
- explicit_url = opts.fetch(:'template-url', nil)
201
- explicit_ref = opts.fetch(:'template-ref', nil)
202
-
203
- # 1. Get the CLI, metadata (or answers if no metadata), and default URIs
204
- # 2. Construct the hash
205
- if explicit_url
206
- explicit_uri = Addressable::URI.parse(uri_safe(explicit_url))
207
- explicit_uri.fragment = explicit_ref || default_template_ref(new(explicit_uri))
208
- else
209
- explicit_uri = nil
210
- end
211
- metadata_uri = if PDK::Util.module_root && PDK::Util::Filesystem.file?(File.join(PDK::Util.module_root, 'metadata.json'))
212
- if PDK::Util.module_metadata['template-url']
213
- new(uri_safe(PDK::Util.module_metadata['template-url'])).uri
214
- else
215
- nil
216
- end
217
- else
218
- nil
219
- end
220
- default_template_url = PDK.config.get_within_scopes('module_defaults.template-url')
221
- answers_uri = if [PACKAGED_TEMPLATE_KEYWORD, DEPRECATED_TEMPLATE_URL].include?(default_template_url)
222
- Addressable::URI.parse(default_template_uri)
223
- elsif default_template_url
224
- new(uri_safe(default_template_url)).uri
225
- else
226
- nil
227
- end
228
- default_uri = default_template_uri.uri
229
- default_uri.fragment = default_template_ref(default_template_uri)
230
-
231
- ary = []
232
- ary << { type: _('--template-url'), uri: explicit_uri, allow_fallback: false } if explicit_url
233
- ary << { type: _('metadata.json'), uri: metadata_uri, allow_fallback: true } if metadata_uri
234
- ary << { type: _('PDK answers'), uri: answers_uri, allow_fallback: true } if answers_uri
235
- ary << { type: _('default'), uri: default_uri, allow_fallback: false }
236
- ary
237
- end
238
-
239
- # @returns String
240
- def self.default_template_ref(uri = nil)
241
- require 'pdk/util'
242
- require 'pdk/version'
243
-
244
- return 'main' if PDK::Util.development_mode?
245
- return PDK::TEMPLATE_REF if uri.nil?
246
-
247
- uri = new(uri) unless uri.is_a?(self)
248
- uri.default? ? PDK::TEMPLATE_REF : 'main'
249
- end
250
-
251
- # @returns Addressable::URI
252
- def self.first_valid_uri(templates_array)
253
- # 1. Get the four sources of URIs
254
- # 2. Pick the first non-nil URI
255
- # 3. Error if the URI is not a valid git repo (missing directory or http 404)
256
- # 4. Leave updating answers/metadata to other code
257
- found_template = templates_array.find { |t| valid_template?(t) }
258
-
259
- raise PDK::CLI::FatalError, _('Unable to find a valid module template to use.') if found_template.nil?
260
- found_template[:uri]
261
- end
262
-
263
- def self.valid_template?(template, context = PDK.context)
264
- require 'addressable'
265
-
266
- return false if template.nil? || !template.is_a?(Hash)
267
- return false if template[:uri].nil? || !template[:uri].is_a?(Addressable::URI)
268
-
269
- return true if PDK::Util::Git.repo?(bare_uri(template[:uri]))
270
- path = human_readable(template[:uri].path)
271
- if PDK::Util::Filesystem.directory?(path)
272
- # We know that it's not a git repository, but it's a valid path on disk
273
- begin
274
- renderer = PDK::Template::Renderer.instance(path, template[:uri], context)
275
- return !renderer.nil?
276
- rescue StandardError
277
- nil
278
- end
279
- end
280
-
281
- unless template[:allow_fallback]
282
- raise PDK::CLI::FatalError, _('Unable to find a valid template at %{uri}') % {
283
- uri: template[:uri].to_s,
284
- }
285
- end
286
-
287
- false
288
- end
289
-
290
- def self.packaged_template?(path)
291
- path == PACKAGED_TEMPLATE_KEYWORD || LEGACY_PACKAGED_TEMPLATE_PATHS.value?(path)
292
- end
293
- end
294
- end
295
- end
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Util
5
+ class TemplateURI
6
+ SCP_PATTERN = %r{\A(?!\w+://)(?:(?<user>.+?)@)?(?<host>[^:/]+):(?<path>.+)\z}
7
+
8
+ PACKAGED_TEMPLATE_KEYWORD = 'pdk-default'.freeze
9
+ DEPRECATED_TEMPLATE_URL = 'https://github.com/puppetlabs/pdk-module-template'.freeze
10
+ PDK_TEMPLATE_URL = 'https://github.com/puppetlabs/pdk-templates'.freeze
11
+
12
+ LEGACY_PACKAGED_TEMPLATE_PATHS = {
13
+ 'windows' => 'file:///C:/Program Files/Puppet Labs/DevelopmentKit/share/cache/pdk-templates.git',
14
+ 'macos' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git',
15
+ 'linux' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git',
16
+ }.freeze
17
+
18
+ # XXX Previously
19
+ # - template_uri used to get the string form of the uri when generating the module and written to pdk answers and metadata
20
+ # - template_path or deuri_path used for humans to see and commands to run
21
+ # - uri_path used only internally by the template selection code; move out
22
+ # - template_ref used by git checkout
23
+ attr_reader :uri
24
+
25
+ # input/output formats:
26
+ #
27
+ # file:///c:/foo (git clone location)
28
+ # c:/foo (shell paths)
29
+ # file:///c:/foo#main (only for metadata)
30
+ # c:/foo#main (only for metadata)
31
+ #
32
+ # non output formats:
33
+ #
34
+ # /c:/foo (internal use only)
35
+ # /c:/foo#main (internal use only)
36
+ #
37
+ def initialize(opts_or_uri)
38
+ require 'addressable'
39
+ # If a uri string is passed, skip the valid uri finding code.
40
+ @uri = if opts_or_uri.is_a?(self.class)
41
+ opts_or_uri.uri
42
+ elsif opts_or_uri.is_a?(String)
43
+ begin
44
+ uri, ref = opts_or_uri.split('#', 2)
45
+ if PDK::Util::TemplateURI.packaged_template?(uri)
46
+ PDK::Util::TemplateURI.default_template_addressable_uri.tap { |default| default.fragment = ref unless ref.nil? || ref.empty? }
47
+ else
48
+ Addressable::URI.parse(opts_or_uri)
49
+ end
50
+ rescue Addressable::URI::InvalidURIError
51
+ raise PDK::CLI::FatalError, _('PDK::Util::TemplateURI attempted initialization with a non-uri string: {string}') % { string: opts_or_uri }
52
+ end
53
+ elsif opts_or_uri.is_a?(Addressable::URI)
54
+ opts_or_uri.dup
55
+ else
56
+ PDK::Util::TemplateURI.first_valid_uri(PDK::Util::TemplateURI.templates(opts_or_uri))
57
+ end
58
+ end
59
+
60
+ def ==(other)
61
+ @uri == other.uri
62
+ end
63
+
64
+ def bare_uri
65
+ PDK::Util::TemplateURI.bare_uri(@uri)
66
+ end
67
+
68
+ # This is the URI represented in a format suitable for writing to
69
+ # metadata.
70
+ #
71
+ # @returns String
72
+ def metadata_format
73
+ @metadata_format ||= if PDK::Util::TemplateURI.packaged_template?(bare_uri)
74
+ PDK::Util::TemplateURI.human_readable("pdk-default##{uri_fragment}")
75
+ else
76
+ PDK::Util::TemplateURI.human_readable(@uri.to_s)
77
+ end
78
+ end
79
+ alias to_s metadata_format
80
+ alias to_str metadata_format
81
+
82
+ # Returns the fragment of the URI, of the default template's ref if one does not exist
83
+ # @returns String
84
+ # @api private
85
+ def uri_fragment
86
+ @uri.fragment || self.class.default_template_ref(self)
87
+ end
88
+
89
+ def uri_fragment=(fragment)
90
+ @uri.fragment = fragment
91
+ end
92
+
93
+ def default?
94
+ bare_uri == PDK::Util::TemplateURI.bare_uri(PDK::Util::TemplateURI.default_template_addressable_uri)
95
+ end
96
+
97
+ def default_ref?
98
+ uri_fragment == self.class.default_template_ref(self)
99
+ end
100
+
101
+ def puppetlabs_template?
102
+ self.class.packaged_template?(bare_uri) || bare_uri == PDK_TEMPLATE_URL
103
+ end
104
+
105
+ # Class Methods
106
+
107
+ # Remove the fragment off of URI. Useful for removing the branch
108
+ # for Git based URIs
109
+ def self.bare_uri(uri)
110
+ require 'addressable'
111
+
112
+ if uri.is_a?(Addressable::URI) && uri.fragment
113
+ human_readable(uri.to_s.chomp('#' + uri.fragment))
114
+ else
115
+ human_readable(uri.to_s)
116
+ end
117
+ end
118
+
119
+ # This is the path of the URI, suitable for accessing directly from the shell.
120
+ # @returns String
121
+ def shell_path
122
+ self.class.human_readable(@uri.path)
123
+ end
124
+
125
+ # @returns PDK::Util::TemplateURI
126
+ def self.default_template_uri
127
+ require 'pdk/util'
128
+ require 'addressable'
129
+
130
+ PDK::Util::TemplateURI.new(default_template_addressable_uri)
131
+ end
132
+
133
+ # @returns Addressable::URI
134
+ # @api private
135
+ def self.default_template_addressable_uri
136
+ require 'pdk/util'
137
+ require 'addressable'
138
+
139
+ if PDK::Util.package_install?
140
+ Addressable::URI.new(scheme: 'file', host: '', path: File.join(PDK::Util.package_cachedir, 'pdk-templates.git'))
141
+ else
142
+ Addressable::URI.parse(PDK_TEMPLATE_URL)
143
+ end
144
+ end
145
+
146
+ # `C:...` urls are not URI-safe. They should be of the form `/C:...` to
147
+ # be URI-safe. scp-like urls like `user@host:/path` are not URI-safe
148
+ # either and so are subsequently converted to ssh:// URIs.
149
+ #
150
+ # @returns String
151
+ def self.uri_safe(string)
152
+ url = (Gem.win_platform? && string =~ %r{^[a-zA-Z][\|:]}) ? "/#{string}" : string
153
+ parse_scp_url(url)
154
+ end
155
+
156
+ # If the passed value is a URI-safe windows path such as `/C:...` then it
157
+ # should be changed to a human-friendly `C:...` form. Otherwise the
158
+ # passed value is left alone.
159
+ #
160
+ # @returns String
161
+ def self.human_readable(string)
162
+ (Gem.win_platform? && string =~ %r{^\/[a-zA-Z][\|:]}) ? string[1..-1] : string
163
+ end
164
+
165
+ def self.parse_scp_url(url)
166
+ require 'pathname'
167
+ require 'addressable'
168
+
169
+ # Valid URIs to avoid catching:
170
+ # - absolute local paths
171
+ # - have :'s in paths when preceeded by a slash
172
+ # - have only digits following the : and preceeding a / or end-of-string that is 0-65535
173
+ # The last item is ambiguous in the case of scp/git paths vs. URI port
174
+ # numbers, but can be made unambiguous by making the form to
175
+ # ssh://git@github.com/1234/repo.git or
176
+ # ssh://git@github.com:1234/user/repo.git
177
+ scp_url = url.match(SCP_PATTERN)
178
+ return url unless Pathname.new(url).relative? && scp_url
179
+
180
+ uri = Addressable::URI.new(scheme: 'ssh', user: scp_url[:user], host: scp_url[:host], path: scp_url[:path])
181
+ PDK.logger.warn _('%{scp_uri} appears to be an SCP style URL; it will be converted to an RFC compliant URI: %{rfc_uri}') % {
182
+ scp_uri: url,
183
+ rfc_uri: uri.to_s,
184
+ }
185
+
186
+ uri.to_s
187
+ end
188
+
189
+ # @return [Array<Hash{Symbol => Object}>] an array of hashes. Each hash
190
+ # contains 3 keys: :type contains a String that describes the template
191
+ # directory, :url contains a String with the URL to the template
192
+ # directory, and :allow_fallback contains a Boolean that specifies if
193
+ # the lookup process should proceed to the next template directory if
194
+ # the template file is not in this template directory.
195
+ def self.templates(opts)
196
+ require 'pdk/answer_file'
197
+ require 'pdk/util'
198
+ require 'addressable'
199
+
200
+ explicit_url = opts.fetch(:'template-url', nil)
201
+ explicit_ref = opts.fetch(:'template-ref', nil)
202
+
203
+ # 1. Get the CLI, metadata (or answers if no metadata), and default URIs
204
+ # 2. Construct the hash
205
+ if explicit_url
206
+ explicit_uri = Addressable::URI.parse(uri_safe(explicit_url))
207
+ explicit_uri.fragment = explicit_ref || default_template_ref(new(explicit_uri))
208
+ else
209
+ explicit_uri = nil
210
+ end
211
+ metadata_uri = if PDK::Util.module_root && PDK::Util::Filesystem.file?(File.join(PDK::Util.module_root, 'metadata.json'))
212
+ if PDK::Util.module_metadata['template-url']
213
+ new(uri_safe(PDK::Util.module_metadata['template-url'])).uri
214
+ else
215
+ nil
216
+ end
217
+ else
218
+ nil
219
+ end
220
+ default_template_url = PDK.config.get_within_scopes('module_defaults.template-url')
221
+ answers_uri = if [PACKAGED_TEMPLATE_KEYWORD, DEPRECATED_TEMPLATE_URL].include?(default_template_url)
222
+ Addressable::URI.parse(default_template_uri)
223
+ elsif default_template_url
224
+ new(uri_safe(default_template_url)).uri
225
+ else
226
+ nil
227
+ end
228
+ default_uri = default_template_uri.uri
229
+ default_uri.fragment = default_template_ref(default_template_uri)
230
+
231
+ ary = []
232
+ ary << { type: _('--template-url'), uri: explicit_uri, allow_fallback: false } if explicit_url
233
+ ary << { type: _('metadata.json'), uri: metadata_uri, allow_fallback: true } if metadata_uri
234
+ ary << { type: _('PDK answers'), uri: answers_uri, allow_fallback: true } if answers_uri
235
+ ary << { type: _('default'), uri: default_uri, allow_fallback: false }
236
+ ary
237
+ end
238
+
239
+ # @returns String
240
+ def self.default_template_ref(uri = nil)
241
+ require 'pdk/util'
242
+ require 'pdk/version'
243
+
244
+ return 'main' if PDK::Util.development_mode?
245
+ return PDK::TEMPLATE_REF if uri.nil?
246
+
247
+ uri = new(uri) unless uri.is_a?(self)
248
+ uri.default? ? PDK::TEMPLATE_REF : 'main'
249
+ end
250
+
251
+ # @returns Addressable::URI
252
+ def self.first_valid_uri(templates_array)
253
+ # 1. Get the four sources of URIs
254
+ # 2. Pick the first non-nil URI
255
+ # 3. Error if the URI is not a valid git repo (missing directory or http 404)
256
+ # 4. Leave updating answers/metadata to other code
257
+ found_template = templates_array.find { |t| valid_template?(t) }
258
+
259
+ raise PDK::CLI::FatalError, _('Unable to find a valid module template to use.') if found_template.nil?
260
+ found_template[:uri]
261
+ end
262
+
263
+ def self.valid_template?(template, context = PDK.context)
264
+ require 'addressable'
265
+
266
+ return false if template.nil? || !template.is_a?(Hash)
267
+ return false if template[:uri].nil? || !template[:uri].is_a?(Addressable::URI)
268
+
269
+ return true if PDK::Util::Git.repo?(bare_uri(template[:uri]))
270
+ path = human_readable(template[:uri].path)
271
+ if PDK::Util::Filesystem.directory?(path)
272
+ # We know that it's not a git repository, but it's a valid path on disk
273
+ begin
274
+ renderer = PDK::Template::Renderer.instance(path, template[:uri], context)
275
+ return !renderer.nil?
276
+ rescue StandardError
277
+ nil
278
+ end
279
+ end
280
+
281
+ unless template[:allow_fallback]
282
+ raise PDK::CLI::FatalError, _('Unable to find a valid template at %{uri}') % {
283
+ uri: template[:uri].to_s,
284
+ }
285
+ end
286
+
287
+ false
288
+ end
289
+
290
+ def self.packaged_template?(path)
291
+ path == PACKAGED_TEMPLATE_KEYWORD || LEGACY_PACKAGED_TEMPLATE_PATHS.value?(path)
292
+ end
293
+ end
294
+ end
295
+ end