1
require 'puppet/util/logging'
1
3
# Support for modules
5
include Puppet::Util::Logging
7
class InvalidName < ArgumentError
9
"Invalid module name; module names must be alphanumeric (plus '-')"
4
13
TEMPLATES = "templates"
6
15
MANIFESTS = "manifests"
18
FILETYPES = [MANIFESTS, FILES, TEMPLATES, PLUGINS]
8
20
# Return an array of paths by splitting the +modulepath+ config
9
21
# parameter. Only consider paths that are absolute and existing
11
23
def self.modulepath(environment = nil)
12
dirs = Puppet.settings.value(:modulepath, environment).split(":")
14
dirs = ENV["PUPPETLIB"].split(":") + dirs
18
p =~ /^#{File::SEPARATOR}/ && File::directory?(p)
22
# Return an array of paths by splitting the +templatedir+ config
24
def self.templatepath(environment = nil)
25
dirs = Puppet.settings.value(:templatedir, environment).split(":")
24
Puppet::Node::Environment.new(environment).modulepath
31
27
# Find and return the +module+ that +path+ belongs to. If +path+ is
32
28
# absolute, or if there is no module whose name is the first component
33
29
# of +path+, return +nil+
34
30
def self.find(modname, environment = nil)
35
if modname =~ %r/^#{File::SEPARATOR}/
39
modpath = modulepath(environment).collect { |path|
40
File::join(path, modname)
41
}.find { |f| File::directory?(f) }
42
return nil unless modpath
44
return self.new(modname, modpath)
47
# Return an array of the full path of every subdirectory in each
48
# directory in the modulepath.
49
def self.all(environment = nil)
50
modulepath(environment).map do |mp|
51
Dir.new(mp).map do |modfile|
52
modpath = File.join(mp, modfile)
53
unless modfile == '.' or modfile == '..' or !File.directory?(modpath)
64
# Find the concrete file denoted by +file+. If +file+ is absolute,
65
# return it directly. Otherwise try to find it as a template in a
66
# module. If that fails, return it relative to the +templatedir+ config
68
# In all cases, an absolute path is returned, which does not
69
# necessarily refer to an existing file
70
def self.find_template(template, environment = nil)
71
if template =~ /^#{File::SEPARATOR}/
75
template_paths = templatepath(environment)
77
# If we can find the template in :templatedir, we return that.
78
td_file = template_paths.collect { |path|
79
File::join(path, template)
80
}.find { |f| File.exists?(f) }
82
return td_file unless td_file == nil
85
td_file = find_template_for_module(template, environment)
87
# check in the default template dir, if there is one
89
raise Puppet::Error, "No valid template directory found, please check templatedir settings" if template_paths.nil?
90
td_file = File::join(template_paths.first, template)
95
def self.find_template_for_module(template, environment = nil)
96
path, file = split_path(template)
98
# Because templates don't have an assumed template name, like manifests do,
99
# we treat templates with no name as being templates in the main template
102
mod = find(path, environment)
104
return mod.template(file)
110
# Return a list of manifests (as absolute filenames) that match +pat+
111
# with the current directory set to +cwd+. If the first component of
112
# +pat+ does not contain any wildcards and is an existing module, return
113
# a list of manifests in that module matching the rest of +pat+
114
# Otherwise, try to find manifests matching +pat+ relative to +cwd+
115
def self.find_manifests(start, options = {})
116
cwd = options[:cwd] || Dir.getwd
117
module_name, pattern = split_path(start)
118
if module_name and mod = find(module_name, options[:environment])
119
return mod.manifests(pattern)
121
abspat = File::expand_path(start, cwd)
122
files = Dir.glob(abspat).reject { |f| FileTest.directory?(f) }
124
files = Dir.glob(abspat + ".pp").reject { |f| FileTest.directory?(f) }
130
# Split the path into the module and the rest of the path.
131
# This method can and often does return nil, so anyone calling
132
# it needs to handle that.
133
def self.split_path(path)
134
if path =~ %r/^#{File::SEPARATOR}/
138
modname, rest = path.split(File::SEPARATOR, 2)
139
return nil if modname.nil? || modname.empty?
143
attr_reader :name, :path
144
def initialize(name, path)
31
return nil unless modname
32
Puppet::Node::Environment.new(environment).module(modname)
35
attr_reader :name, :environment
36
attr_writer :environment
38
def initialize(name, environment = nil)
150
return File::join(path, TEMPLATES, file)
154
return File::join(path, FILES)
43
if environment.is_a?(Puppet::Node::Environment)
44
@environment = environment
46
@environment = Puppet::Node::Environment.new(environment)
50
FILETYPES.each do |type|
51
# A boolean method to let external callers determine if
52
# we have files of a given type.
53
define_method(type +'?') do
54
return false unless path
55
return false unless FileTest.exist?(subpath(type))
59
# A method for returning a given file of a given type.
60
# e.g., file = mod.manifest("my/manifest.pp")
62
# If the file name is nil, then the base directory for the
63
# file type is passed; this is used for fileserving.
64
define_method(type.to_s.sub(/s$/, '')) do |file|
65
return nil unless path
67
# If 'file' is nil then they're asking for the base path.
68
# This is used for things like fileserving.
70
full_path = File.join(subpath(type), file)
72
full_path = subpath(type)
75
return nil unless FileTest.exist?(full_path)
84
# Find the first 'files' directory. This is used by the XMLRPC fileserver.
157
89
# Return the list of manifests matching the given glob pattern,
158
90
# defaulting to 'init.pp' for empty modules.
91
def match_manifests(rest)
92
return find_init_manifest unless rest # Use init.pp
160
94
rest ||= "init.pp"
161
95
p = File::join(path, MANIFESTS, rest)
162
files = Dir.glob(p).reject { |f| FileTest.directory?(f) }
164
files = Dir.glob(p + ".pp")
170
private_class_method :find_template_for_module
96
result = Dir.glob(p).reject { |f| FileTest.directory?(f) }
97
if result.size == 0 and rest !~ /\.pp$/
98
result = Dir.glob(p + ".pp")
100
result.flatten.compact
103
# Find this module in the modulepath.
105
environment.modulepath.collect { |path| File.join(path, name) }.find { |d| FileTest.exist?(d) }
108
# Find all plugin directories. This is used by the Plugins fileserving mount.
114
result = "Module %s" % name
116
result += "(%s)" % path
123
def find_init_manifest
124
return [] unless file = manifest("init.pp")
129
return File.join(path, type) unless type.to_s == "plugins"
131
return backward_compatible_plugins_dir
134
def backward_compatible_plugins_dir
135
if dir = File.join(path, "plugins") and FileTest.exist?(dir)
136
warning "using the deprecated 'plugins' directory for ruby extensions; please move to 'lib'"
139
return File.join(path, "lib")
144
raise InvalidName unless name =~ /^[-\w]+$/