require 'puppet/pops' module Puppet; module Parser; end; end; # Adapts an egrammar/eparser to respond to the public API of the classic parser # class Puppet::Parser::EParserAdapter def initialize(classic_parser) @classic_parser = classic_parser @file = '' @string = '' @use = :undefined end def file=(file) @classic_parser.file = file @file = file @use = :file end def parse(string = nil) if @file =~ /\.rb$/ return parse_ruby_file else self.string= string if string parser = Puppet::Pops::Parser::Parser.new() parse_result = if @use == :string parser.parse_string(@string) else parser.parse_file(@file) end # Compute the source_file to set in created AST objects (it was either given, or it may be unknown # if caller did not set a file and the present a string. # source_file = @file || "unknown-source-location" # Validate validate(parse_result) # Transform the result, but only if not nil parse_result = Puppet::Pops::Model::AstTransformer.new(source_file, @classic_parser).transform(parse_result) if parse_result if parse_result && !parse_result.is_a?(Puppet::Parser::AST::BlockExpression) # Need to transform again, if result is not wrapped in something iterable when handed off to # a new Hostclass as its code. parse_result = Puppet::Parser::AST::BlockExpression.new(:children => [parse_result]) if parse_result end end Puppet::Parser::AST::Hostclass.new('', :code => parse_result) end def validate(parse_result) # TODO: This is too many hoops to jump through... ugly API # could reference a ValidatorFactory.validator_3_1(acceptor) instead. # and let the factory abstract the rest. # return unless parse_result acceptor = Puppet::Pops::Validation::Acceptor.new validator = Puppet::Pops::Validation::ValidatorFactory_3_1.new().validator(acceptor) validator.validate(parse_result) max_errors = Puppet[:max_errors] max_warnings = Puppet[:max_warnings] + 1 max_deprecations = Puppet[:max_deprecations] + 1 # If there are warnings output them warnings = acceptor.warnings if warnings.size > 0 formatter = Puppet::Pops::Validation::DiagnosticFormatterPuppetStyle.new emitted_w = 0 emitted_dw = 0 acceptor.warnings.each {|w| if w.severity == :deprecation # Do *not* call Puppet.deprecation_warning it is for internal deprecation, not # deprecation of constructs in manifests! (It is not designed for that purpose even if # used throughout the code base). # Puppet.warning(formatter.format(w)) if emitted_dw < max_deprecations emitted_dw += 1 else Puppet.warning(formatter.format(w)) if emitted_w < max_warnings emitted_w += 1 end break if emitted_w > max_warnings && emitted_dw > max_deprecations # but only then } end # If there were errors, report the first found. Use a puppet style formatter. errors = acceptor.errors if errors.size > 0 formatter = Puppet::Pops::Validation::DiagnosticFormatterPuppetStyle.new if errors.size == 1 || max_errors <= 1 # raise immediately raise Puppet::ParseError.new(formatter.format(errors[0])) end emitted = 0 errors.each do |e| Puppet.err(formatter.format(e)) emitted += 1 break if emitted >= max_errors end warnings_message = warnings.size > 0 ? ", and #{warnings.size} warnings" : "" giving_up_message = "Found #{errors.size} errors#{warnings_message}. Giving up" exception = Puppet::ParseError.new(giving_up_message) exception.file = errors[0].file raise exception end end def string=(string) @classic_parser.string = string @string = string @use = :string end def parse_ruby_file @classic_parser.parse end end