File: tagging.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 (132 lines) | stat: -rw-r--r-- 3,753 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
# frozen_string_literal: true
require_relative '../../puppet/util/tag_set'

module Puppet::Util::Tagging
  ValidTagRegex = /\A[[:alnum:]_][[:alnum:]_:.-]*\Z/u

  # Add a tag to the current tag set.
  # When a tag set is used for a scope, these tags will be added to all of
  # the objects contained in this scope when the objects are finished.
  #
  def tag(*ary)
    @tags ||= new_tags

    ary.flatten.compact.each do |tag|
      name = tag.to_s.downcase
      # Add the tag before testing if it's valid since this means that
      # we never need to test the same valid tag twice. This speeds things
      # up since we get a lot of duplicates and rarely fail on bad tags
      if @tags.add?(name)
        # not seen before, so now we test if it is valid
        if valid_tag?(name)
          if split_qualified_tags?
          # avoid adding twice by first testing if the string contains '::'
            @tags.merge(name.split('::')) if name.include?('::')
          end
        else
          @tags.delete(name)
          fail(Puppet::ParseError, _("Invalid tag '%{name}'") % { name: name })
        end
      end
    end
  end

  # Add a name to the current tag set. Silently ignore names that does not
  # represent valid tags.
  # 
  # Use this method instead of doing this:
  #
  #  tag(name) if is_valid?(name)
  #
  # since that results in testing the same string twice
  #
  def tag_if_valid(name)
    if name.is_a?(String) && valid_tag?(name)
      name = name.downcase
      @tags ||= new_tags
      if @tags.add?(name) && name.include?('::')
        @tags.merge(name.split('::'))
      end
    end
  end

  # Answers if this resource is tagged with at least one of the given tags.
  #
  # The given tags are converted to downcased strings before the match is performed.
  #
  # @param *tags [String] splat of tags to look for
  # @return [Boolean] true if this instance is tagged with at least one of the provided tags
  #
  def tagged?(*tags)
    raw_tagged?(tags.collect {|t| t.to_s.downcase})
  end

  # Answers if this resource is tagged with at least one of the tags given in downcased string form.
  #
  # The method is a faster variant of the tagged? method that does no conversion of its
  # arguments.
  #
  # @param tag_array [Array[String]] array of tags to look for
  # @return [Boolean] true if this instance is tagged with at least one of the provided tags
  #
  def raw_tagged?(tag_array)
    my_tags = self.tags
    !tag_array.index { |t| my_tags.include?(t) }.nil?
  end

  # Only use this method when copying known tags from one Tagging instance to another
  def set_tags(tag_source)
    @tags = tag_source.tags
  end

  # Return a copy of the tag list, so someone can't ask for our tags
  # and then modify them.
  def tags
    @tags ||= new_tags
    @tags.dup
  end

  # Merge tags from a tagged instance with no attempts to split, downcase
  # or verify the tags
  def merge_tags_from(tag_source)
    @tags ||= new_tags
    tag_source.merge_into(@tags)
  end

  # Merge the tags of this instance into the provide TagSet
  def merge_into(tag_set)
    tag_set.merge(@tags) unless @tags.nil?
  end

  def tags=(tags)
    @tags = new_tags

    return if tags.nil?

    tags = tags.strip.split(/\s*,\s*/) if tags.is_a?(String)
    tag(*tags)
  end

  def valid_tag?(maybe_tag)
    begin
      tag_enc = maybe_tag.encoding
      if tag_enc == Encoding::UTF_8 || tag_enc == Encoding::ASCII
        maybe_tag =~ ValidTagRegex
      else
        maybe_tag.encode(Encoding::UTF_8) =~ ValidTagRegex
      end
    rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError
      false
    end
  end

  private

  def split_qualified_tags?
    true
  end

  def new_tags
    Puppet::Util::TagSet.new
  end
end