File: type_loader.rb

package info (click to toggle)
puppet-agent 7.23.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 19,092 kB
  • sloc: ruby: 245,074; sh: 456; makefile: 38; xml: 33
file content (150 lines) | stat: -rw-r--r-- 4,356 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require 'find'
require 'forwardable'
require_relative '../../puppet/parser/parser_factory'

class Puppet::Parser::TypeLoader
  extend  Forwardable

  class TypeLoaderError < StandardError; end

  # Import manifest files that match a given file glob pattern.
  #
  # @param pattern [String] the file glob to apply when determining which files
  #   to load
  # @param dir [String] base directory to use when the file is not
  #   found in a module
  # @api private
  def import(pattern, dir)
    modname, files = Puppet::Parser::Files.find_manifests_in_modules(pattern, environment)
    if files.empty?
      abspat = File.expand_path(pattern, dir)
      file_pattern = abspat + (File.extname(abspat).empty? ? '.pp' : '' )

      files = Dir.glob(file_pattern).uniq.reject { |f| FileTest.directory?(f) }
      modname = nil

      if files.empty?
        raise_no_files_found(pattern)
      end
    end

    load_files(modname, files)
  end

  # Load all of the manifest files in all known modules.
  # @api private
  def import_all
    # And then load all files from each module, but (relying on system
    # behavior) only load files from the first module of a given name.  E.g.,
    # given first/foo and second/foo, only files from first/foo will be loaded.
    environment.modules.each do |mod|
      load_files(mod.name, mod.all_manifests)
    end
  end

  def_delegator :environment, :known_resource_types

  def initialize(env)
    self.environment = env
  end

  def environment
    @environment
  end

  def environment=(env)
    if env.is_a?(String) or env.is_a?(Symbol)
      @environment = Puppet.lookup(:environments).get!(env)
    else
      @environment = env
    end
  end

  # Try to load the object with the given fully qualified name.
  def try_load_fqname(type, fqname)
    return nil if fqname == "" # special-case main.
    files_to_try_for(fqname).each do |filename|
      begin
        imported_types = import_from_modules(filename)
        result = imported_types.find { |t| t.type == type and t.name == fqname }
        if result
          Puppet.debug {"Automatically imported #{fqname} from #{filename} into #{environment}"}
          return result
        end
      rescue TypeLoaderError
        # I'm not convinced we should just drop these errors, but this
        # preserves existing behaviours.
      end
    end
    # Nothing found.
    return nil
  end

  def parse_file(file)
    Puppet.debug { "importing '#{file}' in environment #{environment}" }
    parser = Puppet::Parser::ParserFactory.parser
    parser.file = file
    return parser.parse
  end

  private

  def import_from_modules(pattern)
    modname, files = Puppet::Parser::Files.find_manifests_in_modules(pattern, environment)
    if files.empty?
      raise_no_files_found(pattern)
    end

    load_files(modname, files)
  end

  def raise_no_files_found(pattern)
    raise TypeLoaderError, _("No file(s) found for import of '%{pattern}'") % { pattern: pattern }
  end

  def load_files(modname, files)
    @loaded ||= {}
    loaded_asts = []
    files.reject { |file| @loaded[file] }.each do |file|
    # The squelch_parse_errors use case is for parsing for the purpose of searching
    # for information and it should not abort.
    # There is currently one user in indirector/resourcetype/parser
    #
    if Puppet.lookup(:squelch_parse_errors) {|| false }
      begin
        loaded_asts << parse_file(file)
      rescue => e
        # Resume from errors so that all parseable files may
        # still be parsed. Mark this file as loaded so that
        # it would not be parsed next time (handle it as if
        # it was successfully parsed).
        Puppet.debug { "Unable to parse '#{file}': #{e.message}" }
      end
    else
      loaded_asts << parse_file(file)
    end

    @loaded[file] = true
    end

    loaded_asts.collect do |ast|
      known_resource_types.import_ast(ast, modname)
    end.flatten
  end

  # Return a list of all file basenames that should be tried in order
  # to load the object with the given fully qualified name.
  def files_to_try_for(qualified_name)
    qualified_name.split('::').inject([]) do |paths, name|
      add_path_for_name(paths, name)
    end
  end

  def add_path_for_name(paths, name)
    if paths.empty?
      [name]
    else
      paths.unshift(File.join(paths.first, name))
    end
  end
end