summaryrefslogtreecommitdiffstats
path: root/lib/puppet/module.rb
blob: 9385812b1a0c3ce8561dfb4b8bb2c3aa498d56ed (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# Support for modules
class Puppet::Module

    TEMPLATES = "templates"
    FILES = "files"
    MANIFESTS = "manifests"
    
    # Return an array of paths by splitting the +modulepath+ config
    # parameter. Only consider paths that are absolute and existing
    # directories
    def self.modulepath(environment = nil)
        dirs = Puppet.settings.value(:modulepath, environment).split(":")
        if ENV["PUPPETLIB"]
            dirs = ENV["PUPPETLIB"].split(":") + dirs
        else
        end
        dirs.select do |p|
            p =~ /^#{File::SEPARATOR}/ && File::directory?(p)
        end
    end

    # Return an array of paths by splitting the +templatedir+ config
    # parameter.
    def self.templatepath(environment = nil)
        dirs = Puppet.settings.value(:templatedir, environment).split(":")
        dirs.select do |p|
            p =~ /^#{File::SEPARATOR}/ && File::directory?(p)
        end
    end

    # Find and return the +module+ that +path+ belongs to. If +path+ is
    # absolute, or if there is no module whose name is the first component
    # of +path+, return +nil+
    def self.find(modname, environment = nil)
        if modname =~ %r/^#{File::SEPARATOR}/
            return nil
        end

        modpath = modulepath(environment).collect { |path|
            File::join(path, modname)
        }.find { |f| File::directory?(f) }
        return nil unless modpath

        return self.new(modname, modpath)
    end

    # Return an array of the full path of every subdirectory in each
    # directory in the modulepath.
    def self.all(environment = nil)
        modulepath(environment).map do |mp|
            Dir.new(mp).map do |modfile|
                modpath = File.join(mp, modfile)
                unless modfile == '.' or modfile == '..' or !File.directory?(modpath)
                    modpath
                else
                    nil
                end
            end
        end.flatten.compact
    end

    # Instance methods

    # Find the concrete file denoted by +file+. If +file+ is absolute,
    # return it directly. Otherwise try to find it as a template in a
    # module. If that fails, return it relative to the +templatedir+ config
    # param.
    # In all cases, an absolute path is returned, which does not
    # necessarily refer to an existing file
    def self.find_template(template, environment = nil)
        if template =~ /^#{File::SEPARATOR}/
            return template
        end

        template_paths = templatepath(environment)
        if template_paths
            # If we can find the template in :templatedir, we return that.
            td_file = template_paths.collect { |path|
                File::join(path, template)
            }.find { |f| File.exists?(f) }

            return td_file unless td_file == nil
        end

        td_file = find_template_for_module(template, environment)

        # check in the default template dir, if there is one
        if td_file.nil?
            raise Puppet::Error, "No valid template directory found, please check templatedir settings" if template_paths.nil?
            td_file = File::join(template_paths.first, template)
        end
        td_file
    end

    def self.find_template_for_module(template, environment = nil)
        path, file = split_path(template)

        # Because templates don't have an assumed template name, like manifests do,
        # we treat templates with no name as being templates in the main template
        # directory.
        if not file.nil?
            mod = find(path, environment)
            if mod
                return mod.template(file)
            end
        end
        nil
    end

    # Return a list of manifests (as absolute filenames) that match +pat+
    # with the current directory set to +cwd+. If the first component of
    # +pat+ does not contain any wildcards and is an existing module, return
    # a list of manifests in that module matching the rest of +pat+
    # Otherwise, try to find manifests matching +pat+ relative to +cwd+
    def self.find_manifests(start, options = {})
        cwd = options[:cwd] || Dir.getwd
        module_name, pattern = split_path(start)
        if module_name and mod = find(module_name, options[:environment])
            return mod.manifests(pattern)
        else
            abspat = File::expand_path(start, cwd)
            files = Dir.glob(abspat).reject { |f| FileTest.directory?(f) }
            if files.size == 0
                files = Dir.glob(abspat + ".pp").reject { |f| FileTest.directory?(f) }
            end
            return files
        end
    end

    # Split the path into the module and the rest of the path.
    # This method can and often does return nil, so anyone calling
    # it needs to handle that.
    def self.split_path(path)
        if path =~ %r/^#{File::SEPARATOR}/
            return nil
        end

        modname, rest = path.split(File::SEPARATOR, 2)
        return nil if modname.nil? || modname.empty?
        return modname, rest
    end

    attr_reader :name, :path
    def initialize(name, path)
        @name = name
        @path = path
    end

    def template(file)
        return File::join(path, TEMPLATES, file)
    end

    def files
        return File::join(path, FILES)
    end

    # Return the list of manifests matching the given glob pattern,
    # defaulting to 'init.pp' for empty modules.
    def manifests(rest)
        rest ||= "init.pp"
        p = File::join(path, MANIFESTS, rest)
        files = Dir.glob(p).reject { |f| FileTest.directory?(f) }
        if files.size == 0
            files = Dir.glob(p + ".pp")
        end
        return files
    end

    private :initialize
    private_class_method :find_template_for_module
end