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}
PACKAGED_TEMPLATE_KEYWORD =
'pdk-default'.freeze
DEPRECATED_TEMPLATE_URL =
'https://github.com/puppetlabs/pdk-module-template'.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#master (only for metadata) c:/foo#master (only for metadata)

non output formats:

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



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

def initialize(opts_or_uri)
  # If a uri string is passed, skip the valid uri finding code.
  @uri = if opts_or_uri.is_a?(self.class)
           opts_or_uri.uri
         elsif opts_or_uri.is_a?(String)
           begin
             uri, ref = opts_or_uri.split('#', 2)
             if self.class.packaged_template?(uri)
               self.class.default_template_uri(ref).uri
             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: {string}') % { string: opts_or_uri }
           end
         elsif opts_or_uri.is_a?(Addressable::URI)
           opts_or_uri.dup
         else
           self.class.first_valid_uri(self.class.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



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

def uri
  @uri
end

Class Method Details

.default_template_ref(uri = nil) ⇒ Object



210
211
212
213
214
215
216
# File 'lib/pdk/util/template_uri.rb', line 210

def self.default_template_ref(uri = nil)
  return 'master' 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 : 'master'
end

.default_template_uri(ref = nil) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/pdk/util/template_uri.rb', line 107

def self.default_template_uri(ref = nil)
  if PDK::Util.package_install?
    PDK::Util::TemplateURI.new(Addressable::URI.new(scheme: 'file', host: '', path: File.join(PDK::Util.package_cachedir, 'pdk-templates.git'), fragment: ref))
  else
    PDK::Util::TemplateURI.new(Addressable::URI.new(scheme: 'https', host: 'github.com', path: '/puppetlabs/pdk-templates', fragment: ref))
  end
end

.first_valid_uri(templates_array) ⇒ Object



219
220
221
222
223
224
225
226
227
228
# File 'lib/pdk/util/template_uri.rb', line 219

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

.git_remote(uri) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/pdk/util/template_uri.rb', line 83

def self.git_remote(uri)
  if uri.is_a?(Addressable::URI) && uri.fragment
    human_readable(uri.to_s.chomp('#' + uri.fragment))
  else
    human_readable(uri.to_s)
  end
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.



138
139
140
# File 'lib/pdk/util/template_uri.rb', line 138

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

.packaged_template?(path) ⇒ Boolean

Returns:

  • (Boolean)


255
256
257
# File 'lib/pdk/util/template_uri.rb', line 255

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

.parse_scp_url(url) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/pdk/util/template_uri.rb', line 142

def self.parse_scp_url(url)
  # 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 _('%{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.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/pdk/util/template_uri.rb', line 170

def self.templates(opts)
  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 && File.file?(File.join(PDK::Util.module_root, 'metadata.json'))
                   if PDK::Util.['template-url']
                     new(uri_safe(PDK::Util.['template-url'])).uri
                   else
                     nil
                   end
                 else
                   nil
                 end
  answers_uri = if [PACKAGED_TEMPLATE_KEYWORD, DEPRECATED_TEMPLATE_URL].include?(PDK.answers['template-url'])
                  Addressable::URI.parse(default_template_uri)
                elsif PDK.answers['template-url']
                  new(uri_safe(PDK.answers['template-url'])).uri
                else
                  nil
                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.



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

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

.valid_template?(template) ⇒ Boolean

Returns:

  • (Boolean)


230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/pdk/util/template_uri.rb', line 230

def self.valid_template?(template)
  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?(git_remote(template[:uri]))

  path = human_readable(template[:uri].path)
  if File.directory?(path)
    begin
      PDK::Module::TemplateDir.new(path) {}
      return true
    rescue ArgumentError
      nil
    end
  end

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

  false
end

Instance Method Details

#==(other) ⇒ Object



58
59
60
# File 'lib/pdk/util/template_uri.rb', line 58

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

#default?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/pdk/util/template_uri.rb', line 115

def default?
  git_remote == self.class.default_template_uri.git_remote
end

#git_refObject



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

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

#git_ref=(ref) ⇒ Object



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

def git_ref=(ref)
  @uri.fragment = ref
end

#git_remoteObject

This is the url without a fragment, suitable for git clones.



79
80
81
# File 'lib/pdk/util/template_uri.rb', line 79

def git_remote
  self.class.git_remote(@uri)
end

#metadata_formatObject Also known as: to_s, to_str

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



66
67
68
69
70
71
72
# File 'lib/pdk/util/template_uri.rb', line 66

def 
  if self.class.packaged_template?(git_remote)
    self.class.human_readable("pdk-default##{git_ref}")
  else
    self.class.human_readable(@uri.to_s)
  end
end

#ref_is_tag?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/pdk/util/template_uri.rb', line 119

def ref_is_tag?
  PDK::Util::Git.git('ls-remote', '--tags', '--exit-code', git_remote, git_ref)[:exit_code].zero?
end

#shell_pathObject

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



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

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