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
|