Class: PDK::Util::TemplateURI

Inherits:
Object
  • Object
show all
Defined in:
lib/pdk/util/template_uri.rb

Constant Summary collapse

SCP_PATTERN =
%r{\A(?!\w+://)(?:(?<user>.+?)@)?(?<host>[^:/]+):(?<path>.+)\z}.freeze
PACKAGED_TEMPLATE_KEYWORD =
'pdk-default'.freeze
DEPRECATED_TEMPLATE_URL =
'https://github.com/puppetlabs/pdk-module-template'.freeze
PDK_TEMPLATE_URL =
'https://github.com/puppetlabs/pdk-templates'.freeze
LEGACY_PACKAGED_TEMPLATE_PATHS =
{
  'windows' => 'file:///C:/Program Files/Puppet Labs/DevelopmentKit/share/cache/pdk-templates.git',
  'macos' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git',
  'linux' => 'file:///opt/puppetlabs/pdk/share/cache/pdk-templates.git'
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts_or_uri) ⇒ TemplateURI

input/output formats:

file:///c:/foo (git clone location) c:/foo (shell paths) file:///c:/foo#main (only for metadata) c:/foo#main (only for metadata)

non output formats:

/c:/foo (internal use only) /c:/foo#main (internal use only)



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/pdk/util/template_uri.rb', line 37

def initialize(opts_or_uri)
  require 'addressable'
  # If a uri string is passed, skip the valid uri finding code.
  @uri = case opts_or_uri
         when self.class
           opts_or_uri.uri
         when String
           begin
             uri, ref = opts_or_uri.split('#', 2)
             if PDK::Util::TemplateURI.packaged_template?(uri)
               PDK::Util::TemplateURI.default_template_addressable_uri.tap { |default| default.fragment = ref unless ref.nil? || ref.empty? }
             else
               Addressable::URI.parse(opts_or_uri)
             end
           rescue Addressable::URI::InvalidURIError
             raise PDK::CLI::FatalError, "PDK::Util::TemplateURI attempted initialization with a non-uri string: #{opts_or_uri}"
           end
         when Addressable::URI
           opts_or_uri.dup
         else
           PDK::Util::TemplateURI.first_valid_uri(PDK::Util::TemplateURI.templates(opts_or_uri))
         end
end

Instance Attribute Details

#uriObject (readonly)

XXX Previously

  • template_uri used to get the string form of the uri when generating the module and written to pdk answers and metadata

  • template_path or deuri_path used for humans to see and commands to run

  • uri_path used only internally by the template selection code; move out

  • template_ref used by git checkout



23
24
25
# File 'lib/pdk/util/template_uri.rb', line 23

def uri
  @uri
end

Class Method Details

.bare_uri(uri) ⇒ Object

Remove the fragment off of URI. Useful for removing the branch for Git based URIs



110
111
112
113
114
115
116
117
118
# File 'lib/pdk/util/template_uri.rb', line 110

def self.bare_uri(uri)
  require 'addressable'

  if uri.is_a?(Addressable::URI) && uri.fragment
    human_readable(uri.to_s.chomp("##{uri.fragment}"))
  else
    human_readable(uri.to_s)
  end
end

.default_template_addressable_uriObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



136
137
138
139
140
141
142
143
144
145
# File 'lib/pdk/util/template_uri.rb', line 136

def self.default_template_addressable_uri
  require 'pdk/util'
  require 'addressable'

  if PDK::Util.package_install?
    Addressable::URI.new(scheme: 'file', host: '', path: File.join(PDK::Util.package_cachedir, 'pdk-templates.git'))
  else
    Addressable::URI.parse(PDK_TEMPLATE_URL)
  end
end

.default_template_ref(uri = nil) ⇒ Object



230
231
232
233
234
235
236
237
238
239
# File 'lib/pdk/util/template_uri.rb', line 230

def self.default_template_ref(uri = nil)
  require 'pdk/util'
  require 'pdk/version'

  return 'main' if PDK::Util.development_mode?
  return PDK::TEMPLATE_REF if uri.nil?

  uri = new(uri) unless uri.is_a?(self)
  uri.default? ? PDK::TEMPLATE_REF : 'main'
end

.default_template_uriObject



127
128
129
130
131
132
# File 'lib/pdk/util/template_uri.rb', line 127

def self.default_template_uri
  require 'pdk/util'
  require 'addressable'

  PDK::Util::TemplateURI.new(default_template_addressable_uri)
end

.first_valid_uri(templates_array) ⇒ Object



242
243
244
245
246
247
248
249
250
251
252
# File 'lib/pdk/util/template_uri.rb', line 242

def self.first_valid_uri(templates_array)
  # 1. Get the four sources of URIs
  # 2. Pick the first non-nil URI
  # 3. Error if the URI is not a valid git repo (missing directory or http 404)
  # 4. Leave updating answers/metadata to other code
  found_template = templates_array.find { |t| valid_template?(t) }

  raise PDK::CLI::FatalError, 'Unable to find a valid module template to use.' if found_template.nil?

  found_template[:uri]
end

.human_readable(string) ⇒ Object

If the passed value is a URI-safe windows path such as ‘/C:…` then it should be changed to a human-friendly `C:…` form. Otherwise the passed value is left alone.



162
163
164
# File 'lib/pdk/util/template_uri.rb', line 162

def self.human_readable(string)
  Gem.win_platform? && string =~ %r{^/[a-zA-Z][|:]} ? string[1..] : string
end

.packaged_template?(path) ⇒ Boolean

Returns:

  • (Boolean)


278
279
280
# File 'lib/pdk/util/template_uri.rb', line 278

def self.packaged_template?(path)
  path == PACKAGED_TEMPLATE_KEYWORD || LEGACY_PACKAGED_TEMPLATE_PATHS.value?(path)
end

.parse_scp_url(url) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/pdk/util/template_uri.rb', line 166

def self.parse_scp_url(url)
  require 'pathname'
  require 'addressable'

  # Valid URIs to avoid catching:
  # - absolute local paths
  # - have :'s in paths when preceeded by a slash
  # - have only digits following the : and preceeding a / or end-of-string that is 0-65535
  # The last item is ambiguous in the case of scp/git paths vs. URI port
  # numbers, but can be made unambiguous by making the form to
  # ssh://[email protected]/1234/repo.git or
  # ssh://[email protected]:1234/user/repo.git
  scp_url = url.match(SCP_PATTERN)
  return url unless Pathname.new(url).relative? && scp_url

  uri = Addressable::URI.new(scheme: 'ssh', user: scp_url[:user], host: scp_url[:host], path: scp_url[:path])
  PDK.logger.warn format('%{scp_uri} appears to be an SCP style URL; it will be converted to an RFC compliant URI: %{rfc_uri}', scp_uri: url, rfc_uri: uri.to_s)

  uri.to_s
end

.templates(opts) ⇒ Array<Hash{Symbol => Object}>

Returns an array of hashes. Each hash contains 3 keys: :type contains a String that describes the template directory, :url contains a String with the URL to the template directory, and :allow_fallback contains a Boolean that specifies if the lookup process should proceed to the next template directory if the template file is not in this template directory.

Returns:

  • (Array<Hash{Symbol => Object}>)

    an array of hashes. Each hash contains 3 keys: :type contains a String that describes the template directory, :url contains a String with the URL to the template directory, and :allow_fallback contains a Boolean that specifies if the lookup process should proceed to the next template directory if the template file is not in this template directory.



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/pdk/util/template_uri.rb', line 193

def self.templates(opts)
  require 'pdk/answer_file'
  require 'pdk/util'
  require 'addressable'

  explicit_url = opts.fetch(:'template-url', nil)
  explicit_ref = opts.fetch(:'template-ref', nil)

  # 1. Get the CLI, metadata (or answers if no metadata), and default URIs
  # 2. Construct the hash
  if explicit_url
    explicit_uri = Addressable::URI.parse(uri_safe(explicit_url))
    explicit_uri.fragment = explicit_ref || default_template_ref(new(explicit_uri))
  else
    explicit_uri = nil
  end
   = if PDK::Util.module_root && PDK::Util::Filesystem.file?(File.join(PDK::Util.module_root, 'metadata.json')) && PDK::Util.['template-url']
                   new(uri_safe(PDK::Util.['template-url'])).uri
                 end
  default_template_url = PDK.config.get_within_scopes('module_defaults.template-url')
  answers_uri = if [PACKAGED_TEMPLATE_KEYWORD, DEPRECATED_TEMPLATE_URL].include?(default_template_url)
                  Addressable::URI.parse(default_template_uri)
                elsif default_template_url
                  new(uri_safe(default_template_url)).uri
                end
  default_uri = default_template_uri.uri
  default_uri.fragment = default_template_ref(default_template_uri)

  ary = []
  ary << { type: '--template-url', uri: explicit_uri, allow_fallback: false } if explicit_url
  ary << { type: 'metadata.json', uri: , allow_fallback: true } if 
  ary << { type: 'PDK answers', uri: answers_uri, allow_fallback: true } if answers_uri
  ary << { type: 'default', uri: default_uri, allow_fallback: false }
  ary
end

.uri_safe(string) ⇒ Object

‘C:…` urls are not URI-safe. They should be of the form `/C:…` to be URI-safe. scp-like urls like `user@host:/path` are not URI-safe either and so are subsequently converted to ssh:// URIs.



152
153
154
155
# File 'lib/pdk/util/template_uri.rb', line 152

def self.uri_safe(string)
  url = Gem.win_platform? && string =~ /^[a-zA-Z][|:]/ ? "/#{string}" : string
  parse_scp_url(url)
end

.valid_template?(template, context = PDK.context) ⇒ Boolean

Returns:

  • (Boolean)

Raises:



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/pdk/util/template_uri.rb', line 254

def self.valid_template?(template, context = PDK.context)
  require 'addressable'

  return false if template.nil? || !template.is_a?(Hash)
  return false if template[:uri].nil? || !template[:uri].is_a?(Addressable::URI)

  return true if PDK::Util::Git.repo?(bare_uri(template[:uri]))

  path = human_readable(template[:uri].path)
  if PDK::Util::Filesystem.directory?(path)
    # We know that it's not a git repository, but it's a valid path on disk
    begin
      renderer = PDK::Template::Renderer.instance(path, template[:uri], context)
      return !renderer.nil?
    rescue StandardError
      nil
    end
  end

  raise PDK::CLI::FatalError, format('Unable to find a valid template at %{uri}', uri: template[:uri].to_s) unless template[:allow_fallback]

  false
end

Instance Method Details

#==(other) ⇒ Object



61
62
63
# File 'lib/pdk/util/template_uri.rb', line 61

def ==(other)
  @uri == other.uri
end

#bare_uriObject



65
66
67
# File 'lib/pdk/util/template_uri.rb', line 65

def bare_uri
  PDK::Util::TemplateURI.bare_uri(@uri)
end

#default?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/pdk/util/template_uri.rb', line 94

def default?
  bare_uri == PDK::Util::TemplateURI.bare_uri(PDK::Util::TemplateURI.default_template_addressable_uri)
end

#default_ref?Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/pdk/util/template_uri.rb', line 98

def default_ref?
  uri_fragment == self.class.default_template_ref(self)
end

#metadata_formatObject Also known as: to_s, to_str

This is the URI represented in a format suitable for writing to metadata.



73
74
75
76
77
78
79
# File 'lib/pdk/util/template_uri.rb', line 73

def 
  @metadata_format ||= if PDK::Util::TemplateURI.packaged_template?(bare_uri)
                         PDK::Util::TemplateURI.human_readable("pdk-default##{uri_fragment}")
                       else
                         PDK::Util::TemplateURI.human_readable(@uri.to_s)
                       end
end

#puppetlabs_template?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/pdk/util/template_uri.rb', line 102

def puppetlabs_template?
  self.class.packaged_template?(bare_uri) || bare_uri == PDK_TEMPLATE_URL
end

#shell_pathObject

This is the path of the URI, suitable for accessing directly from the shell.



122
123
124
# File 'lib/pdk/util/template_uri.rb', line 122

def shell_path
  self.class.human_readable(@uri.path)
end

#uri_fragmentObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the fragment of the URI, of the default template’s ref if one does not exist



86
87
88
# File 'lib/pdk/util/template_uri.rb', line 86

def uri_fragment
  @uri.fragment || self.class.default_template_ref(self)
end

#uri_fragment=(fragment) ⇒ Object



90
91
92
# File 'lib/pdk/util/template_uri.rb', line 90

def uri_fragment=(fragment)
  @uri.fragment = fragment
end