summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/loaded_code.rb
blob: d7f179ae70a743b12841d46670c734dba7128f79 (plain)
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
class Puppet::Parser::LoadedCode
    def initialize
        @hostclasses = {}
        @definitions = {}
        @nodes = {}

        # So we can keep a list and match the first-defined regex
        @node_list = []
    end

    def <<(thing)
        add(thing)
        self
    end

    def add(instance)
        method = "add_#{instance.type}"
        send(method, instance)
        instance.code_collection = self
        instance
    end

    def add_hostclass(instance)
        dupe_check(instance, @hostclasses) { |dupe| "Class #{instance.name} is already defined#{dupe.error_context}; cannot redefine" }
        dupe_check(instance, @definitions) { |dupe| "Definition #{instance.name} is already defined#{dupe.error_context}; cannot be redefined as a class" }

        @hostclasses[instance.name] = instance
        instance
    end

    def hostclass(name)
        @hostclasses[munge_name(name)]
    end

    def add_node(instance)
        dupe_check(instance, @nodes) { |dupe| "Node #{instance.name} is already defined#{dupe.error_context}; cannot redefine" }

        @node_list << instance
        @nodes[instance.name] = instance
        instance
    end

    def node(name)
        name = munge_name(name)

        if node = @nodes[name]
            return node
        end

        @node_list.each do |node|
            next unless node.name_is_regex?
            return node if node.match(name)
        end
        nil
    end

    def node_exists?(name)
        @nodes[munge_name(name)]
    end

    def nodes?
        @nodes.length > 0
    end

    def add_definition(code)
        @definitions[code.name] = code
    end

    def definition(name)
        @definitions[munge_name(name)]
    end

    def find(namespace, name, type)
        if r = find_fully_qualified(name, type)
            return r
        end

        ary = namespace.split("::")

        while ary.length > 0
            tmp_namespace = ary.join("::")
            if r = find_partially_qualified(tmp_namespace, name, type)
                return r
            end

            # Delete the second to last object, which reduces our namespace by one.
            ary.pop
        end

        send(type, name)
    end

    def find_node(name)
        find("", name, :node)
    end

    def find_hostclass(namespace, name)
        find(namespace, name, :hostclass)
    end

    def find_definition(namespace, name)
        find(namespace, name, :definition)
    end

    [:hostclasses, :nodes, :definitions].each do |m|
        define_method(m) do
            instance_variable_get("@#{m}").dup
        end
    end

    private

    def find_fully_qualified(name, type)
        return nil unless name =~ /^::/

        name = name.sub(/^::/, '')

        send(type, name)
    end

    def find_partially_qualified(namespace, name, type)
        send(type, [namespace, name].join("::"))
    end

    def munge_name(name)
        name.to_s.downcase
    end

    def dupe_check(instance, hash)
        return unless dupe = hash[instance.name]
        message = yield dupe
        instance.fail Puppet::ParseError, message
    end
end