Skip to content

Commit

Permalink
Merge pull request #3291 from seanmil/get_target_performance
Browse files Browse the repository at this point in the history
Improve inventory target name resolution
  • Loading branch information
donoghuc authored May 22, 2024
2 parents b748ae6 + 4d6e563 commit b42739f
Showing 1 changed file with 30 additions and 10 deletions.
40 changes: 30 additions & 10 deletions lib/bolt/inventory/inventory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class Inventory
EXTENDED_TARGET_REGEX = /[[:space:],]+(?=[^\]}]*(?:[\[{]|$))/.freeze
TARGET_REGEX = /[[:space:],]+/.freeze

# Pattern which looks for indicators that glob-based target name matching
# should be used.
GLOB_MATCH_REGEX = /[*?\[\]{}]/.freeze

class WildcardError < Bolt::Error
def initialize(target)
super("Found 0 targets matching wildcard pattern #{target}", 'bolt.inventory/wildcard-error')
Expand Down Expand Up @@ -119,19 +123,36 @@ def match_wildcard?(wildcard, target_name, ext_glob: false)
if ext_glob
File.fnmatch(wildcard, target_name, File::FNM_CASEFOLD | File::FNM_EXTGLOB)
else
regexp = Regexp.new("^#{Regexp.escape(wildcard).gsub('\*', '.*?')}$", Regexp::IGNORECASE)
target_name =~ regexp
File.fnmatch(wildcard, target_name, File::FNM_CASEFOLD)
end
end

# If target is a group name, expand it to the members of that group.
# Else match against groups and targets in inventory by name or alias.
# If a wildcard string, error if no matches are found.
# Attempt exact matches for groups, targets, and aliases first for speed.
# If no exact match and the string contains wildcard characters, then check
# and see if the target string might be a URI, if it parses as a URI with
# a scheme then return as-is, otherwise look for a wildcard match and
# error if no matches are found.
# Else fall back to [target] if no matches are found.
def resolve_name(target, ext_glob: false)
if (group = group_lookup[target])
group.all_targets.to_a
else
elsif @targets.key?(target)
[target]
elsif (real_target = groups.target_aliases[target])
[real_target]
elsif GLOB_MATCH_REGEX.match?(target)
# URIs and glob wildcards have some overlapping characters. If the target
# being resolved parses as a valid target URI and has a scheme defined then
# return it as-is and do not try to do further wildcard matching:
uri = begin
Bolt::Inventory::Target.parse_uri(target)
rescue Bolt::ParseError
nil
end
return [target] if uri&.scheme

targets = []

# Find groups that match the glob
Expand All @@ -148,12 +169,11 @@ def resolve_name(target, ext_glob: false)
.select { |tgt_alias, _| match_wildcard?(target, tgt_alias, ext_glob: ext_glob) }
.values

if targets.empty?
raise(WildcardError, target) if target.include?('*')
[target]
else
targets.uniq
end
raise(WildcardError, target) if targets.empty?

targets.uniq
else # rubocop:disable Lint/DuplicateBranch
[target]
end
end
private :resolve_name
Expand Down

0 comments on commit b42739f

Please sign in to comment.