lib/facter/framework/parsers/query_parser.rb in facter-4.5.1 vs lib/facter/framework/parsers/query_parser.rb in facter-4.5.2

- old
+ new

@@ -16,22 +16,22 @@ # e.g. impaddress_end160 # # Because a root fact will always be resolved by a collection of child facts, # we can return one or more child facts for each parent. # - # query - is the user input used to search for facts - # loaded_fact - is a list with all facts for the current operating system + # @param query_list [Array] The list of facts to search for + # @param loaded_facts [Array] All of the fact definitions for the current operating system # - # Returns a list of SearchedFact objects that resolve the users query. - def parse(query_list, loaded_fact) + # @return [Array<SearchedFact>] a list of searchable facts that resolve the user's query + def parse(query_list, loaded_facts) matched_facts = [] @query_list = query_list - return no_user_query(loaded_fact) unless query_list.any? + return no_user_query(loaded_facts) unless query_list.any? query_list.each do |query| - found_facts = search_for_facts(query, loaded_fact) + found_facts = search_for_facts(query, loaded_facts) matched_facts << found_facts end matched_facts.flatten(1) end @@ -42,34 +42,34 @@ searched_facts << SearchedFact.new(loaded_fact.name, loaded_fact.klass, '', loaded_fact.type) end searched_facts end - def search_for_facts(query, loaded_fact_hash) + def search_for_facts(query, loaded_facts) resolvable_fact_list = [] query = query.to_s query_tokens = query.end_with?('.*') ? [query] : query.split('.') size = query_tokens.size + # Try to match the most specific query_tokens to the least, returning the first match size.times do |i| query_token_range = 0..size - i - 1 - resolvable_fact_list = get_facts_matching_tokens(query_tokens, query_token_range, loaded_fact_hash) + query_fact = query_tokens[query_token_range].join('.') + resolvable_fact_list = get_facts_matching_tokens(query_tokens, query_fact, loaded_facts) return resolvable_fact_list if resolvable_fact_list.any? end resolvable_fact_list << SearchedFact.new(query, nil, query, :nil) if resolvable_fact_list.empty? resolvable_fact_list end - def get_facts_matching_tokens(query_tokens, query_token_range, loaded_fact_hash) + def get_facts_matching_tokens(query_tokens, query_fact, loaded_facts) resolvable_fact_list = [] - loaded_fact_hash.each do |loaded_fact| - query_fact = query_tokens[query_token_range].join('.') - + loaded_facts.each do |loaded_fact| next unless found_fact?(loaded_fact.name, query_fact) searched_fact = construct_loaded_fact(query_tokens, loaded_fact) resolvable_fact_list << searched_fact end @@ -77,19 +77,23 @@ @log.debug "List of resolvable facts: #{resolvable_fact_list.inspect}" if resolvable_fact_list.any? resolvable_fact_list end def found_fact?(fact_name, query_fact) + # This is the case where the fact_name contains a wildcard like + # blockdevice_.*_model and we're querying for the legacy fact + # specifically using 'blockdevice_sba_model' and we don't want the query + # 'blockdevice.sba.model' to match fact_with_wildcard = fact_name.include?('.*') && !query_fact.include?('.') - processed_equery_fact = query_fact.gsub('\\', '\\\\\\\\') - - return false if fact_with_wildcard && !query_fact.match("^#{fact_name}$") - - # Must escape metacharacters (like dots) to ensure the correct fact is found - return false unless fact_with_wildcard || fact_name.match("^#{Regexp.escape(processed_equery_fact)}($|\\.)") - - true + if fact_with_wildcard + # fact_name contains wildcard, so we're intentially not escaping. + query_fact.match("^#{fact_name}$") + else + processed_equery_fact = query_fact.gsub('\\', '\\\\\\\\') + # Must escape metacharacters (like dots) to ensure the correct fact is found + fact_name.match("^#{Regexp.escape(processed_equery_fact)}($|\\.)") + end end def construct_loaded_fact(query_tokens, loaded_fact) user_query = @query_list.any? ? query_tokens.join('.') : '' fact_name = loaded_fact.name.to_s