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}

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)



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/pdk/util/template_uri.rb', line 27

def initialize(opts_or_uri)
  # If a uri string is passed, skip the valid uri finding code.
  @uri = if opts_or_uri.is_a?(String) || opts_or_uri.is_a?(self.class)
           begin
             Addressable::URI.parse(opts_or_uri)
           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



13
14
15
# File 'lib/pdk/util/template_uri.rb', line 13

def uri
  @uri
end

Class Method Details

.default_template_refObject



185
186
187
188
189
190
191
# File 'lib/pdk/util/template_uri.rb', line 185

def self.default_template_ref
  if PDK::Util.development_mode?
    'master'
  else
    PDK::TEMPLATE_REF
  end
end

.default_template_uriObject



91
92
93
94
95
96
97
# File 'lib/pdk/util/template_uri.rb', line 91

def self.default_template_uri
  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')))
  else
    PDK::Util::TemplateURI.new('https://github.com/puppetlabs/pdk-templates')
  end
end

.first_valid_uri(templates_array) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/pdk/util/template_uri.rb', line 194

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



63
64
65
66
67
68
69
# File 'lib/pdk/util/template_uri.rb', line 63

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.



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

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



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/pdk/util/template_uri.rb', line 132

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
    # 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 = explicit_url.match(SCP_PATTERN)
    if Pathname.new(uri_safe(explicit_url)).relative? && scp_url
      explicit_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: explicit_url,
        rfc_uri: explicit_uri.to_s,
      }
    end
    explicit_uri ||= Addressable::URI.parse(uri_safe(explicit_url))
    explicit_uri.fragment = explicit_ref || default_template_ref
  else
    explicit_uri = nil
  end
   = if PDK::Util.module_root && File.file?(File.join(PDK::Util.module_root, 'metadata.json'))
                   Addressable::URI.parse(uri_safe(PDK::Util.['template-url']))
                 else
                   nil
                 end
  answers_uri = if PDK.answers['template-url'] == 'https://github.com/puppetlabs/pdk-module-template'
                  # use the new github template-url if it is still the old one.
                  Addressable::URI.parse(default_template_uri)
                elsif PDK.answers['template-url']
                  Addressable::URI.parse(uri_safe(PDK.answers['template-url']))
                else
                  nil
                end
  default_uri = Addressable::URI.parse(default_template_uri)
  default_uri.fragment = default_template_ref

  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 but are not handled here. Should they be?



112
113
114
# File 'lib/pdk/util/template_uri.rb', line 112

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

.valid_template?(template) ⇒ Boolean

Returns:

  • (Boolean)


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/pdk/util/template_uri.rb', line 205

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



42
43
44
# File 'lib/pdk/util/template_uri.rb', line 42

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

#default?Boolean

Returns:

  • (Boolean)


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

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

#git_refObject



78
79
80
81
82
83
84
# File 'lib/pdk/util/template_uri.rb', line 78

def git_ref
  if @uri.fragment
    @uri.fragment
  else
    self.class.default_template_ref
  end
end

#git_ref=(ref) ⇒ Object



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

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

#git_remoteObject

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



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

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.



50
51
52
# File 'lib/pdk/util/template_uri.rb', line 50

def 
  self.class.human_readable(@uri.to_s)
end

#ref_is_tag?Boolean

Returns:

  • (Boolean)


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

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.



73
74
75
# File 'lib/pdk/util/template_uri.rb', line 73

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